1 /* $NetBSD: kill.c,v 1.32 2020/08/30 19:35:09 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.32 2020/08/30 19:35:09 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("illegal 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, "illegal 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("illegal 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