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> 62127412Sgad 63127412Sgad#define STATUS_MATCH 0 64127412Sgad#define STATUS_NOMATCH 1 65127412Sgad#define STATUS_BADUSAGE 2 66127412Sgad#define STATUS_ERROR 3 67127412Sgad 68143874Spjd#define MIN_PID 5 69143874Spjd#define MAX_PID 99999 70143874Spjd 71143877Spjd/* Ignore system-processes (if '-S' flag is not specified) and myself. */ 72143877Spjd#define PSKIP(kp) ((kp)->ki_pid == mypid || \ 73143877Spjd (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0)) 74127425Sgad 75127412Sgadenum listtype { 76127412Sgad LT_GENERIC, 77127412Sgad LT_USER, 78127412Sgad LT_GROUP, 79127412Sgad LT_TTY, 80127412Sgad LT_PGRP, 81164558Syar LT_JID, 82254134Strasz LT_SID, 83254134Strasz LT_CLASS 84127412Sgad}; 85127412Sgad 86127412Sgadstruct list { 87127412Sgad SLIST_ENTRY(list) li_chain; 88127412Sgad long li_number; 89254134Strasz char *li_name; 90127412Sgad}; 91127412Sgad 92127412SgadSLIST_HEAD(listhead, list); 93127412Sgad 94152521Spjdstatic struct kinfo_proc *plist; 95152521Spjdstatic char *selected; 96152521Spjdstatic const char *delim = "\n"; 97152521Spjdstatic int nproc; 98152521Spjdstatic int pgrep; 99152521Spjdstatic int signum = SIGTERM; 100152521Spjdstatic int newest; 101152521Spjdstatic int oldest; 102152521Spjdstatic int interactive; 103152521Spjdstatic int inverse; 104152521Spjdstatic int longfmt; 105152521Spjdstatic int matchargs; 106152521Spjdstatic int fullmatch; 107152521Spjdstatic int kthreads; 108152521Spjdstatic int cflags = REG_EXTENDED; 109203802Spjdstatic int quiet; 110152521Spjdstatic kvm_t *kd; 111152521Spjdstatic pid_t mypid; 112127412Sgad 113201145Santoinestatic struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist); 114201145Santoinestatic struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist); 115201145Santoinestatic struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist); 116201145Santoinestatic struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist); 117201145Santoinestatic struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); 118201145Santoinestatic struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); 119201145Santoinestatic struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); 120201145Santoinestatic struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); 121254134Straszstatic struct listhead classlist = SLIST_HEAD_INITIALIZER(classlist); 122127412Sgad 123152521Spjdstatic void usage(void) __attribute__((__noreturn__)); 124152521Spjdstatic int killact(const struct kinfo_proc *); 125152521Spjdstatic int grepact(const struct kinfo_proc *); 126152521Spjdstatic void makelist(struct listhead *, enum listtype, char *); 127152521Spjdstatic int takepid(const char *, int); 128127412Sgad 129127412Sgadint 130127412Sgadmain(int argc, char **argv) 131127412Sgad{ 132149471Spjd char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; 133127462Sgad const char *execf, *coref; 134209363Sbrian int ancestors, debug_opt, did_action; 135149471Spjd int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; 136127430Sgad size_t jsz; 137152521Spjd int (*action)(const struct kinfo_proc *); 138127425Sgad struct kinfo_proc *kp; 139127412Sgad struct list *li; 140127430Sgad struct timeval best_tval; 141127412Sgad regex_t reg; 142127412Sgad regmatch_t regmatch; 143192242Sbrian pid_t pid; 144127412Sgad 145132198Stjr setlocale(LC_ALL, ""); 146132198Stjr 147127412Sgad if (strcmp(getprogname(), "pgrep") == 0) { 148127412Sgad action = grepact; 149127412Sgad pgrep = 1; 150127412Sgad } else { 151127412Sgad action = killact; 152127412Sgad p = argv[1]; 153127412Sgad 154127412Sgad if (argc > 1 && p[0] == '-') { 155127412Sgad p++; 156127412Sgad i = (int)strtol(p, &q, 10); 157127412Sgad if (*q == '\0') { 158127412Sgad signum = i; 159127412Sgad argv++; 160127412Sgad argc--; 161127412Sgad } else { 162218285Sjilles if (strncasecmp(p, "SIG", 3) == 0) 163127412Sgad p += 3; 164127412Sgad for (i = 1; i < NSIG; i++) 165127412Sgad if (strcasecmp(sys_signame[i], p) == 0) 166127412Sgad break; 167127412Sgad if (i != NSIG) { 168127412Sgad signum = i; 169127412Sgad argv++; 170127412Sgad argc--; 171127412Sgad } 172127412Sgad } 173127412Sgad } 174127412Sgad } 175127412Sgad 176192242Sbrian ancestors = 0; 177127412Sgad criteria = 0; 178127433Sgad debug_opt = 0; 179149471Spjd pidfile = NULL; 180149471Spjd pidfilelock = 0; 181203802Spjd quiet = 0; 182203688Sbrucec execf = NULL; 183203688Sbrucec coref = _PATH_DEVNULL; 184127412Sgad 185254134Strasz while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ac:d:fg:ij:lnoqs:t:u:vx")) != -1) 186127412Sgad switch (ch) { 187127433Sgad case 'D': 188127433Sgad debug_opt++; 189127433Sgad break; 190143874Spjd case 'F': 191149471Spjd pidfile = optarg; 192143874Spjd criteria = 1; 193143874Spjd break; 194127412Sgad case 'G': 195127412Sgad makelist(&rgidlist, LT_GROUP, optarg); 196127412Sgad criteria = 1; 197127412Sgad break; 198152518Spjd case 'I': 199152518Spjd if (pgrep) 200152518Spjd usage(); 201152518Spjd interactive = 1; 202152518Spjd break; 203149471Spjd case 'L': 204149471Spjd pidfilelock = 1; 205149471Spjd break; 206127427Sgad case 'M': 207127427Sgad coref = optarg; 208127427Sgad break; 209127427Sgad case 'N': 210127427Sgad execf = optarg; 211127427Sgad break; 212127412Sgad case 'P': 213127412Sgad makelist(&ppidlist, LT_GENERIC, optarg); 214127412Sgad criteria = 1; 215127412Sgad break; 216143877Spjd case 'S': 217143877Spjd if (!pgrep) 218143877Spjd usage(); 219143877Spjd kthreads = 1; 220143877Spjd break; 221127412Sgad case 'U': 222127412Sgad makelist(&ruidlist, LT_USER, optarg); 223127412Sgad criteria = 1; 224127412Sgad break; 225192242Sbrian case 'a': 226192242Sbrian ancestors++; 227192242Sbrian break; 228254134Strasz case 'c': 229254134Strasz makelist(&classlist, LT_CLASS, optarg); 230254134Strasz criteria = 1; 231254134Strasz 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 longfmt = 1; 253127412Sgad break; 254127412Sgad case 'n': 255127412Sgad newest = 1; 256127412Sgad criteria = 1; 257127412Sgad break; 258143878Spjd case 'o': 259143878Spjd oldest = 1; 260143878Spjd criteria = 1; 261143878Spjd break; 262203802Spjd case 'q': 263203802Spjd if (!pgrep) 264203802Spjd usage(); 265203802Spjd quiet = 1; 266203802Spjd break; 267127412Sgad case 's': 268127412Sgad makelist(&sidlist, LT_SID, optarg); 269127412Sgad criteria = 1; 270127412Sgad break; 271127412Sgad case 't': 272127412Sgad makelist(&tdevlist, LT_TTY, optarg); 273127412Sgad criteria = 1; 274127412Sgad break; 275127412Sgad case 'u': 276127412Sgad makelist(&euidlist, LT_USER, optarg); 277127412Sgad criteria = 1; 278127412Sgad break; 279127412Sgad case 'v': 280127412Sgad inverse = 1; 281127412Sgad break; 282127412Sgad case 'x': 283127412Sgad fullmatch = 1; 284127412Sgad break; 285127412Sgad default: 286127412Sgad usage(); 287127412Sgad /* NOTREACHED */ 288127412Sgad } 289127412Sgad 290127412Sgad argc -= optind; 291127412Sgad argv += optind; 292127412Sgad if (argc != 0) 293127412Sgad criteria = 1; 294127412Sgad if (!criteria) 295127412Sgad usage(); 296143878Spjd if (newest && oldest) 297152521Spjd errx(STATUS_ERROR, "Options -n and -o are mutually exclusive"); 298149471Spjd if (pidfile != NULL) 299149471Spjd pidfromfile = takepid(pidfile, pidfilelock); 300149471Spjd else { 301152521Spjd if (pidfilelock) { 302152521Spjd errx(STATUS_ERROR, 303152521Spjd "Option -L doesn't make sense without -F"); 304152521Spjd } 305149471Spjd pidfromfile = -1; 306149471Spjd } 307127412Sgad 308127412Sgad mypid = getpid(); 309127412Sgad 310127412Sgad /* 311127412Sgad * Retrieve the list of running processes from the kernel. 312127412Sgad */ 313127462Sgad kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); 314127412Sgad if (kd == NULL) 315152521Spjd errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); 316127412Sgad 317127622Sgad /* 318127622Sgad * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we 319127622Sgad * just want processes and not individual kernel threads. 320127622Sgad */ 321127622Sgad plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); 322152521Spjd if (plist == NULL) { 323152521Spjd errx(STATUS_ERROR, "Cannot get process list (%s)", 324152521Spjd kvm_geterr(kd)); 325152521Spjd } 326127412Sgad 327127412Sgad /* 328127412Sgad * Allocate memory which will be used to keep track of the 329127412Sgad * selection. 330127412Sgad */ 331152521Spjd if ((selected = malloc(nproc)) == NULL) { 332152521Spjd err(STATUS_ERROR, "Cannot allocate memory for %d processes", 333152521Spjd nproc); 334152521Spjd } 335127412Sgad memset(selected, 0, nproc); 336127412Sgad 337127412Sgad /* 338127412Sgad * Refine the selection. 339127412Sgad */ 340127412Sgad for (; *argv != NULL; argv++) { 341143875Spjd if ((rv = regcomp(®, *argv, cflags)) != 0) { 342127412Sgad regerror(rv, ®, buf, sizeof(buf)); 343152521Spjd errx(STATUS_BADUSAGE, 344152521Spjd "Cannot compile regular expression `%s' (%s)", 345152521Spjd *argv, buf); 346127412Sgad } 347127412Sgad 348127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 349143877Spjd if (PSKIP(kp)) { 350127433Sgad if (debug_opt > 0) 351127434Sgad fprintf(stderr, "* Skipped %5d %3d %s\n", 352127433Sgad kp->ki_pid, kp->ki_uid, kp->ki_comm); 353127412Sgad continue; 354127433Sgad } 355127412Sgad 356143877Spjd if (matchargs && 357143877Spjd (pargv = kvm_getargv(kd, kp, 0)) != NULL) { 358127430Sgad jsz = 0; 359127430Sgad while (jsz < sizeof(buf) && *pargv != NULL) { 360127430Sgad jsz += snprintf(buf + jsz, 361127430Sgad sizeof(buf) - jsz, 362127412Sgad pargv[1] != NULL ? "%s " : "%s", 363127412Sgad pargv[0]); 364127412Sgad pargv++; 365127412Sgad } 366127412Sgad mstr = buf; 367127412Sgad } else 368127425Sgad mstr = kp->ki_comm; 369127412Sgad 370127412Sgad rv = regexec(®, mstr, 1, ®match, 0); 371127412Sgad if (rv == 0) { 372127412Sgad if (fullmatch) { 373127412Sgad if (regmatch.rm_so == 0 && 374127431Sgad regmatch.rm_eo == 375127431Sgad (off_t)strlen(mstr)) 376127412Sgad selected[i] = 1; 377127412Sgad } else 378127412Sgad selected[i] = 1; 379127412Sgad } else if (rv != REG_NOMATCH) { 380127412Sgad regerror(rv, ®, buf, sizeof(buf)); 381152521Spjd errx(STATUS_ERROR, 382152521Spjd "Regular expression evaluation error (%s)", 383152521Spjd buf); 384127412Sgad } 385127433Sgad if (debug_opt > 1) { 386127433Sgad const char *rv_res = "NoMatch"; 387127433Sgad if (selected[i]) 388127433Sgad rv_res = "Matched"; 389127434Sgad fprintf(stderr, "* %s %5d %3d %s\n", rv_res, 390127433Sgad kp->ki_pid, kp->ki_uid, mstr); 391127433Sgad } 392127412Sgad } 393127412Sgad 394127412Sgad regfree(®); 395127412Sgad } 396127412Sgad 397127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 398143877Spjd if (PSKIP(kp)) 399127412Sgad continue; 400127412Sgad 401143874Spjd if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { 402143874Spjd selected[i] = 0; 403143874Spjd continue; 404143874Spjd } 405143874Spjd 406127412Sgad SLIST_FOREACH(li, &ruidlist, li_chain) 407127425Sgad if (kp->ki_ruid == (uid_t)li->li_number) 408127412Sgad break; 409127412Sgad if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 410127412Sgad selected[i] = 0; 411127412Sgad continue; 412127412Sgad } 413127429Sgad 414127412Sgad SLIST_FOREACH(li, &rgidlist, li_chain) 415127425Sgad if (kp->ki_rgid == (gid_t)li->li_number) 416127412Sgad break; 417127412Sgad if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 418127412Sgad selected[i] = 0; 419127412Sgad continue; 420127412Sgad } 421127412Sgad 422127412Sgad SLIST_FOREACH(li, &euidlist, li_chain) 423127425Sgad if (kp->ki_uid == (uid_t)li->li_number) 424127412Sgad break; 425127412Sgad if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 426127412Sgad selected[i] = 0; 427127412Sgad continue; 428127412Sgad } 429127412Sgad 430127412Sgad SLIST_FOREACH(li, &ppidlist, li_chain) 431127426Sgad if (kp->ki_ppid == (pid_t)li->li_number) 432127412Sgad break; 433127412Sgad if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 434127412Sgad selected[i] = 0; 435127412Sgad continue; 436127412Sgad } 437127412Sgad 438127412Sgad SLIST_FOREACH(li, &pgrplist, li_chain) 439127426Sgad if (kp->ki_pgid == (pid_t)li->li_number) 440127412Sgad break; 441127412Sgad if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 442127412Sgad selected[i] = 0; 443127412Sgad continue; 444127412Sgad } 445127412Sgad 446127412Sgad SLIST_FOREACH(li, &tdevlist, li_chain) { 447127412Sgad if (li->li_number == -1 && 448127425Sgad (kp->ki_flag & P_CONTROLT) == 0) 449127412Sgad break; 450130640Sphk if (kp->ki_tdev == (dev_t)li->li_number) 451127412Sgad break; 452127412Sgad } 453127412Sgad if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 454127412Sgad selected[i] = 0; 455127412Sgad continue; 456127412Sgad } 457127412Sgad 458127412Sgad SLIST_FOREACH(li, &sidlist, li_chain) 459127426Sgad if (kp->ki_sid == (pid_t)li->li_number) 460127412Sgad break; 461127412Sgad if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 462127412Sgad selected[i] = 0; 463127412Sgad continue; 464127412Sgad } 465127412Sgad 466143873Spjd SLIST_FOREACH(li, &jidlist, li_chain) { 467164558Syar /* A particular jail ID, including 0 (not in jail) */ 468164558Syar if (kp->ki_jid == (int)li->li_number) 469164558Syar break; 470164558Syar /* Any jail */ 471164558Syar if (kp->ki_jid > 0 && li->li_number == -1) 472164558Syar break; 473143873Spjd } 474143873Spjd if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { 475143873Spjd selected[i] = 0; 476143873Spjd continue; 477143873Spjd } 478143873Spjd 479254134Strasz SLIST_FOREACH(li, &classlist, li_chain) { 480254134Strasz /* 481254134Strasz * We skip P_SYSTEM processes to match ps(1) output. 482254134Strasz */ 483254134Strasz if ((kp->ki_flag & P_SYSTEM) == 0 && 484254134Strasz strcmp(kp->ki_loginclass, li->li_name) == 0) 485254134Strasz break; 486254134Strasz } 487254134Strasz if (SLIST_FIRST(&classlist) != NULL && li == NULL) { 488254134Strasz selected[i] = 0; 489254134Strasz continue; 490254134Strasz } 491254134Strasz 492127412Sgad if (argc == 0) 493127412Sgad selected[i] = 1; 494127412Sgad } 495127412Sgad 496192242Sbrian if (!ancestors) { 497192242Sbrian pid = mypid; 498192242Sbrian while (pid) { 499192242Sbrian for (i = 0, kp = plist; i < nproc; i++, kp++) { 500192242Sbrian if (PSKIP(kp)) 501192242Sbrian continue; 502192242Sbrian if (kp->ki_pid == pid) { 503192242Sbrian selected[i] = 0; 504192242Sbrian pid = kp->ki_ppid; 505192242Sbrian break; 506192242Sbrian } 507192242Sbrian } 508192242Sbrian if (i == nproc) { 509192242Sbrian if (pid == mypid) 510192242Sbrian pid = getppid(); 511192242Sbrian else 512192242Sbrian break; /* Maybe we're in a jail ? */ 513192242Sbrian } 514192242Sbrian } 515192242Sbrian } 516192242Sbrian 517143878Spjd if (newest || oldest) { 518127430Sgad best_tval.tv_sec = 0; 519127430Sgad best_tval.tv_usec = 0; 520127412Sgad bestidx = -1; 521127412Sgad 522127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 523127412Sgad if (!selected[i]) 524127412Sgad continue; 525143878Spjd if (bestidx == -1) { 526143878Spjd /* The first entry of the list which matched. */ 527143878Spjd ; 528143878Spjd } else if (timercmp(&kp->ki_start, &best_tval, >)) { 529143878Spjd /* This entry is newer than previous "best". */ 530143879Spjd if (oldest) /* but we want the oldest */ 531143878Spjd continue; 532143878Spjd } else { 533143878Spjd /* This entry is older than previous "best". */ 534143879Spjd if (newest) /* but we want the newest */ 535143878Spjd continue; 536127412Sgad } 537143878Spjd /* This entry is better than previous "best" entry. */ 538143878Spjd best_tval.tv_sec = kp->ki_start.tv_sec; 539143878Spjd best_tval.tv_usec = kp->ki_start.tv_usec; 540143878Spjd bestidx = i; 541127412Sgad } 542127412Sgad 543127412Sgad memset(selected, 0, nproc); 544127412Sgad if (bestidx != -1) 545127412Sgad selected[bestidx] = 1; 546127412Sgad } 547127412Sgad 548127412Sgad /* 549127412Sgad * Take the appropriate action for each matched process, if any. 550127412Sgad */ 551209363Sbrian did_action = 0; 552127412Sgad for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 553143877Spjd if (PSKIP(kp)) 554127412Sgad continue; 555127412Sgad if (selected[i]) { 556209363Sbrian if (longfmt && !pgrep) { 557209363Sbrian did_action = 1; 558209363Sbrian printf("kill -%d %d\n", signum, kp->ki_pid); 559209363Sbrian } 560127412Sgad if (inverse) 561127412Sgad continue; 562127412Sgad } else if (!inverse) 563127412Sgad continue; 564152521Spjd rv |= (*action)(kp); 565127412Sgad } 566209363Sbrian if (!did_action && !pgrep && longfmt) 567209363Sbrian fprintf(stderr, 568209363Sbrian "No matching processes belonging to you were found\n"); 569127412Sgad 570127412Sgad exit(rv ? STATUS_MATCH : STATUS_NOMATCH); 571127412Sgad} 572127412Sgad 573152521Spjdstatic void 574127412Sgadusage(void) 575127412Sgad{ 576127412Sgad const char *ustr; 577127412Sgad 578127412Sgad if (pgrep) 579203802Spjd ustr = "[-LSfilnoqvx] [-d delim]"; 580127412Sgad else 581209363Sbrian ustr = "[-signal] [-ILfilnovx]"; 582127412Sgad 583127412Sgad fprintf(stderr, 584143874Spjd "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" 585254134Strasz " [-P ppid] [-U uid] [-c class] [-g pgrp] [-j jid]\n" 586254134Strasz " [-s sid] [-t tty] [-u euid] pattern ...\n", 587254134Strasz getprogname(), ustr); 588127412Sgad 589152521Spjd exit(STATUS_BADUSAGE); 590127412Sgad} 591127412Sgad 592152518Spjdstatic void 593152521Spjdshow_process(const struct kinfo_proc *kp) 594127412Sgad{ 595127412Sgad char **argv; 596127412Sgad 597203802Spjd if (quiet) { 598203802Spjd assert(pgrep); 599203802Spjd return; 600203802Spjd } 601152518Spjd if ((longfmt || !pgrep) && matchargs && 602143877Spjd (argv = kvm_getargv(kd, kp, 0)) != NULL) { 603127425Sgad printf("%d ", (int)kp->ki_pid); 604127412Sgad for (; *argv != NULL; argv++) { 605127412Sgad printf("%s", *argv); 606127412Sgad if (argv[1] != NULL) 607127412Sgad putchar(' '); 608127412Sgad } 609152518Spjd } else if (longfmt || !pgrep) 610127425Sgad printf("%d %s", (int)kp->ki_pid, kp->ki_comm); 611127412Sgad else 612127425Sgad printf("%d", (int)kp->ki_pid); 613152518Spjd} 614127412Sgad 615152521Spjdstatic int 616152521Spjdkillact(const struct kinfo_proc *kp) 617152518Spjd{ 618152518Spjd int ch, first; 619152518Spjd 620152518Spjd if (interactive) { 621152518Spjd /* 622152518Spjd * Be careful, ask before killing. 623152518Spjd */ 624152518Spjd printf("kill "); 625152518Spjd show_process(kp); 626152518Spjd printf("? "); 627152518Spjd fflush(stdout); 628152518Spjd first = ch = getchar(); 629152518Spjd while (ch != '\n' && ch != EOF) 630152518Spjd ch = getchar(); 631152518Spjd if (first != 'y' && first != 'Y') 632152521Spjd return (1); 633152518Spjd } 634152521Spjd if (kill(kp->ki_pid, signum) == -1) { 635152521Spjd /* 636152521Spjd * Check for ESRCH, which indicates that the process 637152521Spjd * disappeared between us matching it and us 638152521Spjd * signalling it; don't issue a warning about it. 639152521Spjd */ 640152521Spjd if (errno != ESRCH) 641152521Spjd warn("signalling pid %d", (int)kp->ki_pid); 642152521Spjd /* 643152521Spjd * Return 0 to indicate that the process should not be 644152521Spjd * considered a match, since we didn't actually get to 645152521Spjd * signal it. 646152521Spjd */ 647152521Spjd return (0); 648152521Spjd } 649152521Spjd return (1); 650152518Spjd} 651152518Spjd 652152521Spjdstatic int 653152521Spjdgrepact(const struct kinfo_proc *kp) 654152518Spjd{ 655152518Spjd 656152518Spjd show_process(kp); 657203802Spjd if (!quiet) 658203802Spjd printf("%s", delim); 659152521Spjd return (1); 660127412Sgad} 661127412Sgad 662152521Spjdstatic void 663127412Sgadmakelist(struct listhead *head, enum listtype type, char *src) 664127412Sgad{ 665127412Sgad struct list *li; 666127412Sgad struct passwd *pw; 667127412Sgad struct group *gr; 668127412Sgad struct stat st; 669183438Sed const char *cp; 670152521Spjd char *sp, *ep, buf[MAXPATHLEN]; 671127412Sgad int empty; 672127412Sgad 673127412Sgad empty = 1; 674127412Sgad 675127412Sgad while ((sp = strsep(&src, ",")) != NULL) { 676127412Sgad if (*sp == '\0') 677127412Sgad usage(); 678127412Sgad 679152521Spjd if ((li = malloc(sizeof(*li))) == NULL) { 680152521Spjd err(STATUS_ERROR, "Cannot allocate %zu bytes", 681152521Spjd sizeof(*li)); 682152521Spjd } 683152521Spjd 684127412Sgad SLIST_INSERT_HEAD(head, li, li_chain); 685127412Sgad empty = 0; 686127412Sgad 687254134Strasz if (type != LT_CLASS) 688254134Strasz li->li_number = (uid_t)strtol(sp, &ep, 0); 689254134Strasz 690254134Strasz if (type != LT_CLASS && *ep == '\0') { 691127412Sgad switch (type) { 692127412Sgad case LT_PGRP: 693127412Sgad if (li->li_number == 0) 694127412Sgad li->li_number = getpgrp(); 695127412Sgad break; 696127412Sgad case LT_SID: 697127412Sgad if (li->li_number == 0) 698127412Sgad li->li_number = getsid(mypid); 699127412Sgad break; 700164558Syar case LT_JID: 701164558Syar if (li->li_number < 0) 702164558Syar errx(STATUS_BADUSAGE, 703164558Syar "Negative jail ID `%s'", sp); 704164558Syar /* For compatibility with old -j */ 705164558Syar if (li->li_number == 0) 706164558Syar li->li_number = -1; /* any jail */ 707164558Syar break; 708201487Sobrien case LT_TTY: 709201487Sobrien if (li->li_number < 0) 710201487Sobrien errx(STATUS_BADUSAGE, 711201487Sobrien "Negative /dev/pts tty `%s'", sp); 712201487Sobrien snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s", 713201487Sobrien sp); 714201487Sobrien if (stat(buf, &st) != -1) 715201487Sobrien goto foundtty; 716201487Sobrien if (errno == ENOENT) 717201487Sobrien errx(STATUS_BADUSAGE, "No such tty: `" 718201487Sobrien _PATH_DEV "pts/%s'", sp); 719201487Sobrien err(STATUS_ERROR, "Cannot access `" 720201487Sobrien _PATH_DEV "pts/%s'", sp); 721201487Sobrien break; 722127412Sgad default: 723127412Sgad break; 724127412Sgad } 725127412Sgad continue; 726127412Sgad } 727127412Sgad 728127412Sgad switch (type) { 729127412Sgad case LT_USER: 730127412Sgad if ((pw = getpwnam(sp)) == NULL) 731152521Spjd errx(STATUS_BADUSAGE, "Unknown user `%s'", sp); 732127412Sgad li->li_number = pw->pw_uid; 733127412Sgad break; 734127412Sgad case LT_GROUP: 735127412Sgad if ((gr = getgrnam(sp)) == NULL) 736152521Spjd errx(STATUS_BADUSAGE, "Unknown group `%s'", sp); 737127412Sgad li->li_number = gr->gr_gid; 738127412Sgad break; 739127412Sgad case LT_TTY: 740127412Sgad if (strcmp(sp, "-") == 0) { 741127412Sgad li->li_number = -1; 742127412Sgad break; 743152521Spjd } else if (strcmp(sp, "co") == 0) { 744127430Sgad cp = "console"; 745152521Spjd } else { 746127430Sgad cp = sp; 747152521Spjd } 748127412Sgad 749183438Sed snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp); 750183502Sed if (stat(buf, &st) != -1) 751183502Sed goto foundtty; 752127412Sgad 753183502Sed snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp); 754183502Sed if (stat(buf, &st) != -1) 755183502Sed goto foundtty; 756127412Sgad 757183502Sed if (errno == ENOENT) 758183502Sed errx(STATUS_BADUSAGE, "No such tty: `%s'", sp); 759183502Sed err(STATUS_ERROR, "Cannot access `%s'", sp); 760183502Sed 761183502Sedfoundtty: if ((st.st_mode & S_IFCHR) == 0) 762152521Spjd errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp); 763127412Sgad 764127412Sgad li->li_number = st.st_rdev; 765127412Sgad break; 766164558Syar case LT_JID: 767164558Syar if (strcmp(sp, "none") == 0) 768164558Syar li->li_number = 0; 769164558Syar else if (strcmp(sp, "any") == 0) 770164558Syar li->li_number = -1; 771164558Syar else if (*ep != '\0') 772164558Syar errx(STATUS_BADUSAGE, 773164558Syar "Invalid jail ID `%s'", sp); 774164558Syar break; 775254134Strasz case LT_CLASS: 776254134Strasz li->li_number = -1; 777254134Strasz li->li_name = strdup(sp); 778254134Strasz if (li->li_name == NULL) 779254134Strasz err(STATUS_ERROR, "Cannot allocate memory"); 780254134Strasz break; 781127412Sgad default: 782127412Sgad usage(); 783152521Spjd } 784127412Sgad } 785127412Sgad 786127412Sgad if (empty) 787127412Sgad usage(); 788127412Sgad} 789143874Spjd 790152521Spjdstatic int 791149471Spjdtakepid(const char *pidfile, int pidfilelock) 792143874Spjd{ 793143874Spjd char *endp, line[BUFSIZ]; 794143874Spjd FILE *fh; 795143874Spjd long rval; 796143879Spjd 797143874Spjd fh = fopen(pidfile, "r"); 798143874Spjd if (fh == NULL) 799152521Spjd err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); 800143879Spjd 801149471Spjd if (pidfilelock) { 802149471Spjd /* 803149471Spjd * If we can lock pidfile, this means that daemon is not 804149471Spjd * running, so would be better not to kill some random process. 805149471Spjd */ 806149471Spjd if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { 807149471Spjd (void)fclose(fh); 808152521Spjd errx(STATUS_ERROR, "File '%s' can be locked", pidfile); 809149471Spjd } else { 810149471Spjd if (errno != EWOULDBLOCK) { 811149471Spjd errx(STATUS_ERROR, 812152521Spjd "Error while locking file '%s'", pidfile); 813149471Spjd } 814149435Spjd } 815149435Spjd } 816149435Spjd 817143874Spjd if (fgets(line, sizeof(line), fh) == NULL) { 818143874Spjd if (feof(fh)) { 819143874Spjd (void)fclose(fh); 820152521Spjd errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); 821143874Spjd } 822143874Spjd (void)fclose(fh); 823152521Spjd err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); 824143874Spjd } 825143874Spjd (void)fclose(fh); 826143879Spjd 827143874Spjd rval = strtol(line, &endp, 10); 828143874Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) 829152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 830143874Spjd else if (rval < MIN_PID || rval > MAX_PID) 831152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 832143874Spjd return (rval); 833143874Spjd} 834