1 /* $NetBSD: kill.c,v 1.28 2017/06/26 22:09:16 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.28 2017/06/26 22:09:16 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 static void printsignals(FILE *); 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); 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); 253 exit(1); 254 /* NOTREACHED */ 255 } 256 257 static void 258 printsignals(FILE *fp) 259 { 260 int sig; 261 int len, nl, pad; 262 const char *name; 263 int termwidth = 80; 264 265 if ((name = getenv("COLUMNS")) != 0) 266 termwidth = atoi(name); 267 else if (isatty(fileno(fp))) { 268 struct winsize win; 269 270 if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0) 271 termwidth = win.ws_col; 272 } 273 274 for (pad = 0, len = 0, sig = 0; (sig = signalnext(sig)) != 0; ) { 275 name = signalname(sig); 276 if (name == NULL) 277 continue; 278 279 nl = strlen(name); 280 281 if (len > 0 && nl + len + pad >= termwidth) { 282 fprintf(fp, "\n"); 283 len = 0; 284 pad = 0; 285 } else if (pad > 0 && len != 0) 286 fprintf(fp, "%*s", pad, ""); 287 else 288 pad = 0; 289 290 len += nl + pad; 291 pad = (nl | 7) + 1 - nl; 292 293 fprintf(fp, "%s", name); 294 } 295 if (len != 0) 296 fprintf(fp, "\n"); 297 } 298 299 static void 300 usage(void) 301 { 302 const char *pn = getprogname(); 303 304 fprintf(stderr, "usage: %s [-s signal_name] pid ...\n" 305 " %s -l [exit_status]\n" 306 " %s -signal_name pid ...\n" 307 " %s -signal_number pid ...\n", 308 pn, pn, pn, pn); 309 exit(1); 310 /* NOTREACHED */ 311 } 312