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 40static 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 */ 61int 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 *); 67void printsignals(FILE *, int); 68static int signum(const char *); 69static int processnum(const char *, pid_t *); 70__dead static void usage(void); 71 72int 73main(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 214static int 215signum(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 230static int 231processnum(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 250static void 251nosig(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 */ 266void 267printsignals(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 317static void 318usage(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