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