Home | History | Annotate | Download | only in example
      1 /* logwrapper.c - Record commands called out of $PATH to a log
      2  *
      3  * Copyright 2019 Rob Landley <rob (at) landley.net>
      4  *
      5  * I made it up. Must be built standalone to work. (Is its own multiplexer.)
      6 
      7 USE_LOGWRAPPER(NEWTOY(logwrapper, 0, TOYFLAG_NOHELP|TOYFLAG_USR|TOYFLAG_BIN))
      8 
      9 config LOGWRAPPER
     10   bool "logwrapper"
     11   default n
     12   help
     13     usage: logwrapper ...
     14 
     15     Append command line to $WRAPLOG, then call second instance
     16     of command in $PATH.
     17 */
     18 
     19 #define FOR_logwrapper
     20 #include "toys.h"
     21 
     22 void logwrapper_main(void)
     23 {
     24   char *log = getenv("WRAPLOG"), *omnom = basename(*toys.argv),
     25        *s, *ss, *sss;
     26   struct string_list *list;
     27   int i, len;
     28 
     29   // Log the command line
     30   if (!log) error_exit("no $WRAPLOG");
     31   len = strlen(omnom)+2;
     32   for (i = 0; i<toys.optc; i++) len += 2*strlen(toys.optargs[i])+3;
     33   ss = stpcpy(s = xmalloc(len), omnom);
     34 
     35   // Copy arguments surrounded by quotes with \ escapes for " \ or \n
     36   for (i = 0; i<toys.optc; i++) {
     37     *(ss++) = ' ';
     38     *(ss++) = '"';
     39     for (sss = toys.optargs[i]; *sss; sss++) {
     40       if (-1 == (len = stridx("\n\\\"", *sss))) *(ss++) = *sss;
     41       else {
     42         *(ss++) = '\\';
     43         *(ss++) = "n\\\""[len];
     44       }
     45     }
     46     *(ss++) = '"';
     47   }
     48   *(ss++) = '\n';
     49 
     50   // Atomically append to log and free buffer
     51   i = xcreate(log, O_RDWR|O_CREAT|O_APPEND, 0644);
     52   xwrite(i, s, ss-s);
     53   close(i);
     54   free(s);
     55 
     56   // Run next instance in $PATH after this one. If we were called via absolute
     57   // path search for this instance, otherwise assume we're first instance
     58   list = find_in_path(getenv("PATH"), omnom);
     59   if (**toys.argv == '/') {
     60     while (list) {
     61       if (!strcmp(list->str, *toys.argv)) break;
     62       free(llist_pop(&list));
     63     }
     64   }
     65 
     66   // Skip first instance and try to run next one, until out of instances.
     67   for (;;) {
     68     if (list) free(llist_pop(&list));
     69     if (!list)
     70       error_exit("no %s after %s in $PATH=%s", omnom,
     71         **toys.argv == '/' ? *toys.argv : "logwrapper", getenv("PATH"));
     72     *toys.argv = list->str;
     73     execve(list->str, toys.argv, environ);
     74   }
     75 }
     76