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