blob: 036fcd32ad4353af2d43f692c516439b2aa96136 [file] [log] [blame]
/* logwrapper.c - Record commands called out of $PATH to a log
*
* Copyright 2019 Rob Landley <rob@landley.net>
*
* I made it up. Must be built standalone to work. (Is its own multiplexer.)
USE_LOGWRAPPER(NEWTOY(logwrapper, 0, TOYFLAG_NOHELP|TOYFLAG_USR|TOYFLAG_BIN))
config LOGWRAPPER
bool "logwrapper"
default n
help
usage: logwrapper ...
Append command line to $WRAPLOG, then call second instance
of command in $PATH.
*/
#define FOR_logwrapper
#include "toys.h"
void logwrapper_main(void)
{
char *log = getenv("WRAPLOG"), *omnom = basename(*toys.argv),
*s, *ss, *sss;
struct string_list *list;
int i, len;
// Log the command line
if (!log) error_exit("no $WRAPLOG");
len = strlen(omnom)+2;
for (i = 0; i<toys.optc; i++) len += 2*strlen(toys.optargs[i])+3;
ss = stpcpy(s = xmalloc(len), omnom);
// Copy arguments surrounded by quotes with \ escapes for " \ or \n
for (i = 0; i<toys.optc; i++) {
*(ss++) = ' ';
*(ss++) = '"';
for (sss = toys.optargs[i]; *sss; sss++) {
if (-1 == (len = stridx("\n\\\"", *sss))) *(ss++) = *sss;
else {
*(ss++) = '\\';
*(ss++) = "n\\\""[len];
}
}
*(ss++) = '"';
}
*(ss++) = '\n';
// Atomically append to log and free buffer
i = xcreate(log, O_RDWR|O_CREAT|O_APPEND, 0644);
xwrite(i, s, ss-s);
close(i);
free(s);
// Run next instance in $PATH after this one. If we were called via absolute
// path search for this instance, otherwise assume we're first instance
list = find_in_path(getenv("PATH"), omnom);
if (**toys.argv == '/') {
while (list) {
if (!strcmp(list->str, *toys.argv)) break;
free(llist_pop(&list));
}
}
// Skip first instance and try to run next one, until out of instances.
for (;;) {
if (list) free(llist_pop(&list));
if (!list)
error_exit("no %s after %s in $PATH=%s", omnom,
**toys.argv == '/' ? *toys.argv : "logwrapper", getenv("PATH"));
*toys.argv = list->str;
execve(list->str, toys.argv, environ);
}
}