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, &regex_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 )
 #
 
 

Reply via email to