1 /* $OpenBSD: pkill.c,v 1.39 2016/10/10 02:22:59 gsoares 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 const 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 static void __dead usage(void); 105 static int killact(struct kinfo_proc *, int); 106 static int grepact(struct kinfo_proc *, int); 107 static void makelist(struct listhead *, enum listtype, char *); 108 static char *getargv(struct kinfo_proc *); 109 static int askyn(struct kinfo_proc *); 110 111 extern char *__progname; 112 113 static char * 114 getargv(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 140 int 141 main(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_flag & (P_SYSTEM | P_THREAD)) != 0 || 301 kp->p_pid == mypid) 302 continue; 303 304 if (matchargs) 305 mstr = getargv(kp); 306 else 307 mstr = kp->p_comm; 308 309 rv = regexec(®, mstr, 1, ®match, 0); 310 if (rv == 0) { 311 if (fullmatch) { 312 if (regmatch.rm_so == 0 && 313 regmatch.rm_eo == strlen(mstr)) 314 selected[i] = 1; 315 } else 316 selected[i] = 1; 317 } else if (rv != REG_NOMATCH) { 318 regerror(rv, ®, buf, sizeof(buf)); 319 errx(STATUS_ERROR, "regexec(): %s", buf); 320 } 321 } 322 323 regfree(®); 324 } 325 326 for (i = 0, kp = plist; i < nproc; i++, kp++) { 327 if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 || 328 kp->p_pid == mypid) 329 continue; 330 331 SLIST_FOREACH(li, &ruidlist, li_chain) 332 if (kp->p_ruid == (uid_t)li->li_number) 333 break; 334 if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 335 selected[i] = 0; 336 continue; 337 } 338 339 SLIST_FOREACH(li, &rgidlist, li_chain) 340 if (kp->p_rgid == (gid_t)li->li_number) 341 break; 342 if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 343 selected[i] = 0; 344 continue; 345 } 346 347 SLIST_FOREACH(li, &euidlist, li_chain) 348 if (kp->p_uid == (uid_t)li->li_number) 349 break; 350 if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 351 selected[i] = 0; 352 continue; 353 } 354 355 SLIST_FOREACH(li, &ppidlist, li_chain) 356 if (kp->p_ppid == (uid_t)li->li_number) 357 break; 358 if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 359 selected[i] = 0; 360 continue; 361 } 362 363 SLIST_FOREACH(li, &pgrplist, li_chain) 364 if (kp->p__pgid == (uid_t)li->li_number) 365 break; 366 if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 367 selected[i] = 0; 368 continue; 369 } 370 371 SLIST_FOREACH(li, &tdevlist, li_chain) { 372 if (li->li_number == -1 && 373 (kp->p_psflags & PS_CONTROLT) == 0) 374 break; 375 if (kp->p_tdev == (uid_t)li->li_number) 376 break; 377 } 378 if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 379 selected[i] = 0; 380 continue; 381 } 382 383 SLIST_FOREACH(li, &sidlist, li_chain) 384 if (kp->p_sid == (uid_t)li->li_number) 385 break; 386 if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 387 selected[i] = 0; 388 continue; 389 } 390 391 SLIST_FOREACH(li, &rtablist, li_chain) 392 if (kp->p_rtableid == (u_int32_t)li->li_number) 393 break; 394 if (SLIST_FIRST(&rtablist) != NULL && li == NULL) { 395 selected[i] = 0; 396 continue; 397 } 398 399 if (argc == 0) 400 selected[i] = 1; 401 } 402 403 if (newest || oldest) { 404 bestidx = -1; 405 406 if (newest) 407 bestsec = bestusec = 0; 408 else 409 bestsec = bestusec = UINT32_MAX; 410 411 for (i = 0, kp = plist; i < nproc; i++, kp++) { 412 if (!selected[i]) 413 continue; 414 415 if ((newest && (kp->p_ustart_sec > bestsec || 416 (kp->p_ustart_sec == bestsec 417 && kp->p_ustart_usec > bestusec))) 418 || (oldest && (kp->p_ustart_sec < bestsec || 419 (kp->p_ustart_sec == bestsec 420 && kp->p_ustart_usec < bestusec)))) { 421 422 bestsec = kp->p_ustart_sec; 423 bestusec = kp->p_ustart_usec; 424 bestidx = i; 425 } 426 } 427 428 memset(selected, 0, nproc); 429 if (bestidx != -1) 430 selected[bestidx] = 1; 431 } 432 433 /* 434 * Take the appropriate action for each matched process, if any. 435 */ 436 rv = STATUS_NOMATCH; 437 for (i = 0, j = 0, kp = plist; i < nproc; i++, kp++) { 438 if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 || 439 kp->p_pid == mypid) 440 continue; 441 if (selected[i] == inverse) 442 continue; 443 444 switch ((*action)(kp, j++)) { 445 case STATUS_MATCH: 446 if (rv != STATUS_ERROR) 447 rv = STATUS_MATCH; 448 break; 449 case STATUS_NOMATCH: 450 j--; 451 break; 452 case STATUS_ERROR: 453 rv = STATUS_ERROR; 454 break; 455 } 456 } 457 if (pgrep && j && !quiet) 458 putchar('\n'); 459 460 return(rv); 461 } 462 463 static void __dead 464 usage(void) 465 { 466 const char *ustr; 467 468 if (pgrep) 469 ustr = "[-flnoqvx] [-d delim]"; 470 else 471 ustr = "[-signal] [-fIlnoqvx]"; 472 473 fprintf(stderr, "usage: %s %s [-G gid] [-g pgrp] [-P ppid] [-s sid]" 474 "\n\t[-T rtable] [-t tty] [-U uid] [-u euid] [pattern ...]\n", 475 __progname, ustr); 476 477 exit(STATUS_BADUSAGE); 478 } 479 480 static int 481 askyn(struct kinfo_proc *kp) 482 { 483 int first, ch; 484 485 printf("kill %d %.60s? ", (int)kp->p_pid, getargv(kp)); 486 fflush(stdout); 487 488 first = ch = getchar(); 489 while (ch != '\n' && ch != EOF) 490 ch = getchar(); 491 return (first == 'y' || first == 'Y'); 492 } 493 494 static int 495 killact(struct kinfo_proc *kp, int dummy) 496 { 497 int doit; 498 499 if (confirmkill) { 500 doit = askyn(kp); 501 } else { 502 if (longfmt && !quiet) 503 printf("%d %s\n", (int)kp->p_pid, kp->p_comm); 504 doit = 1; 505 } 506 507 if (doit && kill(kp->p_pid, signum) == -1) { 508 if (errno == ESRCH) 509 return (STATUS_NOMATCH); 510 warn("signalling pid %d", (int)kp->p_pid); 511 return (STATUS_ERROR); 512 } 513 return (STATUS_MATCH); 514 } 515 516 static int 517 grepact(struct kinfo_proc *kp, int printdelim) 518 { 519 char **argv; 520 521 if (quiet) 522 return (STATUS_MATCH); 523 if (longfmt && matchargs) 524 if ((argv = kvm_getargv(kd, kp, 0)) == NULL) 525 return (errno == ESRCH ? STATUS_NOMATCH : STATUS_ERROR); 526 if (printdelim) 527 fputs(delim, stdout); 528 if (longfmt && matchargs) { 529 printf("%d ", (int)kp->p_pid); 530 for (; *argv != NULL; argv++) { 531 printf("%s", *argv); 532 if (argv[1] != NULL) 533 putchar(' '); 534 } 535 } else if (longfmt) 536 printf("%d %s", (int)kp->p_pid, kp->p_comm); 537 else 538 printf("%d", (int)kp->p_pid); 539 540 return (STATUS_MATCH); 541 } 542 543 static void 544 makelist(struct listhead *head, enum listtype type, char *src) 545 { 546 struct list *li; 547 struct passwd *pw; 548 struct group *gr; 549 struct stat st; 550 char *sp, *p, buf[PATH_MAX]; 551 int empty; 552 553 empty = 1; 554 555 while ((sp = strsep(&src, ",")) != NULL) { 556 if (*sp == '\0') 557 usage(); 558 559 if ((li = malloc(sizeof(*li))) == NULL) 560 errx(STATUS_ERROR, "memory allocation failure"); 561 SLIST_INSERT_HEAD(head, li, li_chain); 562 empty = 0; 563 564 li->li_number = strtol(sp, &p, 0); 565 if (*p == '\0') { 566 switch (type) { 567 case LT_PGRP: 568 if (li->li_number == 0) 569 li->li_number = getpgrp(); 570 break; 571 case LT_SID: 572 if (li->li_number == 0) 573 li->li_number = getsid(mypid); 574 break; 575 case LT_RTABLE: 576 if (li->li_number < 0 || 577 li->li_number > RT_TABLEID_MAX) 578 errx(STATUS_BADUSAGE, 579 "rtable out of range"); 580 break; 581 case LT_TTY: 582 usage(); 583 default: 584 break; 585 } 586 continue; 587 } 588 589 switch (type) { 590 case LT_USER: 591 if ((pw = getpwnam(sp)) == NULL) 592 errx(STATUS_BADUSAGE, "unknown user `%s'", sp); 593 li->li_number = pw->pw_uid; 594 break; 595 case LT_GROUP: 596 if ((gr = getgrnam(sp)) == NULL) 597 errx(STATUS_BADUSAGE, "unknown group `%s'", sp); 598 li->li_number = gr->gr_gid; 599 break; 600 case LT_TTY: 601 if (strcmp(sp, "-") == 0) { 602 li->li_number = -1; 603 break; 604 } else if (strcmp(sp, "co") == 0) 605 p = "console"; 606 else if (strncmp(sp, "tty", 3) == 0) 607 p = sp; 608 else 609 p = NULL; 610 611 if (p == NULL) 612 snprintf(buf, sizeof(buf), "/dev/tty%s", sp); 613 else 614 snprintf(buf, sizeof(buf), "/dev/%s", p); 615 616 if (stat(buf, &st) < 0) { 617 if (errno == ENOENT) 618 errx(STATUS_BADUSAGE, 619 "no such tty: `%s'", sp); 620 err(STATUS_ERROR, "stat(%s)", sp); 621 } 622 623 if (!S_ISCHR(st.st_mode)) 624 errx(STATUS_BADUSAGE, "not a tty: `%s'", sp); 625 626 li->li_number = st.st_rdev; 627 break; 628 default: 629 usage(); 630 } 631 } 632 633 if (empty) 634 usage(); 635 } 636