Add signal names to kill

mksh provides a kill primitive with signal names, but also offer it in
our toolbox binary. This will allow anyone to use "kill -HUP <pid>" or
"kill -l" to look at the name to number signal mapping.

Change-Id: Id683721f4ad3f2b518b4dc54a6073510290cbe04
diff --git a/toolbox/kill.c b/toolbox/kill.c
index 4d0e479..b79805f 100644
--- a/toolbox/kill.c
+++ b/toolbox/kill.c
@@ -5,16 +5,127 @@
 #include <sys/types.h>
 #include <signal.h>
 
+static struct {
+    unsigned int number;
+    char *name;
+} signals[] = {
+#define _SIG(name) {SIG##name, #name}
+    /* Single Unix Specification signals */
+    _SIG(ABRT),
+    _SIG(ALRM),
+    _SIG(FPE),
+    _SIG(HUP),
+    _SIG(ILL),
+    _SIG(INT),
+    _SIG(KILL),
+    _SIG(PIPE),
+    _SIG(QUIT),
+    _SIG(SEGV),
+    _SIG(TERM),
+    _SIG(USR1),
+    _SIG(USR2),
+    _SIG(CHLD),
+    _SIG(CONT),
+    _SIG(STOP),
+    _SIG(TSTP),
+    _SIG(TTIN),
+    _SIG(TTOU),
+    _SIG(BUS),
+    _SIG(POLL),
+    _SIG(PROF),
+    _SIG(SYS),
+    _SIG(TRAP),
+    _SIG(URG),
+    _SIG(VTALRM),
+    _SIG(XCPU),
+    _SIG(XFSZ),
+    /* non-SUS signals */
+    _SIG(IO),
+    _SIG(PWR),
+    _SIG(STKFLT),
+    _SIG(WINCH),
+#undef _SIG
+};
+
+/* To indicate a matching signal was not found */
+static const unsigned int SENTINEL = (unsigned int) -1;
+
+void list_signals()
+{
+    unsigned int sorted_signals[_NSIG];
+    unsigned int i;
+    unsigned int num;
+
+    memset(sorted_signals, SENTINEL, sizeof(sorted_signals));
+
+    // Sort the signals
+    for (i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) {
+        sorted_signals[signals[i].number] = i;
+    }
+
+    num = 0;
+    for (i = 1; i < _NSIG; i++) {
+        unsigned int index = sorted_signals[i];
+        if (index == SENTINEL) {
+            continue;
+        }
+
+        fprintf(stderr, "%2d) SIG%-9s ", i, signals[index].name);
+
+        if ((num++ % 4) == 3) {
+            fprintf(stderr, "\n");
+        }
+    }
+
+    if ((num % 4) == 3) {
+        fprintf(stderr, "\n");
+    }
+}
+
+unsigned int name_to_signal(const char* name)
+{
+    unsigned int i;
+
+    for (i = 1; i < sizeof(signals) / sizeof(signals[0]); i++) {
+        if (!strcasecmp(name, signals[i].name)) {
+            return signals[i].number;
+        }
+    }
+
+    return SENTINEL;
+}
+
 int kill_main(int argc, char **argv)
 {
-    int sig = SIGTERM;
+    unsigned int sig = SIGTERM;
     int result = 0;
-    
+
     argc--;
     argv++;
 
-    if(argc >= 2 && argv[0][0] == '-'){
-        sig = atoi(argv[0] + 1);
+    if (argc >= 1 && argv[0][0] == '-') {
+        char *endptr;
+        size_t arg_len = strlen(argv[0]);
+        if (arg_len < 2) {
+            fprintf(stderr, "invalid argument: -\n");
+            return -1;
+        }
+
+        char* arg = argv[0] + 1;
+        if (arg_len == 2 && *arg == 'l') {
+            list_signals();
+            return 0;
+        }
+
+        sig = strtol(arg, &endptr, 10);
+        if (*endptr != '\0') {
+            sig = name_to_signal(arg);
+            if (sig == SENTINEL) {
+                fprintf(stderr, "invalid signal name: %s\n", arg);
+                return -1;
+            }
+        }
+
         argc--;
         argv++;
     }
@@ -26,10 +137,10 @@
             result = err;
             fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno));
         }
-            
+
         argc--;
         argv++;
     }
-    
+
     return result;
 }