pkill.c revision 203802
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 * 3. All advertising materials mentioning features or use of this software 20127412Sgad * must display the following acknowledgement: 21127412Sgad * This product includes software developed by the NetBSD 22127412Sgad * Foundation, Inc. and its contributors. 23127412Sgad * 4. Neither the name of The NetBSD Foundation nor the names of its 24127412Sgad * contributors may be used to endorse or promote products derived 25127412Sgad * from this software without specific prior written permission. 26127412Sgad * 27127412Sgad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28127412Sgad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29127412Sgad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30127412Sgad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31127412Sgad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32127412Sgad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33127412Sgad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34127412Sgad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35127412Sgad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36127412Sgad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37127412Sgad * POSSIBILITY OF SUCH DAMAGE. 38127412Sgad */ 39127412Sgad 40127412Sgad#include <sys/cdefs.h> 41127412Sgad__FBSDID("$FreeBSD: head/bin/pkill/pkill.c 203802 2010-02-12 18:52:24Z pjd $"); 42127412Sgad 43127412Sgad#include <sys/types.h> 44127412Sgad#include <sys/param.h> 45127412Sgad#include <sys/sysctl.h> 46127412Sgad#include <sys/proc.h> 47127412Sgad#include <sys/queue.h> 48127412Sgad#include <sys/stat.h> 49143878Spjd#include <sys/time.h> 50127425Sgad#include <sys/user.h> 51127412Sgad 52203802Spjd#include <assert.h> 53127412Sgad#include <stdio.h> 54127412Sgad#include <stdlib.h> 55127412Sgad#include <limits.h> 56127425Sgad#include <paths.h> 57127412Sgad#include <string.h> 58127412Sgad#include <unistd.h> 59127412Sgad#include <signal.h> 60127412Sgad#include <regex.h> 61127412Sgad#include <ctype.h> 62127425Sgad#include <fcntl.h> 63127412Sgad#include <kvm.h> 64127412Sgad#include <err.h> 65127412Sgad#include <pwd.h> 66127412Sgad#include <grp.h> 67127412Sgad#include <errno.h> 68132198Stjr#include <locale.h> 69127412Sgad 70127412Sgad#define STATUS_MATCH 0 71127412Sgad#define STATUS_NOMATCH 1 72127412Sgad#define STATUS_BADUSAGE 2 73127412Sgad#define STATUS_ERROR 3 74127412Sgad 75143874Spjd#define MIN_PID 5 76143874Spjd#define MAX_PID 99999 77143874Spjd 78143877Spjd/* Ignore system-processes (if '-S' flag is not specified) and myself. */ 79143877Spjd#define PSKIP(kp) ((kp)->ki_pid == mypid || \ 80143877Spjd (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0)) 81127425Sgad 82127412Sgadenum listtype { 83127412Sgad LT_GENERIC, 84127412Sgad LT_USER, 85127412Sgad LT_GROUP, 86127412Sgad LT_TTY, 87127412Sgad LT_PGRP, 88164558Syar LT_JID, 89127412Sgad LT_SID 90127412Sgad}; 91127412Sgad 92127412Sgadstruct list { 93127412Sgad SLIST_ENTRY(list) li_chain; 94127412Sgad long li_number; 95127412Sgad}; 96127412Sgad 97127412SgadSLIST_HEAD(listhead, list); 98127412Sgad 99152521Spjdstatic struct kinfo_proc *plist; 100152521Spjdstatic char *selected; 101152521Spjdstatic const char *delim = "\n"; 102152521Spjdstatic int nproc; 103152521Spjdstatic int pgrep; 104152521Spjdstatic int signum = SIGTERM; 105152521Spjdstatic int newest; 106152521Spjdstatic int oldest; 107152521Spjdstatic int interactive; 108152521Spjdstatic int inverse; 109152521Spjdstatic int longfmt; 110152521Spjdstatic int matchargs; 111152521Spjdstatic int fullmatch; 112152521Spjdstatic int kthreads; 113152521Spjdstatic int cflags = REG_EXTENDED; 114203802Spjdstatic int quiet; 115152521Spjdstatic kvm_t *kd; 116152521Spjdstatic pid_t mypid; 117127412Sgad 118201145Santoinestatic struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist); 119201145Santoinestatic struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist); 120201145Santoinestatic struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist); 121201145Santoinestatic struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist); 122201145Santoinestatic struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); 123201145Santoinestatic struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); 124201145Santoinestatic struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); 125201145Santoinestatic struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); 126127412Sgad 127152521Spjdstatic void usage(void) __attribute__((__noreturn__)); 128152521Spjdstatic int killact(const struct kinfo_proc *); 129152521Spjdstatic int grepact(const struct kinfo_proc *); 130152521Spjdstatic void makelist(struct listhead *, enum listtype, char *); 131152521Spjdstatic int takepid(const char *, int); 132127412Sgad 133127412Sgadint 134127412Sgadmain(int argc, char **argv) 135127412Sgad{ 136149471Spjd char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; 137127462Sgad const char *execf, *coref; 138192242Sbrian int ancestors, debug_opt; 139149471Spjd int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; 140127430Sgad size_t jsz; 141152521Spjd int (*action)(const struct kinfo_proc *); 142127425Sgad struct kinfo_proc *kp; 143127412Sgad struct list *li; 144127430Sgad struct timeval best_tval; 145127412Sgad regex_t reg; 146127412Sgad regmatch_t regmatch; 147192242Sbrian pid_t pid; 148127412Sgad 149132198Stjr setlocale(LC_ALL, ""); 150132198Stjr 151127412Sgad if (strcmp(getprogname(), "pgrep") == 0) { 152127412Sgad action = grepact; 153127412Sgad pgrep = 1; 154127412Sgad } else { 155127412Sgad action = killact; 156127412Sgad p = argv[1]; 157127412Sgad 158127412Sgad if (argc > 1 && p[0] == '-') { 159127412Sgad p++; 160127412Sgad i = (int)strtol(p, &q, 10); 161127412Sgad if (*q == '\0') { 162127412Sgad signum = i; 163127412Sgad argv++; 164127412Sgad argc--; 165127412Sgad } else { 166127412Sgad if (strncasecmp(p, "sig", 3) == 0) 167127412Sgad p += 3; 168127412Sgad for (i = 1; i < NSIG; i++) 169127412Sgad if (strcasecmp(sys_signame[i], p) == 0) 170127412Sgad break; 171127412Sgad if (i != NSIG) { 172127412Sgad signum = i; 173127412Sgad argv++; 174127412Sgad argc--; 175127412Sgad } 176127412Sgad } 177127412Sgad } 178127412Sgad } 179127412Sgad 180192242Sbrian ancestors = 0; 181127412Sgad criteria = 0; 182127433Sgad debug_opt = 0; 183149471Spjd pidfile = NULL; 184149471Spjd pidfilelock = 0; 185203802Spjd quiet = 0; 186203688Sbrucec execf = NULL; 187203688Sbrucec coref = _PATH_DEVNULL; 188127412Sgad 189203802Spjd while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1) 190127412Sgad switch (ch) { 191127433Sgad case 'D': 192127433Sgad debug_opt++; 193127433Sgad break; 194143874Spjd case 'F': 195149471Spjd pidfile = optarg; 196143874Spjd criteria = 1; 197143874Spjd break; 198127412Sgad case 'G': 199127412Sgad makelist(&rgidlist, LT_GROUP, optarg); 200127412Sgad criteria = 1; 201127412Sgad break; 202152518Spjd case 'I': 203152518Spjd if (pgrep) 204152518Spjd usage(); 205152518Spjd interactive = 1; 206152518Spjd break; 207149471Spjd case 'L': 208149471Spjd pidfilelock = 1; 209149471Spjd break; 210127427Sgad case 'M': 211127427Sgad coref = optarg; 212127427Sgad break; 213127427Sgad case 'N': 214127427Sgad execf = optarg; 215127427Sgad break; 216127412Sgad case 'P': 217127412Sgad makelist(&ppidlist, LT_GENERIC, optarg); 218127412Sgad criteria = 1; 219127412Sgad break; 220143877Spjd case 'S': 221143877Spjd if (!pgrep) 222143877Spjd usage(); 223143877Spjd kthreads = 1; 224143877Spjd break; 225127412Sgad case 'U': 226127412Sgad makelist(&ruidlist, LT_USER, optarg); 227127412Sgad criteria = 1; 228127412Sgad break; 229192242Sbrian case 'a': 230192242Sbrian ancestors++; 231192242Sbrian break; 232127412Sgad case 'd': 233127412Sgad if (!pgrep) 234127412Sgad usage(); 235127412Sgad delim = optarg; 236127412Sgad break; 237127412Sgad case 'f': 238127412Sgad matchargs = 1; 239127412Sgad break; 240127412Sgad case 'g': 241127412Sgad makelist(&pgrplist, LT_PGRP, optarg); 242127412Sgad criteria = 1; 243127412Sgad break; 244143875Spjd case 'i': 245143875Spjd cflags |= REG_ICASE; 246143875Spjd break; 247143873Spjd case 'j': 248164558Syar makelist(&jidlist, LT_JID, optarg); 249143873Spjd criteria = 1; 250143873Spjd break; 251127412Sgad case 'l': 252127412Sgad if (!pgrep) 253127412Sgad usage(); 254127412Sgad longfmt = 1; 255127412Sgad break; 256127412Sgad case 'n': 257127412Sgad newest = 1; 258127412Sgad criteria = 1; 259127412Sgad break; 260143878Spjd case 'o': 261143878Spjd oldest = 1; 262143878Spjd criteria = 1; 263143878Spjd break; 264203802Spjd case 'q': 265203802Spjd if (!pgrep) 266203802Spjd usage(); 267203802Spjd quiet = 1; 268203802Spjd break; 269127412Sgad case 's': 270127412Sgad makelist(&sidlist, LT_SID, optarg); 271127412Sgad criteria = 1; 272127412Sgad break; 273127412Sgad case 't': 274127412Sgad makelist(&tdevlist, LT_TTY, optarg); 275127412Sgad criteria = 1; 276127412Sgad break; 277127412Sgad case 'u': 278127412Sgad makelist(&euidlist, LT_USER, optarg); 279127412Sgad criteria = 1; 280127412Sgad break; 281127412Sgad case 'v': 282127412Sgad inverse = 1; 283127412Sgad break; 284127412Sgad case 'x': 285127412Sgad fullmatch = 1; 286127412Sgad break; 287127412Sgad default: 288127412Sgad usage(); 289127412Sgad /* NOTREACHED */ 290127412Sgad } 291127412Sgad 292127412Sgad argc -= optind; 293127412Sgad argv += optind; 294127412Sgad if (argc != 0) 295127412Sgad criteria = 1; 296127412Sgad if (!criteria) 297127412Sgad usage(); 298143878Spjd if (newest && oldest) 299152521Spjd errx(STATUS_ERROR, "Options -n and -o are mutually exclusive"); 300149471Spjd if (pidfile != NULL) 301149471Spjd pidfromfile = takepid(pidfile, pidfilelock); 302149471Spjd else { 303152521Spjd if (pidfilelock) { 304152521Spjd errx(STATUS_ERROR, 305152521Spjd "Option -L doesn't make sense without -F"); 306152521Spjd } 307149471Spjd pidfromfile = -1; 308149471Spjd } 309127412Sgad 310127412Sgad mypid = getpid(); 311127412Sgad 312127412Sgad /* 313127412Sgad * Retrieve the list of running processes from the kernel. 314127412Sgad */ 315127462Sgad kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); 316127412Sgad if (kd == NULL) 317152521Spjd errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); 318127412Sgad 319127622Sgad /* 320127622Sgad * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we 321127622Sgad * just want processes and not individual kernel threads. 322127622Sgad */ 323127622Sgad plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); 324152521Spjd if (plist == NULL) { 325152521Spjd errx(STATUS_ERROR, "Cannot get process list (%s)", 326152521Spjd kvm_geterr(kd)); 327152521Spjd } 328127412Sgad 329127412Sgad /* 330127412Sgad * Allocate memory which will be used to keep track of the 331127412Sgad * selection. 332127412Sgad */ 333152521Spjd if ((selected = malloc(nproc)) == NULL) { 334152521Spjd err(STATUS_ERROR, "Cannot allocate memory for %d processes", 335152521Spjd nproc); 336152521Spjd } 337127412Sgad memset(selected, 0, nproc); 338127412Sgad 339127412Sgad /* 340127412Sgad * Refine the selection. 341127412Sgad */ 342127412Sgad for (; *argv != NULL; argv++) { 343143875Spjd if ((rv = regcomp(®, *argv, cflags)) != 0) { 344127412Sgad regerror(rv, ®, buf, sizeof(buf)); 345152521Spjd errx(STATUS_BADUSAGE, 346152521Spjd "Cannot compile regular expression `%s' (%s)", 347152521Spjd *argv, buf); 348127412Sgad } 349127412Sgad 350127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 351143877Spjd if (PSKIP(kp)) { 352127433Sgad if (debug_opt > 0) 353127434Sgad fprintf(stderr, "* Skipped %5d %3d %s\n", 354127433Sgad kp->ki_pid, kp->ki_uid, kp->ki_comm); 355127412Sgad continue; 356127433Sgad } 357127412Sgad 358143877Spjd if (matchargs && 359143877Spjd (pargv = kvm_getargv(kd, kp, 0)) != NULL) { 360127430Sgad jsz = 0; 361127430Sgad while (jsz < sizeof(buf) && *pargv != NULL) { 362127430Sgad jsz += snprintf(buf + jsz, 363127430Sgad sizeof(buf) - jsz, 364127412Sgad pargv[1] != NULL ? "%s " : "%s", 365127412Sgad pargv[0]); 366127412Sgad pargv++; 367127412Sgad } 368127412Sgad mstr = buf; 369127412Sgad } else 370127425Sgad mstr = kp->ki_comm; 371127412Sgad 372127412Sgad rv = regexec(®, mstr, 1, ®match, 0); 373127412Sgad if (rv == 0) { 374127412Sgad if (fullmatch) { 375127412Sgad if (regmatch.rm_so == 0 && 376127431Sgad regmatch.rm_eo == 377127431Sgad (off_t)strlen(mstr)) 378127412Sgad selected[i] = 1; 379127412Sgad } else 380127412Sgad selected[i] = 1; 381127412Sgad } else if (rv != REG_NOMATCH) { 382127412Sgad regerror(rv, ®, buf, sizeof(buf)); 383152521Spjd errx(STATUS_ERROR, 384152521Spjd "Regular expression evaluation error (%s)", 385152521Spjd buf); 386127412Sgad } 387127433Sgad if (debug_opt > 1) { 388127433Sgad const char *rv_res = "NoMatch"; 389127433Sgad if (selected[i]) 390127433Sgad rv_res = "Matched"; 391127434Sgad fprintf(stderr, "* %s %5d %3d %s\n", rv_res, 392127433Sgad kp->ki_pid, kp->ki_uid, mstr); 393127433Sgad } 394127412Sgad } 395127412Sgad 396127412Sgad regfree(®); 397127412Sgad } 398127412Sgad 399127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 400143877Spjd if (PSKIP(kp)) 401127412Sgad continue; 402127412Sgad 403143874Spjd if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { 404143874Spjd selected[i] = 0; 405143874Spjd continue; 406143874Spjd } 407143874Spjd 408127412Sgad SLIST_FOREACH(li, &ruidlist, li_chain) 409127425Sgad if (kp->ki_ruid == (uid_t)li->li_number) 410127412Sgad break; 411127412Sgad if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 412127412Sgad selected[i] = 0; 413127412Sgad continue; 414127412Sgad } 415127429Sgad 416127412Sgad SLIST_FOREACH(li, &rgidlist, li_chain) 417127425Sgad if (kp->ki_rgid == (gid_t)li->li_number) 418127412Sgad break; 419127412Sgad if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 420127412Sgad selected[i] = 0; 421127412Sgad continue; 422127412Sgad } 423127412Sgad 424127412Sgad SLIST_FOREACH(li, &euidlist, li_chain) 425127425Sgad if (kp->ki_uid == (uid_t)li->li_number) 426127412Sgad break; 427127412Sgad if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 428127412Sgad selected[i] = 0; 429127412Sgad continue; 430127412Sgad } 431127412Sgad 432127412Sgad SLIST_FOREACH(li, &ppidlist, li_chain) 433127426Sgad if (kp->ki_ppid == (pid_t)li->li_number) 434127412Sgad break; 435127412Sgad if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 436127412Sgad selected[i] = 0; 437127412Sgad continue; 438127412Sgad } 439127412Sgad 440127412Sgad SLIST_FOREACH(li, &pgrplist, li_chain) 441127426Sgad if (kp->ki_pgid == (pid_t)li->li_number) 442127412Sgad break; 443127412Sgad if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 444127412Sgad selected[i] = 0; 445127412Sgad continue; 446127412Sgad } 447127412Sgad 448127412Sgad SLIST_FOREACH(li, &tdevlist, li_chain) { 449127412Sgad if (li->li_number == -1 && 450127425Sgad (kp->ki_flag & P_CONTROLT) == 0) 451127412Sgad break; 452130640Sphk if (kp->ki_tdev == (dev_t)li->li_number) 453127412Sgad break; 454127412Sgad } 455127412Sgad if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 456127412Sgad selected[i] = 0; 457127412Sgad continue; 458127412Sgad } 459127412Sgad 460127412Sgad SLIST_FOREACH(li, &sidlist, li_chain) 461127426Sgad if (kp->ki_sid == (pid_t)li->li_number) 462127412Sgad break; 463127412Sgad if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 464127412Sgad selected[i] = 0; 465127412Sgad continue; 466127412Sgad } 467127412Sgad 468143873Spjd SLIST_FOREACH(li, &jidlist, li_chain) { 469164558Syar /* A particular jail ID, including 0 (not in jail) */ 470164558Syar if (kp->ki_jid == (int)li->li_number) 471164558Syar break; 472164558Syar /* Any jail */ 473164558Syar if (kp->ki_jid > 0 && li->li_number == -1) 474164558Syar break; 475143873Spjd } 476143873Spjd if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { 477143873Spjd selected[i] = 0; 478143873Spjd continue; 479143873Spjd } 480143873Spjd 481127412Sgad if (argc == 0) 482127412Sgad selected[i] = 1; 483127412Sgad } 484127412Sgad 485192242Sbrian if (!ancestors) { 486192242Sbrian pid = mypid; 487192242Sbrian while (pid) { 488192242Sbrian for (i = 0, kp = plist; i < nproc; i++, kp++) { 489192242Sbrian if (PSKIP(kp)) 490192242Sbrian continue; 491192242Sbrian if (kp->ki_pid == pid) { 492192242Sbrian selected[i] = 0; 493192242Sbrian pid = kp->ki_ppid; 494192242Sbrian break; 495192242Sbrian } 496192242Sbrian } 497192242Sbrian if (i == nproc) { 498192242Sbrian if (pid == mypid) 499192242Sbrian pid = getppid(); 500192242Sbrian else 501192242Sbrian break; /* Maybe we're in a jail ? */ 502192242Sbrian } 503192242Sbrian } 504192242Sbrian } 505192242Sbrian 506143878Spjd if (newest || oldest) { 507127430Sgad best_tval.tv_sec = 0; 508127430Sgad best_tval.tv_usec = 0; 509127412Sgad bestidx = -1; 510127412Sgad 511127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 512127412Sgad if (!selected[i]) 513127412Sgad continue; 514143878Spjd if (bestidx == -1) { 515143878Spjd /* The first entry of the list which matched. */ 516143878Spjd ; 517143878Spjd } else if (timercmp(&kp->ki_start, &best_tval, >)) { 518143878Spjd /* This entry is newer than previous "best". */ 519143879Spjd if (oldest) /* but we want the oldest */ 520143878Spjd continue; 521143878Spjd } else { 522143878Spjd /* This entry is older than previous "best". */ 523143879Spjd if (newest) /* but we want the newest */ 524143878Spjd continue; 525127412Sgad } 526143878Spjd /* This entry is better than previous "best" entry. */ 527143878Spjd best_tval.tv_sec = kp->ki_start.tv_sec; 528143878Spjd best_tval.tv_usec = kp->ki_start.tv_usec; 529143878Spjd bestidx = i; 530127412Sgad } 531127412Sgad 532127412Sgad memset(selected, 0, nproc); 533127412Sgad if (bestidx != -1) 534127412Sgad selected[bestidx] = 1; 535127412Sgad } 536127412Sgad 537127412Sgad /* 538127412Sgad * Take the appropriate action for each matched process, if any. 539127412Sgad */ 540127412Sgad for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 541143877Spjd if (PSKIP(kp)) 542127412Sgad continue; 543127412Sgad if (selected[i]) { 544127412Sgad if (inverse) 545127412Sgad continue; 546127412Sgad } else if (!inverse) 547127412Sgad continue; 548152521Spjd rv |= (*action)(kp); 549127412Sgad } 550127412Sgad 551127412Sgad exit(rv ? STATUS_MATCH : STATUS_NOMATCH); 552127412Sgad} 553127412Sgad 554152521Spjdstatic void 555127412Sgadusage(void) 556127412Sgad{ 557127412Sgad const char *ustr; 558127412Sgad 559127412Sgad if (pgrep) 560203802Spjd ustr = "[-LSfilnoqvx] [-d delim]"; 561127412Sgad else 562152518Spjd ustr = "[-signal] [-ILfinovx]"; 563127412Sgad 564127412Sgad fprintf(stderr, 565143874Spjd "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" 566143873Spjd " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n" 567143873Spjd " [-t tty] [-u euid] pattern ...\n", getprogname(), 568143873Spjd ustr); 569127412Sgad 570152521Spjd exit(STATUS_BADUSAGE); 571127412Sgad} 572127412Sgad 573152518Spjdstatic void 574152521Spjdshow_process(const struct kinfo_proc *kp) 575127412Sgad{ 576127412Sgad char **argv; 577127412Sgad 578203802Spjd if (quiet) { 579203802Spjd assert(pgrep); 580203802Spjd return; 581203802Spjd } 582152518Spjd if ((longfmt || !pgrep) && matchargs && 583143877Spjd (argv = kvm_getargv(kd, kp, 0)) != NULL) { 584127425Sgad printf("%d ", (int)kp->ki_pid); 585127412Sgad for (; *argv != NULL; argv++) { 586127412Sgad printf("%s", *argv); 587127412Sgad if (argv[1] != NULL) 588127412Sgad putchar(' '); 589127412Sgad } 590152518Spjd } else if (longfmt || !pgrep) 591127425Sgad printf("%d %s", (int)kp->ki_pid, kp->ki_comm); 592127412Sgad else 593127425Sgad printf("%d", (int)kp->ki_pid); 594152518Spjd} 595127412Sgad 596152521Spjdstatic int 597152521Spjdkillact(const struct kinfo_proc *kp) 598152518Spjd{ 599152518Spjd int ch, first; 600152518Spjd 601152518Spjd if (interactive) { 602152518Spjd /* 603152518Spjd * Be careful, ask before killing. 604152518Spjd */ 605152518Spjd printf("kill "); 606152518Spjd show_process(kp); 607152518Spjd printf("? "); 608152518Spjd fflush(stdout); 609152518Spjd first = ch = getchar(); 610152518Spjd while (ch != '\n' && ch != EOF) 611152518Spjd ch = getchar(); 612152518Spjd if (first != 'y' && first != 'Y') 613152521Spjd return (1); 614152518Spjd } 615152521Spjd if (kill(kp->ki_pid, signum) == -1) { 616152521Spjd /* 617152521Spjd * Check for ESRCH, which indicates that the process 618152521Spjd * disappeared between us matching it and us 619152521Spjd * signalling it; don't issue a warning about it. 620152521Spjd */ 621152521Spjd if (errno != ESRCH) 622152521Spjd warn("signalling pid %d", (int)kp->ki_pid); 623152521Spjd /* 624152521Spjd * Return 0 to indicate that the process should not be 625152521Spjd * considered a match, since we didn't actually get to 626152521Spjd * signal it. 627152521Spjd */ 628152521Spjd return (0); 629152521Spjd } 630152521Spjd return (1); 631152518Spjd} 632152518Spjd 633152521Spjdstatic int 634152521Spjdgrepact(const struct kinfo_proc *kp) 635152518Spjd{ 636152518Spjd 637152518Spjd show_process(kp); 638203802Spjd if (!quiet) 639203802Spjd printf("%s", delim); 640152521Spjd return (1); 641127412Sgad} 642127412Sgad 643152521Spjdstatic void 644127412Sgadmakelist(struct listhead *head, enum listtype type, char *src) 645127412Sgad{ 646127412Sgad struct list *li; 647127412Sgad struct passwd *pw; 648127412Sgad struct group *gr; 649127412Sgad struct stat st; 650183438Sed const char *cp; 651152521Spjd char *sp, *ep, buf[MAXPATHLEN]; 652127412Sgad int empty; 653127412Sgad 654127412Sgad empty = 1; 655127412Sgad 656127412Sgad while ((sp = strsep(&src, ",")) != NULL) { 657127412Sgad if (*sp == '\0') 658127412Sgad usage(); 659127412Sgad 660152521Spjd if ((li = malloc(sizeof(*li))) == NULL) { 661152521Spjd err(STATUS_ERROR, "Cannot allocate %zu bytes", 662152521Spjd sizeof(*li)); 663152521Spjd } 664152521Spjd 665127412Sgad SLIST_INSERT_HEAD(head, li, li_chain); 666127412Sgad empty = 0; 667127412Sgad 668152521Spjd li->li_number = (uid_t)strtol(sp, &ep, 0); 669152521Spjd if (*ep == '\0') { 670127412Sgad switch (type) { 671127412Sgad case LT_PGRP: 672127412Sgad if (li->li_number == 0) 673127412Sgad li->li_number = getpgrp(); 674127412Sgad break; 675127412Sgad case LT_SID: 676127412Sgad if (li->li_number == 0) 677127412Sgad li->li_number = getsid(mypid); 678127412Sgad break; 679164558Syar case LT_JID: 680164558Syar if (li->li_number < 0) 681164558Syar errx(STATUS_BADUSAGE, 682164558Syar "Negative jail ID `%s'", sp); 683164558Syar /* For compatibility with old -j */ 684164558Syar if (li->li_number == 0) 685164558Syar li->li_number = -1; /* any jail */ 686164558Syar break; 687201487Sobrien case LT_TTY: 688201487Sobrien if (li->li_number < 0) 689201487Sobrien errx(STATUS_BADUSAGE, 690201487Sobrien "Negative /dev/pts tty `%s'", sp); 691201487Sobrien snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s", 692201487Sobrien sp); 693201487Sobrien if (stat(buf, &st) != -1) 694201487Sobrien goto foundtty; 695201487Sobrien if (errno == ENOENT) 696201487Sobrien errx(STATUS_BADUSAGE, "No such tty: `" 697201487Sobrien _PATH_DEV "pts/%s'", sp); 698201487Sobrien err(STATUS_ERROR, "Cannot access `" 699201487Sobrien _PATH_DEV "pts/%s'", sp); 700201487Sobrien break; 701127412Sgad default: 702127412Sgad break; 703127412Sgad } 704127412Sgad continue; 705127412Sgad } 706127412Sgad 707127412Sgad switch (type) { 708127412Sgad case LT_USER: 709127412Sgad if ((pw = getpwnam(sp)) == NULL) 710152521Spjd errx(STATUS_BADUSAGE, "Unknown user `%s'", sp); 711127412Sgad li->li_number = pw->pw_uid; 712127412Sgad break; 713127412Sgad case LT_GROUP: 714127412Sgad if ((gr = getgrnam(sp)) == NULL) 715152521Spjd errx(STATUS_BADUSAGE, "Unknown group `%s'", sp); 716127412Sgad li->li_number = gr->gr_gid; 717127412Sgad break; 718127412Sgad case LT_TTY: 719127412Sgad if (strcmp(sp, "-") == 0) { 720127412Sgad li->li_number = -1; 721127412Sgad break; 722152521Spjd } else if (strcmp(sp, "co") == 0) { 723127430Sgad cp = "console"; 724152521Spjd } else { 725127430Sgad cp = sp; 726152521Spjd } 727127412Sgad 728183438Sed snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp); 729183502Sed if (stat(buf, &st) != -1) 730183502Sed goto foundtty; 731127412Sgad 732183502Sed snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp); 733183502Sed if (stat(buf, &st) != -1) 734183502Sed goto foundtty; 735127412Sgad 736183502Sed if (errno == ENOENT) 737183502Sed errx(STATUS_BADUSAGE, "No such tty: `%s'", sp); 738183502Sed err(STATUS_ERROR, "Cannot access `%s'", sp); 739183502Sed 740183502Sedfoundtty: if ((st.st_mode & S_IFCHR) == 0) 741152521Spjd errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp); 742127412Sgad 743127412Sgad li->li_number = st.st_rdev; 744127412Sgad break; 745164558Syar case LT_JID: 746164558Syar if (strcmp(sp, "none") == 0) 747164558Syar li->li_number = 0; 748164558Syar else if (strcmp(sp, "any") == 0) 749164558Syar li->li_number = -1; 750164558Syar else if (*ep != '\0') 751164558Syar errx(STATUS_BADUSAGE, 752164558Syar "Invalid jail ID `%s'", sp); 753164558Syar break; 754127412Sgad default: 755127412Sgad usage(); 756152521Spjd } 757127412Sgad } 758127412Sgad 759127412Sgad if (empty) 760127412Sgad usage(); 761127412Sgad} 762143874Spjd 763152521Spjdstatic int 764149471Spjdtakepid(const char *pidfile, int pidfilelock) 765143874Spjd{ 766143874Spjd char *endp, line[BUFSIZ]; 767143874Spjd FILE *fh; 768143874Spjd long rval; 769143879Spjd 770143874Spjd fh = fopen(pidfile, "r"); 771143874Spjd if (fh == NULL) 772152521Spjd err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); 773143879Spjd 774149471Spjd if (pidfilelock) { 775149471Spjd /* 776149471Spjd * If we can lock pidfile, this means that daemon is not 777149471Spjd * running, so would be better not to kill some random process. 778149471Spjd */ 779149471Spjd if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { 780149471Spjd (void)fclose(fh); 781152521Spjd errx(STATUS_ERROR, "File '%s' can be locked", pidfile); 782149471Spjd } else { 783149471Spjd if (errno != EWOULDBLOCK) { 784149471Spjd errx(STATUS_ERROR, 785152521Spjd "Error while locking file '%s'", pidfile); 786149471Spjd } 787149435Spjd } 788149435Spjd } 789149435Spjd 790143874Spjd if (fgets(line, sizeof(line), fh) == NULL) { 791143874Spjd if (feof(fh)) { 792143874Spjd (void)fclose(fh); 793152521Spjd errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); 794143874Spjd } 795143874Spjd (void)fclose(fh); 796152521Spjd err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); 797143874Spjd } 798143874Spjd (void)fclose(fh); 799143879Spjd 800143874Spjd rval = strtol(line, &endp, 10); 801143874Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) 802152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 803143874Spjd else if (rval < MIN_PID || rval > MAX_PID) 804152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 805143874Spjd return (rval); 806143874Spjd} 807