ash,kill: use common code for kill applet/builtin
authorDenis Vlasenko <vda.linux@googlemail.com>
Sun, 29 Apr 2007 23:42:54 +0000 (23:42 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sun, 29 Apr 2007 23:42:54 +0000 (23:42 -0000)
# make bloatcheck
function                                             old     new   delta
evaltreenr                                           644     654     +10
evaltree                                             644     654     +10
parse_conf                                          1440    1444      +4
dpkg_deb_main                                        426     429      +3
ed_main                                             3319    3321      +2
passwd_main                                         2093    2091      -2
kill_main                                            830     826      -4
singlemount                                         4609    4601      -8
find_command                                         962     954      -8
get_lcm                                              123     105     -18
.rodata                                           132243  132147     -96
killcmd                                              449     120    -329
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/7 up/down: 29/-465)          Total: -436 bytes

# size busybox_old busybox_unstripped
   text    data     bss     dec     hex filename
 723901    2940   27504  754345   b82a9 busybox_old
 723457    2940   27504  753901   b80ed busybox_unstripped

include/libbb.h
procps/Kbuild
procps/kill.c
shell/ash.c

index 9950c61..be51f25 100644 (file)
@@ -636,6 +636,7 @@ extern void bb_vinfo_msg(const char *s, va_list p);
 int bb_cat(char** argv);
 int bb_echo(char** argv);
 int bb_test(int argc, char** argv);
+int kill_main(int argc, char **argv);
 #if ENABLE_ROUTE
 void bb_displayroutes(int noresolve, int netstatfmt);
 #endif
index 6a9a866..33f616f 100644 (file)
@@ -7,6 +7,7 @@
 lib-y:=
 lib-$(CONFIG_FREE)     += free.o
 lib-$(CONFIG_KILL)     += kill.o
+lib-$(CONFIG_ASH)      += kill.o  # used for built-in kill by ash
 lib-$(CONFIG_PIDOF)    += pidof.o
 lib-$(CONFIG_PS)       += ps.o
 lib-$(CONFIG_RENICE)   += renice.o
index 9a6e936..e2b029d 100644 (file)
 
 #include "busybox.h"
 
+/* Note: kill_main is directly called from shell in order to implement
+ * kill built-in. Shell substitutes job ids with process groups first.
+ *
+ * This brings some complications:
+ *
+ * + we can't use xfunc here
+ * + we can't use applet_name
+ * + we can't use bb_show_usage
+ * (Above doesn't apply for killall[5] cases)
+ *
+ * kill %n gets translated into kill ' -<process group>' by shell (note space!)
+ * This is needed to avoid collision with kill -9 ... syntax
+ */
+
 int kill_main(int argc, char **argv);
 int kill_main(int argc, char **argv)
 {
        char *arg;
        pid_t pid;
        int signo = SIGTERM, errors = 0, quiet = 0;
-       const int killall = (ENABLE_KILLALL && applet_name[4] == 'a'
-                      && (!ENABLE_KILLALL5 || applet_name[7] != '5'));
-       const int killall5 = (ENABLE_KILLALL5 && applet_name[4] == 'a'
-                         && (!ENABLE_KILLALL || applet_name[7] == '5'));
+       const int killall = (ENABLE_KILLALL && argv[0][4] == 'a'
+                      && (!ENABLE_KILLALL5 || argv[0][7] != '5'));
+       const int killall5 = (ENABLE_KILLALL5 && argv[0][4] == 'a'
+                         && (!ENABLE_KILLALL || argv[0][7] == '5'));
 
        /* Parse any options */
        argc--;
@@ -29,34 +43,38 @@ int kill_main(int argc, char **argv)
                goto do_it_now;
        }
 
-       /* The -l option, which prints out signal names. */
+       /* The -l option, which prints out signal names.
+        * Intended usage in shell:
+        * echo "Died of SIG`kill -l $?`"
+        * We try to mimic what kill from coreutils-6.8 does */
        if (arg[1] == 'l' && arg[2] == '\0') {
-               const char *name;
                if (argc == 1) {
                        /* Print the whole signal list */
-                       int col = 0;
                        for (signo = 1; signo < 32; signo++) {
-                               name = get_signame(signo);
-                               if (isdigit(name[0])) continue;
-                               if (col > 66) {
-                                       puts("");
-                                       col = 0;
-                               }
-                               col += printf("%2d) %-6s", signo, name);
+                               puts(get_signame(signo));
                        }
-                       puts("");
                } else { /* -l <sig list> */
                        while ((arg = *++argv)) {
                                if (isdigit(arg[0])) {
-                                       signo = xatoi_u(arg);
-                                       name = get_signame(signo);
+                                       signo = bb_strtou(arg, NULL, 10);
+                                       if (errno) {
+                                               bb_error_msg("unknown signal '%s'", arg);
+                                               return EXIT_FAILURE;
+                                       }
+                                       /* Exitcodes >= 0x80 are to be treated
+                                        * as "killed by signal (exitcode & 0x7f)" */
+                                       puts(get_signame(signo & 0x7f));
+                                       /* TODO: 'bad' signal# - coreutils says:
+                                        * kill: 127: invalid signal
+                                        * we just print "127" instead */
                                } else {
                                        signo = get_signum(arg);
-                                       if (signo < 0)
-                                               bb_error_msg_and_die("unknown signal '%s'", arg);
-                                       name = get_signame(signo);
+                                       if (signo < 0) {
+                                               bb_error_msg("unknown signal '%s'", arg);
+                                               return EXIT_FAILURE;
+                                       }
+                                       printf("%d\n", signo);
                                }
-                               printf("%2d) %s\n", signo, name);
                        }
                }
                /* If they specified -l, we are all done */
@@ -74,8 +92,10 @@ int kill_main(int argc, char **argv)
 
        /* -SIG */
        signo = get_signum(&arg[1]);
-       if (signo < 0)
-               bb_error_msg_and_die("bad signal name '%s'", &arg[1]);
+       if (signo < 0) { /* || signo > MAX_SIGNUM ? */
+               bb_error_msg("bad signal name '%s'", &arg[1]);
+               return EXIT_FAILURE;
+       }
        arg = *++argv;
        argc--;
 
@@ -85,10 +105,6 @@ do_it_now:
                pid_t sid;
                procps_status_t* p = NULL;
 
-// Cannot happen anyway? We don't TERM ourself, we STOP
-//             /* kill(-1, sig) on Linux (at least 2.1.x)
-//              * might send signal to the calling process too */
-//             signal(SIGTERM, SIG_IGN);
                /* Now stop all processes */
                kill(-1, SIGSTOP);
                /* Find out our own session id */
@@ -104,9 +120,11 @@ do_it_now:
                return 0;
        }
 
-       /* Pid or name required for kill/killall */
-       if (argc < 1)
-               bb_show_usage();
+       /* Pid or name is required for kill/killall */
+       if (argc < 1) {
+               puts("You need to specify whom to kill");
+               return EXIT_FAILURE;
+       }
 
        if (killall) {
                /* Looks like they want to do a killall.  Do that */
@@ -140,14 +158,15 @@ do_it_now:
 
        /* Looks like they want to do a kill. Do that */
        while (arg) {
-               /* Huh?
-               if (!isdigit(arg[0]) && arg[0] != '-')
-                       bb_error_msg_and_die("bad pid '%s'", arg);
-               */
-               pid = xatou(arg);
-               /* FIXME: better overflow check? */
-               if (kill(pid, signo) != 0) {
-                       bb_perror_msg("cannot kill pid %u", (unsigned)pid);
+               /* Support shell 'space' trick */
+               if (arg[0] == ' ')
+                       arg++;
+               pid = bb_strtoi(arg, NULL, 10);
+               if (errno) {
+                       bb_error_msg("bad pid '%s'", arg);
+                       errors++;
+               } else if (kill(pid, signo) != 0) {
+                       bb_perror_msg("cannot kill pid %d", (int)pid);
                        errors++;
                }
                arg = *++argv;
index 16818cf..4b37f40 100644 (file)
@@ -3519,91 +3519,22 @@ setjobctl(int on)
 static int
 killcmd(int argc, char **argv)
 {
-       int signo = -1;
-       int list = 0;
-       int i;
-       pid_t pid;
-       struct job *jp;
-
-       if (argc <= 1) {
- usage:
-               ash_msg_and_raise_error(
-"usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
-"kill -l [exitstatus]"
-               );
-       }
-
-       if (**++argv == '-') {
-               signo = get_signum(*argv + 1);
-               if (signo < 0) {
-                       int c;
-
-                       while ((c = nextopt("ls:")) != '\0') {
-                               switch (c) {
-                               default:
-#if DEBUG
-                                       abort();
-#endif
-                               case 'l':
-                                       list = 1;
-                                       break;
-                               case 's':
-                                       signo = get_signum(optionarg);
-                                       if (signo < 0) {
-                                               ash_msg_and_raise_error(
-                                                       "invalid signal number or name: %s",
-                                                       optionarg
-                                               );
-                                       }
-                                       break;
-                               }
-                       }
-                       argv = argptr;
-               } else
-                       argv++;
-       }
-
-       if (!list && signo < 0)
-               signo = SIGTERM;
-
-       if ((signo < 0 || !*argv) ^ list) {
-               goto usage;
-       }
-
-       if (list) {
-               const char *name;
-
-               if (!*argv) {
-                       for (i = 1; i < NSIG; i++) {
-                               name = get_signame(i);
-                               if (!isdigit(*name))
-                                       out1fmt(snlfmt, name);
+       if (argv[1] && strcmp(argv[1], "-l") != 0) {
+               int i = 1;
+               do {
+                       if (argv[i][0] == '%') {
+                               struct job *jp = getjob(argv[i], 0);
+                               unsigned pid = jp->ps[0].pid;
+                               /* Enough space for ' -NNN<nul>' */
+                               argv[i] = alloca(sizeof(int)*3 + 3);
+                               /* kill_main has matching code to expect
+                                * leading space. Needed to not confuse
+                                * negative pids with "kill -SIGNAL_NO" syntax */
+                               sprintf(argv[i], " -%u", pid);
                        }
-                       return 0;
-               }
-               name = get_signame(signo);
-               if (!isdigit(*name))
-                       ash_msg_and_raise_error("invalid signal number or exit status: %s", *argptr);
-               out1fmt(snlfmt, name);
-               return 0;
+               } while (argv[++i]);
        }
-
-       i = 0;
-       do {
-               if (**argv == '%') {
-                       jp = getjob(*argv, 0);
-                       pid = -jp->ps[0].pid;
-               } else {
-                       pid = **argv == '-' ?
-                               -number(*argv + 1) : number(*argv);
-               }
-               if (kill(pid, signo) != 0) {
-                       ash_msg("(%d) - %m", pid);
-                       i = 1;
-               }
-       } while (*++argv);
-
-       return i;
+       return kill_main(argc, argv);
 }
 
 static void
@@ -3642,7 +3573,8 @@ restartjob(struct job *jp, int mode)
                if (WIFSTOPPED(ps->status)) {
                        ps->status = -1;
                }
-       } while (ps++, --i);
+               ps++;
+       } while (--i);
  out:
        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
        INT_ON;
@@ -5070,8 +5002,9 @@ esclen(const char *start, const char *p)
 static char *
 _rmescapes(char *str, int flag)
 {
+       static const char qchars[] = { CTLESC, CTLQUOTEMARK, '\0' };
+
        char *p, *q, *r;
-       static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
        unsigned inquotes;
        int notescaped;
        int globbing;
@@ -11117,13 +11050,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
                return;
        }
 
-#if ENABLE_FEATURE_SH_STANDALONE
-       if (find_applet_by_name(name)) {
-               entry->cmdtype = CMDNORMAL;
-               entry->u.index = -1;
-               return;
-       }
-#endif
+/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
 
        updatetbl = (path == pathval());
        if (!updatetbl) {
@@ -11173,6 +11100,14 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
                }
        }
 
+#if ENABLE_FEATURE_SH_STANDALONE
+       if (find_applet_by_name(name)) {
+               entry->cmdtype = CMDNORMAL;
+               entry->u.index = -1;
+               return;
+       }
+#endif
+
        /* We have to search path. */
        prev = -1;              /* where to start */
        if (cmdp && cmdp->rehash) {     /* doing a rehash */