From f20de5bb42f9a4f2c8417f6a1a2db7e2f2cafd5b Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sun, 29 Apr 2007 23:42:54 +0000 Subject: [PATCH] ash,kill: use common code for kill applet/builtin # 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 | 1 + procps/Kbuild | 1 + procps/kill.c | 95 ++++++++++++++++++++++---------------- shell/ash.c | 119 +++++++++++------------------------------------- 4 files changed, 86 insertions(+), 130 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 9950c61f2..be51f2520 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -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 diff --git a/procps/Kbuild b/procps/Kbuild index 6a9a86637..33f616fc2 100644 --- a/procps/Kbuild +++ b/procps/Kbuild @@ -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 diff --git a/procps/kill.c b/procps/kill.c index 9a6e93665..e2b029d20 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -10,16 +10,30 @@ #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 ' -' 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 */ 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; diff --git a/shell/ash.c b/shell/ash.c index 16818cfc9..4b37f403c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -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; - } + 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' */ + 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); } - argv = argptr; - } else - argv++; + } while (argv[++i]); } - - 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); - } - 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; - } - - 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 */