diff options
-rwxr-xr-x | scripts/record-commands | 33 | ||||
-rw-r--r-- | toys/example/logwrapper.c | 76 |
2 files changed, 109 insertions, 0 deletions
diff --git a/scripts/record-commands b/scripts/record-commands new file mode 100755 index 00000000..0201ac31 --- /dev/null +++ b/scripts/record-commands @@ -0,0 +1,33 @@ +#!/bin/bash + +# Set up command recording wrapper + +[ -z "$WRAPDIR" ] && WRAPDIR="$PWD"/record-commands +[ -z "$WRAPLOG" ] && export WRAPLOG="$PWD"/log.txt && CLEANUP=1 + +if [ $# -eq 0 ] +then + echo "Usage: WRAPDIR=dir WRAPLOG=log.txt record-commands command..." + echo "Then examine log.txt" + exit 1 +fi + +if [ ! -x "$WRAPDIR/logwrapper" ] +then + make logwrapper + mkdir -p "$WRAPDIR" && mv logwrapper "$WRAPDIR" || exit 1 + + echo "$PATH" | tr : '\n' | while read DIR + do + ls "$DIR/" | while read FILE + do + ln -s logwrapper "$WRAPDIR/$FILE" 2>/dev/null + done + done +fi + +PATH="$WRAPDIR:$PATH" "$@" +X=$? +[ ! -z "$CLEANUP" ] && rm -rf "$WRAPDIR" + +exit $X diff --git a/toys/example/logwrapper.c b/toys/example/logwrapper.c new file mode 100644 index 00000000..0f87df24 --- /dev/null +++ b/toys/example/logwrapper.c @@ -0,0 +1,76 @@ +/* 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 = 1; i<toys.optc; i++) len += 2*strlen(toys.argv[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 == '/') { + if (!readlink0("/proc/self/exe", s = toybuf, sizeof(toybuf))) + perror_exit("/proc/self/exe"); + + while (list) { + if (!strcmp(list->str, s)) 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 logwrapper in $PATH", omnom); + *toys.argv = list->str; + execve(list->str, toys.argv, environ); + } +} |