Package: debianutils
Version: 3.4
Severity: normal
Replying to:
#404772 Please enhance run-parts to visually distinguish jobs in email
I had the same problem and just wrote a solution for it. The following
patch adds a new parameter --prefix or -p to run-parts. It puts another
command call in front of each script. In combination with another
script, which sends the output of a command by mail only if there is any
output or the exit code is != 0, this seems to solve exactly what is
asked in this bug report.
I think, the code (at least the run-parts script) is "ready for production"
the mailiffail script is only a demo and is currently missing a cleanup
trigger.
Attachments:
patch_full.diff - the patch for run-parts.c, tested against version
3.4 in squeeze
runtests.sh - additionally: a little script for testing the new
feature
runtests-out.txt - the test output
mailiffail - a sample script for the mail job
mailiffail-crontab.diff - the changes in the /etc/crontab file
Btw: sorry if my mail format is a bit unusual. I'm not very experience
with the debian bts and it's not easy for newbies to handle it. I hope
they switch to something like launchpad at least next century...
Daniel Alder
-- System Information:
Debian Release: 6.0.6
APT prefers stable
APT policy: (500, 'stable')
Architecture: i386 (x86_64)
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)
Shell: /bin/sh linked to /bin/dash
Versions of packages debianutils depends on:
ii libc6 2.11.3-4 Embedded GNU C Library:
Shared lib
ii sensible-utils 0.0.4 Utilities for sensible
alternative
debianutils recommends no packages.
debianutils suggests no packages.
-- no debconf information
--- run-parts.c_realorig 2013-01-20 22:51:13.000000000 +0100
+++ run-parts.c 2013-01-20 23:01:19.000000000 +0100
@@ -45,7 +45,7 @@
int exit_on_error_mode = 0;
int new_session_mode = 0;
-int argcount = 0, argsize = 0;
+int argcount = 0, argsize = 0, argsprogpos = 0;
char **args = 0;
char *custom_ere;
@@ -97,6 +97,7 @@
" --regex=PATTERN validate filenames based on POSIX ERE pattern PATTERN.\n"
" -u, --umask=UMASK sets umask to UMASK (octal), default is 022.\n"
" -a, --arg=ARGUMENT pass ARGUMENT to scripts, use once for each argument.\n"
+ " -p, --prefix=CMD run scripts over CMD\n"
" -V, --version output version information and exit.\n"
" -h, --help display this help and exit.\n");
exit(0);
@@ -135,6 +136,24 @@
args[argcount] = 0;
}
+/* Add an argument at the end of the prefix list, right before the progname
+ * placeholder. */
+void add_prefix(char *newarg)
+{
+ if (argcount + 1 >= argsize) {
+ argsize = argsize ? argsize * 2 : 4;
+ args = realloc(args, argsize * (sizeof(char *)));
+ if (!args) {
+ error("failed to reallocate memory for arguments: %s", strerror(errno));
+ exit(1);
+ }
+ }
+ memmove(&args[argsprogpos+1], &args[argsprogpos],
+ (argcount-argsprogpos) * (sizeof(char *)));
+ args[argsprogpos++] = newarg;
+ args[++argcount] = 0;
+}
+
/* True or false? Is this a valid filename? */
int valid_name(const struct dirent *d)
{
@@ -189,8 +208,8 @@
close(pout[1]);
close(perr[1]);
}
- args[0] = progname;
- execv(progname, args);
+ args[argsprogpos] = progname;
+ execv(args[0], args);
error("failed to exec %s: %s", progname, strerror(errno));
exit(1);
}
@@ -352,9 +371,11 @@
if (argcount) {
char **a = args;
- fprintf(stderr, "run-parts: executing %s", filename);
- while(*(++a))
+ fprintf(stderr, "run-parts: executing");
+ args[argsprogpos] = filename;
+ do {
fprintf(stderr, " %s", *a);
+ } while(*(++a));
fprintf(stderr, "\n");
} else {
fprintf(stderr, "run-parts: executing %s\n", filename);
@@ -394,6 +415,9 @@
{
custom_ere = NULL;
umask(022);
+
+ // placeholder for progname
+ argsprogpos = 0;
add_argument(0);
for (;;) {
@@ -414,10 +438,11 @@
{"regex", 1, ®ex_mode, RUNPARTS_ERE},
{"exit-on-error", 0, &exit_on_error_mode, 1},
{"new-session", 0, &new_session_mode, 1},
+ {"prefix", 1, 0, 'p'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "u:ha:vV", long_options, &option_index);
+ c = getopt_long(argc, argv, "u:ha:p:vV", long_options, &option_index);
if (c == EOF)
break;
switch (c) {
@@ -432,6 +457,9 @@
case 'a':
add_argument(optarg);
break;
+ case 'p':
+ add_prefix(optarg);
+ break;
case 'h':
usage();
break;
#!/bin/sh
rm -Rf test
mkdir test
mkdir test/scripts
cat >test/scripts/a.sh <<.e
#!/bin/sh
echo " DIRECT CALL scripts/a: "
echo " \$0 \$@"
..e
cat >test/scripts/b.sh <<.e
#!/bin/sh
echo " DIRECT CALL scripts/a: "
echo " \$0 \$@"
..e
cat >test/scripts/c.sh <<.e
#!/bin/sh
echo " DIRECT CALL scripts/a: "
echo " \$0 \$@"
..e
cat >test/runner.sh <<.e
#!/bin/sh
echo " INDIRECT CALL: "
echo " \$0 \$@"
..e
chmod +x test/scripts/*.sh test/runner.sh
runtest() {
(
set -x
./run-parts -v --regex '\.sh' "$@" test/scripts
)
}
echo
echo "== Test direct without args =="
runtest
echo
echo "== Test direct with args =="
runtest -a arg1 -a arg2 -a arg3
echo
echo "== Test indirect with prefix =="
runtest -p test/runner.sh
echo
echo "== Test indirect with prefixes =="
runtest -p test/runner.sh -p parg1 -p parg2
echo
echo "== Test indirect with prefixes and args, mixed =="
runtest -p test/runner.sh -a arg1 -p parg1 -a arg2 -p parg2 -p parg3
echo
== Test direct without args ==
+ ./run-parts -v --regex \.sh test/scripts
run-parts: executing test/scripts/a.sh
DIRECT CALL scripts/a:
test/scripts/a.sh
run-parts: executing test/scripts/b.sh
DIRECT CALL scripts/a:
test/scripts/b.sh
run-parts: executing test/scripts/c.sh
DIRECT CALL scripts/a:
test/scripts/c.sh
== Test direct with args ==
+ ./run-parts -v --regex \.sh -a arg1 -a arg2 -a arg3 test/scripts
run-parts: executing test/scripts/a.sh arg1 arg2 arg3
DIRECT CALL scripts/a:
test/scripts/a.sh arg1 arg2 arg3
run-parts: executing test/scripts/b.sh arg1 arg2 arg3
DIRECT CALL scripts/a:
test/scripts/b.sh arg1 arg2 arg3
run-parts: executing test/scripts/c.sh arg1 arg2 arg3
DIRECT CALL scripts/a:
test/scripts/c.sh arg1 arg2 arg3
== Test indirect with prefix ==
+ ./run-parts -v --regex \.sh -p test/runner.sh test/scripts
run-parts: executing test/runner.sh test/scripts/a.sh
INDIRECT CALL:
test/runner.sh test/scripts/a.sh
run-parts: executing test/runner.sh test/scripts/b.sh
INDIRECT CALL:
test/runner.sh test/scripts/b.sh
run-parts: executing test/runner.sh test/scripts/c.sh
INDIRECT CALL:
test/runner.sh test/scripts/c.sh
== Test indirect with prefixes ==
+ ./run-parts -v --regex \.sh -p test/runner.sh -p parg1 -p parg2 test/scripts
run-parts: executing test/runner.sh parg1 parg2 test/scripts/a.sh
INDIRECT CALL:
test/runner.sh parg1 parg2 test/scripts/a.sh
run-parts: executing test/runner.sh parg1 parg2 test/scripts/b.sh
INDIRECT CALL:
test/runner.sh parg1 parg2 test/scripts/b.sh
run-parts: executing test/runner.sh parg1 parg2 test/scripts/c.sh
INDIRECT CALL:
test/runner.sh parg1 parg2 test/scripts/c.sh
== Test indirect with prefixes and args, mixed ==
+ ./run-parts -v --regex \.sh -p test/runner.sh -a arg1 -p parg1 -a arg2 -p
parg2 -p parg3 test/scripts
run-parts: executing test/runner.sh parg1 parg2 parg3 test/scripts/a.sh arg1
arg2
INDIRECT CALL:
test/runner.sh parg1 parg2 parg3 test/scripts/a.sh arg1 arg2
run-parts: executing test/runner.sh parg1 parg2 parg3 test/scripts/b.sh arg1
arg2
INDIRECT CALL:
test/runner.sh parg1 parg2 parg3 test/scripts/b.sh arg1 arg2
run-parts: executing test/runner.sh parg1 parg2 parg3 test/scripts/c.sh arg1
arg2
INDIRECT CALL:
test/runner.sh parg1 parg2 parg3 test/scripts/c.sh arg1 arg2
#!/bin/sh
if [ -z "$1" ]; then
echo "mailiffail {commandline}" >&2
exit 1
fi
logfile=/tmp/log.$$
"$@" >$logfile
res=$?
if [ "$res" != "0" ]; then
echo "exit code $res" >>$logfile
fi
if [ -s $logfile ]; then
(
echo "To: `whoami`"
echo "Subject: [Script error] $@"
echo
echo "$@:"
echo
cat $logfile
) | sendmail `whoami`
fi
rm $logfile
exit $res
--- /etc/crontab_130120 2010-12-19 00:46:16.000000000 +0100
+++ /etc/crontab 2013-01-20 23:48:13.281730845 +0100
@@ -9,9 +9,9 @@
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
-25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts
--report /etc/cron.daily )
-47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts
--report /etc/cron.weekly )
-52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts
--report /etc/cron.monthly )
+25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts
--prefix /opt/ald_svrmgmt/mailiffail /etc/cron.daily )
+47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts
--prefix /opt/ald_svrmgmt/mailiffail /etc/cron.weekly )
+52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts
--prefix /opt/ald_svrmgmt/mailiffail /etc/cron.monthly )
#