2 * Copyright (c) 1988, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * oct 5 1994 -- almost entirely re-written to allow for process names.
35 * modifications (c) salvatore valente <svalente@mit.edu>
36 * may be used / modified / distributed under the same terms as the original.
38 * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL>
39 * - added Native Language Support
41 * 1999-11-13 aeb Accept signal numers 128+s.
43 * Copyright (C) 2014 Sami Kerola <kerolasa@iki.fi>
44 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
47 #include <ctype.h> /* for isdigit() */
55 #include "closestream.h"
57 #include "procutils.h"
62 /* partial success, otherwise we return regular EXIT_{SUCCESS,FAILURE} */
63 #define KILL_EXIT_SOMEOK 64
66 KILL_FIELD_WIDTH
= 11,
67 KILL_OUTPUT_WIDTH
= 72
90 { "HUP", SIGHUP
}, /* 1 */
91 { "INT", SIGINT
}, /* 2 */
92 { "QUIT", SIGQUIT
}, /* 3 */
93 { "ILL", SIGILL
}, /* 4 */
95 { "TRAP", SIGTRAP
}, /* 5 */
97 { "ABRT", SIGABRT
}, /* 6 */
99 { "IOT", SIGIOT
}, /* 6, same as SIGABRT */
102 { "EMT", SIGEMT
}, /* 7 (mips,alpha,sparc*) */
105 { "BUS", SIGBUS
}, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
107 { "FPE", SIGFPE
}, /* 8 */
108 { "KILL", SIGKILL
}, /* 9 */
109 { "USR1", SIGUSR1
}, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
110 { "SEGV", SIGSEGV
}, /* 11 */
111 { "USR2", SIGUSR2
}, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
112 { "PIPE", SIGPIPE
}, /* 13 */
113 { "ALRM", SIGALRM
}, /* 14 */
114 { "TERM", SIGTERM
}, /* 15 */
116 { "STKFLT", SIGSTKFLT
}, /* 16 (arm,i386,m68k,ppc) */
118 { "CHLD", SIGCHLD
}, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
120 { "CLD", SIGCLD
}, /* same as SIGCHLD (mips) */
122 { "CONT", SIGCONT
}, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
123 { "STOP", SIGSTOP
}, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
124 { "TSTP", SIGTSTP
}, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
125 { "TTIN", SIGTTIN
}, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
126 { "TTOU", SIGTTOU
}, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
128 { "URG", SIGURG
}, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
131 { "XCPU", SIGXCPU
}, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
134 { "XFSZ", SIGXFSZ
}, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
137 { "VTALRM", SIGVTALRM
}, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
140 { "PROF", SIGPROF
}, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
143 { "WINCH", SIGWINCH
}, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
146 { "IO", SIGIO
}, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
149 { "POLL", SIGPOLL
}, /* same as SIGIO */
152 { "INFO", SIGINFO
}, /* 29 (alpha) */
155 { "LOST", SIGLOST
}, /* 29 (arm,i386,m68k,ppc,sparc*) */
158 { "PWR", SIGPWR
}, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
161 { "UNUSED", SIGUNUSED
}, /* 31 (arm,i386,m68k,ppc) */
164 { "SYS", SIGSYS
}, /* 31 (mips,alpha,sparc*) */
168 static void print_signal_name(int signum
)
172 for (n
= 0; n
< ARRAY_SIZE(sys_signame
); n
++) {
173 if (sys_signame
[n
].val
== signum
) {
174 printf("%s\n", sys_signame
[n
].name
);
179 if (SIGRTMIN
<= signum
&& signum
<= SIGRTMAX
) {
180 printf("RT%d\n", signum
- SIGRTMIN
);
184 printf("%d\n", signum
);
187 static void pretty_print_signal(FILE *fp
, size_t term_width
, size_t *lpos
,
188 int signum
, const char *name
)
190 if (term_width
< (*lpos
+ KILL_FIELD_WIDTH
)) {
194 *lpos
+= KILL_FIELD_WIDTH
;
195 fprintf(fp
, "%2d %-8s", signum
, name
);
198 static void print_all_signals(FILE *fp
, int pretty
)
200 size_t n
, lth
, lpos
= 0, width
;
203 for (n
= 0; n
< ARRAY_SIZE(sys_signame
); n
++) {
204 lth
= 1 + strlen(sys_signame
[n
].name
);
205 if (KILL_OUTPUT_WIDTH
< lpos
+ lth
) {
211 fputs(sys_signame
[n
].name
, fp
);
214 fputs(" RT<N> RTMIN+<N> RTMAX-<N>", fp
);
221 width
= get_terminal_width();
223 width
= KILL_OUTPUT_WIDTH
;
226 for (n
= 0; n
< ARRAY_SIZE(sys_signame
); n
++)
227 pretty_print_signal(fp
, width
, &lpos
,
228 sys_signame
[n
].val
, sys_signame
[n
].name
);
230 pretty_print_signal(fp
, width
, &lpos
, SIGRTMIN
, "RTMIN");
231 pretty_print_signal(fp
, width
, &lpos
, SIGRTMAX
, "RTMAX");
236 static void err_nosig(char *name
)
238 warnx(_("unknown signal %s; valid signals:"), name
);
239 print_all_signals(stderr
, 1);
244 static int rtsig_to_signum(char *sig
)
249 if (strncasecmp(sig
, "min+", 4) == 0)
251 else if (strncasecmp(sig
, "max-", 4) == 0) {
258 num
= strtol(sig
, &ep
, 10);
259 if (!ep
|| sig
== ep
|| errno
|| num
< 0)
261 num
= maxi
? SIGRTMAX
- num
: SIGRTMIN
+ num
;
262 if (num
< SIGRTMIN
|| SIGRTMAX
< num
)
268 static int signame_to_signum(char *sig
)
272 if (!strncasecmp(sig
, "sig", 3))
276 if (!strncasecmp(sig
, "rt", 2))
277 return rtsig_to_signum(sig
+ 2);
280 for (n
= 0; n
< ARRAY_SIZE(sys_signame
); n
++) {
281 if (!strcasecmp(sys_signame
[n
].name
, sig
))
282 return sys_signame
[n
].val
;
287 static int arg_to_signum(char *arg
, int maskbit
)
293 numsig
= strtol(arg
, &ep
, 10);
294 if (NSIG
<= numsig
&& maskbit
&& (numsig
& 128) != 0)
296 if (*ep
!= 0 || numsig
< 0 || NSIG
<= numsig
)
300 return signame_to_signum(arg
);
303 static void __attribute__((__noreturn__
)) usage(FILE *out
)
305 fputs(USAGE_HEADER
, out
);
306 fprintf(out
, _(" %s [options] <pid|name>...\n"), program_invocation_short_name
);
308 fputs(USAGE_OPTIONS
, out
);
309 fputs(_(" -a, --all do not restrict the name-to-pid conversion to processes\n"
310 " with the same uid as the present process\n"), out
);
311 fputs(_(" -s, --signal <sig> send specified signal\n"), out
);
313 fputs(_(" -q, --queue <sig> use sigqueue(2) rather than kill(2)\n"), out
);
315 fputs(_(" -p, --pid print pids without signaling them\n"), out
);
316 fputs(_(" -l, --list [=<signal>] list signal names, or convert one to a name\n"), out
);
317 fputs(_(" -L, --table list signal names and numbers\n"), out
);
318 fputs(_(" --verbose print pids that will be signaled\n"), out
);
320 fputs(USAGE_SEPARATOR
, out
);
321 fputs(USAGE_HELP
, out
);
322 fputs(USAGE_VERSION
, out
);
323 fprintf(out
, USAGE_MAN_TAIL("kill(1)"));
325 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
328 static char **parse_arguments(int argc
, char **argv
, struct kill_control
*ctl
)
332 /* Loop through the arguments. Actually, -a is the only option
333 * can be used with other options. The 'kill' is basically a
334 * one-option-at-most program. */
335 for (argc
--, argv
++; 0 < argc
; argc
--, argv
++) {
339 if (!strcmp(arg
, "--")) {
343 if (!strcmp(arg
, "-v") || !strcmp(arg
, "-V") ||
344 !strcmp(arg
, "--version")) {
345 printf(UTIL_LINUX_VERSION
);
348 if (!strcmp(arg
, "-h") || !strcmp(arg
, "--help"))
350 if (!strcmp(arg
, "--verbose")) {
354 if (!strcmp(arg
, "-a") || !strcmp(arg
, "--all")) {
358 if (!strcmp(arg
, "-l") || !strcmp(arg
, "--list")) {
360 print_all_signals(stdout
, 0);
364 errx(EXIT_FAILURE
, _("too many arguments"));
365 /* argc == 2, accept "kill -l $?" */
367 if ((ctl
->numsig
= arg_to_signum(arg
, 1)) < 0)
368 errx(EXIT_FAILURE
, _("unknown signal: %s"),
370 print_signal_name(ctl
->numsig
);
373 /* for compatibility with procps kill(1) */
374 if (!strncmp(arg
, "--list=", 7) || !strncmp(arg
, "-l=", 3)) {
375 char *p
= strchr(arg
, '=') + 1;
376 if ((ctl
->numsig
= arg_to_signum(p
, 1)) < 0)
377 errx(EXIT_FAILURE
, _("unknown signal: %s"), p
);
378 print_signal_name(ctl
->numsig
);
381 if (!strcmp(arg
, "-L") || !strcmp(arg
, "--table")) {
382 print_all_signals(stdout
, 1);
385 if (!strcmp(arg
, "-p") || !strcmp(arg
, "--pid")) {
388 errx(EXIT_FAILURE
, _("%s and %s are mutually exclusive"), "--pid", "--signal");
391 errx(EXIT_FAILURE
, _("%s and %s are mutually exclusive"), "--pid", "--queue");
395 if (!strcmp(arg
, "-s") || !strcmp(arg
, "--signal")) {
397 errx(EXIT_FAILURE
, _("not enough arguments"));
400 errx(EXIT_FAILURE
, _("%s and %s are mutually exclusive"), "--pid", "--signal");
403 if ((ctl
->numsig
= arg_to_signum(arg
, 0)) < 0)
408 if (!strcmp(arg
, "-q") || !strcmp(arg
, "--queue")) {
410 errx(EXIT_FAILURE
, _("option '%s' requires an argument"), arg
);
412 errx(EXIT_FAILURE
, _("%s and %s are mutually exclusive"), "--pid", "--queue");
415 ctl
->sigdata
.sival_int
= strtos32_or_err(arg
, _("argument error"));
420 /* 'arg' begins with a dash but is not a known option.
421 * So it's probably something like -HUP, or -1/-n try to
424 * -n could be signal n, or pid -n (i.e., process group
425 * number). In case of doubt POSIX tells us to assume a
426 * signal. If a signal has been parsed, assume it is a
431 if ((ctl
->numsig
= arg_to_signum(arg
, 0)) < 0)
432 errx(EXIT_FAILURE
, _("invalid sigval argument"));
435 errx(EXIT_FAILURE
, _("%s and %s are mutually exclusive"), "--pid", "--signal");
439 errx(EXIT_FAILURE
, _("not enough arguments"));
444 static int kill_verbose(const struct kill_control
*ctl
)
449 printf(_("sending signal %d to pid %d\n"), ctl
->numsig
, ctl
->pid
);
451 printf("%ld\n", (long) ctl
->pid
);
456 rc
= sigqueue(ctl
->pid
, ctl
->numsig
, ctl
->sigdata
);
459 rc
= kill(ctl
->pid
, ctl
->numsig
);
462 warn(_("sending signal to %s failed"), ctl
->arg
);
466 int main(int argc
, char **argv
)
468 struct kill_control ctl
= { .numsig
= SIGTERM
};
469 int nerrs
= 0, ct
= 0;
471 setlocale(LC_ALL
, "");
472 bindtextdomain(PACKAGE
, LOCALEDIR
);
474 atexit(close_stdout
);
476 ctl
.do_pid
= (!strcmp(program_invocation_short_name
, "pid")); /* Yecch */
477 if (ctl
.do_pid
) /* FIXME: remove in March 2016. */
478 warnx(_("use of 'kill --pid' option as command name is deprecated"));
480 argv
= parse_arguments(argc
, argv
, &ctl
);
482 /* The rest of the arguments should be process ids and names. */
483 for ( ; (ctl
.arg
= *argv
) != NULL
; argv
++) {
487 ctl
.pid
= strtol(ctl
.arg
, &ep
, 10);
488 if (errno
== 0 && ep
&& *ep
== '\0' && ctl
.arg
< ep
) {
489 if (kill_verbose(&ctl
) != 0)
493 struct proc_processes
*ps
= proc_open_processes();
499 proc_processes_filter_by_uid(ps
, getuid());
501 proc_processes_filter_by_name(ps
, ctl
.arg
);
502 while (proc_next_pid(ps
, &ctl
.pid
) == 0) {
503 if (kill_verbose(&ctl
) != 0)
508 proc_close_processes(ps
);
512 warnx(_("cannot find process \"%s\"."), ctl
.arg
);
517 if (ct
&& nerrs
== 0)
518 return EXIT_SUCCESS
; /* full success */
519 else if (ct
== nerrs
)
520 return EXIT_FAILURE
; /* all failed */
522 return KILL_EXIT_SOMEOK
; /* partial success */