xref: /aosp_15_r20/external/toybox/toys/example/logpath.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* logpath.c - Record commands called out of $PATH to a log
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2019 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  *
5*cf5a6c84SAndroid Build Coastguard Worker  * I made it up. Must be built standalone to work. (Is its own multiplexer.)
6*cf5a6c84SAndroid Build Coastguard Worker 
7*cf5a6c84SAndroid Build Coastguard Worker USE_LOGPATH(NEWTOY(logpath, 0, TOYFLAG_NOHELP|TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker 
9*cf5a6c84SAndroid Build Coastguard Worker config LOGPATH
10*cf5a6c84SAndroid Build Coastguard Worker   bool "logpath"
11*cf5a6c84SAndroid Build Coastguard Worker   default n
12*cf5a6c84SAndroid Build Coastguard Worker   help
13*cf5a6c84SAndroid Build Coastguard Worker     usage: logpath ...
14*cf5a6c84SAndroid Build Coastguard Worker 
15*cf5a6c84SAndroid Build Coastguard Worker     Append command line to $LOGPATH, then call second instance
16*cf5a6c84SAndroid Build Coastguard Worker     of command in $PATH.
17*cf5a6c84SAndroid Build Coastguard Worker */
18*cf5a6c84SAndroid Build Coastguard Worker 
19*cf5a6c84SAndroid Build Coastguard Worker #define FOR_logpath
20*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
21*cf5a6c84SAndroid Build Coastguard Worker 
22*cf5a6c84SAndroid Build Coastguard Worker #if CFG_TOYBOX
23*cf5a6c84SAndroid Build Coastguard Worker #warning Must be built standalone to work.
24*cf5a6c84SAndroid Build Coastguard Worker #endif
25*cf5a6c84SAndroid Build Coastguard Worker 
logpath_main(void)26*cf5a6c84SAndroid Build Coastguard Worker void logpath_main(void)
27*cf5a6c84SAndroid Build Coastguard Worker {
28*cf5a6c84SAndroid Build Coastguard Worker   char *log = getenv("LOGPATH"), *omnom = basename(*toys.argv), *s, *ss, *sss;
29*cf5a6c84SAndroid Build Coastguard Worker   struct string_list *list;
30*cf5a6c84SAndroid Build Coastguard Worker   int i, len;
31*cf5a6c84SAndroid Build Coastguard Worker 
32*cf5a6c84SAndroid Build Coastguard Worker   // Log the command line
33*cf5a6c84SAndroid Build Coastguard Worker   if (!log) error_exit("no $LOGPATH");
34*cf5a6c84SAndroid Build Coastguard Worker   len = strlen(omnom)+2;
35*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i<toys.optc; i++) len += 2*strlen(toys.optargs[i])+3;
36*cf5a6c84SAndroid Build Coastguard Worker   ss = stpcpy(s = xmalloc(len), omnom);
37*cf5a6c84SAndroid Build Coastguard Worker 
38*cf5a6c84SAndroid Build Coastguard Worker   // Copy arguments surrounded by quotes with \ escapes for " \ or \n
39*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i<toys.optc; i++) {
40*cf5a6c84SAndroid Build Coastguard Worker     *(ss++) = ' ';
41*cf5a6c84SAndroid Build Coastguard Worker     *(ss++) = '"';
42*cf5a6c84SAndroid Build Coastguard Worker     for (sss = toys.optargs[i]; *sss; sss++) {
43*cf5a6c84SAndroid Build Coastguard Worker       if (-1 == (len = stridx("\n\\\"", *sss))) *(ss++) = *sss;
44*cf5a6c84SAndroid Build Coastguard Worker       else {
45*cf5a6c84SAndroid Build Coastguard Worker         *(ss++) = '\\';
46*cf5a6c84SAndroid Build Coastguard Worker         *(ss++) = "n\\\""[len];
47*cf5a6c84SAndroid Build Coastguard Worker       }
48*cf5a6c84SAndroid Build Coastguard Worker     }
49*cf5a6c84SAndroid Build Coastguard Worker     *(ss++) = '"';
50*cf5a6c84SAndroid Build Coastguard Worker   }
51*cf5a6c84SAndroid Build Coastguard Worker   *(ss++) = '\n';
52*cf5a6c84SAndroid Build Coastguard Worker 
53*cf5a6c84SAndroid Build Coastguard Worker   // Atomically append to log and free buffer
54*cf5a6c84SAndroid Build Coastguard Worker   i = xcreate(log, O_WRONLY|O_CREAT|O_APPEND, 0644);
55*cf5a6c84SAndroid Build Coastguard Worker   xwrite(i, s, ss-s);
56*cf5a6c84SAndroid Build Coastguard Worker   close(i);
57*cf5a6c84SAndroid Build Coastguard Worker   free(s);
58*cf5a6c84SAndroid Build Coastguard Worker 
59*cf5a6c84SAndroid Build Coastguard Worker   // Run next instance in $PATH after this one. If we were called via absolute
60*cf5a6c84SAndroid Build Coastguard Worker   // path search for this instance, otherwise assume we're first instance
61*cf5a6c84SAndroid Build Coastguard Worker   list = find_in_path(getenv("PATH"), omnom);
62*cf5a6c84SAndroid Build Coastguard Worker   if (**toys.argv == '/') {
63*cf5a6c84SAndroid Build Coastguard Worker     while (list) {
64*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(list->str, *toys.argv)) break;
65*cf5a6c84SAndroid Build Coastguard Worker       free(llist_pop(&list));
66*cf5a6c84SAndroid Build Coastguard Worker     }
67*cf5a6c84SAndroid Build Coastguard Worker   }
68*cf5a6c84SAndroid Build Coastguard Worker 
69*cf5a6c84SAndroid Build Coastguard Worker   // Skip first instance and try to run next one, continuing until one works
70*cf5a6c84SAndroid Build Coastguard Worker   for (;list; free(llist_pop(&list))) {
71*cf5a6c84SAndroid Build Coastguard Worker     free(llist_pop(&list));
72*cf5a6c84SAndroid Build Coastguard Worker     *toys.argv = list->str;
73*cf5a6c84SAndroid Build Coastguard Worker     execve(list->str, toys.argv, environ);
74*cf5a6c84SAndroid Build Coastguard Worker   }
75*cf5a6c84SAndroid Build Coastguard Worker   error_exit("no %s after %s in $PATH=%s", omnom,
76*cf5a6c84SAndroid Build Coastguard Worker     **toys.argv == '/' ? *toys.argv : "logpath", getenv("PATH"));
77*cf5a6c84SAndroid Build Coastguard Worker }
78