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