1 /* $OpenBSD: pkill.c,v 1.38 2015/10/11 03:08:20 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/param.h> /* MAXCOMLEN */ 34 #include <sys/types.h> 35 #include <sys/sysctl.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 61 enum listtype { 62 LT_GENERIC, 63 LT_USER, 64 LT_GROUP, 65 LT_TTY, 66 LT_PGRP, 67 LT_SID, 68 LT_RTABLE 69 }; 70 71 struct list { 72 SLIST_ENTRY(list) li_chain; 73 long li_number; 74 }; 75 76 SLIST_HEAD(listhead, list); 77 78 struct kinfo_proc *plist; 79 char *selected; 80 char *delim = "\n"; 81 int nproc; 82 int pgrep; 83 int signum = SIGTERM; 84 int newest; 85 int oldest; 86 int quiet; 87 int inverse; 88 int longfmt; 89 int matchargs; 90 int fullmatch; 91 int confirmkill; 92 kvm_t *kd; 93 pid_t mypid; 94 95 struct listhead euidlist = SLIST_HEAD_INITIALIZER(list); 96 struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list); 97 struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list); 98 struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list); 99 struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list); 100 struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list); 101 struct listhead sidlist = SLIST_HEAD_INITIALIZER(list); 102 struct listhead rtablist = SLIST_HEAD_INITIALIZER(list); 103 104 int main(int, char **); 105 void usage(void); 106 int killact(struct kinfo_proc *, int); 107 int grepact(struct kinfo_proc *, int); 108 void makelist(struct listhead *, enum listtype, char *); 109 char *getargv(struct kinfo_proc *); 110 int askyn(struct kinfo_proc *); 111 112 extern char *__progname; 113 114 char * 115 getargv(struct kinfo_proc *kp) 116 { 117 static char buf[_POSIX2_LINE_MAX]; 118 char **pargv; 119 size_t j; 120 121 if ((pargv = kvm_getargv(kd, kp, 0)) == NULL) { 122 strlcpy(buf, kp->p_comm, sizeof(buf)); 123 return buf; 124 } 125 126 j = 0; 127 while (j < sizeof(buf) && *pargv != NULL) { 128 int ret; 129 130 ret = snprintf(buf + j, sizeof(buf) - j, 131 pargv[1] != NULL ? "%s " : "%s", pargv[0]); 132 if (ret >= sizeof(buf) - j) 133 j += sizeof(buf) - j - 1; 134 else if (ret > 0) 135 j += ret; 136 pargv++; 137 } 138 return buf; 139 } 140 141 int 142 main(int argc, char **argv) 143 { 144 extern char *optarg; 145 extern int optind; 146 char buf[_POSIX2_LINE_MAX], *mstr, *p, *q; 147 int i, j, ch, bestidx, rv, criteria; 148 int (*action)(struct kinfo_proc *, int); 149 struct kinfo_proc *kp; 150 struct list *li; 151 u_int32_t bestsec, bestusec; 152 regex_t reg; 153 regmatch_t regmatch; 154 155 if (strcmp(__progname, "pgrep") == 0) { 156 action = grepact; 157 pgrep = 1; 158 } else { 159 action = killact; 160 p = argv[1]; 161 162 if (argc > 1 && p[0] == '-') { 163 p++; 164 i = (int)strtol(p, &q, 10); 165 if (*q == '\0') { 166 signum = i; 167 argv++; 168 argc--; 169 } else { 170 if (strncasecmp(p, "sig", 3) == 0) 171 p += 3; 172 for (i = 1; i < NSIG; i++) 173 if (strcasecmp(sys_signame[i], p) == 0) 174 break; 175 if (i != NSIG) { 176 signum = i; 177 argv++; 178 argc--; 179 } 180 } 181 } 182 } 183 184 criteria = 0; 185 186 while ((ch = getopt(argc, argv, "G:P:T:U:d:fg:Ilnoqs:t:u:vx")) != -1) 187 switch (ch) { 188 case 'G': 189 makelist(&rgidlist, LT_GROUP, optarg); 190 criteria = 1; 191 break; 192 case 'P': 193 makelist(&ppidlist, LT_GENERIC, optarg); 194 criteria = 1; 195 break; 196 case 'T': 197 makelist(&rtablist, LT_RTABLE, optarg); 198 criteria = 1; 199 break; 200 case 'U': 201 makelist(&ruidlist, LT_USER, optarg); 202 criteria = 1; 203 break; 204 case 'd': 205 if (!pgrep) 206 usage(); 207 delim = optarg; 208 break; 209 case 'f': 210 matchargs = 1; 211 break; 212 case 'g': 213 makelist(&pgrplist, LT_PGRP, optarg); 214 criteria = 1; 215 break; 216 case 'I': 217 confirmkill = 1; 218 break; 219 case 'l': 220 longfmt = 1; 221 break; 222 case 'n': 223 newest = 1; 224 criteria = 1; 225 break; 226 case 'o': 227 oldest = 1; 228 criteria = 1; 229 break; 230 case 'q': 231 quiet = 1; 232 break; 233 case 's': 234 makelist(&sidlist, LT_SID, optarg); 235 criteria = 1; 236 break; 237 case 't': 238 makelist(&tdevlist, LT_TTY, optarg); 239 criteria = 1; 240 break; 241 case 'u': 242 makelist(&euidlist, LT_USER, optarg); 243 criteria = 1; 244 break; 245 case 'v': 246 inverse = 1; 247 break; 248 case 'x': 249 fullmatch = 1; 250 break; 251 default: 252 usage(); 253 /* NOTREACHED */ 254 } 255 256 argc -= optind; 257 argv += optind; 258 if (argc != 0) 259 criteria = 1; 260 if (!criteria || (newest && oldest)) 261 usage(); 262 263 mypid = getpid(); 264 265 /* 266 * Retrieve the list of running processes from the kernel. 267 */ 268 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf); 269 if (kd == NULL) 270 errx(STATUS_ERROR, "kvm_openfiles(): %s", buf); 271 272 plist = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc); 273 if (plist == NULL) 274 errx(STATUS_ERROR, "kvm_getprocs() failed"); 275 276 if (matchargs == 0 && confirmkill == 0) { 277 if (action == killact) { 278 if (pledge("stdio proc", NULL) == -1) 279 err(1, "pledge"); 280 } else if (action == grepact) { 281 if (pledge("stdio", NULL) == -1) 282 err(1, "pledge"); 283 } 284 } 285 286 /* 287 * Allocate memory which will be used to keep track of the 288 * selection. 289 */ 290 if ((selected = calloc(nproc, 1)) == NULL) 291 errx(STATUS_ERROR, "memory allocation failure"); 292 293 /* 294 * Refine the selection. 295 */ 296 for (; *argv != NULL; argv++) { 297 if ((rv = regcomp(®, *argv, REG_EXTENDED)) != 0) { 298 regerror(rv, ®, buf, sizeof(buf)); 299 errx(STATUS_BADUSAGE, "bad expression: %s", buf); 300 } 301 302 for (i = 0, kp = plist; i < nproc; i++, kp++) { 303 if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 || 304 kp->p_pid == mypid) 305 continue; 306 307 if (matchargs) 308 mstr = getargv(kp); 309 else 310 mstr = kp->p_comm; 311 312 rv = regexec(®, mstr, 1, ®match, 0); 313 if (rv == 0) { 314 if (fullmatch) { 315 if (regmatch.rm_so == 0 && 316 regmatch.rm_eo == strlen(mstr)) 317 selected[i] = 1; 318 } else 319 selected[i] = 1; 320 } else if (rv != REG_NOMATCH) { 321 regerror(rv, ®, buf, sizeof(buf)); 322 errx(STATUS_ERROR, "regexec(): %s", buf); 323 } 324 } 325 326 regfree(®); 327 } 328 329 for (i = 0, kp = plist; i < nproc; i++, kp++) { 330 if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 || 331 kp->p_pid == mypid) 332 continue; 333 334 SLIST_FOREACH(li, &ruidlist, li_chain) 335 if (kp->p_ruid == (uid_t)li->li_number) 336 break; 337 if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 338 selected[i] = 0; 339 continue; 340 } 341 342 SLIST_FOREACH(li, &rgidlist, li_chain) 343 if (kp->p_rgid == (gid_t)li->li_number) 344 break; 345 if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 346 selected[i] = 0; 347 continue; 348 } 349 350 SLIST_FOREACH(li, &euidlist, li_chain) 351 if (kp->p_uid == (uid_t)li->li_number) 352 break; 353 if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 354 selected[i] = 0; 355 continue; 356 } 357 358 SLIST_FOREACH(li, &ppidlist, li_chain) 359 if (kp->p_ppid == (uid_t)li->li_number) 360 break; 361 if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 362 selected[i] = 0; 363 continue; 364 } 365 366 SLIST_FOREACH(li, &pgrplist, li_chain) 367 if (kp->p__pgid == (uid_t)li->li_number) 368 break; 369 if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 370 selected[i] = 0; 371 continue; 372 } 373 374 SLIST_FOREACH(li, &tdevlist, li_chain) { 375 if (li->li_number == -1 && 376 (kp->p_psflags & PS_CONTROLT) == 0) 377 break; 378 if (kp->p_tdev == (uid_t)li->li_number) 379 break; 380 } 381 if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 382 selected[i] = 0; 383 continue; 384 } 385 386 SLIST_FOREACH(li, &sidlist, li_chain) 387 if (kp->p_sid == (uid_t)li->li_number) 388 break; 389 if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 390 selected[i] = 0; 391 continue; 392 } 393 394 SLIST_FOREACH(li, &rtablist, li_chain) 395 if (kp->p_rtableid == (u_int32_t)li->li_number) 396 break; 397 if (SLIST_FIRST(&rtablist) != NULL && li == NULL) { 398 selected[i] = 0; 399 continue; 400 } 401 402 if (argc == 0) 403 selected[i] = 1; 404 } 405 406 if (newest || oldest) { 407 bestidx = -1; 408 409 if (newest) 410 bestsec = bestusec = 0; 411 else 412 bestsec = bestusec = UINT32_MAX; 413 414 for (i = 0, kp = plist; i < nproc; i++, kp++) { 415 if (!selected[i]) 416 continue; 417 418 if ((newest && (kp->p_ustart_sec > bestsec || 419 (kp->p_ustart_sec == bestsec 420 && kp->p_ustart_usec > bestusec))) 421 || (oldest && (kp->p_ustart_sec < bestsec || 422 (kp->p_ustart_sec == bestsec 423 && kp->p_ustart_usec < bestusec)))) { 424 425 bestsec = kp->p_ustart_sec; 426 bestusec = kp->p_ustart_usec; 427 bestidx = i; 428 } 429 } 430 431 memset(selected, 0, nproc); 432 if (bestidx != -1) 433 selected[bestidx] = 1; 434 } 435 436 /* 437 * Take the appropriate action for each matched process, if any. 438 */ 439 rv = STATUS_NOMATCH; 440 for (i = 0, j = 0, kp = plist; i < nproc; i++, kp++) { 441 if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 || 442 kp->p_pid == mypid) 443 continue; 444 if (selected[i] == inverse) 445 continue; 446 447 switch ((*action)(kp, j++)) { 448 case STATUS_MATCH: 449 if (rv != STATUS_ERROR) 450 rv = STATUS_MATCH; 451 break; 452 case STATUS_NOMATCH: 453 j--; 454 break; 455 case STATUS_ERROR: 456 rv = STATUS_ERROR; 457 break; 458 } 459 } 460 if (pgrep && j && !quiet) 461 putchar('\n'); 462 463 exit(rv); 464 } 465 466 void 467 usage(void) 468 { 469 const char *ustr; 470 471 if (pgrep) 472 ustr = "[-flnoqvx] [-d delim]"; 473 else 474 ustr = "[-signal] [-fIlnoqvx]"; 475 476 fprintf(stderr, "usage: %s %s [-G gid] [-g pgrp] [-P ppid] [-s sid]" 477 "\n\t[-T rtable] [-t tty] [-U uid] [-u euid] [pattern ...]\n", 478 __progname, ustr); 479 480 exit(STATUS_BADUSAGE); 481 } 482 483 int 484 askyn(struct kinfo_proc *kp) 485 { 486 int first, ch; 487 488 printf("kill %d %.60s? ", (int)kp->p_pid, getargv(kp)); 489 fflush(stdout); 490 491 first = ch = getchar(); 492 while (ch != '\n' && ch != EOF) 493 ch = getchar(); 494 return (first == 'y' || first == 'Y'); 495 } 496 497 int 498 killact(struct kinfo_proc *kp, int dummy) 499 { 500 int doit; 501 502 if (confirmkill) { 503 doit = askyn(kp); 504 } else { 505 if (longfmt && !quiet) 506 printf("%d %s\n", (int)kp->p_pid, kp->p_comm); 507 doit = 1; 508 } 509 510 if (doit && kill(kp->p_pid, signum) == -1) { 511 if (errno == ESRCH) 512 return (STATUS_NOMATCH); 513 warn("signalling pid %d", (int)kp->p_pid); 514 return (STATUS_ERROR); 515 } 516 return (STATUS_MATCH); 517 } 518 519 int 520 grepact(struct kinfo_proc *kp, int printdelim) 521 { 522 char **argv; 523 524 if (quiet) 525 return (STATUS_MATCH); 526 if (longfmt && matchargs) 527 if ((argv = kvm_getargv(kd, kp, 0)) == NULL) 528 return (errno == ESRCH ? STATUS_NOMATCH : STATUS_ERROR); 529 if (printdelim) 530 fputs(delim, stdout); 531 if (longfmt && matchargs) { 532 printf("%d ", (int)kp->p_pid); 533 for (; *argv != NULL; argv++) { 534 printf("%s", *argv); 535 if (argv[1] != NULL) 536 putchar(' '); 537 } 538 } else if (longfmt) 539 printf("%d %s", (int)kp->p_pid, kp->p_comm); 540 else 541 printf("%d", (int)kp->p_pid); 542 543 return (STATUS_MATCH); 544 } 545 546 void 547 makelist(struct listhead *head, enum listtype type, char *src) 548 { 549 struct list *li; 550 struct passwd *pw; 551 struct group *gr; 552 struct stat st; 553 char *sp, *p, buf[PATH_MAX]; 554 int empty; 555 556 empty = 1; 557 558 while ((sp = strsep(&src, ",")) != NULL) { 559 if (*sp == '\0') 560 usage(); 561 562 if ((li = malloc(sizeof(*li))) == NULL) 563 errx(STATUS_ERROR, "memory allocation failure"); 564 SLIST_INSERT_HEAD(head, li, li_chain); 565 empty = 0; 566 567 li->li_number = strtol(sp, &p, 0); 568 if (*p == '\0') { 569 switch (type) { 570 case LT_PGRP: 571 if (li->li_number == 0) 572 li->li_number = getpgrp(); 573 break; 574 case LT_SID: 575 if (li->li_number == 0) 576 li->li_number = getsid(mypid); 577 break; 578 case LT_RTABLE: 579 if (li->li_number < 0 || 580 li->li_number > RT_TABLEID_MAX) 581 errx(STATUS_BADUSAGE, 582 "rtable out of range"); 583 break; 584 case LT_TTY: 585 usage(); 586 default: 587 break; 588 } 589 continue; 590 } 591 592 switch (type) { 593 case LT_USER: 594 if ((pw = getpwnam(sp)) == NULL) 595 errx(STATUS_BADUSAGE, "unknown user `%s'", sp); 596 li->li_number = pw->pw_uid; 597 break; 598 case LT_GROUP: 599 if ((gr = getgrnam(sp)) == NULL) 600 errx(STATUS_BADUSAGE, "unknown group `%s'", sp); 601 li->li_number = gr->gr_gid; 602 break; 603 case LT_TTY: 604 if (strcmp(sp, "-") == 0) { 605 li->li_number = -1; 606 break; 607 } else if (strcmp(sp, "co") == 0) 608 p = "console"; 609 else if (strncmp(sp, "tty", 3) == 0) 610 p = sp; 611 else 612 p = NULL; 613 614 if (p == NULL) 615 snprintf(buf, sizeof(buf), "/dev/tty%s", sp); 616 else 617 snprintf(buf, sizeof(buf), "/dev/%s", p); 618 619 if (stat(buf, &st) < 0) { 620 if (errno == ENOENT) 621 errx(STATUS_BADUSAGE, 622 "no such tty: `%s'", sp); 623 err(STATUS_ERROR, "stat(%s)", sp); 624 } 625 626 if (!S_ISCHR(st.st_mode)) 627 errx(STATUS_BADUSAGE, "not a tty: `%s'", sp); 628 629 li->li_number = st.st_rdev; 630 break; 631 default: 632 usage(); 633 } 634 } 635 636 if (empty) 637 usage(); 638 } 639