Home | History | Annotate | Line # | Download | only in kill
kill.c revision 1.30
      1 /* $NetBSD: kill.c,v 1.30 2018/12/12 20:22:43 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.30 2018/12/12 20:22:43 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 pid_t processnum(const char *);
     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 		if (*argv[0] == '%') {
    181 			pid = getjobpgrp(*argv);
    182 			if (pid == 0) {
    183 				warnx("illegal job id: %s", *argv);
    184 				errors = 1;
    185 				continue;
    186 			}
    187 		} else
    188 #endif
    189 			if ((pid = processnum(*argv)) == (pid_t)-1) {
    190 				errors = 1;
    191 				continue;
    192 			}
    193 
    194 		if (kill(pid, numsig) == -1) {
    195 			warn("%s", *argv);
    196 			errors = 1;
    197 		}
    198 #ifdef SHELL
    199 		/*
    200 		 * Wakeup the process if it was suspended, so it can
    201 		 * exit without an explicit 'fg'.
    202 		 *	(kernel handles this for SIGKILL)
    203 		 */
    204 		if (numsig == SIGTERM || numsig == SIGHUP)
    205 			kill(pid, SIGCONT);
    206 #endif
    207 	}
    208 
    209 	exit(errors);
    210 	/* NOTREACHED */
    211 }
    212 
    213 static int
    214 signum(const char *sn)
    215 {
    216 	intmax_t n;
    217 	char *ep;
    218 
    219 	n = strtoimax(sn, &ep, 10);
    220 
    221 	/* check for correctly parsed number */
    222 	if (*ep || n <= INT_MIN || n >= INT_MAX )
    223 		errx(EXIT_FAILURE, "illegal signal number: %s", sn);
    224 		/* NOTREACHED */
    225 
    226 	return (int)n;
    227 }
    228 
    229 static pid_t
    230 processnum(const char *s)
    231 {
    232 	intmax_t n;
    233 	char *ep;
    234 
    235 	n = strtoimax(s, &ep, 10);
    236 
    237 	/* check for correctly parsed number */
    238 	if (*ep || n == INTMAX_MIN || n == INTMAX_MAX || (pid_t)n != n ||
    239 	    n == -1) {
    240 		warnx("illegal process%s id: %s", (n < 0 ? " group" : ""), s);
    241 		n = -1;
    242 	}
    243 
    244 	return (pid_t)n;
    245 }
    246 
    247 static void
    248 nosig(const char *name)
    249 {
    250 
    251 	warnx("unknown signal %s; valid signals:", name);
    252 	printsignals(stderr, 0);
    253 	exit(1);
    254 	/* NOTREACHED */
    255 }
    256 
    257 #ifndef SHELL
    258 /*
    259  * Print the names of all the signals (neatly) to fp
    260  * "len" gives the number of chars already printed to
    261  * the current output line (in kill.c, always 0)
    262  */
    263 void
    264 printsignals(FILE *fp, int len)
    265 {
    266 	int sig;
    267 	int nl, pad;
    268 	const char *name;
    269 	int termwidth = 80;
    270 
    271 	if ((name = getenv("COLUMNS")) != 0)
    272 		termwidth = atoi(name);
    273 	else if (isatty(fileno(fp))) {
    274 		struct winsize win;
    275 
    276 		if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
    277 			termwidth = win.ws_col;
    278 	}
    279 
    280 	pad = (len | 7) + 1 - len;
    281 
    282 	for (sig = 0; (sig = signalnext(sig)) != 0; ) {
    283 		name = signalname(sig);
    284 		if (name == NULL)
    285 			continue;
    286 
    287 		nl = strlen(name);
    288 
    289 		if (len > 0 && nl + len + pad >= termwidth) {
    290 			fprintf(fp, "\n");
    291 			len = 0;
    292 			pad = 0;
    293 		} else if (pad > 0 && len != 0)
    294 			fprintf(fp, "%*s", pad, "");
    295 		else
    296 			pad = 0;
    297 
    298 		len += nl + pad;
    299 		pad = (nl | 7) + 1 - nl;
    300 
    301 		fprintf(fp, "%s", name);
    302 	}
    303 	if (len != 0)
    304 		fprintf(fp, "\n");
    305 }
    306 #endif
    307 
    308 static void
    309 usage(void)
    310 {
    311 	const char *pn = getprogname();
    312 
    313 	fprintf(stderr, "usage: %s [-s signal_name] pid ...\n"
    314 			"       %s -l [exit_status]\n"
    315 			"       %s -signal_name pid ...\n"
    316 			"       %s -signal_number pid ...\n",
    317 	    pn, pn, pn, pn);
    318 	exit(1);
    319 	/* NOTREACHED */
    320 }
    321