Home | History | Annotate | Line # | Download | only in kill
      1 /* $NetBSD: kill.c,v 1.33 2022/05/16 10:53:14 kre Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1988, 1993, 1994
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #if !defined(lint) && !defined(SHELL)
     34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
     35  The Regents of the University of California.  All rights reserved.");
     36 #endif /* not lint */
     37 
     38 #ifndef lint
     39 #if 0
     40 static char sccsid[] = "@(#)kill.c	8.4 (Berkeley) 4/28/95";
     41 #else
     42 __RCSID("$NetBSD: kill.c,v 1.33 2022/05/16 10:53:14 kre Exp $");
     43 #endif
     44 #endif /* not lint */
     45 
     46 #include <ctype.h>
     47 #include <err.h>
     48 #include <errno.h>
     49 #include <signal.h>
     50 #include <stdio.h>
     51 #include <stdlib.h>
     52 #include <limits.h>
     53 #include <inttypes.h>
     54 #include <string.h>
     55 #include <termios.h>
     56 #include <unistd.h>
     57 #include <locale.h>
     58 #include <sys/ioctl.h>
     59 
     60 #ifdef SHELL            /* sh (aka ash) builtin */
     61 int killcmd(int, char *argv[]);
     62 #define main killcmd
     63 #include "../../bin/sh/bltin/bltin.h"
     64 #endif /* SHELL */
     65 
     66 __dead static void nosig(const char *);
     67 void printsignals(FILE *, int);
     68 static int signum(const char *);
     69 static int processnum(const char *, pid_t *);
     70 __dead static void usage(void);
     71 
     72 int
     73 main(int argc, char *argv[])
     74 {
     75 	int errors;
     76 	int numsig;
     77 	pid_t pid;
     78 	const char *sn;
     79 
     80 	setprogname(argv[0]);
     81 	setlocale(LC_ALL, "");
     82 	if (argc < 2)
     83 		usage();
     84 
     85 	numsig = SIGTERM;
     86 
     87 	argc--, argv++;
     88 
     89 	/*
     90 	 * Process exactly 1 option, if there is one.
     91 	 */
     92 	if (argv[0][0] == '-') {
     93 		switch (argv[0][1]) {
     94 		case 'l':
     95 			if (argv[0][2] != '\0')
     96 				sn = argv[0] + 2;
     97 			else {
     98 				argc--; argv++;
     99 				sn = argv[0];
    100 			}
    101 			if (argc > 1)
    102 				usage();
    103 			if (argc == 1) {
    104 				if (isdigit((unsigned char)*sn) == 0)
    105 					usage();
    106 				numsig = signum(sn);
    107 				if (numsig >= 128)
    108 					numsig -= 128;
    109 				if (numsig == 0 || signalnext(numsig) == -1)
    110 					nosig(sn);
    111 				sn = signalname(numsig);
    112 				if (sn == NULL)
    113 					errx(EXIT_FAILURE,
    114 					   "unknown signal number: %d", numsig);
    115 				printf("%s\n", sn);
    116 				exit(0);
    117 			}
    118 			printsignals(stdout, 0);
    119 			exit(0);
    120 
    121 		case 's':
    122 			if (argv[0][2] != '\0')
    123 				sn = argv[0] + 2;
    124 			else {
    125 				argc--, argv++;
    126 				if (argc < 1) {
    127 					warnx(
    128 					    "option requires an argument -- s");
    129 					usage();
    130 				}
    131 				sn = argv[0];
    132 			}
    133 			if (strcmp(sn, "0") == 0)
    134 				numsig = 0;
    135 			else if ((numsig = signalnumber(sn)) == 0) {
    136 				if (sn != argv[0])
    137 					goto trysignal;
    138 				nosig(sn);
    139 			}
    140 			argc--, argv++;
    141 			break;
    142 
    143 		case '-':
    144 			if (argv[0][2] == '\0') {
    145 				/* process this one again later */
    146 				break;
    147 			}
    148 			/* FALL THROUGH */
    149 		case '\0':
    150 			usage();
    151 			break;
    152 
    153 		default:
    154  trysignal:
    155 			sn = *argv + 1;
    156 			if (((numsig = signalnumber(sn)) == 0)) {
    157 				if (isdigit((unsigned char)*sn))
    158 					numsig = signum(sn);
    159 				else
    160 					nosig(sn);
    161 			}
    162 
    163 			if (numsig != 0 && signalnext(numsig) == -1)
    164 				nosig(sn);
    165 			argc--, argv++;
    166 			break;
    167 		}
    168 	}
    169 
    170 	/* deal with the optional '--' end of options option */
    171 	if (argc > 0 && strcmp(*argv, "--") == 0)
    172 		argc--, argv++;
    173 
    174 	if (argc == 0)
    175 		usage();
    176 
    177 	for (errors = 0; argc; argc--, argv++) {
    178 #ifdef SHELL
    179 		extern int getjobpgrp(const char *);
    180 
    181 		if (*argv[0] == '%') {
    182 			pid = getjobpgrp(*argv);
    183 			if (pid == 0) {
    184 				warnx("bad job id: %s", *argv);
    185 				errors = 1;
    186 				continue;
    187 			}
    188 		} else
    189 #endif
    190 			if (processnum(*argv, &pid) != 0) {
    191 				errors = 1;
    192 				continue;
    193 			}
    194 
    195 		if (kill(pid, numsig) == -1) {
    196 			warn("%s %s", pid < -1 ? "pgrp" : "pid", *argv);
    197 			errors = 1;
    198 		}
    199 #ifdef SHELL
    200 		/*
    201 		 * Wakeup the process if it was suspended, so it can
    202 		 * exit without an explicit 'fg'.
    203 		 *	(kernel handles this for SIGKILL)
    204 		 */
    205 		if (numsig == SIGTERM || numsig == SIGHUP)
    206 			kill(pid, SIGCONT);
    207 #endif
    208 	}
    209 
    210 	exit(errors);
    211 	/* NOTREACHED */
    212 }
    213 
    214 static int
    215 signum(const char *sn)
    216 {
    217 	intmax_t n;
    218 	char *ep;
    219 
    220 	n = strtoimax(sn, &ep, 10);
    221 
    222 	/* check for correctly parsed number */
    223 	if (*ep || n <= INT_MIN || n >= INT_MAX )
    224 		errx(EXIT_FAILURE, "bad signal number: %s", sn);
    225 		/* NOTREACHED */
    226 
    227 	return (int)n;
    228 }
    229 
    230 static int
    231 processnum(const char *s, pid_t *pid)
    232 {
    233 	intmax_t n;
    234 	char *ep;
    235 
    236 	errno = 0;
    237 	n = strtoimax(s, &ep, 10);
    238 
    239 	/* check for correctly parsed number */
    240 	if (ep == s || *ep || n == INTMAX_MIN || n == INTMAX_MAX ||
    241 	    (pid_t)n != n || errno != 0) {
    242 		warnx("bad process%s id: '%s'", (n < 0 ? " group" : ""), s);
    243 		return -1;
    244 	}
    245 
    246 	*pid = (pid_t)n;
    247 	return 0;
    248 }
    249 
    250 static void
    251 nosig(const char *name)
    252 {
    253 
    254 	warnx("unknown signal %s; valid signals:", name);
    255 	printsignals(stderr, 0);
    256 	exit(1);
    257 	/* NOTREACHED */
    258 }
    259 
    260 #ifndef SHELL
    261 /*
    262  * Print the names of all the signals (neatly) to fp
    263  * "len" gives the number of chars already printed to
    264  * the current output line (in kill.c, always 0)
    265  */
    266 void
    267 printsignals(FILE *fp, int len)
    268 {
    269 	int sig;
    270 	int nl, pad;
    271 	const char *name;
    272 	int termwidth = 80;
    273 	int posix;
    274 
    275 	posix = getenv("POSIXLY_CORRECT") != 0;
    276 	if ((name = getenv("COLUMNS")) != 0)
    277 		termwidth = atoi(name);
    278 	else if (isatty(fileno(fp))) {
    279 		struct winsize win;
    280 
    281 		if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
    282 			termwidth = win.ws_col;
    283 	}
    284 
    285 	pad = (len | 7) + 1 - len;
    286 	if (posix && pad)
    287 		pad = 1;
    288 
    289 	for (sig = 0; (sig = signalnext(sig)) != 0; ) {
    290 		name = signalname(sig);
    291 		if (name == NULL)
    292 			continue;
    293 
    294 		nl = strlen(name);
    295 
    296 		if (len > 0 && nl + len + pad >= termwidth) {
    297 			fprintf(fp, "\n");
    298 			len = 0;
    299 			pad = 0;
    300 		} else if (pad > 0 && len != 0)
    301 			fprintf(fp, "%*s", pad, "");
    302 		else
    303 			pad = 0;
    304 
    305 		len += nl + pad;
    306 		pad = (nl | 7) + 1 - nl;
    307 		if (posix && pad)
    308 			pad = 1;
    309 
    310 		fprintf(fp, "%s", name);
    311 	}
    312 	if (len != 0)
    313 		fprintf(fp, "\n");
    314 }
    315 #endif
    316 
    317 static void
    318 usage(void)
    319 {
    320 	const char *pn = getprogname();
    321 
    322 	fprintf(stderr, "usage: %s [-s signal_name] pid ...\n"
    323 			"       %s -l [exit_status]\n"
    324 			"       %s -signal_name pid ...\n"
    325 			"       %s -signal_number pid ...\n",
    326 	    pn, pn, pn, pn);
    327 	exit(1);
    328 	/* NOTREACHED */
    329 }
    330