aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2019-01-30 16:16:07 -0600
committerRob Landley <rob@landley.net>2019-01-30 16:16:07 -0600
commita242b5be0b486fb1137c45c87e2867aef2e1fcb3 (patch)
tree92e4d956cf4f39745a26af72e7e88a0c6bb8a325
parenta8ade49b0566cf0b55b404e0e3c175c9c17d7dc0 (diff)
downloadtoybox-a242b5be0b486fb1137c45c87e2867aef2e1fcb3.tar.gz
Command logging wrapper to help analyze what commands scripts call and how.
-rwxr-xr-xscripts/record-commands33
-rw-r--r--toys/example/logwrapper.c76
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);
+ }
+}