• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
logwrapper_main(void)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