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