~vcs-imports/busybox/trunk

« back to all changes in this revision

Viewing changes to procps/kill.c

  • Committer: Eric Andersen
  • Date: 1999-11-24 09:04:33 UTC
  • Revision ID: git-v1:b99df0fd65abe3245fa2d04115326100847f865e
First draft

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* vi: set sw=4 ts=4: */
2
1
/*
3
 
 * Mini kill/killall[5] implementation for busybox
 
2
 * Mini kill implementation for busybox
4
3
 *
5
4
 * 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
 
//config:config KILL
11
 
//config:       bool "kill (3.4 kb)"
12
 
//config:       default y
13
 
//config:       help
14
 
//config:       The command kill sends the specified signal to the specified
15
 
//config:       process or process group. If no signal is specified, the TERM
16
 
//config:       signal is sent.
17
 
//config:
18
 
//config:config KILLALL
19
 
//config:       bool "killall (5.9 kb)"
20
 
//config:       default y
21
 
//config:       help
22
 
//config:       killall sends a signal to all processes running any of the
23
 
//config:       specified commands. If no signal name is specified, SIGTERM is
24
 
//config:       sent.
25
 
//config:
26
 
//config:config KILLALL5
27
 
//config:       bool "killall5 (5.6 kb)"
28
 
//config:       default y
29
 
//config:       help
30
 
//config:       The SystemV killall command. killall5 sends a signal
31
 
//config:       to all processes except kernel threads and the processes
32
 
//config:       in its own session, so it won't kill the shell that is running
33
 
//config:       the script it was called from.
34
 
 
35
 
//applet:IF_KILL(    APPLET_NOFORK(kill,     kill, BB_DIR_BIN,      BB_SUID_DROP, kill))
36
 
//                   APPLET_NOFORK:name      main  location         suid_type     help
37
 
//applet:IF_KILLALL( APPLET_NOFORK(killall,  kill, BB_DIR_USR_BIN,  BB_SUID_DROP, killall))
38
 
//applet:IF_KILLALL5(APPLET_NOFORK(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5))
39
 
 
40
 
//kbuild:lib-$(CONFIG_KILL) += kill.o
41
 
//kbuild:lib-$(CONFIG_KILLALL) += kill.o
42
 
//kbuild:lib-$(CONFIG_KILLALL5) += kill.o
43
 
 
44
 
//usage:#define kill_trivial_usage
45
 
//usage:       "[-l] [-SIG] PID..."
46
 
//usage:#define kill_full_usage "\n\n"
47
 
//usage:       "Send a signal (default: TERM) to given PIDs\n"
48
 
//usage:     "\n        -l      List all signal names and numbers"
49
 
/* //usage:  "\n        -s SIG  Yet another way of specifying SIG" */
50
 
//usage:
51
 
//usage:#define kill_example_usage
52
 
//usage:       "$ ps | grep apache\n"
53
 
//usage:       "252 root     root     S [apache]\n"
54
 
//usage:       "263 www-data www-data S [apache]\n"
55
 
//usage:       "264 www-data www-data S [apache]\n"
56
 
//usage:       "265 www-data www-data S [apache]\n"
57
 
//usage:       "266 www-data www-data S [apache]\n"
58
 
//usage:       "267 www-data www-data S [apache]\n"
59
 
//usage:       "$ kill 252\n"
60
 
//usage:
61
 
//usage:#define killall_trivial_usage
62
 
//usage:       "[-lq] [-SIG] PROCESS_NAME..."
63
 
//usage:#define killall_full_usage "\n\n"
64
 
//usage:       "Send a signal (default: TERM) to given processes\n"
65
 
//usage:     "\n        -l      List all signal names and numbers"
66
 
/* //usage:  "\n        -s SIG  Yet another way of specifying SIG" */
67
 
//usage:     "\n        -q      Don't complain if no processes were killed"
68
 
//usage:
69
 
//usage:#define killall_example_usage
70
 
//usage:       "$ killall apache\n"
71
 
//usage:
72
 
//usage:#define killall5_trivial_usage
73
 
//usage:       "[-l] [-SIG] [-o PID]..."
74
 
//usage:#define killall5_full_usage "\n\n"
75
 
//usage:       "Send a signal (default: TERM) to all processes outside current session\n"
76
 
//usage:     "\n        -l      List all signal names and numbers"
77
 
//usage:     "\n        -o PID  Don't signal this PID"
78
 
/* //usage:  "\n        -s SIG  Yet another way of specifying SIG" */
79
 
 
80
 
#include "libbb.h"
81
 
 
82
 
/* Note: kill_main is directly called from shell in order to implement
83
 
 * kill built-in. Shell substitutes job ids with process groups first.
84
 
 *
85
 
 * This brings some complications:
86
 
 *
87
 
 * + we can't use xfunc here
88
 
 * + we can't use bb_show_usage
89
 
 * + applet_name can be the name of the shell
90
 
 * (doesn't apply for killall[5], still should be careful b/c NOFORK)
91
 
 *
92
 
 * kill %n gets translated into kill ' -<process group>' by shell (note space!)
93
 
 * This is needed to avoid collision with kill -9 ... syntax
94
 
 */
95
 
 
96
 
//kbuild:lib-$(CONFIG_ASH_JOB_CONTROL) += kill.o
97
 
//kbuild:lib-$(CONFIG_HUSH_KILL) += kill.o
98
 
 
99
 
#define SH_KILL (ENABLE_ASH_JOB_CONTROL || ENABLE_HUSH_KILL)
100
 
/* If shells want to have "kill", for ifdefs it's like ENABLE_KILL=1 */
101
 
#if SH_KILL
102
 
# undef  ENABLE_KILL
103
 
# define ENABLE_KILL 1
104
 
#endif
105
 
#define KILL_APPLET_CNT (ENABLE_KILL + ENABLE_KILLALL + ENABLE_KILLALL5)
106
 
 
107
 
int kill_main(int argc UNUSED_PARAM, char **argv)
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
14
 * General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
19
 *
 
20
 */
 
21
 
 
22
 
 
23
#include "internal.h"
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <unistd.h>
 
27
#include <signal.h>
 
28
#include <ctype.h>
 
29
 
 
30
const char kill_usage[] = "kill [-signal] process-id [process-id ...]\n";
 
31
 
 
32
struct signal_name {
 
33
    const char *name;
 
34
    int number;
 
35
};
 
36
 
 
37
const struct signal_name signames[] = {
 
38
    {"HUP", SIGHUP},
 
39
    {"INT", SIGINT},
 
40
    {"QUIT", SIGQUIT},
 
41
    {"ILL", SIGILL},
 
42
    {"TRAP", SIGTRAP},
 
43
    {"ABRT", SIGABRT},
 
44
#ifndef __alpha__
 
45
    {"IOT", SIGIOT},
 
46
#endif
 
47
#if defined(__sparc__) || defined(__alpha__)
 
48
    {"EMT", SIGEMT},
 
49
#else
 
50
    {"BUS", SIGBUS},
 
51
#endif
 
52
    {"FPE", SIGFPE},
 
53
    {"KILL", SIGKILL},
 
54
#if defined(__sparc__) || defined(__alpha__)
 
55
    {"BUS", SIGBUS},
 
56
#else
 
57
    {"USR1", SIGUSR1},
 
58
#endif
 
59
    {"SEGV", SIGSEGV},
 
60
#if defined(__sparc__) || defined(__alpha__)
 
61
    {"SYS", SIGSYS},
 
62
#else
 
63
    {"USR2", SIGUSR2},
 
64
#endif
 
65
    {"PIPE", SIGPIPE},
 
66
    {"ALRM", SIGALRM},
 
67
    {"TERM", SIGTERM},
 
68
#if defined(__sparc__) || defined(__alpha__)
 
69
    {"URG", SIGURG},
 
70
    {"STOP", SIGSTOP},
 
71
    {"TSTP", SIGTSTP},
 
72
    {"CONT", SIGCONT},
 
73
    {"CHLD", SIGCHLD},
 
74
    {"TTIN", SIGTTIN},
 
75
    {"TTOU", SIGTTOU},
 
76
    {"IO", SIGIO},
 
77
# ifndef __alpha__
 
78
    {"POLL", SIGIO},
 
79
# endif
 
80
    {"XCPU", SIGXCPU},
 
81
    {"XFSZ", SIGXFSZ},
 
82
    {"VTALRM", SIGVTALRM},
 
83
    {"PROF", SIGPROF},
 
84
    {"WINCH", SIGWINCH},
 
85
# ifdef __alpha__
 
86
    {"INFO", SIGINFO},
 
87
# else
 
88
    {"LOST", SIGLOST},
 
89
# endif
 
90
    {"USR1", SIGUSR1},
 
91
    {"USR2", SIGUSR2},
 
92
#else
 
93
    {"STKFLT", SIGSTKFLT},
 
94
    {"CHLD", SIGCHLD},
 
95
    {"CONT", SIGCONT},
 
96
    {"STOP", SIGSTOP},
 
97
    {"TSTP", SIGTSTP},
 
98
    {"TTIN", SIGTTIN},
 
99
    {"TTOU", SIGTTOU},
 
100
    {"URG", SIGURG},
 
101
    {"XCPU", SIGXCPU},
 
102
    {"XFSZ", SIGXFSZ},
 
103
    {"VTALRM", SIGVTALRM},
 
104
    {"PROF", SIGPROF},
 
105
    {"WINCH", SIGWINCH},
 
106
    {"IO", SIGIO},
 
107
    {"POLL", SIGPOLL},
 
108
    {"PWR", SIGPWR},
 
109
    {"UNUSED", SIGUNUSED},
 
110
#endif
 
111
    {0, 0}
 
112
};
 
113
 
 
114
extern int kill_main (int argc, char **argv)
108
115
{
109
 
        char *arg;
110
 
        pid_t pid;
111
 
        int signo = SIGTERM, errors = 0;
112
 
#if ENABLE_KILL || ENABLE_KILLALL
113
 
        int quiet = 0;
114
 
#endif
115
 
 
116
 
#if KILL_APPLET_CNT == 1
117
 
# define is_killall  ENABLE_KILLALL
118
 
# define is_killall5 ENABLE_KILLALL5
119
 
#else
120
 
/* How to determine who we are? find 3rd char from the end:
121
 
 * kill, killall, killall5
122
 
 *  ^i       ^a        ^l  - it's unique
123
 
 * (checking from the start is complicated by /bin/kill... case) */
124
 
        const char char3 = argv[0][strlen(argv[0]) - 3];
125
 
# define is_killall  (ENABLE_KILLALL  && char3 == 'a')
126
 
# define is_killall5 (ENABLE_KILLALL5 && char3 == 'l')
127
 
#endif
128
 
 
129
 
        /* Parse any options */
130
 
        arg = *++argv;
131
 
 
132
 
        if (!arg || arg[0] != '-') {
133
 
                goto do_it_now;
134
 
        }
135
 
 
136
 
        /* The -l option, which prints out signal names.
137
 
         * Intended usage in shell:
138
 
         * echo "Died of SIG`kill -l $?`"
139
 
         * We try to mimic what kill from coreutils-6.8 does */
140
 
        if (arg[1] == 'l' && arg[2] == '\0') {
141
 
                arg = *++argv;
142
 
                if (!arg) {
143
 
                        /* Print the whole signal list */
144
 
                        print_signames();
145
 
                        return 0;
146
 
                }
147
 
                /* -l <sig list> */
148
 
                do {
149
 
                        if (isdigit(arg[0])) {
150
 
                                signo = bb_strtou(arg, NULL, 10);
151
 
                                if (errno) {
152
 
                                        bb_error_msg("unknown signal '%s'", arg);
153
 
                                        return EXIT_FAILURE;
154
 
                                }
155
 
                                /* Exitcodes >= 0x80 are to be treated
156
 
                                 * as "killed by signal (exitcode & 0x7f)" */
157
 
                                puts(get_signame(signo & 0x7f));
158
 
                                /* TODO: 'bad' signal# - coreutils says:
159
 
                                 * kill: 127: invalid signal
160
 
                                 * we just print "127" instead */
161
 
                        } else {
162
 
                                signo = get_signum(arg);
163
 
                                if (signo < 0) {
164
 
                                        bb_error_msg("unknown signal '%s'", arg);
165
 
                                        return EXIT_FAILURE;
166
 
                                }
167
 
                                printf("%d\n", signo);
168
 
                        }
169
 
                        arg = *++argv;
170
 
                } while (arg);
171
 
                return EXIT_SUCCESS;
172
 
        }
173
 
 
174
 
        /* The -q quiet option */
175
 
        if (is_killall && arg[1] == 'q' && arg[2] == '\0') {
176
 
#if ENABLE_KILL || ENABLE_KILLALL
177
 
                quiet = 1;
178
 
#endif
179
 
                arg = *++argv;
180
 
                if (!arg)
181
 
                        bb_show_usage();
182
 
                if (arg[0] != '-')
183
 
                        goto do_it_now;
184
 
        }
185
 
 
186
 
        arg++; /* skip '-' */
187
 
 
188
 
        /* -o PID? (if present, it always is at the end of command line) */
189
 
        if (is_killall5 && arg[0] == 'o')
190
 
                goto do_it_now;
191
 
 
192
 
        /* "--" separates options from args. Testcase: "kill -- -123" */
193
 
        if (!is_killall5 && arg[0] == '-' && arg[1] == '\0')
194
 
                goto do_it_sooner;
195
 
 
196
 
        if (argv[1] && arg[0] == 's' && arg[1] == '\0') { /* -s SIG? */
197
 
                arg = *++argv;
198
 
        } /* else it must be -SIG */
199
 
        signo = get_signum(arg);
200
 
        if (signo < 0) {
201
 
                bb_error_msg("bad signal name '%s'", arg);
202
 
                return EXIT_FAILURE;
203
 
        }
204
 
 do_it_sooner:
205
 
        arg = *++argv;
206
 
 
207
 
 do_it_now:
208
 
        pid = getpid();
209
 
 
210
 
        if (is_killall5) {
211
 
                pid_t sid;
212
 
                procps_status_t* p = NULL;
213
 
                /* compat: exitcode 2 is "no one was signaled" */
214
 
                errors = 2;
215
 
 
216
 
                /* Find out our session id */
217
 
                sid = getsid(pid);
218
 
                /* Stop all processes */
219
 
                if (signo != SIGSTOP && signo != SIGCONT)
220
 
                        kill(-1, SIGSTOP);
221
 
                /* Signal all processes except those in our session */
222
 
                while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) {
223
 
                        char **args;
224
 
 
225
 
                        if (p->sid == (unsigned)sid
226
 
                         || p->sid == 0 /* compat: kernel thread, don't signal it */
227
 
                         || p->pid == (unsigned)pid
228
 
                         || p->pid == 1
229
 
                        ) {
230
 
                                continue;
231
 
                        }
232
 
 
233
 
                        /* All remaining args must be -o PID options.
234
 
                         * Check p->pid against them. */
235
 
                        args = argv;
236
 
                        while (*args) {
237
 
                                pid_t omit;
238
 
 
239
 
                                arg = *args++;
240
 
                                if (arg[0] != '-' || arg[1] != 'o') {
241
 
                                        bb_error_msg("bad option '%s'", arg);
242
 
                                        errors = 1;
243
 
                                        goto resume;
244
 
                                }
245
 
                                arg += 2;
246
 
                                if (!arg[0] && *args)
247
 
                                        arg = *args++;
248
 
                                omit = bb_strtoi(arg, NULL, 10);
249
 
                                if (errno) {
250
 
                                        bb_error_msg("invalid number '%s'", arg);
251
 
                                        errors = 1;
252
 
                                        goto resume;
253
 
                                }
254
 
                                if (p->pid == omit)
255
 
                                        goto dont_kill;
256
 
                        }
257
 
                        kill(p->pid, signo);
258
 
                        errors = 0;
259
 
 dont_kill: ;
260
 
                }
261
 
 resume:
262
 
                /* And let them continue */
263
 
                if (signo != SIGSTOP && signo != SIGCONT)
264
 
                        kill(-1, SIGCONT);
265
 
                return errors;
266
 
        }
267
 
 
268
 
#if ENABLE_KILL || ENABLE_KILLALL
269
 
        /* Pid or name is required for kill/killall */
270
 
        if (!arg) {
271
 
                bb_simple_error_msg("you need to specify whom to kill");
272
 
                return EXIT_FAILURE;
273
 
        }
274
 
 
275
 
        if (!ENABLE_KILL || is_killall) {
276
 
                /* Looks like they want to do a killall.  Do that */
277
 
                do {
278
 
                        pid_t* pidList;
279
 
 
280
 
                        pidList = find_pid_by_name(arg);
281
 
                        if (*pidList == 0) {
282
 
                                errors++;
283
 
                                if (!quiet)
284
 
                                        bb_error_msg("%s: no process killed", arg);
285
 
                        } else {
286
 
                                pid_t *pl;
287
 
 
288
 
                                for (pl = pidList; *pl; pl++) {
289
 
                                        if (*pl == pid)
290
 
                                                continue;
291
 
                                        if (kill(*pl, signo) == 0)
292
 
                                                continue;
293
 
                                        errors++;
294
 
                                        if (!quiet)
295
 
                                                bb_perror_msg("can't kill pid %d", (int)*pl);
296
 
                                }
297
 
                        }
298
 
                        free(pidList);
299
 
                        arg = *++argv;
300
 
                } while (arg);
301
 
                return errors;
302
 
        }
303
 
#endif
304
 
 
305
 
#if ENABLE_KILL
306
 
        /* Looks like they want to do a kill. Do that */
307
 
        while (arg) {
308
 
# if SH_KILL
309
 
                /*
310
 
                 * We need to support shell's "hack formats" of
311
 
                 * " -PRGP_ID" (yes, with a leading space)
312
 
                 * and " PID1 PID2 PID3" (with degenerate case "")
313
 
                 */
314
 
                while (*arg != '\0') {
315
 
                        char *end;
316
 
                        if (*arg == ' ')
317
 
                                arg++;
318
 
                        pid = bb_strtoi(arg, &end, 10);
319
 
                        if (errno && (errno != EINVAL || *end != ' ')) {
320
 
                                bb_error_msg("invalid number '%s'", arg);
321
 
                                errors++;
322
 
                                break;
323
 
                        }
324
 
                        if (kill(pid, signo) != 0) {
325
 
                                bb_perror_msg("can't kill pid %d", (int)pid);
326
 
                                errors++;
327
 
                        }
328
 
                        arg = end; /* can only point to ' ' or '\0' now */
329
 
                }
330
 
# else /* ENABLE_KILL but !SH_KILL */
331
 
                pid = bb_strtoi(arg, NULL, 10);
332
 
                if (errno) {
333
 
                        bb_error_msg("invalid number '%s'", arg);
334
 
                        errors++;
335
 
                } else if (kill(pid, signo) != 0) {
336
 
                        bb_perror_msg("can't kill pid %d", (int)pid);
337
 
                        errors++;
338
 
                }
339
 
# endif
340
 
                arg = *++argv;
341
 
        }
342
 
        return errors;
343
 
#endif
 
116
    int sig = SIGTERM;
 
117
 
 
118
    if ( argc < 2 )
 
119
        usage (kill_usage);
 
120
 
 
121
    if ( **(argv+1) == '-' ) {
 
122
        if (isdigit( *(*(++argv)+1) )) {
 
123
            sig = atoi (*argv);
 
124
            if (sig < 0 || sig >= NSIG)
 
125
                goto end;
 
126
        }
 
127
        else {
 
128
            const struct signal_name *s = signames;
 
129
            while (s->name != 0) {
 
130
                if (strcasecmp (s->name, *argv+1) == 0) {
 
131
                    sig = s->number;
 
132
                    break;
 
133
                }
 
134
                s++;
 
135
            }
 
136
            if (s->name == 0)
 
137
                goto end;
 
138
        }
 
139
    }
 
140
 
 
141
    while (--argc > 1) {
 
142
        int pid;
 
143
        if (! isdigit( **(++argv))) {
 
144
            fprintf(stderr, "bad PID: %s\n", *argv);
 
145
            exit( FALSE);
 
146
        }
 
147
        pid = atoi (*argv);
 
148
        if (kill (pid, sig) != 0) {
 
149
            perror (*argv);
 
150
            exit ( FALSE);
 
151
        }
 
152
    }
 
153
 
 
154
end:
 
155
    fprintf(stderr, "bad signal name: %s\n", *argv);
 
156
    exit (TRUE);
344
157
}
 
158
 
 
159