]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/kill.c
docs: AUTHORS: remove four duplicate entries
[thirdparty/util-linux.git] / misc-utils / kill.c
1 /*
2 * Copyright (c) 1988, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
20 *
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
31 * SUCH DAMAGE.
32 */
33 /*
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.
37 *
38 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
39 * - added Native Language Support
40 *
41 * 1999-11-13 aeb Accept signal numers 128+s.
42 *
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h> /* for isdigit() */
49 #include <unistd.h>
50 #include <signal.h>
51
52 #include "c.h"
53 #include "kill.h"
54 #include "nls.h"
55 #include "closestream.h"
56 #include "strutils.h"
57
58 struct signv {
59 char *name;
60 int val;
61 } sys_signame[] = {
62 /* POSIX signals */
63 { "HUP", SIGHUP }, /* 1 */
64 { "INT", SIGINT }, /* 2 */
65 { "QUIT", SIGQUIT }, /* 3 */
66 { "ILL", SIGILL }, /* 4 */
67 { "ABRT", SIGABRT }, /* 6 */
68 { "FPE", SIGFPE }, /* 8 */
69 { "KILL", SIGKILL }, /* 9 */
70 { "SEGV", SIGSEGV }, /* 11 */
71 { "PIPE", SIGPIPE }, /* 13 */
72 { "ALRM", SIGALRM }, /* 14 */
73 { "TERM", SIGTERM }, /* 15 */
74 { "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
75 { "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
76 { "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
77 { "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
78 { "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
79 { "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
80 { "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
81 { "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
82 /* Miscellaneous other signals */
83 #ifdef SIGTRAP
84 { "TRAP", SIGTRAP }, /* 5 */
85 #endif
86 #ifdef SIGIOT
87 { "IOT", SIGIOT }, /* 6, same as SIGABRT */
88 #endif
89 #ifdef SIGEMT
90 { "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */
91 #endif
92 #ifdef SIGBUS
93 { "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
94 #endif
95 #ifdef SIGSYS
96 { "SYS", SIGSYS }, /* 12 (mips,alpha,sparc*) */
97 #endif
98 #ifdef SIGSTKFLT
99 { "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */
100 #endif
101 #ifdef SIGURG
102 { "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
103 #endif
104 #ifdef SIGIO
105 { "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
106 #endif
107 #ifdef SIGPOLL
108 { "POLL", SIGPOLL }, /* same as SIGIO */
109 #endif
110 #ifdef SIGCLD
111 { "CLD", SIGCLD }, /* same as SIGCHLD (mips) */
112 #endif
113 #ifdef SIGXCPU
114 { "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
115 #endif
116 #ifdef SIGXFSZ
117 { "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
118 #endif
119 #ifdef SIGVTALRM
120 { "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
121 #endif
122 #ifdef SIGPROF
123 { "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
124 #endif
125 #ifdef SIGPWR
126 { "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
127 #endif
128 #ifdef SIGINFO
129 { "INFO", SIGINFO }, /* 29 (alpha) */
130 #endif
131 #ifdef SIGLOST
132 { "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */
133 #endif
134 #ifdef SIGWINCH
135 { "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
136 #endif
137 #ifdef SIGUNUSED
138 { "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */
139 #endif
140 };
141
142 extern char *mybasename(char *);
143
144 static int arg_to_signum (char *arg, int mask);
145 static void nosig (char *name);
146 static void printsig (int sig);
147 static void printsignals (FILE *fp);
148 static int usage (int status);
149 static int kill_verbose (char *procname, int pid, int sig);
150
151 static char *progname;
152
153 #ifdef HAVE_SIGQUEUE
154 static int use_sigval;
155 static union sigval sigdata;
156 #endif
157
158 int main (int argc, char *argv[])
159 {
160 int errors, numsig, pid;
161 char *ep, *arg, *p;
162 int do_pid, do_kill, check_all;
163 int *pids, *ip;
164
165 progname = argv[0];
166 if ((p = strrchr(progname, '/')) != NULL)
167 progname = p+1;
168
169 setlocale(LC_ALL, "");
170 bindtextdomain(PACKAGE, LOCALEDIR);
171 textdomain(PACKAGE);
172 atexit(close_stdout);
173
174 numsig = SIGTERM;
175 do_pid = (! strcmp (progname, "pid")); /* Yecch */
176 do_kill = 0;
177 check_all = 0;
178
179 /* loop through the arguments.
180 actually, -a is the only option can be used with other options.
181 `kill' is basically a one-option-at-most program. */
182 for (argc--, argv++; argc > 0; argc--, argv++) {
183 arg = *argv;
184 if (*arg != '-') {
185 break;
186 }
187 if (! strcmp (arg, "--")) {
188 argc--, argv++;
189 break;
190 }
191 if (! strcmp (arg, "-v") || ! strcmp (arg, "-V") ||
192 ! strcmp (arg, "--version")) {
193 printf(UTIL_LINUX_VERSION);
194 return 0;
195 }
196 if (! strcmp (arg, "-a")) {
197 check_all++;
198 continue;
199 }
200 if (! strcmp (arg, "-l")) {
201 if (argc < 2) {
202 printsignals (stdout);
203 return 0;
204 }
205 if (argc > 2) {
206 return usage (1);
207 }
208 /* argc == 2, accept "kill -l $?" */
209 arg = argv[1];
210 if ((numsig = arg_to_signum (arg, 1)) < 0) {
211 fprintf (stderr, _("%s: unknown signal %s\n"), progname, arg);
212 return 1;
213 }
214 printsig (numsig);
215 return 0;
216 }
217 if (! strcmp (arg, "-p")) {
218 do_pid++;
219 if (do_kill)
220 return usage (1);
221 continue;
222 }
223 if (! strcmp (arg, "-s")) {
224 if (argc < 2) {
225 return usage (1);
226 }
227 do_kill++;
228 if (do_pid)
229 return usage (1);
230 argc--, argv++;
231 arg = *argv;
232 if ((numsig = arg_to_signum (arg, 0)) < 0) {
233 nosig (arg);
234 return 1;
235 }
236 continue;
237 }
238 if (! strcmp (arg, "-q")) {
239 if (argc < 2)
240 return usage (1);
241 argc--, argv++;
242 arg = *argv;
243 #ifdef HAVE_SIGQUEUE
244 sigdata.sival_int = strtos32_or_err(arg, _("invalid sigval argument"));
245 use_sigval = 1;
246 #endif
247 continue;
248 }
249 /* `arg' begins with a dash but is not a known option.
250 so it's probably something like -HUP, or -1/-n
251 try to deal with it.
252 -n could be signal n, or pid -n (i.e. process group n).
253 In case of doubt POSIX tells us to assume a signal.
254 If a signal has been parsed, assume it's a pid, break */
255 if (do_kill)
256 break;
257 arg++;
258 if ((numsig = arg_to_signum (arg, 0)) < 0) {
259 return usage (1);
260 }
261 do_kill++;
262 if (do_pid)
263 return usage (1);
264 continue;
265 }
266
267 if (! *argv) {
268 return usage (1);
269 }
270 if (do_pid) {
271 numsig = -1;
272 }
273
274 /* we're done with the options.
275 the rest of the arguments should be process ids and names.
276 kill them. */
277 for (errors = 0; (arg = *argv) != NULL; argv++) {
278 pid = strtol (arg, &ep, 10);
279 if (! *ep)
280 errors += kill_verbose (arg, pid, numsig);
281 else {
282 pids = get_pids (arg, check_all);
283 if (! pids) {
284 errors++;
285 fprintf (stderr, _("%s: can't find process \"%s\"\n"),
286 progname, arg);
287 continue;
288 }
289 for (ip = pids; *ip >= 0; ip++)
290 errors += kill_verbose (arg, *ip, numsig);
291 free (pids);
292 }
293 }
294 return (errors);
295 }
296
297 #ifdef SIGRTMIN
298 static int rtsig_to_signum(char *sig)
299 {
300 int num, maxi = 0;
301 char *ep = NULL;
302
303 if (strncasecmp(sig, "min+", 4) == 0)
304 sig += 4;
305 else if (strncasecmp(sig, "max-", 4) == 0) {
306 sig += 4;
307 maxi = 1;
308 }
309
310 if (!isdigit(*sig))
311 return -1;
312
313 errno = 0;
314 num = strtol(sig, &ep, 10);
315 if (!ep || sig == ep || errno || num < 0)
316 return -1;
317
318 num = maxi ? SIGRTMAX - num : SIGRTMIN + num;
319
320 if (num < SIGRTMIN || num > SIGRTMAX)
321 return -1;
322
323 return num;
324 }
325 #endif
326
327 static int signame_to_signum (char *sig)
328 {
329 size_t n;
330
331 if (! strncasecmp (sig, "sig", 3))
332 sig += 3;
333
334 #ifdef SIGRTMIN
335 /* RT signals */
336 if (!strncasecmp(sig, "rt", 2))
337 return rtsig_to_signum(sig + 2);
338 #endif
339 /* Normal sugnals */
340 for (n = 0; n < ARRAY_SIZE(sys_signame); n++) {
341 if (! strcasecmp (sys_signame[n].name, sig))
342 return sys_signame[n].val;
343 }
344 return (-1);
345 }
346
347 static int arg_to_signum (char *arg, int maskbit)
348 {
349 int numsig;
350 char *ep;
351
352 if (isdigit (*arg)) {
353 numsig = strtol (arg, &ep, 10);
354 if (numsig >= NSIG && maskbit && (numsig & 128) != 0)
355 numsig -= 128;
356 if (*ep != 0 || numsig < 0 || numsig >= NSIG)
357 return (-1);
358 return (numsig);
359 }
360 return signame_to_signum (arg);
361 }
362
363 static void nosig (char *name)
364 {
365 fprintf (stderr, _("%s: unknown signal %s; valid signals:\n"), progname, name);
366 printsignals (stderr);
367 }
368
369 static void printsig (int sig)
370 {
371 size_t n;
372
373 for (n = 0; n < ARRAY_SIZE(sys_signame); n++) {
374 if (sys_signame[n].val == sig) {
375 printf ("%s\n", sys_signame[n].name);
376 return;
377 }
378 }
379 #ifdef SIGRTMIN
380 if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
381 printf ("RT%d\n", sig - SIGRTMIN);
382 return;
383 }
384 #endif
385 printf("%d\n", sig);
386 }
387
388 static void printsignals (FILE *fp)
389 {
390 size_t n, lth, lpos = 0;
391
392 for (n = 0; n < ARRAY_SIZE(sys_signame); n++) {
393 lth = 1+strlen(sys_signame[n].name);
394 if (lpos+lth > 72) {
395 fputc ('\n', fp);
396 lpos = 0;
397 } else if (lpos)
398 fputc (' ', fp);
399 lpos += lth;
400 fputs (sys_signame[n].name, fp);
401 }
402 #ifdef SIGRTMIN
403 fputs (" RT<N> RTMIN+<N> RTMAX-<N>", fp);
404 #endif
405 fputc ('\n', fp);
406 }
407
408 static int usage (int status)
409 {
410 FILE *fp;
411
412 fp = (status == 0 ? stdout : stderr);
413 fprintf (fp, _("usage: %s [ -s signal | -p ] [ -a ] pid ...\n"), progname);
414 fprintf (fp, _(" %s -l [ signal ]\n"), progname);
415 return status;
416 }
417
418 static int kill_verbose (char *procname, int pid, int sig)
419 {
420 int rc;
421
422 if (sig < 0) {
423 printf ("%d\n", pid);
424 return 0;
425 }
426 #ifdef HAVE_SIGQUEUE
427 if (use_sigval)
428 rc = sigqueue(pid, sig, sigdata);
429 else
430 #endif
431 rc = kill (pid, sig);
432
433 if (rc < 0) {
434 fprintf (stderr, "%s ", progname);
435 perror (procname);
436 return 1;
437 }
438 return 0;
439 }