1152521Spjd/* $NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $ */ 2127412Sgad 3127412Sgad/*- 4127412Sgad * Copyright (c) 2002 The NetBSD Foundation, Inc. 5152518Spjd * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 6127412Sgad * All rights reserved. 7127412Sgad * 8127412Sgad * This code is derived from software contributed to The NetBSD Foundation 9127412Sgad * by Andrew Doran. 10127412Sgad * 11127412Sgad * Redistribution and use in source and binary forms, with or without 12127412Sgad * modification, are permitted provided that the following conditions 13127412Sgad * are met: 14127412Sgad * 1. Redistributions of source code must retain the above copyright 15127412Sgad * notice, this list of conditions and the following disclaimer. 16127412Sgad * 2. Redistributions in binary form must reproduce the above copyright 17127412Sgad * notice, this list of conditions and the following disclaimer in the 18127412Sgad * documentation and/or other materials provided with the distribution. 19127412Sgad * 20127412Sgad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21127412Sgad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22127412Sgad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23127412Sgad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24127412Sgad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25127412Sgad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26127412Sgad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27127412Sgad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28127412Sgad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29127412Sgad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30127412Sgad * POSSIBILITY OF SUCH DAMAGE. 31127412Sgad */ 32127412Sgad 33127412Sgad#include <sys/cdefs.h> 34127412Sgad__FBSDID("$FreeBSD$"); 35127412Sgad 36127412Sgad#include <sys/types.h> 37127412Sgad#include <sys/param.h> 38127412Sgad#include <sys/sysctl.h> 39127412Sgad#include <sys/proc.h> 40127412Sgad#include <sys/queue.h> 41127412Sgad#include <sys/stat.h> 42143878Spjd#include <sys/time.h> 43127425Sgad#include <sys/user.h> 44127412Sgad 45203802Spjd#include <assert.h> 46127412Sgad#include <stdio.h> 47127412Sgad#include <stdlib.h> 48127412Sgad#include <limits.h> 49127425Sgad#include <paths.h> 50127412Sgad#include <string.h> 51127412Sgad#include <unistd.h> 52127412Sgad#include <signal.h> 53127412Sgad#include <regex.h> 54127412Sgad#include <ctype.h> 55127425Sgad#include <fcntl.h> 56127412Sgad#include <kvm.h> 57127412Sgad#include <err.h> 58127412Sgad#include <pwd.h> 59127412Sgad#include <grp.h> 60127412Sgad#include <errno.h> 61132198Stjr#include <locale.h> 62287269Sjamie#include <jail.h> 63127412Sgad 64127412Sgad#define STATUS_MATCH 0 65127412Sgad#define STATUS_NOMATCH 1 66127412Sgad#define STATUS_BADUSAGE 2 67127412Sgad#define STATUS_ERROR 3 68127412Sgad 69143874Spjd#define MIN_PID 5 70143874Spjd#define MAX_PID 99999 71143874Spjd 72143877Spjd/* Ignore system-processes (if '-S' flag is not specified) and myself. */ 73143877Spjd#define PSKIP(kp) ((kp)->ki_pid == mypid || \ 74143877Spjd (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0)) 75127425Sgad 76127412Sgadenum listtype { 77127412Sgad LT_GENERIC, 78127412Sgad LT_USER, 79127412Sgad LT_GROUP, 80127412Sgad LT_TTY, 81127412Sgad LT_PGRP, 82287269Sjamie LT_JAIL, 83254134Strasz LT_SID, 84254134Strasz LT_CLASS 85127412Sgad}; 86127412Sgad 87127412Sgadstruct list { 88127412Sgad SLIST_ENTRY(list) li_chain; 89127412Sgad long li_number; 90254134Strasz char *li_name; 91127412Sgad}; 92127412Sgad 93127412SgadSLIST_HEAD(listhead, list); 94127412Sgad 95152521Spjdstatic struct kinfo_proc *plist; 96152521Spjdstatic char *selected; 97152521Spjdstatic const char *delim = "\n"; 98152521Spjdstatic int nproc; 99152521Spjdstatic int pgrep; 100152521Spjdstatic int signum = SIGTERM; 101152521Spjdstatic int newest; 102152521Spjdstatic int oldest; 103152521Spjdstatic int interactive; 104152521Spjdstatic int inverse; 105152521Spjdstatic int longfmt; 106152521Spjdstatic int matchargs; 107152521Spjdstatic int fullmatch; 108152521Spjdstatic int kthreads; 109152521Spjdstatic int cflags = REG_EXTENDED; 110203802Spjdstatic int quiet; 111152521Spjdstatic kvm_t *kd; 112152521Spjdstatic pid_t mypid; 113127412Sgad 114201145Santoinestatic struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist); 115201145Santoinestatic struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist); 116201145Santoinestatic struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist); 117201145Santoinestatic struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist); 118201145Santoinestatic struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); 119201145Santoinestatic struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); 120201145Santoinestatic struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); 121201145Santoinestatic struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); 122254134Straszstatic struct listhead classlist = SLIST_HEAD_INITIALIZER(classlist); 123127412Sgad 124152521Spjdstatic void usage(void) __attribute__((__noreturn__)); 125152521Spjdstatic int killact(const struct kinfo_proc *); 126152521Spjdstatic int grepact(const struct kinfo_proc *); 127152521Spjdstatic void makelist(struct listhead *, enum listtype, char *); 128152521Spjdstatic int takepid(const char *, int); 129127412Sgad 130127412Sgadint 131127412Sgadmain(int argc, char **argv) 132127412Sgad{ 133149471Spjd char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; 134127462Sgad const char *execf, *coref; 135209363Sbrian int ancestors, debug_opt, did_action; 136149471Spjd int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; 137127430Sgad size_t jsz; 138152521Spjd int (*action)(const struct kinfo_proc *); 139127425Sgad struct kinfo_proc *kp; 140127412Sgad struct list *li; 141127430Sgad struct timeval best_tval; 142127412Sgad regex_t reg; 143127412Sgad regmatch_t regmatch; 144192242Sbrian pid_t pid; 145127412Sgad 146132198Stjr setlocale(LC_ALL, ""); 147132198Stjr 148127412Sgad if (strcmp(getprogname(), "pgrep") == 0) { 149127412Sgad action = grepact; 150127412Sgad pgrep = 1; 151127412Sgad } else { 152127412Sgad action = killact; 153127412Sgad p = argv[1]; 154127412Sgad 155127412Sgad if (argc > 1 && p[0] == '-') { 156127412Sgad p++; 157127412Sgad i = (int)strtol(p, &q, 10); 158127412Sgad if (*q == '\0') { 159127412Sgad signum = i; 160127412Sgad argv++; 161127412Sgad argc--; 162127412Sgad } else { 163218285Sjilles if (strncasecmp(p, "SIG", 3) == 0) 164127412Sgad p += 3; 165127412Sgad for (i = 1; i < NSIG; i++) 166127412Sgad if (strcasecmp(sys_signame[i], p) == 0) 167127412Sgad break; 168127412Sgad if (i != NSIG) { 169127412Sgad signum = i; 170127412Sgad argv++; 171127412Sgad argc--; 172127412Sgad } 173127412Sgad } 174127412Sgad } 175127412Sgad } 176127412Sgad 177192242Sbrian ancestors = 0; 178127412Sgad criteria = 0; 179127433Sgad debug_opt = 0; 180149471Spjd pidfile = NULL; 181149471Spjd pidfilelock = 0; 182203802Spjd quiet = 0; 183203688Sbrucec execf = NULL; 184203688Sbrucec coref = _PATH_DEVNULL; 185127412Sgad 186254134Strasz while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ac:d:fg:ij:lnoqs:t:u:vx")) != -1) 187127412Sgad switch (ch) { 188127433Sgad case 'D': 189127433Sgad debug_opt++; 190127433Sgad break; 191143874Spjd case 'F': 192149471Spjd pidfile = optarg; 193143874Spjd criteria = 1; 194143874Spjd break; 195127412Sgad case 'G': 196127412Sgad makelist(&rgidlist, LT_GROUP, optarg); 197127412Sgad criteria = 1; 198127412Sgad break; 199152518Spjd case 'I': 200152518Spjd if (pgrep) 201152518Spjd usage(); 202152518Spjd interactive = 1; 203152518Spjd break; 204149471Spjd case 'L': 205149471Spjd pidfilelock = 1; 206149471Spjd break; 207127427Sgad case 'M': 208127427Sgad coref = optarg; 209127427Sgad break; 210127427Sgad case 'N': 211127427Sgad execf = optarg; 212127427Sgad break; 213127412Sgad case 'P': 214127412Sgad makelist(&ppidlist, LT_GENERIC, optarg); 215127412Sgad criteria = 1; 216127412Sgad break; 217143877Spjd case 'S': 218143877Spjd if (!pgrep) 219143877Spjd usage(); 220143877Spjd kthreads = 1; 221143877Spjd break; 222127412Sgad case 'U': 223127412Sgad makelist(&ruidlist, LT_USER, optarg); 224127412Sgad criteria = 1; 225127412Sgad break; 226192242Sbrian case 'a': 227192242Sbrian ancestors++; 228192242Sbrian break; 229254134Strasz case 'c': 230254134Strasz makelist(&classlist, LT_CLASS, optarg); 231254134Strasz criteria = 1; 232254134Strasz break; 233127412Sgad case 'd': 234127412Sgad if (!pgrep) 235127412Sgad usage(); 236127412Sgad delim = optarg; 237127412Sgad break; 238127412Sgad case 'f': 239127412Sgad matchargs = 1; 240127412Sgad break; 241127412Sgad case 'g': 242127412Sgad makelist(&pgrplist, LT_PGRP, optarg); 243127412Sgad criteria = 1; 244127412Sgad break; 245143875Spjd case 'i': 246143875Spjd cflags |= REG_ICASE; 247143875Spjd break; 248143873Spjd case 'j': 249287269Sjamie makelist(&jidlist, LT_JAIL, optarg); 250143873Spjd criteria = 1; 251143873Spjd break; 252127412Sgad case 'l': 253127412Sgad longfmt = 1; 254127412Sgad break; 255127412Sgad case 'n': 256127412Sgad newest = 1; 257127412Sgad criteria = 1; 258127412Sgad break; 259143878Spjd case 'o': 260143878Spjd oldest = 1; 261143878Spjd criteria = 1; 262143878Spjd break; 263203802Spjd case 'q': 264203802Spjd if (!pgrep) 265203802Spjd usage(); 266203802Spjd quiet = 1; 267203802Spjd break; 268127412Sgad case 's': 269127412Sgad makelist(&sidlist, LT_SID, optarg); 270127412Sgad criteria = 1; 271127412Sgad break; 272127412Sgad case 't': 273127412Sgad makelist(&tdevlist, LT_TTY, optarg); 274127412Sgad criteria = 1; 275127412Sgad break; 276127412Sgad case 'u': 277127412Sgad makelist(&euidlist, LT_USER, optarg); 278127412Sgad criteria = 1; 279127412Sgad break; 280127412Sgad case 'v': 281127412Sgad inverse = 1; 282127412Sgad break; 283127412Sgad case 'x': 284127412Sgad fullmatch = 1; 285127412Sgad break; 286127412Sgad default: 287127412Sgad usage(); 288127412Sgad /* NOTREACHED */ 289127412Sgad } 290127412Sgad 291127412Sgad argc -= optind; 292127412Sgad argv += optind; 293127412Sgad if (argc != 0) 294127412Sgad criteria = 1; 295127412Sgad if (!criteria) 296127412Sgad usage(); 297143878Spjd if (newest && oldest) 298152521Spjd errx(STATUS_ERROR, "Options -n and -o are mutually exclusive"); 299149471Spjd if (pidfile != NULL) 300149471Spjd pidfromfile = takepid(pidfile, pidfilelock); 301149471Spjd else { 302152521Spjd if (pidfilelock) { 303152521Spjd errx(STATUS_ERROR, 304152521Spjd "Option -L doesn't make sense without -F"); 305152521Spjd } 306149471Spjd pidfromfile = -1; 307149471Spjd } 308127412Sgad 309127412Sgad mypid = getpid(); 310127412Sgad 311127412Sgad /* 312127412Sgad * Retrieve the list of running processes from the kernel. 313127412Sgad */ 314127462Sgad kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); 315127412Sgad if (kd == NULL) 316152521Spjd errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); 317127412Sgad 318127622Sgad /* 319127622Sgad * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we 320127622Sgad * just want processes and not individual kernel threads. 321127622Sgad */ 322127622Sgad plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); 323152521Spjd if (plist == NULL) { 324152521Spjd errx(STATUS_ERROR, "Cannot get process list (%s)", 325152521Spjd kvm_geterr(kd)); 326152521Spjd } 327127412Sgad 328127412Sgad /* 329127412Sgad * Allocate memory which will be used to keep track of the 330127412Sgad * selection. 331127412Sgad */ 332152521Spjd if ((selected = malloc(nproc)) == NULL) { 333152521Spjd err(STATUS_ERROR, "Cannot allocate memory for %d processes", 334152521Spjd nproc); 335152521Spjd } 336127412Sgad memset(selected, 0, nproc); 337127412Sgad 338127412Sgad /* 339127412Sgad * Refine the selection. 340127412Sgad */ 341127412Sgad for (; *argv != NULL; argv++) { 342143875Spjd if ((rv = regcomp(®, *argv, cflags)) != 0) { 343127412Sgad regerror(rv, ®, buf, sizeof(buf)); 344152521Spjd errx(STATUS_BADUSAGE, 345152521Spjd "Cannot compile regular expression `%s' (%s)", 346152521Spjd *argv, buf); 347127412Sgad } 348127412Sgad 349127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 350143877Spjd if (PSKIP(kp)) { 351127433Sgad if (debug_opt > 0) 352127434Sgad fprintf(stderr, "* Skipped %5d %3d %s\n", 353127433Sgad kp->ki_pid, kp->ki_uid, kp->ki_comm); 354127412Sgad continue; 355127433Sgad } 356127412Sgad 357143877Spjd if (matchargs && 358143877Spjd (pargv = kvm_getargv(kd, kp, 0)) != NULL) { 359127430Sgad jsz = 0; 360127430Sgad while (jsz < sizeof(buf) && *pargv != NULL) { 361127430Sgad jsz += snprintf(buf + jsz, 362127430Sgad sizeof(buf) - jsz, 363127412Sgad pargv[1] != NULL ? "%s " : "%s", 364127412Sgad pargv[0]); 365127412Sgad pargv++; 366127412Sgad } 367127412Sgad mstr = buf; 368127412Sgad } else 369127425Sgad mstr = kp->ki_comm; 370127412Sgad 371127412Sgad rv = regexec(®, mstr, 1, ®match, 0); 372127412Sgad if (rv == 0) { 373127412Sgad if (fullmatch) { 374127412Sgad if (regmatch.rm_so == 0 && 375127431Sgad regmatch.rm_eo == 376127431Sgad (off_t)strlen(mstr)) 377127412Sgad selected[i] = 1; 378127412Sgad } else 379127412Sgad selected[i] = 1; 380127412Sgad } else if (rv != REG_NOMATCH) { 381127412Sgad regerror(rv, ®, buf, sizeof(buf)); 382152521Spjd errx(STATUS_ERROR, 383152521Spjd "Regular expression evaluation error (%s)", 384152521Spjd buf); 385127412Sgad } 386127433Sgad if (debug_opt > 1) { 387127433Sgad const char *rv_res = "NoMatch"; 388127433Sgad if (selected[i]) 389127433Sgad rv_res = "Matched"; 390127434Sgad fprintf(stderr, "* %s %5d %3d %s\n", rv_res, 391127433Sgad kp->ki_pid, kp->ki_uid, mstr); 392127433Sgad } 393127412Sgad } 394127412Sgad 395127412Sgad regfree(®); 396127412Sgad } 397127412Sgad 398127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 399143877Spjd if (PSKIP(kp)) 400127412Sgad continue; 401127412Sgad 402143874Spjd if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { 403143874Spjd selected[i] = 0; 404143874Spjd continue; 405143874Spjd } 406143874Spjd 407127412Sgad SLIST_FOREACH(li, &ruidlist, li_chain) 408127425Sgad if (kp->ki_ruid == (uid_t)li->li_number) 409127412Sgad break; 410127412Sgad if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 411127412Sgad selected[i] = 0; 412127412Sgad continue; 413127412Sgad } 414127429Sgad 415127412Sgad SLIST_FOREACH(li, &rgidlist, li_chain) 416127425Sgad if (kp->ki_rgid == (gid_t)li->li_number) 417127412Sgad break; 418127412Sgad if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 419127412Sgad selected[i] = 0; 420127412Sgad continue; 421127412Sgad } 422127412Sgad 423127412Sgad SLIST_FOREACH(li, &euidlist, li_chain) 424127425Sgad if (kp->ki_uid == (uid_t)li->li_number) 425127412Sgad break; 426127412Sgad if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 427127412Sgad selected[i] = 0; 428127412Sgad continue; 429127412Sgad } 430127412Sgad 431127412Sgad SLIST_FOREACH(li, &ppidlist, li_chain) 432127426Sgad if (kp->ki_ppid == (pid_t)li->li_number) 433127412Sgad break; 434127412Sgad if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 435127412Sgad selected[i] = 0; 436127412Sgad continue; 437127412Sgad } 438127412Sgad 439127412Sgad SLIST_FOREACH(li, &pgrplist, li_chain) 440127426Sgad if (kp->ki_pgid == (pid_t)li->li_number) 441127412Sgad break; 442127412Sgad if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 443127412Sgad selected[i] = 0; 444127412Sgad continue; 445127412Sgad } 446127412Sgad 447127412Sgad SLIST_FOREACH(li, &tdevlist, li_chain) { 448127412Sgad if (li->li_number == -1 && 449127425Sgad (kp->ki_flag & P_CONTROLT) == 0) 450127412Sgad break; 451130640Sphk if (kp->ki_tdev == (dev_t)li->li_number) 452127412Sgad break; 453127412Sgad } 454127412Sgad if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 455127412Sgad selected[i] = 0; 456127412Sgad continue; 457127412Sgad } 458127412Sgad 459127412Sgad SLIST_FOREACH(li, &sidlist, li_chain) 460127426Sgad if (kp->ki_sid == (pid_t)li->li_number) 461127412Sgad break; 462127412Sgad if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 463127412Sgad selected[i] = 0; 464127412Sgad continue; 465127412Sgad } 466127412Sgad 467143873Spjd SLIST_FOREACH(li, &jidlist, li_chain) { 468164558Syar /* A particular jail ID, including 0 (not in jail) */ 469164558Syar if (kp->ki_jid == (int)li->li_number) 470164558Syar break; 471164558Syar /* Any jail */ 472164558Syar if (kp->ki_jid > 0 && li->li_number == -1) 473164558Syar break; 474143873Spjd } 475143873Spjd if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { 476143873Spjd selected[i] = 0; 477143873Spjd continue; 478143873Spjd } 479143873Spjd 480254134Strasz SLIST_FOREACH(li, &classlist, li_chain) { 481254134Strasz /* 482254134Strasz * We skip P_SYSTEM processes to match ps(1) output. 483254134Strasz */ 484254134Strasz if ((kp->ki_flag & P_SYSTEM) == 0 && 485254134Strasz strcmp(kp->ki_loginclass, li->li_name) == 0) 486254134Strasz break; 487254134Strasz } 488254134Strasz if (SLIST_FIRST(&classlist) != NULL && li == NULL) { 489254134Strasz selected[i] = 0; 490254134Strasz continue; 491254134Strasz } 492254134Strasz 493127412Sgad if (argc == 0) 494127412Sgad selected[i] = 1; 495127412Sgad } 496127412Sgad 497192242Sbrian if (!ancestors) { 498192242Sbrian pid = mypid; 499192242Sbrian while (pid) { 500192242Sbrian for (i = 0, kp = plist; i < nproc; i++, kp++) { 501192242Sbrian if (PSKIP(kp)) 502192242Sbrian continue; 503192242Sbrian if (kp->ki_pid == pid) { 504192242Sbrian selected[i] = 0; 505192242Sbrian pid = kp->ki_ppid; 506192242Sbrian break; 507192242Sbrian } 508192242Sbrian } 509192242Sbrian if (i == nproc) { 510192242Sbrian if (pid == mypid) 511192242Sbrian pid = getppid(); 512192242Sbrian else 513192242Sbrian break; /* Maybe we're in a jail ? */ 514192242Sbrian } 515192242Sbrian } 516192242Sbrian } 517192242Sbrian 518143878Spjd if (newest || oldest) { 519127430Sgad best_tval.tv_sec = 0; 520127430Sgad best_tval.tv_usec = 0; 521127412Sgad bestidx = -1; 522127412Sgad 523127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 524127412Sgad if (!selected[i]) 525127412Sgad continue; 526143878Spjd if (bestidx == -1) { 527143878Spjd /* The first entry of the list which matched. */ 528143878Spjd ; 529143878Spjd } else if (timercmp(&kp->ki_start, &best_tval, >)) { 530143878Spjd /* This entry is newer than previous "best". */ 531143879Spjd if (oldest) /* but we want the oldest */ 532143878Spjd continue; 533143878Spjd } else { 534143878Spjd /* This entry is older than previous "best". */ 535143879Spjd if (newest) /* but we want the newest */ 536143878Spjd continue; 537127412Sgad } 538143878Spjd /* This entry is better than previous "best" entry. */ 539143878Spjd best_tval.tv_sec = kp->ki_start.tv_sec; 540143878Spjd best_tval.tv_usec = kp->ki_start.tv_usec; 541143878Spjd bestidx = i; 542127412Sgad } 543127412Sgad 544127412Sgad memset(selected, 0, nproc); 545127412Sgad if (bestidx != -1) 546127412Sgad selected[bestidx] = 1; 547127412Sgad } 548127412Sgad 549127412Sgad /* 550127412Sgad * Take the appropriate action for each matched process, if any. 551127412Sgad */ 552209363Sbrian did_action = 0; 553127412Sgad for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 554143877Spjd if (PSKIP(kp)) 555127412Sgad continue; 556127412Sgad if (selected[i]) { 557209363Sbrian if (longfmt && !pgrep) { 558209363Sbrian did_action = 1; 559209363Sbrian printf("kill -%d %d\n", signum, kp->ki_pid); 560209363Sbrian } 561127412Sgad if (inverse) 562127412Sgad continue; 563127412Sgad } else if (!inverse) 564127412Sgad continue; 565152521Spjd rv |= (*action)(kp); 566127412Sgad } 567209363Sbrian if (!did_action && !pgrep && longfmt) 568209363Sbrian fprintf(stderr, 569209363Sbrian "No matching processes belonging to you were found\n"); 570127412Sgad 571127412Sgad exit(rv ? STATUS_MATCH : STATUS_NOMATCH); 572127412Sgad} 573127412Sgad 574152521Spjdstatic void 575127412Sgadusage(void) 576127412Sgad{ 577127412Sgad const char *ustr; 578127412Sgad 579127412Sgad if (pgrep) 580203802Spjd ustr = "[-LSfilnoqvx] [-d delim]"; 581127412Sgad else 582209363Sbrian ustr = "[-signal] [-ILfilnovx]"; 583127412Sgad 584127412Sgad fprintf(stderr, 585143874Spjd "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" 586287269Sjamie " [-P ppid] [-U uid] [-c class] [-g pgrp] [-j jail]\n" 587254134Strasz " [-s sid] [-t tty] [-u euid] pattern ...\n", 588254134Strasz getprogname(), ustr); 589127412Sgad 590152521Spjd exit(STATUS_BADUSAGE); 591127412Sgad} 592127412Sgad 593152518Spjdstatic void 594152521Spjdshow_process(const struct kinfo_proc *kp) 595127412Sgad{ 596127412Sgad char **argv; 597127412Sgad 598203802Spjd if (quiet) { 599203802Spjd assert(pgrep); 600203802Spjd return; 601203802Spjd } 602152518Spjd if ((longfmt || !pgrep) && matchargs && 603143877Spjd (argv = kvm_getargv(kd, kp, 0)) != NULL) { 604127425Sgad printf("%d ", (int)kp->ki_pid); 605127412Sgad for (; *argv != NULL; argv++) { 606127412Sgad printf("%s", *argv); 607127412Sgad if (argv[1] != NULL) 608127412Sgad putchar(' '); 609127412Sgad } 610152518Spjd } else if (longfmt || !pgrep) 611127425Sgad printf("%d %s", (int)kp->ki_pid, kp->ki_comm); 612127412Sgad else 613127425Sgad printf("%d", (int)kp->ki_pid); 614152518Spjd} 615127412Sgad 616152521Spjdstatic int 617152521Spjdkillact(const struct kinfo_proc *kp) 618152518Spjd{ 619152518Spjd int ch, first; 620152518Spjd 621152518Spjd if (interactive) { 622152518Spjd /* 623152518Spjd * Be careful, ask before killing. 624152518Spjd */ 625152518Spjd printf("kill "); 626152518Spjd show_process(kp); 627152518Spjd printf("? "); 628152518Spjd fflush(stdout); 629152518Spjd first = ch = getchar(); 630152518Spjd while (ch != '\n' && ch != EOF) 631152518Spjd ch = getchar(); 632152518Spjd if (first != 'y' && first != 'Y') 633152521Spjd return (1); 634152518Spjd } 635152521Spjd if (kill(kp->ki_pid, signum) == -1) { 636152521Spjd /* 637152521Spjd * Check for ESRCH, which indicates that the process 638152521Spjd * disappeared between us matching it and us 639152521Spjd * signalling it; don't issue a warning about it. 640152521Spjd */ 641152521Spjd if (errno != ESRCH) 642152521Spjd warn("signalling pid %d", (int)kp->ki_pid); 643152521Spjd /* 644152521Spjd * Return 0 to indicate that the process should not be 645152521Spjd * considered a match, since we didn't actually get to 646152521Spjd * signal it. 647152521Spjd */ 648152521Spjd return (0); 649152521Spjd } 650152521Spjd return (1); 651152518Spjd} 652152518Spjd 653152521Spjdstatic int 654152521Spjdgrepact(const struct kinfo_proc *kp) 655152518Spjd{ 656152518Spjd 657152518Spjd show_process(kp); 658203802Spjd if (!quiet) 659203802Spjd printf("%s", delim); 660152521Spjd return (1); 661127412Sgad} 662127412Sgad 663152521Spjdstatic void 664127412Sgadmakelist(struct listhead *head, enum listtype type, char *src) 665127412Sgad{ 666127412Sgad struct list *li; 667127412Sgad struct passwd *pw; 668127412Sgad struct group *gr; 669127412Sgad struct stat st; 670183438Sed const char *cp; 671152521Spjd char *sp, *ep, buf[MAXPATHLEN]; 672127412Sgad int empty; 673127412Sgad 674127412Sgad empty = 1; 675127412Sgad 676127412Sgad while ((sp = strsep(&src, ",")) != NULL) { 677127412Sgad if (*sp == '\0') 678127412Sgad usage(); 679127412Sgad 680152521Spjd if ((li = malloc(sizeof(*li))) == NULL) { 681152521Spjd err(STATUS_ERROR, "Cannot allocate %zu bytes", 682152521Spjd sizeof(*li)); 683152521Spjd } 684152521Spjd 685127412Sgad SLIST_INSERT_HEAD(head, li, li_chain); 686127412Sgad empty = 0; 687127412Sgad 688254134Strasz if (type != LT_CLASS) 689254134Strasz li->li_number = (uid_t)strtol(sp, &ep, 0); 690254134Strasz 691254134Strasz if (type != LT_CLASS && *ep == '\0') { 692127412Sgad switch (type) { 693127412Sgad case LT_PGRP: 694127412Sgad if (li->li_number == 0) 695127412Sgad li->li_number = getpgrp(); 696127412Sgad break; 697127412Sgad case LT_SID: 698127412Sgad if (li->li_number == 0) 699127412Sgad li->li_number = getsid(mypid); 700127412Sgad break; 701287269Sjamie case LT_JAIL: 702164558Syar if (li->li_number < 0) 703164558Syar errx(STATUS_BADUSAGE, 704164558Syar "Negative jail ID `%s'", sp); 705164558Syar /* For compatibility with old -j */ 706164558Syar if (li->li_number == 0) 707164558Syar li->li_number = -1; /* any jail */ 708164558Syar break; 709201487Sobrien case LT_TTY: 710201487Sobrien if (li->li_number < 0) 711201487Sobrien errx(STATUS_BADUSAGE, 712201487Sobrien "Negative /dev/pts tty `%s'", sp); 713201487Sobrien snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s", 714201487Sobrien sp); 715201487Sobrien if (stat(buf, &st) != -1) 716201487Sobrien goto foundtty; 717201487Sobrien if (errno == ENOENT) 718201487Sobrien errx(STATUS_BADUSAGE, "No such tty: `" 719201487Sobrien _PATH_DEV "pts/%s'", sp); 720201487Sobrien err(STATUS_ERROR, "Cannot access `" 721201487Sobrien _PATH_DEV "pts/%s'", sp); 722201487Sobrien break; 723127412Sgad default: 724127412Sgad break; 725127412Sgad } 726127412Sgad continue; 727127412Sgad } 728127412Sgad 729127412Sgad switch (type) { 730127412Sgad case LT_USER: 731127412Sgad if ((pw = getpwnam(sp)) == NULL) 732152521Spjd errx(STATUS_BADUSAGE, "Unknown user `%s'", sp); 733127412Sgad li->li_number = pw->pw_uid; 734127412Sgad break; 735127412Sgad case LT_GROUP: 736127412Sgad if ((gr = getgrnam(sp)) == NULL) 737152521Spjd errx(STATUS_BADUSAGE, "Unknown group `%s'", sp); 738127412Sgad li->li_number = gr->gr_gid; 739127412Sgad break; 740127412Sgad case LT_TTY: 741127412Sgad if (strcmp(sp, "-") == 0) { 742127412Sgad li->li_number = -1; 743127412Sgad break; 744152521Spjd } else if (strcmp(sp, "co") == 0) { 745127430Sgad cp = "console"; 746152521Spjd } else { 747127430Sgad cp = sp; 748152521Spjd } 749127412Sgad 750183438Sed snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp); 751183502Sed if (stat(buf, &st) != -1) 752183502Sed goto foundtty; 753127412Sgad 754183502Sed snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp); 755183502Sed if (stat(buf, &st) != -1) 756183502Sed goto foundtty; 757127412Sgad 758183502Sed if (errno == ENOENT) 759183502Sed errx(STATUS_BADUSAGE, "No such tty: `%s'", sp); 760183502Sed err(STATUS_ERROR, "Cannot access `%s'", sp); 761183502Sed 762183502Sedfoundtty: if ((st.st_mode & S_IFCHR) == 0) 763152521Spjd errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp); 764127412Sgad 765127412Sgad li->li_number = st.st_rdev; 766127412Sgad break; 767287269Sjamie case LT_JAIL: { 768287269Sjamie int jid; 769287269Sjamie 770164558Syar if (strcmp(sp, "none") == 0) 771164558Syar li->li_number = 0; 772164558Syar else if (strcmp(sp, "any") == 0) 773164558Syar li->li_number = -1; 774287269Sjamie else if ((jid = jail_getid(sp)) != -1) 775287269Sjamie li->li_number = jid; 776164558Syar else if (*ep != '\0') 777164558Syar errx(STATUS_BADUSAGE, 778287269Sjamie "Invalid jail ID or name `%s'", sp); 779164558Syar break; 780287269Sjamie } 781254134Strasz case LT_CLASS: 782254134Strasz li->li_number = -1; 783254134Strasz li->li_name = strdup(sp); 784254134Strasz if (li->li_name == NULL) 785254134Strasz err(STATUS_ERROR, "Cannot allocate memory"); 786254134Strasz break; 787127412Sgad default: 788127412Sgad usage(); 789152521Spjd } 790127412Sgad } 791127412Sgad 792127412Sgad if (empty) 793127412Sgad usage(); 794127412Sgad} 795143874Spjd 796152521Spjdstatic int 797149471Spjdtakepid(const char *pidfile, int pidfilelock) 798143874Spjd{ 799143874Spjd char *endp, line[BUFSIZ]; 800143874Spjd FILE *fh; 801143874Spjd long rval; 802143879Spjd 803143874Spjd fh = fopen(pidfile, "r"); 804143874Spjd if (fh == NULL) 805152521Spjd err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); 806143879Spjd 807149471Spjd if (pidfilelock) { 808149471Spjd /* 809149471Spjd * If we can lock pidfile, this means that daemon is not 810149471Spjd * running, so would be better not to kill some random process. 811149471Spjd */ 812149471Spjd if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { 813149471Spjd (void)fclose(fh); 814152521Spjd errx(STATUS_ERROR, "File '%s' can be locked", pidfile); 815149471Spjd } else { 816149471Spjd if (errno != EWOULDBLOCK) { 817149471Spjd errx(STATUS_ERROR, 818152521Spjd "Error while locking file '%s'", pidfile); 819149471Spjd } 820149435Spjd } 821149435Spjd } 822149435Spjd 823143874Spjd if (fgets(line, sizeof(line), fh) == NULL) { 824143874Spjd if (feof(fh)) { 825143874Spjd (void)fclose(fh); 826152521Spjd errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); 827143874Spjd } 828143874Spjd (void)fclose(fh); 829152521Spjd err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); 830143874Spjd } 831143874Spjd (void)fclose(fh); 832143879Spjd 833143874Spjd rval = strtol(line, &endp, 10); 834143874Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) 835152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 836143874Spjd else if (rval < MIN_PID || rval > MAX_PID) 837152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 838143874Spjd return (rval); 839143874Spjd} 840