Home | History | Annotate | Download | only in kill
      1 /* $NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg 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.27 2011/08/29 14:51:18 joerg 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(char *);
     67 static void printsignals(FILE *);
     68 static int signame_to_signum(char *);
     69 __dead static void usage(void);
     70 
     71 int
     72 main(int argc, char *argv[])
     73 {
     74 	int errors;
     75 	intmax_t numsig, pid;
     76 	char *ep;
     77 
     78 	setprogname(argv[0]);
     79 	setlocale(LC_ALL, "");
     80 	if (argc < 2)
     81 		usage();
     82 
     83 	numsig = SIGTERM;
     84 
     85 	argc--, argv++;
     86 	if (strcmp(*argv, "-l") == 0) {
     87 		argc--, argv++;
     88 		if (argc > 1)
     89 			usage();
     90 		if (argc == 1) {
     91 			if (isdigit((unsigned char)**argv) == 0)
     92 				usage();
     93 			numsig = strtoimax(*argv, &ep, 10);
     94 			/* check for correctly parsed number */
     95 			if (*ep != '\0' || numsig == INTMAX_MIN || numsig == INTMAX_MAX) {
     96 				errx(EXIT_FAILURE, "illegal signal number: %s",
     97 						*argv);
     98 				/* NOTREACHED */
     99 			}
    100 			if (numsig >= 128)
    101 				numsig -= 128;
    102 			/* and whether it fits into signals range */
    103 			if (numsig <= 0 || numsig >= NSIG)
    104 				nosig(*argv);
    105 			printf("%s\n", sys_signame[(int) numsig]);
    106 			exit(0);
    107 		}
    108 		printsignals(stdout);
    109 		exit(0);
    110 	}
    111 
    112 	if (!strcmp(*argv, "-s")) {
    113 		argc--, argv++;
    114 		if (argc < 1) {
    115 			warnx("option requires an argument -- s");
    116 			usage();
    117 		}
    118 		if (strcmp(*argv, "0")) {
    119 			if ((numsig = signame_to_signum(*argv)) < 0)
    120 				nosig(*argv);
    121 		} else
    122 			numsig = 0;
    123 		argc--, argv++;
    124 	} else if (**argv == '-') {
    125 		char *sn = *argv + 1;
    126 		if (isalpha((unsigned char)*sn)) {
    127 			if ((numsig = signame_to_signum(sn)) < 0)
    128 				nosig(sn);
    129 		} else if (isdigit((unsigned char)*sn)) {
    130 			numsig = strtoimax(sn, &ep, 10);
    131 			/* check for correctly parsed number */
    132 			if (*ep || numsig == INTMAX_MIN || numsig == INTMAX_MAX ) {
    133 				errx(EXIT_FAILURE, "illegal signal number: %s",
    134 						sn);
    135 				/* NOTREACHED */
    136 			}
    137 			/* and whether it fits into signals range */
    138 			if (numsig < 0 || numsig >= NSIG)
    139 				nosig(sn);
    140 		} else
    141 			nosig(sn);
    142 		argc--, argv++;
    143 	}
    144 
    145 	if (argc == 0)
    146 		usage();
    147 
    148 	for (errors = 0; argc; argc--, argv++) {
    149 #ifdef SHELL
    150 		extern int getjobpgrp(const char *);
    151 		if (*argv[0] == '%') {
    152 			pid = getjobpgrp(*argv);
    153 			if (pid == 0) {
    154 				warnx("illegal job id: %s", *argv);
    155 				errors = 1;
    156 				continue;
    157 			}
    158 		} else
    159 #endif
    160 		{
    161 			pid = strtoimax(*argv, &ep, 10);
    162 			/* make sure the pid is a number and fits into pid_t */
    163 			if (!**argv || *ep || pid == INTMAX_MIN ||
    164 				pid == INTMAX_MAX || pid != (pid_t) pid) {
    165 
    166 				warnx("illegal process id: %s", *argv);
    167 				errors = 1;
    168 				continue;
    169 			}
    170 		}
    171 		if (kill((pid_t) pid, (int) numsig) == -1) {
    172 			warn("%s", *argv);
    173 			errors = 1;
    174 		}
    175 #ifdef SHELL
    176 		/* Wakeup the process if it was suspended, so it can
    177 		   exit without an explicit 'fg'. */
    178 		if (numsig == SIGTERM || numsig == SIGHUP)
    179 			kill((pid_t) pid, SIGCONT);
    180 #endif
    181 	}
    182 
    183 	exit(errors);
    184 	/* NOTREACHED */
    185 }
    186 
    187 static int
    188 signame_to_signum(char *sig)
    189 {
    190 	int n;
    191 
    192 	if (strncasecmp(sig, "sig", 3) == 0)
    193 		sig += 3;
    194 	for (n = 1; n < NSIG; n++) {
    195 		if (!strcasecmp(sys_signame[n], sig))
    196 			return (n);
    197 	}
    198 	return (-1);
    199 }
    200 
    201 static void
    202 nosig(char *name)
    203 {
    204 
    205 	warnx("unknown signal %s; valid signals:", name);
    206 	printsignals(stderr);
    207 	exit(1);
    208 	/* NOTREACHED */
    209 }
    210 
    211 static void
    212 printsignals(FILE *fp)
    213 {
    214 	int sig;
    215 	int len, nl;
    216 	const char *name;
    217 	int termwidth = 80;
    218 
    219 	if (isatty(fileno(fp))) {
    220 		struct winsize win;
    221 		if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
    222 			termwidth = win.ws_col;
    223 	}
    224 
    225 	for (len = 0, sig = 1; sig < NSIG; sig++) {
    226 		name = sys_signame[sig];
    227 		nl = 1 + strlen(name);
    228 
    229 		if (len + nl >= termwidth) {
    230 			fprintf(fp, "\n");
    231 			len = 0;
    232 		} else
    233 			if (len != 0)
    234 				fprintf(fp, " ");
    235 		len += nl;
    236 		fprintf(fp, "%s", name);
    237 	}
    238 	if (len != 0)
    239 		fprintf(fp, "\n");
    240 }
    241 
    242 static void
    243 usage(void)
    244 {
    245 
    246 	fprintf(stderr, "usage: %s [-s signal_name] pid ...\n"
    247 	    "       %s -l [exit_status]\n"
    248 	    "       %s -signal_name pid ...\n"
    249 	    "       %s -signal_number pid ...\n",
    250 	    getprogname(), getprogname(), getprogname(), getprogname());
    251 	exit(1);
    252 	/* NOTREACHED */
    253 }
    254