Package: debianutils
Version: 5.23.2
Severity: wishlist
Tags: patch

Dear Maintainer,

I'm having troubles monitoring what happens during the cron.daily process.
While a --time option (see bug#282553) might help, I got the feeling that
after some trials I'd have to tweak it further.  So, for maximum flexibility,
I turned to -A and -B which allow a user-supplied utility to be called
after or before each script execution.  Such utility can log the time, but also
examine various other things.

I add a patch for run-parts.c and run-parts.8.


-- System Information:
Distributor ID: Devuan
Description:    Devuan GNU/Linux 6 (excalibur)
Release:        6
Codename:       excalibur
Architecture: x86_64

Kernel: Linux 6.12.73+deb13-amd64 (SMP w/8 CPU threads; PREEMPT)
Locale: LANG=en_IE.UTF-8, LC_CTYPE=en_IE.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/bash
Init: sysvinit (via /sbin/init)

Versions of packages debianutils depends on:
ii  libc6  2.41-12+deb13u2

debianutils recommends no packages.

debianutils suggests no packages.

-- no debconf information
Add optional arguments -A, --after and -B, --before for greater control.
--- a/run-parts.8
+++ b/run-parts.8
@@ -11,7 +11,8 @@
 .SH SYNOPSIS
 .B run\-parts
 [\-\-test] [\-\-verbose] [\-\-debug] [\-\-report] [\-\-lsbsysinit] 
[\-\-regex=RE]
-[\-\-umask=umask] [\-\-arg=argument] [\-\-exit\-on\-error] [\-\-help]
+[\-\-umask=umask] [\-\-arg=argument] [\-\-after=PROG] [\-\-before=PROG]
+[\-\-exit\-on\-error] [\-\-help]
 [\-\-version] [\-\-list] [\-\-reverse] [\-\-] DIRECTORY [DIRECTORY ...]
 .PP
 .B run\-parts
@@ -109,6 +110,24 @@
 .B \-\-arg
 once for each argument you want passed.
 .TP
+.BI "\-A, \-\-after=" program
+run
+.I program
+after each script runs.  The program will be called with three
+arguments: script name, exit status, and total amount written to
+the output and error streams.  The last argument will always be 0
+unless the \-\-report option is also specified.  If this option is
+used multiple times, only the last one will take effect.  If the
+called program exits with an error code, it won't be called again.
+.TP
+.BI "\-B, \-\-before=" program
+run
+.I program
+before running each script.  The program will be called with one
+argument: the script name.  If this option is used multiple
+times, only the last one will take effect.  If the called program
+exits with an error code, it won't be called again.
+.TP
 .B "\-\-"
 specifies that this is the end of the options.  Any filename after
 .B "\-\-"
--- a/run-parts.c
+++ b/run-parts.c
@@ -31,6 +31,7 @@
 #include <signal.h>
 #include <sys/time.h>
 #include <regex.h>
+#include <inttypes.h>
 
 #define RUNPARTS_NORMAL 0
 #define RUNPARTS_ERE 1
@@ -56,6 +57,8 @@
 char *custom_ere;
 regex_t hierre, tradre, excsre, classicalre, customre;
 
+char *run_before, *run_after;
+
 static void catch_signals();
 static void restore_signals();
 
@@ -108,6 +111,8 @@
          "      --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"
+         "  -A, --after=PROG    run PROG after each script runs.\n"
+         "  -B, --before=PROG   run PROG before running each script.\n"
          "  -V, --version       output version information and exit.\n"
          "  -h, --help          display this help and exit.\n");
   exit(0);
@@ -182,12 +187,79 @@
     return retval;
 }
 
+/* wait for call return */
+static void wait_for_call(pid_t pid, char *progname, char **run_what)
+{
+  int result, rtc = 0, r;
+  r = waitpid(pid, &result, 0);
+
+  if (r == -1) {
+    error("waitpid: %s", strerror(errno));
+    exit(1);
+  }
+
+  if (WIFEXITED(result) && WEXITSTATUS(result)) {
+    error("%s %s exited with return code %d", *run_what, progname,
+      rtc = WEXITSTATUS(result));
+  }
+  else if (WIFSIGNALED(result)) {
+    error("%s exited because of uncaught signal %d", *run_what,
+      WTERMSIG(result));
+    rtc = 1;
+  }
+
+  if (rtc)
+    *run_what = NULL;
+}
+
+/* run run_before */
+static void call_run_before(char *progname)
+{
+  pid_t pid = fork();
+  if (pid < 0) {
+    error("failed to fork: %s", strerror(errno));
+    exit(1);
+  }
+  else if (!pid) {
+    restore_signals();
+    char *argv[3] = {run_before, progname, NULL};
+    execvp(run_before, argv);
+    error("failed to exec %s: %s", run_before, strerror(errno));
+    exit(1);
+  }
+
+  wait_for_call(pid, progname, &run_before);
+}
+
+/* run run_after */
+static void call_run_after(char *progname, uint64_t tot_wrote)
+{
+  pid_t pid = fork();
+  if (pid < 0) {
+    error("failed to fork: %s", strerror(errno));
+    exit(1);
+  }
+  else if (!pid) {
+    char wrote[32], status[32];
+    restore_signals();
+    snprintf(status, sizeof status, "%d", exitstatus);
+    snprintf(wrote, sizeof wrote, "%" PRIu64, tot_wrote);
+    char *argv[5] = {run_after, progname, status, wrote, NULL};
+    execvp(run_after, argv);
+    error("failed to exec %s: %s", run_after, strerror(errno));
+    exit(1);
+  }
+
+  wait_for_call(pid, progname, &run_after);
+}
+
 /* Execute a file */
 void run_part(char *progname)
 {
   int result, waited;
   int pid, r;
   int pout[2], perr[2];
+  uint64_t tot_wrote = 0;
 
   waited = 0;
 
@@ -195,6 +267,10 @@
     error("pipe: %s", strerror(errno));
     exit(1);
   }
+
+  if (run_before)
+    call_run_before(progname);
+
   if ((pid = fork()) < 0) {
     error("failed to fork: %s", strerror(errno));
     exit(1);
@@ -303,6 +379,7 @@
              fflush(stdout);
              printflag = 1;
            }
+           tot_wrote += c;
            ignored = write(STDOUT_FILENO, buf, c);
          }
          else if (c == 0) {
@@ -323,6 +400,7 @@
              fflush(stderr);
              printflag = 1;
            }
+           tot_wrote += c;
            ignored = write(STDERR_FILENO, buf, c);
          }
          else if (c == 0) {
@@ -368,6 +446,9 @@
          WTERMSIG(result));
     exitstatus = 1;
   }
+
+  if (run_after)
+    call_run_after(progname, tot_wrote);
 }
 
 static void handle_signal(int s)
@@ -709,10 +790,12 @@
       {"stdin", 0, &stdin_mode, 1},
       {"exit-on-error", 0, &exit_on_error_mode, 1},
       {"new-session", 0, &new_session_mode, 1},
+      {"after", 1, 0, 'A'},
+      {"before", 1, 0, 'B'},
       {0, 0, 0, 0}
     };
 
-    c = getopt_long(argc, argv, "u:ha:vV", long_options, &option_index);
+    c = getopt_long(argc, argv, "u:ha:A:B:vV", long_options, &option_index);
     if (c == EOF)
       break;
     switch (c) {
@@ -736,6 +819,12 @@
     case 'd':
       debug_mode = 1;
       break;
+    case 'A':
+      run_after = optarg;
+      break;
+    case 'B':
+      run_before = optarg;
+      break;
     case 'V':
       version();
       break;
  • Bug#1131375: debianutils: Add options -A, --after and -B... Alessandro Vesely

Reply via email to