busybox/procps/kill.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Mini kill/killall[5] implementation for busybox
   4 *
   5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
   6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
   7 *
   8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   9 */
  10
  11#include "libbb.h"
  12
  13/* Note: kill_main is directly called from shell in order to implement
  14 * kill built-in. Shell substitutes job ids with process groups first.
  15 *
  16 * This brings some complications:
  17 *
  18 * + we can't use xfunc here
  19 * + we can't use applet_name
  20 * + we can't use bb_show_usage
  21 * (Above doesn't apply for killall[5] cases)
  22 *
  23 * kill %n gets translated into kill ' -<process group>' by shell (note space!)
  24 * This is needed to avoid collision with kill -9 ... syntax
  25 */
  26
  27int kill_main(int argc, char **argv)
  28{
  29        char *arg;
  30        pid_t pid;
  31        int signo = SIGTERM, errors = 0, quiet = 0;
  32#if !ENABLE_KILLALL && !ENABLE_KILLALL5
  33#define killall 0
  34#define killall5 0
  35#else
  36/* How to determine who we are? find 3rd char from the end:
  37 * kill, killall, killall5
  38 *  ^i       ^a        ^l  - it's unique
  39 * (checking from the start is complicated by /bin/kill... case) */
  40        const char char3 = argv[0][strlen(argv[0]) - 3];
  41#define killall (ENABLE_KILLALL && char3 == 'a')
  42#define killall5 (ENABLE_KILLALL5 && char3 == 'l')
  43#endif
  44
  45        /* Parse any options */
  46        argc--;
  47        arg = *++argv;
  48
  49        if (argc < 1 || arg[0] != '-') {
  50                goto do_it_now;
  51        }
  52
  53        /* The -l option, which prints out signal names.
  54         * Intended usage in shell:
  55         * echo "Died of SIG`kill -l $?`"
  56         * We try to mimic what kill from coreutils-6.8 does */
  57        if (arg[1] == 'l' && arg[2] == '\0') {
  58                if (argc == 1) {
  59                        /* Print the whole signal list */
  60                        print_signames();
  61                        return 0;
  62                }
  63                /* -l <sig list> */
  64                while ((arg = *++argv)) {
  65                        if (isdigit(arg[0])) {
  66                                signo = bb_strtou(arg, NULL, 10);
  67                                if (errno) {
  68                                        bb_error_msg("unknown signal '%s'", arg);
  69                                        return EXIT_FAILURE;
  70                                }
  71                                /* Exitcodes >= 0x80 are to be treated
  72                                 * as "killed by signal (exitcode & 0x7f)" */
  73                                puts(get_signame(signo & 0x7f));
  74                                /* TODO: 'bad' signal# - coreutils says:
  75                                 * kill: 127: invalid signal
  76                                 * we just print "127" instead */
  77                        } else {
  78                                signo = get_signum(arg);
  79                                if (signo < 0) {
  80                                        bb_error_msg("unknown signal '%s'", arg);
  81                                        return EXIT_FAILURE;
  82                                }
  83                                printf("%d\n", signo);
  84                        }
  85                }
  86                /* If they specified -l, we are all done */
  87                return EXIT_SUCCESS;
  88        }
  89
  90        /* The -q quiet option */
  91        if (killall && arg[1] == 'q' && arg[2] == '\0') {
  92                quiet = 1;
  93                arg = *++argv;
  94                argc--;
  95                if (argc < 1)
  96                        bb_show_usage();
  97                if (arg[0] != '-')
  98                        goto do_it_now;
  99        }
 100
 101        arg++; /* skip '-' */
 102
 103        /* -o PID? (if present, it always is at the end of command line) */
 104        if (killall5 && arg[0] == 'o')
 105                goto do_it_now;
 106
 107        if (argc > 1 && arg[0] == 's' && arg[1] == '\0') { /* -s SIG? */
 108                argc--;
 109                arg = *++argv;
 110        } /* else it must be -SIG */
 111        signo = get_signum(arg);
 112        if (signo < 0) { /* || signo > MAX_SIGNUM ? */
 113                bb_error_msg("bad signal name '%s'", arg);
 114                return EXIT_FAILURE;
 115        }
 116        arg = *++argv;
 117        argc--;
 118
 119 do_it_now:
 120        pid = getpid();
 121
 122        if (killall5) {
 123                pid_t sid;
 124                procps_status_t* p = NULL;
 125                int ret = 0;
 126
 127                /* Find out our session id */
 128                sid = getsid(pid);
 129                /* Stop all processes */
 130                kill(-1, SIGSTOP);
 131                /* Signal all processes except those in our session */
 132                while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) {
 133                        int i;
 134
 135                        if (p->sid == (unsigned)sid
 136                         || p->pid == (unsigned)pid
 137                         || p->pid == 1)
 138                                continue;
 139
 140                        /* All remaining args must be -o PID options.
 141                         * Check p->pid against them. */
 142                        for (i = 0; i < argc; i++) {
 143                                pid_t omit;
 144
 145                                arg = argv[i];
 146                                if (arg[0] != '-' || arg[1] != 'o') {
 147                                        bb_error_msg("bad option '%s'", arg);
 148                                        ret = 1;
 149                                        goto resume;
 150                                }
 151                                arg += 2;
 152                                if (!arg[0] && argv[++i])
 153                                        arg = argv[i];
 154                                omit = bb_strtoi(arg, NULL, 10);
 155                                if (errno) {
 156                                        bb_error_msg("invalid number '%s'", arg);
 157                                        ret = 1;
 158                                        goto resume;
 159                                }
 160                                if (p->pid == omit)
 161                                        goto dont_kill;
 162                        }
 163                        kill(p->pid, signo);
 164 dont_kill: ;
 165                }
 166 resume:
 167                /* And let them continue */
 168                kill(-1, SIGCONT);
 169                return ret;
 170        }
 171
 172        /* Pid or name is required for kill/killall */
 173        if (argc < 1) {
 174                bb_error_msg("you need to specify whom to kill");
 175                return EXIT_FAILURE;
 176        }
 177
 178        if (killall) {
 179                /* Looks like they want to do a killall.  Do that */
 180                while (arg) {
 181                        pid_t* pidList;
 182
 183                        pidList = find_pid_by_name(arg);
 184                        if (*pidList == 0) {
 185                                errors++;
 186                                if (!quiet)
 187                                        bb_error_msg("%s: no process killed", arg);
 188                        } else {
 189                                pid_t *pl;
 190
 191                                for (pl = pidList; *pl; pl++) {
 192                                        if (*pl == pid)
 193                                                continue;
 194                                        if (kill(*pl, signo) == 0)
 195                                                continue;
 196                                        errors++;
 197                                        if (!quiet)
 198                                                bb_perror_msg("can't kill pid %d", (int)*pl);
 199                                }
 200                        }
 201                        free(pidList);
 202                        arg = *++argv;
 203                }
 204                return errors;
 205        }
 206
 207        /* Looks like they want to do a kill. Do that */
 208        while (arg) {
 209                /* Support shell 'space' trick */
 210                if (arg[0] == ' ')
 211                        arg++;
 212                pid = bb_strtoi(arg, NULL, 10);
 213                if (errno) {
 214                        bb_error_msg("invalid number '%s'", arg);
 215                        errors++;
 216                } else if (kill(pid, signo) != 0) {
 217                        bb_perror_msg("can't kill pid %d", (int)pid);
 218                        errors++;
 219                }
 220                arg = *++argv;
 221        }
 222        return errors;
 223}
 224