xref: /netbsd-src/bin/kill/kill.c (revision 32cc3b02487f28a4afee3a936163698c954d5a47)
1*32cc3b02Skre /* $NetBSD: kill.c,v 1.33 2022/05/16 10:53:14 kre Exp $ */
249f0ad86Scgd 
361f28255Scgd /*
4667b5ea1Smycroft  * Copyright (c) 1988, 1993, 1994
5667b5ea1Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
3251e9bcecSchristos #include <sys/cdefs.h>
33c02b3bbdSchristos #if !defined(lint) && !defined(SHELL)
342fe2731dSlukem __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
352fe2731dSlukem  The Regents of the University of California.  All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd 
3861f28255Scgd #ifndef lint
3949f0ad86Scgd #if 0
40f859c958Sjtc static char sccsid[] = "@(#)kill.c	8.4 (Berkeley) 4/28/95";
4149f0ad86Scgd #else
42*32cc3b02Skre __RCSID("$NetBSD: kill.c,v 1.33 2022/05/16 10:53:14 kre Exp $");
4349f0ad86Scgd #endif
4461f28255Scgd #endif /* not lint */
4561f28255Scgd 
46667b5ea1Smycroft #include <ctype.h>
47667b5ea1Smycroft #include <err.h>
4861f28255Scgd #include <errno.h>
49667b5ea1Smycroft #include <signal.h>
5061f28255Scgd #include <stdio.h>
5161f28255Scgd #include <stdlib.h>
52f1afa090Sspz #include <limits.h>
53f1afa090Sspz #include <inttypes.h>
5461f28255Scgd #include <string.h>
55c02b3bbdSchristos #include <termios.h>
56c02b3bbdSchristos #include <unistd.h>
57c02b3bbdSchristos #include <locale.h>
58c02b3bbdSchristos #include <sys/ioctl.h>
5961f28255Scgd 
60c02b3bbdSchristos #ifdef SHELL            /* sh (aka ash) builtin */
615bb1ddccSjoerg int killcmd(int, char *argv[]);
62c02b3bbdSchristos #define main killcmd
63c02b3bbdSchristos #include "../../bin/sh/bltin/bltin.h"
64c02b3bbdSchristos #endif /* SHELL */
65c02b3bbdSchristos 
66a3be5e86Skre __dead static void nosig(const char *);
6733a05de6Skre void printsignals(FILE *, int);
68a3be5e86Skre static int signum(const char *);
694d4d1642Skre static int processnum(const char *, pid_t *);
705bb1ddccSjoerg __dead static void usage(void);
71667b5ea1Smycroft 
72667b5ea1Smycroft int
main(int argc,char * argv[])73e54efb95Swiz main(int argc, char *argv[])
7461f28255Scgd {
75f1afa090Sspz 	int errors;
76a3be5e86Skre 	int numsig;
77a3be5e86Skre 	pid_t pid;
78a3be5e86Skre 	const char *sn;
7961f28255Scgd 
80ed7b508eSwiz 	setprogname(argv[0]);
81c02b3bbdSchristos 	setlocale(LC_ALL, "");
8261f28255Scgd 	if (argc < 2)
8361f28255Scgd 		usage();
8461f28255Scgd 
850ba34484Sjtc 	numsig = SIGTERM;
8661f28255Scgd 
87667b5ea1Smycroft 	argc--, argv++;
88a3be5e86Skre 
89a3be5e86Skre 	/*
90a3be5e86Skre 	 * Process exactly 1 option, if there is one.
91a3be5e86Skre 	 */
92a3be5e86Skre 	if (argv[0][0] == '-') {
93a3be5e86Skre 		switch (argv[0][1]) {
94a3be5e86Skre 		case 'l':
95a3be5e86Skre 			if (argv[0][2] != '\0')
96a3be5e86Skre 				sn = argv[0] + 2;
97a3be5e86Skre 			else {
98a3be5e86Skre 				argc--; argv++;
99a3be5e86Skre 				sn = argv[0];
100a3be5e86Skre 			}
101667b5ea1Smycroft 			if (argc > 1)
1020ba34484Sjtc 				usage();
103667b5ea1Smycroft 			if (argc == 1) {
104a3be5e86Skre 				if (isdigit((unsigned char)*sn) == 0)
105667b5ea1Smycroft 					usage();
106a3be5e86Skre 				numsig = signum(sn);
107667b5ea1Smycroft 				if (numsig >= 128)
108667b5ea1Smycroft 					numsig -= 128;
109a3be5e86Skre 				if (numsig == 0 || signalnext(numsig) == -1)
110a3be5e86Skre 					nosig(sn);
111a3be5e86Skre 				sn = signalname(numsig);
112a3be5e86Skre 				if (sn == NULL)
113a3be5e86Skre 					errx(EXIT_FAILURE,
114a3be5e86Skre 					   "unknown signal number: %d", numsig);
115a3be5e86Skre 				printf("%s\n", sn);
116667b5ea1Smycroft 				exit(0);
1170ba34484Sjtc 			}
11833a05de6Skre 			printsignals(stdout, 0);
1190ba34484Sjtc 			exit(0);
120667b5ea1Smycroft 
121a3be5e86Skre 		case 's':
122a3be5e86Skre 			if (argv[0][2] != '\0')
123a3be5e86Skre 				sn = argv[0] + 2;
124a3be5e86Skre 			else {
125667b5ea1Smycroft 				argc--, argv++;
126667b5ea1Smycroft 				if (argc < 1) {
127a3be5e86Skre 					warnx(
128a3be5e86Skre 					    "option requires an argument -- s");
1290ba34484Sjtc 					usage();
1300ba34484Sjtc 				}
131a3be5e86Skre 				sn = argv[0];
132a3be5e86Skre 			}
133a3be5e86Skre 			if (strcmp(sn, "0") == 0)
134667b5ea1Smycroft 				numsig = 0;
135a3be5e86Skre 			else if ((numsig = signalnumber(sn)) == 0) {
136a3be5e86Skre 				if (sn != argv[0])
137a3be5e86Skre 					goto trysignal;
13865b5013eSchristos 				nosig(sn);
139458ed234Sjschauma 			}
140a3be5e86Skre 			argc--, argv++;
141a3be5e86Skre 			break;
142a3be5e86Skre 
143a3be5e86Skre 		case '-':
144a3be5e86Skre 			if (argv[0][2] == '\0') {
145a3be5e86Skre 				/* process this one again later */
146a3be5e86Skre 				break;
147a3be5e86Skre 			}
148a3be5e86Skre 			/* FALL THROUGH */
149a3be5e86Skre 		case '\0':
150a3be5e86Skre 			usage();
151a3be5e86Skre 			break;
152a3be5e86Skre 
153a3be5e86Skre 		default:
154a3be5e86Skre  trysignal:
155a3be5e86Skre 			sn = *argv + 1;
156a3be5e86Skre 			if (((numsig = signalnumber(sn)) == 0)) {
157a3be5e86Skre 				if (isdigit((unsigned char)*sn))
158a3be5e86Skre 					numsig = signum(sn);
159a3be5e86Skre 				else
16065b5013eSchristos 					nosig(sn);
161a3be5e86Skre 			}
162a3be5e86Skre 
163a3be5e86Skre 			if (numsig != 0 && signalnext(numsig) == -1)
16465b5013eSchristos 				nosig(sn);
1650ba34484Sjtc 			argc--, argv++;
166a3be5e86Skre 			break;
16761f28255Scgd 		}
168a3be5e86Skre 	}
169a3be5e86Skre 
170a3be5e86Skre 	/* deal with the optional '--' end of options option */
171a3be5e86Skre 	if (argc > 0 && strcmp(*argv, "--") == 0)
172a3be5e86Skre 		argc--, argv++;
17361f28255Scgd 
174667b5ea1Smycroft 	if (argc == 0)
17561f28255Scgd 		usage();
17661f28255Scgd 
177667b5ea1Smycroft 	for (errors = 0; argc; argc--, argv++) {
178c02b3bbdSchristos #ifdef SHELL
179c02b3bbdSchristos 		extern int getjobpgrp(const char *);
1804d4d1642Skre 
181c02b3bbdSchristos 		if (*argv[0] == '%') {
182c02b3bbdSchristos 			pid = getjobpgrp(*argv);
183c02b3bbdSchristos 			if (pid == 0) {
184*32cc3b02Skre 				warnx("bad job id: %s", *argv);
185c02b3bbdSchristos 				errors = 1;
186c02b3bbdSchristos 				continue;
187c02b3bbdSchristos 			}
188c02b3bbdSchristos 		} else
189c02b3bbdSchristos #endif
1904d4d1642Skre 			if (processnum(*argv, &pid) != 0) {
191667b5ea1Smycroft 				errors = 1;
192c02b3bbdSchristos 				continue;
193c02b3bbdSchristos 			}
194a3be5e86Skre 
195a3be5e86Skre 		if (kill(pid, numsig) == -1) {
1964d4d1642Skre 			warn("%s %s", pid < -1 ? "pgrp" : "pid", *argv);
19761f28255Scgd 			errors = 1;
19861f28255Scgd 		}
19934100a19Schristos #ifdef SHELL
200a3be5e86Skre 		/*
201a3be5e86Skre 		 * Wakeup the process if it was suspended, so it can
202a3be5e86Skre 		 * exit without an explicit 'fg'.
203a3be5e86Skre 		 *	(kernel handles this for SIGKILL)
204a3be5e86Skre 		 */
20534100a19Schristos 		if (numsig == SIGTERM || numsig == SIGHUP)
206a3be5e86Skre 			kill(pid, SIGCONT);
20734100a19Schristos #endif
20861f28255Scgd 	}
209667b5ea1Smycroft 
21061f28255Scgd 	exit(errors);
2111381f684Smycroft 	/* NOTREACHED */
21261f28255Scgd }
21361f28255Scgd 
214c02b3bbdSchristos static int
signum(const char * sn)215a3be5e86Skre signum(const char *sn)
2160ba34484Sjtc {
217a3be5e86Skre 	intmax_t n;
218a3be5e86Skre 	char *ep;
2190ba34484Sjtc 
220a3be5e86Skre 	n = strtoimax(sn, &ep, 10);
221a3be5e86Skre 
222a3be5e86Skre 	/* check for correctly parsed number */
223a3be5e86Skre 	if (*ep || n <= INT_MIN || n >= INT_MAX )
224*32cc3b02Skre 		errx(EXIT_FAILURE, "bad signal number: %s", sn);
225a3be5e86Skre 		/* NOTREACHED */
226a3be5e86Skre 
227a3be5e86Skre 	return (int)n;
2280ba34484Sjtc }
229a3be5e86Skre 
2304d4d1642Skre static int
processnum(const char * s,pid_t * pid)2314d4d1642Skre processnum(const char *s, pid_t *pid)
232a3be5e86Skre {
233a3be5e86Skre 	intmax_t n;
234a3be5e86Skre 	char *ep;
235a3be5e86Skre 
2364d4d1642Skre 	errno = 0;
237a3be5e86Skre 	n = strtoimax(s, &ep, 10);
238a3be5e86Skre 
239a3be5e86Skre 	/* check for correctly parsed number */
2404d4d1642Skre 	if (ep == s || *ep || n == INTMAX_MIN || n == INTMAX_MAX ||
2414d4d1642Skre 	    (pid_t)n != n || errno != 0) {
242*32cc3b02Skre 		warnx("bad process%s id: '%s'", (n < 0 ? " group" : ""), s);
2434d4d1642Skre 		return -1;
244a3be5e86Skre 	}
245a3be5e86Skre 
2464d4d1642Skre 	*pid = (pid_t)n;
2474d4d1642Skre 	return 0;
2480ba34484Sjtc }
2490ba34484Sjtc 
250c02b3bbdSchristos static void
nosig(const char * name)251a3be5e86Skre nosig(const char *name)
25261f28255Scgd {
253667b5ea1Smycroft 
254667b5ea1Smycroft 	warnx("unknown signal %s; valid signals:", name);
25533a05de6Skre 	printsignals(stderr, 0);
25661f28255Scgd 	exit(1);
2579dc385beSmycroft 	/* NOTREACHED */
25861f28255Scgd }
25961f28255Scgd 
260af2cfdd7Skre #ifndef SHELL
26133a05de6Skre /*
26233a05de6Skre  * Print the names of all the signals (neatly) to fp
26333a05de6Skre  * "len" gives the number of chars already printed to
26433a05de6Skre  * the current output line (in kill.c, always 0)
26533a05de6Skre  */
26633a05de6Skre void
printsignals(FILE * fp,int len)26733a05de6Skre printsignals(FILE *fp, int len)
26861f28255Scgd {
269c02b3bbdSchristos 	int sig;
27033a05de6Skre 	int nl, pad;
271c02b3bbdSchristos 	const char *name;
272c02b3bbdSchristos 	int termwidth = 80;
273075741c0Skre 	int posix;
27461f28255Scgd 
275075741c0Skre 	posix = getenv("POSIXLY_CORRECT") != 0;
276a3be5e86Skre 	if ((name = getenv("COLUMNS")) != 0)
277a3be5e86Skre 		termwidth = atoi(name);
278a3be5e86Skre 	else if (isatty(fileno(fp))) {
279c02b3bbdSchristos 		struct winsize win;
280a3be5e86Skre 
281c02b3bbdSchristos 		if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
282c02b3bbdSchristos 			termwidth = win.ws_col;
28361f28255Scgd 	}
28461f28255Scgd 
28533a05de6Skre 	pad = (len | 7) + 1 - len;
286075741c0Skre 	if (posix && pad)
287075741c0Skre 		pad = 1;
28833a05de6Skre 
28933a05de6Skre 	for (sig = 0; (sig = signalnext(sig)) != 0; ) {
290a3be5e86Skre 		name = signalname(sig);
291a3be5e86Skre 		if (name == NULL)
292a3be5e86Skre 			continue;
293c02b3bbdSchristos 
294a3be5e86Skre 		nl = strlen(name);
295a3be5e86Skre 
296a3be5e86Skre 		if (len > 0 && nl + len + pad >= termwidth) {
297c02b3bbdSchristos 			fprintf(fp, "\n");
298c02b3bbdSchristos 			len = 0;
299a3be5e86Skre 			pad = 0;
300a3be5e86Skre 		} else if (pad > 0 && len != 0)
301a3be5e86Skre 			fprintf(fp, "%*s", pad, "");
302a3be5e86Skre 		else
303a3be5e86Skre 			pad = 0;
304a3be5e86Skre 
305a3be5e86Skre 		len += nl + pad;
306a3be5e86Skre 		pad = (nl | 7) + 1 - nl;
307075741c0Skre 		if (posix && pad)
308075741c0Skre 			pad = 1;
309a3be5e86Skre 
310c02b3bbdSchristos 		fprintf(fp, "%s", name);
311c02b3bbdSchristos 	}
312c02b3bbdSchristos 	if (len != 0)
313c02b3bbdSchristos 		fprintf(fp, "\n");
314c02b3bbdSchristos }
315af2cfdd7Skre #endif
316c02b3bbdSchristos 
317c02b3bbdSchristos static void
usage(void)318e54efb95Swiz usage(void)
31961f28255Scgd {
320a3be5e86Skre 	const char *pn = getprogname();
321667b5ea1Smycroft 
322c02b3bbdSchristos 	fprintf(stderr, "usage: %s [-s signal_name] pid ...\n"
323ed7b508eSwiz 			"       %s -l [exit_status]\n"
324ed7b508eSwiz 			"       %s -signal_name pid ...\n"
325ed7b508eSwiz 			"       %s -signal_number pid ...\n",
326a3be5e86Skre 	    pn, pn, pn, pn);
32761f28255Scgd 	exit(1);
3289dc385beSmycroft 	/* NOTREACHED */
32961f28255Scgd }
330