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 the GPL v2 or later, see the file LICENSE in this tarball. 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); 28int kill_main(int argc, char **argv) 29{ 30 char *arg; 31 pid_t pid; 32 int signo = SIGTERM, errors = 0, quiet = 0; 33#if !ENABLE_KILLALL && !ENABLE_KILLALL5 34#define killall 0 35#define killall5 0 36#else 37/* How to determine who we are? find 3rd char from the end: 38 * kill, killall, killall5 39 * ^i ^a ^l - it's unique 40 * (checking from the start is complicated by /bin/kill... case) */ 41 const char char3 = argv[0][strlen(argv[0]) - 3]; 42#define killall (ENABLE_KILLALL && char3 == 'a') 43#define killall5 (ENABLE_KILLALL5 && char3 == 'l') 44#endif 45 46 /* Parse any options */ 47 argc--; 48 arg = *++argv; 49 50 if (argc < 1 || arg[0] != '-') { 51 goto do_it_now; 52 } 53 54 /* The -l option, which prints out signal names. 55 * Intended usage in shell: 56 * echo "Died of SIG`kill -l $?`" 57 * We try to mimic what kill from coreutils-6.8 does */ 58 if (arg[1] == 'l' && arg[2] == '\0') { 59 if (argc == 1) { 60 /* Print the whole signal list */ 61 for (signo = 1; signo < 32; signo++) { 62 const char *name = get_signame(signo); 63 if (!isdigit(name[0])) 64 puts(name); 65 } 66 } else { /* -l <sig list> */ 67 while ((arg = *++argv)) { 68 if (isdigit(arg[0])) { 69 signo = bb_strtou(arg, NULL, 10); 70 if (errno) { 71 bb_error_msg("unknown signal '%s'", arg); 72 return EXIT_FAILURE; 73 } 74 /* Exitcodes >= 0x80 are to be treated 75 * as "killed by signal (exitcode & 0x7f)" */ 76 puts(get_signame(signo & 0x7f)); 77 /* TODO: 'bad' signal# - coreutils says: 78 * kill: 127: invalid signal 79 * we just print "127" instead */ 80 } else { 81 signo = get_signum(arg); 82 if (signo < 0) { 83 bb_error_msg("unknown signal '%s'", arg); 84 return EXIT_FAILURE; 85 } 86 printf("%d\n", signo); 87 } 88 } 89 } 90 /* If they specified -l, we are all done */ 91 return EXIT_SUCCESS; 92 } 93 94 /* The -q quiet option */ 95 if (killall && arg[1] == 'q' && arg[2] == '\0') { 96 quiet = 1; 97 arg = *++argv; 98 argc--; 99 if (argc < 1) bb_show_usage(); 100 if (arg[0] != '-') goto do_it_now; 101 } 102 103 /* -SIG */ 104 signo = get_signum(&arg[1]); 105 if (signo < 0) { /* || signo > MAX_SIGNUM ? */ 106 bb_error_msg("bad signal name '%s'", &arg[1]); 107 return EXIT_FAILURE; 108 } 109 arg = *++argv; 110 argc--; 111 112do_it_now: 113 114 if (killall5) { 115 pid_t sid; 116 procps_status_t* p = NULL; 117 118 /* Now stop all processes */ 119 kill(-1, SIGSTOP); 120 /* Find out our own session id */ 121 pid = getpid(); 122 sid = getsid(pid); 123 /* Now kill all processes except our session */ 124 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { 125 if (p->sid != sid && p->pid != pid && p->pid != 1) 126 kill(p->pid, signo); 127 } 128 /* And let them continue */ 129 kill(-1, SIGCONT); 130 return 0; 131 } 132 133 /* Pid or name is required for kill/killall */ 134 if (argc < 1) { 135 puts("You need to specify whom to kill"); 136 return EXIT_FAILURE; 137 } 138 139 if (killall) { 140 /* Looks like they want to do a killall. Do that */ 141 pid = getpid(); 142 while (arg) { 143 pid_t* pidList; 144 145 pidList = find_pid_by_name(arg); 146 if (*pidList == 0) { 147 errors++; 148 if (!quiet) 149 bb_error_msg("%s: no process killed", arg); 150 } else { 151 pid_t *pl; 152 153 for (pl = pidList; *pl; pl++) { 154 if (*pl == pid) 155 continue; 156 if (kill(*pl, signo) == 0) 157 continue; 158 errors++; 159 if (!quiet) 160 bb_perror_msg("cannot kill pid %u", (unsigned)*pl); 161 } 162 } 163 free(pidList); 164 arg = *++argv; 165 } 166 return errors; 167 } 168 169 /* Looks like they want to do a kill. Do that */ 170 while (arg) { 171 /* Support shell 'space' trick */ 172 if (arg[0] == ' ') 173 arg++; 174 pid = bb_strtoi(arg, NULL, 10); 175 if (errno) { 176 bb_error_msg("bad pid '%s'", arg); 177 errors++; 178 } else if (kill(pid, signo) != 0) { 179 bb_perror_msg("cannot kill pid %d", (int)pid); 180 errors++; 181 } 182 arg = *++argv; 183 } 184 return errors; 185} 186