1/* $NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $ */ 2 3/*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 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/cdefs.h> 34__FBSDID("$FreeBSD: src/bin/pkill/pkill.c,v 1.12 2011/02/04 16:40:50 jilles Exp $"); 35 36#include <sys/types.h> 37#include <sys/param.h> 38#include <sys/sysctl.h> 39#include <sys/proc.h> 40#include <sys/queue.h> 41#include <sys/stat.h> 42#include <sys/time.h> 43#include <sys/user.h> 44 45#include <assert.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <limits.h> 49#include <paths.h> 50#include <string.h> 51#include <unistd.h> 52#include <signal.h> 53#include <regex.h> 54#include <ctype.h> 55#include <fcntl.h> 56#ifndef __APPLE__ 57#include <kvm.h> 58#endif 59#include <err.h> 60#include <pwd.h> 61#include <grp.h> 62#include <errno.h> 63#include <locale.h> 64 65#ifdef __APPLE__ 66#include <xpc/xpc.h> 67#include <sys/proc_info.h> 68#include <os/assumes.h> 69#include <sysmon.h> 70#endif 71 72#define STATUS_MATCH 0 73#define STATUS_NOMATCH 1 74#define STATUS_BADUSAGE 2 75#define STATUS_ERROR 3 76 77#define MIN_PID 5 78#define MAX_PID 99999 79 80#ifdef __APPLE__ 81/* Ignore system processes and myself. */ 82#define PSKIP(kp) ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == mypid || \ 83 ((xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_SYSTEM) != 0)) 84#else 85/* Ignore system-processes (if '-S' flag is not specified) and myself. */ 86#define PSKIP(kp) ((kp)->ki_pid == mypid || \ 87 (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0)) 88#endif 89 90enum listtype { 91 LT_GENERIC, 92 LT_USER, 93 LT_GROUP, 94 LT_TTY, 95 LT_PGRP, 96#ifndef __APPLE__ 97 LT_JID, 98#endif 99 LT_SID 100}; 101 102struct list { 103 SLIST_ENTRY(list) li_chain; 104 long li_number; 105}; 106 107SLIST_HEAD(listhead, list); 108 109#ifdef __APPLE__ 110static sysmon_table_t plist; 111#else 112static struct kinfo_proc *plist; 113#endif 114static char *selected; 115static const char *delim = "\n"; 116static int nproc; 117static int pgrep; 118static int signum = SIGTERM; 119static int newest; 120static int oldest; 121static int interactive; 122static int inverse; 123static int longfmt; 124static int matchargs; 125static int fullmatch; 126#ifndef __APPLE__ 127static int kthreads; 128#endif 129static int cflags = REG_EXTENDED; 130static int quiet; 131#ifndef __APPLE__ 132static kvm_t *kd; 133#endif 134static pid_t mypid; 135 136static struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist); 137static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist); 138static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist); 139static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist); 140static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); 141static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); 142#ifndef __APPLE__ 143static struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); 144static struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); 145#endif 146 147static void usage(void) __attribute__((__noreturn__)); 148#ifdef __APPLE__ 149static int killact(const sysmon_row_t); 150static int grepact(const sysmon_row_t); 151#else 152static int killact(const struct kinfo_proc *); 153static int grepact(const struct kinfo_proc *); 154#endif 155static void makelist(struct listhead *, enum listtype, char *); 156static int takepid(const char *, int); 157 158#ifdef __APPLE__ 159static sysmon_table_t 160copy_process_info(void) 161{ 162 dispatch_semaphore_t sema; 163 sysmon_request_t request; 164 __block sysmon_table_t result = NULL; 165 166 sema = dispatch_semaphore_create(0); 167 request = sysmon_request_create(SYSMON_REQUEST_TYPE_PROCESS, ^(sysmon_table_t table) { 168 result = sysmon_retain(table); 169 dispatch_semaphore_signal(sema); 170 }); 171 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PID); 172 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_FLAGS); 173 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_UID); 174 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_COMM); 175 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_ARGUMENTS); 176 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RUID); 177 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RGID); 178 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PPID); 179 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PGID); 180 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_TDEV); 181 sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_START); 182 sysmon_request_execute(request); 183 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 184 dispatch_release(sema); 185 sysmon_release(request); 186 187 return result; 188} 189#endif /* __APPLE__ */ 190 191int 192main(int argc, char **argv) 193{ 194#ifdef __APPLE__ 195 char buf[_POSIX2_LINE_MAX], *bufp, *mstr, *p, *q, *pidfile; 196 xpc_object_t pargv; 197#else 198 char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; 199 const char *execf, *coref; 200#endif 201 int ancestors, debug_opt, did_action; 202 int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; 203#ifdef __APPLE__ 204 __block size_t jsz; 205 int (*action)(const sysmon_row_t); 206 sysmon_row_t kp; 207#else 208 size_t jsz; 209 int (*action)(const struct kinfo_proc *); 210 struct kinfo_proc *kp; 211#endif 212 struct list *li; 213#ifdef __APPLE__ 214 int64_t best_tval; 215#else 216 struct timeval best_tval; 217#endif 218 regex_t reg; 219 regmatch_t regmatch; 220 pid_t pid; 221 222 setlocale(LC_ALL, ""); 223 224 if (strcmp(getprogname(), "pgrep") == 0) { 225 action = grepact; 226 pgrep = 1; 227 } else { 228 action = killact; 229 p = argv[1]; 230 231 if (argc > 1 && p[0] == '-') { 232 p++; 233 i = (int)strtol(p, &q, 10); 234 if (*q == '\0') { 235 signum = i; 236 argv++; 237 argc--; 238 } else { 239 if (strncasecmp(p, "SIG", 3) == 0) 240 p += 3; 241 for (i = 1; i < NSIG; i++) 242 if (strcasecmp(sys_signame[i], p) == 0) 243 break; 244 if (i != NSIG) { 245 signum = i; 246 argv++; 247 argc--; 248 } 249 } 250 } 251 } 252 253 ancestors = 0; 254 criteria = 0; 255 debug_opt = 0; 256 pidfile = NULL; 257 pidfilelock = 0; 258 quiet = 0; 259#ifndef __APPLE__ 260 execf = NULL; 261 coref = _PATH_DEVNULL; 262#endif 263 264#ifdef __APPLE__ 265 while ((ch = getopt(argc, argv, "DF:G:ILP:U:ad:fg:ilnoqt:u:vx")) != -1) 266#else 267 while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1) 268#endif 269 switch (ch) { 270 case 'D': 271 debug_opt++; 272 break; 273 case 'F': 274 pidfile = optarg; 275 criteria = 1; 276 break; 277 case 'G': 278 makelist(&rgidlist, LT_GROUP, optarg); 279 criteria = 1; 280 break; 281 case 'I': 282 if (pgrep) 283 usage(); 284 interactive = 1; 285 break; 286 case 'L': 287 pidfilelock = 1; 288 break; 289#ifndef __APPLE__ 290 case 'M': 291 coref = optarg; 292 break; 293 case 'N': 294 execf = optarg; 295 break; 296#endif 297 case 'P': 298 makelist(&ppidlist, LT_GENERIC, optarg); 299 criteria = 1; 300 break; 301#ifndef __APPLE__ 302 case 'S': 303 if (!pgrep) 304 usage(); 305 kthreads = 1; 306 break; 307#endif 308 case 'U': 309 makelist(&ruidlist, LT_USER, optarg); 310 criteria = 1; 311 break; 312 case 'a': 313 ancestors++; 314 break; 315 case 'd': 316 if (!pgrep) 317 usage(); 318 delim = optarg; 319 break; 320 case 'f': 321 matchargs = 1; 322 break; 323 case 'g': 324 makelist(&pgrplist, LT_PGRP, optarg); 325 criteria = 1; 326 break; 327 case 'i': 328 cflags |= REG_ICASE; 329 break; 330#ifndef __APPLE__ 331 case 'j': 332 makelist(&jidlist, LT_JID, optarg); 333 criteria = 1; 334 break; 335#endif 336 case 'l': 337 longfmt = 1; 338 break; 339 case 'n': 340 newest = 1; 341 criteria = 1; 342 break; 343 case 'o': 344 oldest = 1; 345 criteria = 1; 346 break; 347 case 'q': 348 if (!pgrep) 349 usage(); 350 quiet = 1; 351 break; 352#ifndef __APPLE__ 353 case 's': 354 makelist(&sidlist, LT_SID, optarg); 355 criteria = 1; 356 break; 357#endif /* !__APPLE__ */ 358 case 't': 359 makelist(&tdevlist, LT_TTY, optarg); 360 criteria = 1; 361 break; 362 case 'u': 363 makelist(&euidlist, LT_USER, optarg); 364 criteria = 1; 365 break; 366 case 'v': 367 inverse = 1; 368 break; 369 case 'x': 370 fullmatch = 1; 371 break; 372 default: 373 usage(); 374 /* NOTREACHED */ 375 } 376 377 argc -= optind; 378 argv += optind; 379 if (argc != 0) 380 criteria = 1; 381 if (!criteria) 382 usage(); 383 if (newest && oldest) 384 errx(STATUS_ERROR, "Options -n and -o are mutually exclusive"); 385 if (pidfile != NULL) 386 pidfromfile = takepid(pidfile, pidfilelock); 387 else { 388 if (pidfilelock) { 389 errx(STATUS_ERROR, 390 "Option -L doesn't make sense without -F"); 391 } 392 pidfromfile = -1; 393 } 394 395 mypid = getpid(); 396 397#ifdef __APPLE__ 398 plist = copy_process_info(); 399 if (plist == NULL) { 400 errx(STATUS_ERROR, "Cannot get process list"); 401 } 402 nproc = sysmon_table_get_count(plist); 403#else 404 /* 405 * Retrieve the list of running processes from the kernel. 406 */ 407 kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); 408 if (kd == NULL) 409 errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); 410 411 /* 412 * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we 413 * just want processes and not individual kernel threads. 414 */ 415 plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); 416 if (plist == NULL) { 417 errx(STATUS_ERROR, "Cannot get process list (%s)", 418 kvm_geterr(kd)); 419 } 420#endif 421 422 /* 423 * Allocate memory which will be used to keep track of the 424 * selection. 425 */ 426 if ((selected = malloc(nproc)) == NULL) { 427 err(STATUS_ERROR, "Cannot allocate memory for %d processes", 428 nproc); 429 } 430 memset(selected, 0, nproc); 431 432 /* 433 * Refine the selection. 434 */ 435 for (; *argv != NULL; argv++) { 436 if ((rv = regcomp(®, *argv, cflags)) != 0) { 437 regerror(rv, ®, buf, sizeof(buf)); 438 errx(STATUS_BADUSAGE, 439 "Cannot compile regular expression `%s' (%s)", 440 *argv, buf); 441 } 442 443#ifdef __APPLE__ 444 for (i = 0; i < nproc; i++) { 445 kp = sysmon_table_get_row(plist, i); 446#else 447 for (i = 0, kp = plist; i < nproc; i++, kp++) { 448#endif 449 if (PSKIP(kp)) { 450 if (debug_opt > 0) 451 fprintf(stderr, "* Skipped %5d %3d %s\n", 452#ifdef __APPLE__ 453 (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), 454 (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)), 455 xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM))); 456#else 457 kp->ki_pid, kp->ki_uid, kp->ki_comm); 458#endif 459 continue; 460 } 461 462#ifdef __APPLE__ 463 if (matchargs && 464 (pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) { 465 jsz = 0; 466 os_assert(sizeof(buf) == _POSIX2_LINE_MAX); 467 bufp = buf; 468 xpc_array_apply(pargv, ^(size_t index, xpc_object_t value) { 469 if (jsz >= _POSIX2_LINE_MAX) { 470 return (bool)false; 471 } 472 jsz += snprintf(bufp + jsz, 473 _POSIX2_LINE_MAX - jsz, 474 index < xpc_array_get_count(pargv) - 1 ? "%s " : "%s", 475 xpc_string_get_string_ptr(value)); 476 return (bool)true; 477 }); 478#else 479 if (matchargs && 480 (pargv = kvm_getargv(kd, kp, 0)) != NULL) { 481 jsz = 0; 482 while (jsz < sizeof(buf) && *pargv != NULL) { 483 jsz += snprintf(buf + jsz, 484 sizeof(buf) - jsz, 485 pargv[1] != NULL ? "%s " : "%s", 486 pargv[0]); 487 pargv++; 488 } 489#endif 490 mstr = buf; 491 } else 492#ifdef __APPLE__ 493 { 494 /* 495 * comm is limited to 15 bytes (MAXCOMLEN - 1). 496 * Try to use argv[0] (trimmed) if available. 497 */ 498 mstr = NULL; 499 pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS); 500 if (pargv != NULL && xpc_array_get_count(pargv) > 0) { 501 const char *tmp = xpc_array_get_string(pargv, 0); 502 if (tmp != NULL) { 503 mstr = strrchr(tmp, '/'); 504 if (mstr != NULL) { 505 mstr++; 506 } else { 507 mstr = (char *)tmp; 508 } 509 } 510 } 511 512 /* Fall back to "comm" if we failed to get argv[0]. */ 513 if (mstr == NULL || *mstr == '\0') { 514 mstr = (char *)xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM)); 515 } 516 517 /* Couldn't find process name, it probably exited. */ 518 if (mstr == NULL) { 519 continue; 520 } 521 } 522#else 523 mstr = kp->ki_comm; 524#endif 525 526 rv = regexec(®, mstr, 1, ®match, 0); 527 if (rv == 0) { 528 if (fullmatch) { 529 if (regmatch.rm_so == 0 && 530 regmatch.rm_eo == 531 (off_t)strlen(mstr)) 532 selected[i] = 1; 533 } else 534 selected[i] = 1; 535 } else if (rv != REG_NOMATCH) { 536 regerror(rv, ®, buf, sizeof(buf)); 537 errx(STATUS_ERROR, 538 "Regular expression evaluation error (%s)", 539 buf); 540 } 541 if (debug_opt > 1) { 542 const char *rv_res = "NoMatch"; 543 if (selected[i]) 544 rv_res = "Matched"; 545 fprintf(stderr, "* %s %5d %3d %s\n", rv_res, 546#ifdef __APPLE__ 547 (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), 548 (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)), 549 mstr); 550#else 551 kp->ki_pid, kp->ki_uid, mstr); 552#endif 553 } 554 } 555 556 regfree(®); 557 } 558 559#ifdef __APPLE__ 560 for (i = 0; i < nproc; i++) { 561 kp = sysmon_table_get_row(plist, i); 562#else 563 for (i = 0, kp = plist; i < nproc; i++, kp++) { 564#endif 565 if (PSKIP(kp)) 566 continue; 567 568#ifdef __APPLE__ 569 if (pidfromfile >= 0 && (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) != pidfromfile) { 570#else 571 if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { 572#endif 573 selected[i] = 0; 574 continue; 575 } 576 577 SLIST_FOREACH(li, &ruidlist, li_chain) 578#ifdef __APPLE__ 579 if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RUID)) == (uid_t)li->li_number) 580#else 581 if (kp->ki_ruid == (uid_t)li->li_number) 582#endif 583 break; 584 if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 585 selected[i] = 0; 586 continue; 587 } 588 589 SLIST_FOREACH(li, &rgidlist, li_chain) 590#ifdef __APPLE__ 591 if ((gid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RGID)) == (gid_t)li->li_number) 592#else 593 if (kp->ki_rgid == (gid_t)li->li_number) 594#endif 595 break; 596 if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 597 selected[i] = 0; 598 continue; 599 } 600 601 SLIST_FOREACH(li, &euidlist, li_chain) 602#ifdef __APPLE__ 603 if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)) == (uid_t)li->li_number) 604#else 605 if (kp->ki_uid == (uid_t)li->li_number) 606#endif 607 break; 608 if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 609 selected[i] = 0; 610 continue; 611 } 612 613 SLIST_FOREACH(li, &ppidlist, li_chain) 614#ifdef __APPLE__ 615 if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID)) == (pid_t)li->li_number) 616#else 617 if (kp->ki_ppid == (pid_t)li->li_number) 618#endif 619 break; 620 if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 621 selected[i] = 0; 622 continue; 623 } 624 625 SLIST_FOREACH(li, &pgrplist, li_chain) 626#ifdef __APPLE__ 627 if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PGID)) == (pid_t)li->li_number) 628#else 629 if (kp->ki_pgid == (pid_t)li->li_number) 630#endif 631 break; 632 if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 633 selected[i] = 0; 634 continue; 635 } 636 637 SLIST_FOREACH(li, &tdevlist, li_chain) { 638 if (li->li_number == -1 && 639#ifdef __APPLE__ 640 (xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_CONTROLT) == 0) 641#else 642 (kp->ki_flag & P_CONTROLT) == 0) 643#endif 644 break; 645#ifdef __APPLE__ 646 if ((dev_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_TDEV)) == (dev_t)li->li_number) 647#else 648 if (kp->ki_tdev == (dev_t)li->li_number) 649#endif 650 break; 651 } 652 if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 653 selected[i] = 0; 654 continue; 655 } 656 657#ifndef __APPLE__ 658 SLIST_FOREACH(li, &sidlist, li_chain) 659 if (kp->ki_sid == (pid_t)li->li_number) 660 break; 661 if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 662 selected[i] = 0; 663 continue; 664 } 665 666 SLIST_FOREACH(li, &jidlist, li_chain) { 667 /* A particular jail ID, including 0 (not in jail) */ 668 if (kp->ki_jid == (int)li->li_number) 669 break; 670 /* Any jail */ 671 if (kp->ki_jid > 0 && li->li_number == -1) 672 break; 673 } 674 if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { 675 selected[i] = 0; 676 continue; 677 } 678#endif /* !__APPLE__ */ 679 680 if (argc == 0) 681 selected[i] = 1; 682 } 683 684 if (!ancestors) { 685 pid = mypid; 686 while (pid) { 687#ifdef __APPLE__ 688 for (i = 0; i < nproc; i++) { 689 kp = sysmon_table_get_row(plist, i); 690#else 691 for (i = 0, kp = plist; i < nproc; i++, kp++) { 692#endif 693 if (PSKIP(kp)) 694 continue; 695#ifdef __APPLE__ 696 if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == pid) { 697 selected[i] = 0; 698 pid = (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID)); 699 break; 700 } 701#else 702 if (kp->ki_pid == pid) { 703 selected[i] = 0; 704 pid = kp->ki_ppid; 705 break; 706 } 707#endif 708 } 709 if (i == nproc) { 710 if (pid == mypid) 711 pid = getppid(); 712 else 713 break; /* Maybe we're in a jail ? */ 714 } 715 } 716 } 717 718 if (newest || oldest) { 719#ifdef __APPLE__ 720 best_tval = 0; 721#else 722 best_tval.tv_sec = 0; 723 best_tval.tv_usec = 0; 724#endif 725 bestidx = -1; 726 727#ifdef __APPLE__ 728 for (i = 0; i < nproc; i++) { 729 kp = sysmon_table_get_row(plist, i); 730#else 731 for (i = 0, kp = plist; i < nproc; i++, kp++) { 732#endif 733 if (!selected[i]) 734 continue; 735 if (bestidx == -1) { 736 /* The first entry of the list which matched. */ 737 ; 738#ifdef __APPLE__ 739 } else if (xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START)) > best_tval) { 740#else 741 } else if (timercmp(&kp->ki_start, &best_tval, >)) { 742#endif 743 /* This entry is newer than previous "best". */ 744 if (oldest) /* but we want the oldest */ 745 continue; 746 } else { 747 /* This entry is older than previous "best". */ 748 if (newest) /* but we want the newest */ 749 continue; 750 } 751 /* This entry is better than previous "best" entry. */ 752#ifdef __APPLE__ 753 best_tval = xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START)); 754#else 755 best_tval.tv_sec = kp->ki_start.tv_sec; 756 best_tval.tv_usec = kp->ki_start.tv_usec; 757#endif 758 bestidx = i; 759 } 760 761 memset(selected, 0, nproc); 762 if (bestidx != -1) 763 selected[bestidx] = 1; 764 } 765 766 /* 767 * Take the appropriate action for each matched process, if any. 768 */ 769 did_action = 0; 770#ifdef __APPLE__ 771 for (i = 0, rv = 0; i < nproc; i++) { 772 kp = sysmon_table_get_row(plist, i); 773#else 774 for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 775#endif 776 if (PSKIP(kp)) 777 continue; 778 if (selected[i]) { 779 if (longfmt && !pgrep) { 780 did_action = 1; 781#ifdef __APPLE__ 782 printf("kill -%d %d\n", signum, (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID))); 783#else 784 printf("kill -%d %d\n", signum, kp->ki_pid); 785#endif 786 } 787 if (inverse) 788 continue; 789 } else if (!inverse) 790 continue; 791 rv |= (*action)(kp); 792 } 793 if (!did_action && !pgrep && longfmt) 794 fprintf(stderr, 795 "No matching processes belonging to you were found\n"); 796 797 exit(rv ? STATUS_MATCH : STATUS_NOMATCH); 798} 799 800static void 801usage(void) 802{ 803 const char *ustr; 804 805 if (pgrep) 806#ifdef __APPLE__ 807 ustr = "[-Lfilnoqvx] [-d delim]"; 808#else 809 ustr = "[-LSfilnoqvx] [-d delim]"; 810#endif 811 else 812 ustr = "[-signal] [-ILfilnovx]"; 813 814 fprintf(stderr, 815#ifdef __APPLE__ 816 "usage: %s %s [-F pidfile] [-G gid]\n" 817 " [-P ppid] [-U uid] [-g pgrp]\n" 818#else 819 "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" 820 " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n" 821#endif 822 " [-t tty] [-u euid] pattern ...\n", getprogname(), 823 ustr); 824 825 exit(STATUS_BADUSAGE); 826} 827 828static void 829#ifdef __APPLE__ 830show_process(const sysmon_row_t kp) 831#else 832show_process(const struct kinfo_proc *kp) 833#endif 834{ 835#ifdef __APPLE__ 836 xpc_object_t argv; 837#else 838 char **argv; 839#endif 840 841 if (quiet) { 842 assert(pgrep); 843 return; 844 } 845#ifdef __APPLE__ 846 if ((longfmt || !pgrep) && matchargs && 847 (argv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) { 848 printf("%d ", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID))); 849 (void)xpc_array_apply(argv, ^(size_t index, xpc_object_t value) { 850 printf("%s", xpc_string_get_string_ptr(value)); 851 if (index < xpc_array_get_count(argv) - 1) 852 putchar(' '); 853 return (bool)true; 854 }); 855 } else if (longfmt || !pgrep) 856 printf("%d %s", 857 (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), 858 xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM))); 859 else 860 printf("%d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID))); 861#else 862 if ((longfmt || !pgrep) && matchargs && 863 (argv = kvm_getargv(kd, kp, 0)) != NULL) { 864 printf("%d ", (int)kp->ki_pid); 865 for (; *argv != NULL; argv++) { 866 printf("%s", *argv); 867 if (argv[1] != NULL) 868 putchar(' '); 869 } 870 } else if (longfmt || !pgrep) 871 printf("%d %s", (int)kp->ki_pid, kp->ki_comm); 872 else 873 printf("%d", (int)kp->ki_pid); 874#endif 875} 876 877static int 878#ifdef __APPLE__ 879killact(const sysmon_row_t kp) 880#else 881killact(const struct kinfo_proc *kp) 882#endif 883{ 884 int ch, first; 885 886 if (interactive) { 887 /* 888 * Be careful, ask before killing. 889 */ 890 printf("kill "); 891 show_process(kp); 892 printf("? "); 893 fflush(stdout); 894 first = ch = getchar(); 895 while (ch != '\n' && ch != EOF) 896 ch = getchar(); 897 if (first != 'y' && first != 'Y') 898 return (1); 899 } 900#ifdef __APPLE__ 901 if (kill((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), signum) == -1) { 902#else 903 if (kill(kp->ki_pid, signum) == -1) { 904#endif 905 /* 906 * Check for ESRCH, which indicates that the process 907 * disappeared between us matching it and us 908 * signalling it; don't issue a warning about it. 909 */ 910 if (errno != ESRCH) 911#ifdef __APPLE__ 912 warn("signalling pid %d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID))); 913#else 914 warn("signalling pid %d", (int)kp->ki_pid); 915#endif 916 /* 917 * Return 0 to indicate that the process should not be 918 * considered a match, since we didn't actually get to 919 * signal it. 920 */ 921 return (0); 922 } 923 return (1); 924} 925 926static int 927#ifdef __APPLE__ 928grepact(const sysmon_row_t kp) 929#else 930grepact(const struct kinfo_proc *kp) 931#endif 932{ 933 934 show_process(kp); 935 if (!quiet) 936 printf("%s", delim); 937 return (1); 938} 939 940static void 941makelist(struct listhead *head, enum listtype type, char *src) 942{ 943 struct list *li; 944 struct passwd *pw; 945 struct group *gr; 946 struct stat st; 947 const char *cp; 948 char *sp, *ep, buf[MAXPATHLEN]; 949 int empty; 950 951 empty = 1; 952 953 while ((sp = strsep(&src, ",")) != NULL) { 954 if (*sp == '\0') 955 usage(); 956 957 if ((li = malloc(sizeof(*li))) == NULL) { 958 err(STATUS_ERROR, "Cannot allocate %zu bytes", 959 sizeof(*li)); 960 } 961 962 SLIST_INSERT_HEAD(head, li, li_chain); 963 empty = 0; 964 965 li->li_number = (uid_t)strtol(sp, &ep, 0); 966 if (*ep == '\0') { 967 switch (type) { 968 case LT_PGRP: 969 if (li->li_number == 0) 970 li->li_number = getpgrp(); 971 break; 972#ifndef __APPLE__ 973 case LT_SID: 974 if (li->li_number == 0) 975 li->li_number = getsid(mypid); 976 break; 977 case LT_JID: 978 if (li->li_number < 0) 979 errx(STATUS_BADUSAGE, 980 "Negative jail ID `%s'", sp); 981 /* For compatibility with old -j */ 982 if (li->li_number == 0) 983 li->li_number = -1; /* any jail */ 984 break; 985#endif /* !__APPLE__ */ 986 case LT_TTY: 987 if (li->li_number < 0) 988 errx(STATUS_BADUSAGE, 989 "Negative /dev/pts tty `%s'", sp); 990 snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s", 991 sp); 992 if (stat(buf, &st) != -1) 993 goto foundtty; 994 if (errno == ENOENT) 995 errx(STATUS_BADUSAGE, "No such tty: `" 996 _PATH_DEV "pts/%s'", sp); 997 err(STATUS_ERROR, "Cannot access `" 998 _PATH_DEV "pts/%s'", sp); 999 break; 1000 default: 1001 break; 1002 } 1003 continue; 1004 } 1005 1006 switch (type) { 1007 case LT_USER: 1008 if ((pw = getpwnam(sp)) == NULL) 1009 errx(STATUS_BADUSAGE, "Unknown user `%s'", sp); 1010 li->li_number = pw->pw_uid; 1011 break; 1012 case LT_GROUP: 1013 if ((gr = getgrnam(sp)) == NULL) 1014 errx(STATUS_BADUSAGE, "Unknown group `%s'", sp); 1015 li->li_number = gr->gr_gid; 1016 break; 1017 case LT_TTY: 1018 if (strcmp(sp, "-") == 0) { 1019 li->li_number = -1; 1020 break; 1021 } else if (strcmp(sp, "co") == 0) { 1022 cp = "console"; 1023 } else { 1024 cp = sp; 1025 } 1026 1027 snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp); 1028 if (stat(buf, &st) != -1) 1029 goto foundtty; 1030 1031 snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp); 1032 if (stat(buf, &st) != -1) 1033 goto foundtty; 1034 1035 if (errno == ENOENT) 1036 errx(STATUS_BADUSAGE, "No such tty: `%s'", sp); 1037 err(STATUS_ERROR, "Cannot access `%s'", sp); 1038 1039foundtty: if ((st.st_mode & S_IFCHR) == 0) 1040 errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp); 1041 1042 li->li_number = st.st_rdev; 1043 break; 1044#ifndef __APPLE__ 1045 case LT_JID: 1046 if (strcmp(sp, "none") == 0) 1047 li->li_number = 0; 1048 else if (strcmp(sp, "any") == 0) 1049 li->li_number = -1; 1050 else if (*ep != '\0') 1051 errx(STATUS_BADUSAGE, 1052 "Invalid jail ID `%s'", sp); 1053 break; 1054#endif /* !__APPLE__ */ 1055 default: 1056 usage(); 1057 } 1058 } 1059 1060 if (empty) 1061 usage(); 1062} 1063 1064static int 1065takepid(const char *pidfile, int pidfilelock) 1066{ 1067 char *endp, line[BUFSIZ]; 1068 FILE *fh; 1069 long rval; 1070 1071 fh = fopen(pidfile, "r"); 1072 if (fh == NULL) 1073 err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); 1074 1075 if (pidfilelock) { 1076 /* 1077 * If we can lock pidfile, this means that daemon is not 1078 * running, so would be better not to kill some random process. 1079 */ 1080 if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { 1081 (void)fclose(fh); 1082 errx(STATUS_ERROR, "File '%s' can be locked", pidfile); 1083 } else { 1084 if (errno != EWOULDBLOCK) { 1085 errx(STATUS_ERROR, 1086 "Error while locking file '%s'", pidfile); 1087 } 1088 } 1089 } 1090 1091 if (fgets(line, sizeof(line), fh) == NULL) { 1092 if (feof(fh)) { 1093 (void)fclose(fh); 1094 errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); 1095 } 1096 (void)fclose(fh); 1097 err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); 1098 } 1099 (void)fclose(fh); 1100 1101 rval = strtol(line, &endp, 10); 1102 if (*endp != '\0' && !isspace((unsigned char)*endp)) 1103 errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 1104 else if (rval < MIN_PID || rval > MAX_PID) 1105 errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 1106 return (rval); 1107} 1108