10f66f451Sopenharmony_ci/* logwrapper.c - Record commands called out of $PATH to a log 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2019 Rob Landley <rob@landley.net> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * I made it up. Must be built standalone to work. (Is its own multiplexer.) 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ciUSE_LOGWRAPPER(NEWTOY(logwrapper, 0, TOYFLAG_NOHELP|TOYFLAG_USR|TOYFLAG_BIN)) 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciconfig LOGWRAPPER 100f66f451Sopenharmony_ci bool "logwrapper" 110f66f451Sopenharmony_ci default n 120f66f451Sopenharmony_ci help 130f66f451Sopenharmony_ci usage: logwrapper ... 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ci Append command line to $WRAPLOG, then call second instance 160f66f451Sopenharmony_ci of command in $PATH. 170f66f451Sopenharmony_ci*/ 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci#define FOR_logwrapper 200f66f451Sopenharmony_ci#include "toys.h" 210f66f451Sopenharmony_ci 220f66f451Sopenharmony_civoid logwrapper_main(void) 230f66f451Sopenharmony_ci{ 240f66f451Sopenharmony_ci char *log = getenv("WRAPLOG"), *omnom = basename(*toys.argv), 250f66f451Sopenharmony_ci *s, *ss, *sss; 260f66f451Sopenharmony_ci struct string_list *list; 270f66f451Sopenharmony_ci int i, len; 280f66f451Sopenharmony_ci 290f66f451Sopenharmony_ci // Log the command line 300f66f451Sopenharmony_ci if (!log) error_exit("no $WRAPLOG"); 310f66f451Sopenharmony_ci len = strlen(omnom)+2; 320f66f451Sopenharmony_ci for (i = 0; i<toys.optc; i++) len += 2*strlen(toys.optargs[i])+3; 330f66f451Sopenharmony_ci ss = stpcpy(s = xmalloc(len), omnom); 340f66f451Sopenharmony_ci 350f66f451Sopenharmony_ci // Copy arguments surrounded by quotes with \ escapes for " \ or \n 360f66f451Sopenharmony_ci for (i = 0; i<toys.optc; i++) { 370f66f451Sopenharmony_ci *(ss++) = ' '; 380f66f451Sopenharmony_ci *(ss++) = '"'; 390f66f451Sopenharmony_ci for (sss = toys.optargs[i]; *sss; sss++) { 400f66f451Sopenharmony_ci if (-1 == (len = stridx("\n\\\"", *sss))) *(ss++) = *sss; 410f66f451Sopenharmony_ci else { 420f66f451Sopenharmony_ci *(ss++) = '\\'; 430f66f451Sopenharmony_ci *(ss++) = "n\\\""[len]; 440f66f451Sopenharmony_ci } 450f66f451Sopenharmony_ci } 460f66f451Sopenharmony_ci *(ss++) = '"'; 470f66f451Sopenharmony_ci } 480f66f451Sopenharmony_ci *(ss++) = '\n'; 490f66f451Sopenharmony_ci 500f66f451Sopenharmony_ci // Atomically append to log and free buffer 510f66f451Sopenharmony_ci i = xcreate(log, O_RDWR|O_CREAT|O_APPEND, 0644); 520f66f451Sopenharmony_ci xwrite(i, s, ss-s); 530f66f451Sopenharmony_ci close(i); 540f66f451Sopenharmony_ci free(s); 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_ci // Run next instance in $PATH after this one. If we were called via absolute 570f66f451Sopenharmony_ci // path search for this instance, otherwise assume we're first instance 580f66f451Sopenharmony_ci list = find_in_path(getenv("PATH"), omnom); 590f66f451Sopenharmony_ci if (**toys.argv == '/') { 600f66f451Sopenharmony_ci while (list) { 610f66f451Sopenharmony_ci if (!strcmp(list->str, *toys.argv)) break; 620f66f451Sopenharmony_ci free(llist_pop(&list)); 630f66f451Sopenharmony_ci } 640f66f451Sopenharmony_ci } 650f66f451Sopenharmony_ci 660f66f451Sopenharmony_ci // Skip first instance and try to run next one, until out of instances. 670f66f451Sopenharmony_ci for (;;) { 680f66f451Sopenharmony_ci if (list) free(llist_pop(&list)); 690f66f451Sopenharmony_ci if (!list) 700f66f451Sopenharmony_ci error_exit("no %s after %s in $PATH=%s", omnom, 710f66f451Sopenharmony_ci **toys.argv == '/' ? *toys.argv : "logwrapper", getenv("PATH")); 720f66f451Sopenharmony_ci *toys.argv = list->str; 730f66f451Sopenharmony_ci execve(list->str, toys.argv, environ); 740f66f451Sopenharmony_ci } 750f66f451Sopenharmony_ci} 76