toybox/toys/example/logwrapper.c
<<
>>
Prefs
   1/* logwrapper.c - Record commands called out of $PATH to a log
   2 *
   3 * Copyright 2019 Rob Landley <rob@landley.net>
   4 *
   5 * I made it up. Must be built standalone to work. (Is its own multiplexer.)
   6
   7USE_LOGWRAPPER(NEWTOY(logwrapper, 0, TOYFLAG_NOHELP|TOYFLAG_USR|TOYFLAG_BIN))
   8
   9config 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
  22void 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