1/* $OpenBSD: pkill.c,v 1.43 2021/09/01 15:54:40 deraadt Exp $ */ 2/* $NetBSD: pkill.c,v 1.5 2002/10/27 11:49:34 kleink Exp $ */ 3 4/*- 5 * Copyright (c) 2002 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/types.h> 34#include <sys/sysctl.h> 35#include <sys/signal.h> 36#include <sys/proc.h> 37#include <sys/queue.h> 38#include <sys/stat.h> 39#include <sys/socket.h> 40 41#include <stdio.h> 42#include <stdlib.h> 43#include <stdint.h> 44#include <limits.h> 45#include <string.h> 46#include <unistd.h> 47#include <signal.h> 48#include <regex.h> 49#include <ctype.h> 50#include <kvm.h> 51#include <err.h> 52#include <pwd.h> 53#include <grp.h> 54#include <errno.h> 55 56#define STATUS_MATCH 0 57#define STATUS_NOMATCH 1 58#define STATUS_BADUSAGE 2 59#define STATUS_ERROR 3 60 61enum listtype { 62 LT_GENERIC, 63 LT_USER, 64 LT_GROUP, 65 LT_TTY, 66 LT_PGRP, 67 LT_SID, 68 LT_RTABLE 69}; 70 71struct list { 72 SLIST_ENTRY(list) li_chain; 73 long li_number; 74}; 75 76SLIST_HEAD(listhead, list); 77 78struct kinfo_proc *plist; 79char *selected; 80const char *delim = "\n"; 81int nproc; 82int pgrep; 83int signum = SIGTERM; 84int newest; 85int oldest; 86int quiet; 87int inverse; 88int longfmt; 89int matchargs; 90int fullmatch; 91int confirmkill; 92kvm_t *kd; 93pid_t mypid; 94 95struct listhead euidlist = SLIST_HEAD_INITIALIZER(list); 96struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list); 97struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list); 98struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list); 99struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list); 100struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list); 101struct listhead sidlist = SLIST_HEAD_INITIALIZER(list); 102struct listhead rtablist = SLIST_HEAD_INITIALIZER(list); 103 104static void __dead usage(void); 105static int killact(struct kinfo_proc *, int); 106static int grepact(struct kinfo_proc *, int); 107static void makelist(struct listhead *, enum listtype, char *); 108static char *getargv(struct kinfo_proc *); 109static int askyn(struct kinfo_proc *); 110 111extern char *__progname; 112 113static char * 114getargv(struct kinfo_proc *kp) 115{ 116 static char buf[_POSIX2_LINE_MAX]; 117 char **pargv; 118 size_t j; 119 120 if ((pargv = kvm_getargv(kd, kp, 0)) == NULL) { 121 strlcpy(buf, kp->p_comm, sizeof(buf)); 122 return buf; 123 } 124 125 j = 0; 126 while (j < sizeof(buf) && *pargv != NULL) { 127 int ret; 128 129 ret = snprintf(buf + j, sizeof(buf) - j, 130 pargv[1] != NULL ? "%s " : "%s", pargv[0]); 131 if (ret >= sizeof(buf) - j) 132 j += sizeof(buf) - j - 1; 133 else if (ret > 0) 134 j += ret; 135 pargv++; 136 } 137 return buf; 138} 139 140int 141main(int argc, char **argv) 142{ 143 char buf[_POSIX2_LINE_MAX], *mstr, *p, *q; 144 int i, j, ch, bestidx, rv, criteria; 145 int (*action)(struct kinfo_proc *, int); 146 struct kinfo_proc *kp; 147 struct list *li; 148 u_int32_t bestsec, bestusec; 149 regex_t reg; 150 regmatch_t regmatch; 151 152 if (strcmp(__progname, "pgrep") == 0) { 153 action = grepact; 154 pgrep = 1; 155 } else { 156 action = killact; 157 p = argv[1]; 158 159 if (argc > 1 && p[0] == '-') { 160 p++; 161 i = (int)strtol(p, &q, 10); 162 if (*q == '\0') { 163 signum = i; 164 argv++; 165 argc--; 166 } else { 167 if (strncasecmp(p, "sig", 3) == 0) 168 p += 3; 169 for (i = 1; i < NSIG; i++) 170 if (strcasecmp(sys_signame[i], p) == 0) 171 break; 172 if (i != NSIG) { 173 signum = i; 174 argv++; 175 argc--; 176 } 177 } 178 } 179 } 180 181 criteria = 0; 182 183 while ((ch = getopt(argc, argv, "G:P:T:U:d:fg:Ilnoqs:t:u:vx")) != -1) 184 switch (ch) { 185 case 'G': 186 makelist(&rgidlist, LT_GROUP, optarg); 187 criteria = 1; 188 break; 189 case 'P': 190 makelist(&ppidlist, LT_GENERIC, optarg); 191 criteria = 1; 192 break; 193 case 'T': 194 makelist(&rtablist, LT_RTABLE, optarg); 195 criteria = 1; 196 break; 197 case 'U': 198 makelist(&ruidlist, LT_USER, optarg); 199 criteria = 1; 200 break; 201 case 'd': 202 if (!pgrep) 203 usage(); 204 delim = optarg; 205 break; 206 case 'f': 207 matchargs = 1; 208 break; 209 case 'g': 210 makelist(&pgrplist, LT_PGRP, optarg); 211 criteria = 1; 212 break; 213 case 'I': 214 confirmkill = 1; 215 break; 216 case 'l': 217 longfmt = 1; 218 break; 219 case 'n': 220 newest = 1; 221 criteria = 1; 222 break; 223 case 'o': 224 oldest = 1; 225 criteria = 1; 226 break; 227 case 'q': 228 quiet = 1; 229 break; 230 case 's': 231 makelist(&sidlist, LT_SID, optarg); 232 criteria = 1; 233 break; 234 case 't': 235 makelist(&tdevlist, LT_TTY, optarg); 236 criteria = 1; 237 break; 238 case 'u': 239 makelist(&euidlist, LT_USER, optarg); 240 criteria = 1; 241 break; 242 case 'v': 243 inverse = 1; 244 break; 245 case 'x': 246 fullmatch = 1; 247 break; 248 default: 249 usage(); 250 /* NOTREACHED */ 251 } 252 253 argc -= optind; 254 argv += optind; 255 if (argc != 0) 256 criteria = 1; 257 if (!criteria || (newest && oldest)) 258 usage(); 259 260 mypid = getpid(); 261 262 /* 263 * Retrieve the list of running processes from the kernel. 264 */ 265 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf); 266 if (kd == NULL) 267 errx(STATUS_ERROR, "kvm_openfiles(): %s", buf); 268 269 plist = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc); 270 if (plist == NULL) 271 errx(STATUS_ERROR, "kvm_getprocs() failed"); 272 273 if (matchargs == 0 && confirmkill == 0) { 274 if (action == killact) { 275 if (pledge("stdio proc", NULL) == -1) 276 err(STATUS_ERROR, "pledge"); 277 } else if (action == grepact) { 278 if (pledge("stdio", NULL) == -1) 279 err(STATUS_ERROR, "pledge"); 280 } 281 } 282 283 /* 284 * Allocate memory which will be used to keep track of the 285 * selection. 286 */ 287 if ((selected = calloc(nproc, 1)) == NULL) 288 errx(STATUS_ERROR, "memory allocation failure"); 289 290 /* 291 * Refine the selection. 292 */ 293 for (; *argv != NULL; argv++) { 294 if ((rv = regcomp(®, *argv, REG_EXTENDED)) != 0) { 295 regerror(rv, ®, buf, sizeof(buf)); 296 errx(STATUS_BADUSAGE, "bad expression: %s", buf); 297 } 298 299 for (i = 0, kp = plist; i < nproc; i++, kp++) { 300 if (kp->p_pid == mypid) 301 continue; 302 303 if (matchargs) 304 mstr = getargv(kp); 305 else 306 mstr = kp->p_comm; 307 308 rv = regexec(®, mstr, 1, ®match, 0); 309 if (rv == 0) { 310 if (fullmatch) { 311 if (regmatch.rm_so == 0 && 312 regmatch.rm_eo == strlen(mstr)) 313 selected[i] = 1; 314 } else 315 selected[i] = 1; 316 } else if (rv != REG_NOMATCH) { 317 regerror(rv, ®, buf, sizeof(buf)); 318 errx(STATUS_ERROR, "regexec(): %s", buf); 319 } 320 } 321 322 regfree(®); 323 } 324 325 for (i = 0, kp = plist; i < nproc; i++, kp++) { 326 if (kp->p_pid == mypid) 327 continue; 328 329 SLIST_FOREACH(li, &ruidlist, li_chain) 330 if (kp->p_ruid == (uid_t)li->li_number) 331 break; 332 if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 333 selected[i] = 0; 334 continue; 335 } 336 337 SLIST_FOREACH(li, &rgidlist, li_chain) 338 if (kp->p_rgid == (gid_t)li->li_number) 339 break; 340 if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 341 selected[i] = 0; 342 continue; 343 } 344 345 SLIST_FOREACH(li, &euidlist, li_chain) 346 if (kp->p_uid == (uid_t)li->li_number) 347 break; 348 if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 349 selected[i] = 0; 350 continue; 351 } 352 353 SLIST_FOREACH(li, &ppidlist, li_chain) 354 if (kp->p_ppid == (uid_t)li->li_number) 355 break; 356 if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 357 selected[i] = 0; 358 continue; 359 } 360 361 SLIST_FOREACH(li, &pgrplist, li_chain) 362 if (kp->p__pgid == (uid_t)li->li_number) 363 break; 364 if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 365 selected[i] = 0; 366 continue; 367 } 368 369 SLIST_FOREACH(li, &tdevlist, li_chain) { 370 if (li->li_number == -1 && 371 (kp->p_psflags & PS_CONTROLT) == 0) 372 break; 373 if (kp->p_tdev == (uid_t)li->li_number) 374 break; 375 } 376 if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 377 selected[i] = 0; 378 continue; 379 } 380 381 SLIST_FOREACH(li, &sidlist, li_chain) 382 if (kp->p_sid == (uid_t)li->li_number) 383 break; 384 if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 385 selected[i] = 0; 386 continue; 387 } 388 389 SLIST_FOREACH(li, &rtablist, li_chain) 390 if (kp->p_rtableid == (u_int32_t)li->li_number) 391 break; 392 if (SLIST_FIRST(&rtablist) != NULL && li == NULL) { 393 selected[i] = 0; 394 continue; 395 } 396 397 if (argc == 0) 398 selected[i] = 1; 399 } 400 401 if (newest || oldest) { 402 bestidx = -1; 403 404 if (newest) 405 bestsec = bestusec = 0; 406 else 407 bestsec = bestusec = UINT32_MAX; 408 409 for (i = 0, kp = plist; i < nproc; i++, kp++) { 410 if (!selected[i]) 411 continue; 412 413 if ((newest && (kp->p_ustart_sec > bestsec || 414 (kp->p_ustart_sec == bestsec 415 && kp->p_ustart_usec > bestusec))) 416 || (oldest && (kp->p_ustart_sec < bestsec || 417 (kp->p_ustart_sec == bestsec 418 && kp->p_ustart_usec < bestusec)))) { 419 420 bestsec = kp->p_ustart_sec; 421 bestusec = kp->p_ustart_usec; 422 bestidx = i; 423 } 424 } 425 426 memset(selected, 0, nproc); 427 if (bestidx != -1) 428 selected[bestidx] = 1; 429 } 430 431 /* 432 * Take the appropriate action for each matched process, if any. 433 */ 434 rv = STATUS_NOMATCH; 435 for (i = 0, j = 0, kp = plist; i < nproc; i++, kp++) { 436 if (kp->p_pid == mypid) 437 continue; 438 if (selected[i] == inverse) 439 continue; 440 441 switch ((*action)(kp, j++)) { 442 case STATUS_MATCH: 443 if (rv != STATUS_ERROR) 444 rv = STATUS_MATCH; 445 break; 446 case STATUS_NOMATCH: 447 j--; 448 break; 449 case STATUS_ERROR: 450 rv = STATUS_ERROR; 451 break; 452 } 453 } 454 if (pgrep && j && !quiet) 455 putchar('\n'); 456 457 return(rv); 458} 459 460static void __dead 461usage(void) 462{ 463 const char *ustr; 464 465 if (pgrep) 466 ustr = "[-flnoqvx] [-d delim]"; 467 else 468 ustr = "[-signal] [-fIlnoqvx]"; 469 470 fprintf(stderr, "usage: %s %s [-G gid] [-g pgrp] [-P ppid] [-s sid]" 471 "\n\t[-T rtable] [-t tty] [-U uid] [-u euid] [pattern ...]\n", 472 __progname, ustr); 473 474 exit(STATUS_BADUSAGE); 475} 476 477static int 478askyn(struct kinfo_proc *kp) 479{ 480 int first, ch; 481 482 printf("kill %d %.60s? ", (int)kp->p_pid, getargv(kp)); 483 fflush(stdout); 484 485 first = ch = getchar(); 486 while (ch != '\n' && ch != EOF) 487 ch = getchar(); 488 return (first == 'y' || first == 'Y'); 489} 490 491static int 492killact(struct kinfo_proc *kp, int dummy) 493{ 494 int doit; 495 496 if (confirmkill) { 497 doit = askyn(kp); 498 } else { 499 if (longfmt && !quiet) 500 printf("%d %s\n", (int)kp->p_pid, kp->p_comm); 501 doit = 1; 502 } 503 504 if (doit && kill(kp->p_pid, signum) == -1) { 505 if (errno == ESRCH) 506 return (STATUS_NOMATCH); 507 warn("signalling pid %d", (int)kp->p_pid); 508 return (STATUS_ERROR); 509 } 510 return (STATUS_MATCH); 511} 512 513static int 514grepact(struct kinfo_proc *kp, int printdelim) 515{ 516 char **argv; 517 518 if (quiet) 519 return (STATUS_MATCH); 520 if (longfmt && matchargs) 521 if ((argv = kvm_getargv(kd, kp, 0)) == NULL) 522 return (errno == ESRCH ? STATUS_NOMATCH : STATUS_ERROR); 523 if (printdelim) 524 fputs(delim, stdout); 525 if (longfmt && matchargs) { 526 printf("%d ", (int)kp->p_pid); 527 for (; *argv != NULL; argv++) { 528 printf("%s", *argv); 529 if (argv[1] != NULL) 530 putchar(' '); 531 } 532 } else if (longfmt) 533 printf("%d %s", (int)kp->p_pid, kp->p_comm); 534 else 535 printf("%d", (int)kp->p_pid); 536 537 return (STATUS_MATCH); 538} 539 540static void 541makelist(struct listhead *head, enum listtype type, char *src) 542{ 543 struct list *li; 544 struct stat st; 545 char *sp, *p, buf[PATH_MAX]; 546 uid_t uid; 547 gid_t gid; 548 int empty; 549 550 empty = 1; 551 552 while ((sp = strsep(&src, ",")) != NULL) { 553 if (*sp == '\0') 554 usage(); 555 556 if ((li = malloc(sizeof(*li))) == NULL) 557 errx(STATUS_ERROR, "memory allocation failure"); 558 SLIST_INSERT_HEAD(head, li, li_chain); 559 empty = 0; 560 561 li->li_number = strtol(sp, &p, 0); 562 if (*p == '\0') { 563 switch (type) { 564 case LT_PGRP: 565 if (li->li_number == 0) 566 li->li_number = getpgrp(); 567 break; 568 case LT_SID: 569 if (li->li_number == 0) 570 li->li_number = getsid(mypid); 571 break; 572 case LT_RTABLE: 573 if (li->li_number < 0 || 574 li->li_number > RT_TABLEID_MAX) 575 errx(STATUS_BADUSAGE, 576 "rtable out of range"); 577 break; 578 case LT_TTY: 579 usage(); 580 default: 581 break; 582 } 583 continue; 584 } 585 586 switch (type) { 587 case LT_USER: 588 if (uid_from_user(sp, &uid) == -1) 589 errx(STATUS_BADUSAGE, "unknown user `%s'", sp); 590 li->li_number = uid; 591 break; 592 case LT_GROUP: 593 if (gid_from_group(sp, &gid) == -1) 594 errx(STATUS_BADUSAGE, "unknown group `%s'", sp); 595 li->li_number = gid; 596 break; 597 case LT_TTY: 598 if (strcmp(sp, "-") == 0) { 599 li->li_number = -1; 600 break; 601 } else if (strcmp(sp, "co") == 0) 602 p = "console"; 603 else if (strncmp(sp, "tty", 3) == 0) 604 p = sp; 605 else 606 p = NULL; 607 608 if (p == NULL) 609 snprintf(buf, sizeof(buf), "/dev/tty%s", sp); 610 else 611 snprintf(buf, sizeof(buf), "/dev/%s", p); 612 613 if (stat(buf, &st) == -1) { 614 if (errno == ENOENT) 615 errx(STATUS_BADUSAGE, 616 "no such tty: `%s'", sp); 617 err(STATUS_ERROR, "stat(%s)", sp); 618 } 619 620 if (!S_ISCHR(st.st_mode)) 621 errx(STATUS_BADUSAGE, "not a tty: `%s'", sp); 622 623 li->li_number = st.st_rdev; 624 break; 625 default: 626 usage(); 627 } 628 } 629 630 if (empty) 631 usage(); 632} 633