1 #include <signal.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <unistd.h> 6 7 #define TOOL(name) int name##_main(int, char**); 8 #include "tools.h" 9 #undef TOOL 10 11 static struct { 12 const char* name; 13 int (*func)(int, char**); 14 } tools[] = { 15 #define TOOL(name) { #name, name##_main }, 16 #include "tools.h" 17 #undef TOOL 18 { 0, 0 }, 19 }; 20 21 static void SIGPIPE_handler(int signal) { 22 // Those desktop Linux tools that catch SIGPIPE seem to agree that it's 23 // a successful way to exit, not a failure. (Which makes sense --- we were 24 // told to stop by a reader, rather than failing to continue ourselves.) 25 _exit(0); 26 } 27 28 int main(int argc, char** argv) { 29 // Let's assume that none of this code handles broken pipes. At least ls, 30 // ps, and top were broken (though I'd previously added this fix locally 31 // to top). We exit rather than use SIG_IGN because tools like top will 32 // just keep on writing to nowhere forever if we don't stop them. 33 signal(SIGPIPE, SIGPIPE_handler); 34 35 char* cmd = strrchr(argv[0], '/'); 36 char* name = cmd ? (cmd + 1) : argv[0]; 37 38 for (size_t i = 0; tools[i].name; i++) { 39 if (!strcmp(tools[i].name, name)) { 40 return tools[i].func(argc, argv); 41 } 42 } 43 44 printf("%s: no such tool\n", argv[0]); 45 return 127; 46 } 47 48 int toolbox_main(int argc, char** argv) { 49 // "toolbox foo ..." is equivalent to "foo ..." 50 if (argc > 1) { 51 return main(argc - 1, argv + 1); 52 } 53 54 // Plain "toolbox" lists the tools. 55 for (size_t i = 1; tools[i].name; i++) { 56 printf("%s%c", tools[i].name, tools[i+1].name ? ' ' : '\n'); 57 } 58 return 0; 59 } 60