1152521Spjd/* $NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $ */ 2127412Sgad 3127412Sgad/*- 4330449Seadler * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5330449Seadler * 6127412Sgad * Copyright (c) 2002 The NetBSD Foundation, Inc. 7152518Spjd * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 8127412Sgad * All rights reserved. 9127412Sgad * 10127412Sgad * This code is derived from software contributed to The NetBSD Foundation 11127412Sgad * by Andrew Doran. 12127412Sgad * 13127412Sgad * Redistribution and use in source and binary forms, with or without 14127412Sgad * modification, are permitted provided that the following conditions 15127412Sgad * are met: 16127412Sgad * 1. Redistributions of source code must retain the above copyright 17127412Sgad * notice, this list of conditions and the following disclaimer. 18127412Sgad * 2. Redistributions in binary form must reproduce the above copyright 19127412Sgad * notice, this list of conditions and the following disclaimer in the 20127412Sgad * documentation and/or other materials provided with the distribution. 21127412Sgad * 22127412Sgad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23127412Sgad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24127412Sgad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25127412Sgad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26127412Sgad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27127412Sgad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28127412Sgad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29127412Sgad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30127412Sgad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31127412Sgad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32127412Sgad * POSSIBILITY OF SUCH DAMAGE. 33127412Sgad */ 34127412Sgad 35127412Sgad#include <sys/cdefs.h> 36127412Sgad__FBSDID("$FreeBSD: stable/11/bin/pkill/pkill.c 330449 2018-03-05 07:26:05Z eadler $"); 37127412Sgad 38127412Sgad#include <sys/types.h> 39127412Sgad#include <sys/param.h> 40127412Sgad#include <sys/sysctl.h> 41127412Sgad#include <sys/proc.h> 42127412Sgad#include <sys/queue.h> 43127412Sgad#include <sys/stat.h> 44143878Spjd#include <sys/time.h> 45127425Sgad#include <sys/user.h> 46127412Sgad 47203802Spjd#include <assert.h> 48330324Seadler#include <stdbool.h> 49127412Sgad#include <stdio.h> 50127412Sgad#include <stdlib.h> 51127412Sgad#include <limits.h> 52127425Sgad#include <paths.h> 53127412Sgad#include <string.h> 54127412Sgad#include <unistd.h> 55127412Sgad#include <signal.h> 56127412Sgad#include <regex.h> 57127412Sgad#include <ctype.h> 58127425Sgad#include <fcntl.h> 59127412Sgad#include <kvm.h> 60127412Sgad#include <err.h> 61127412Sgad#include <pwd.h> 62127412Sgad#include <grp.h> 63127412Sgad#include <errno.h> 64132198Stjr#include <locale.h> 65287012Sjamie#include <jail.h> 66127412Sgad 67127412Sgad#define STATUS_MATCH 0 68127412Sgad#define STATUS_NOMATCH 1 69127412Sgad#define STATUS_BADUSAGE 2 70127412Sgad#define STATUS_ERROR 3 71127412Sgad 72143874Spjd#define MIN_PID 5 73143874Spjd#define MAX_PID 99999 74143874Spjd 75143877Spjd/* Ignore system-processes (if '-S' flag is not specified) and myself. */ 76143877Spjd#define PSKIP(kp) ((kp)->ki_pid == mypid || \ 77295435Skib (!kthreads && ((kp)->ki_flag & P_KPROC) != 0)) 78127425Sgad 79127412Sgadenum listtype { 80127412Sgad LT_GENERIC, 81127412Sgad LT_USER, 82127412Sgad LT_GROUP, 83127412Sgad LT_TTY, 84127412Sgad LT_PGRP, 85287012Sjamie LT_JAIL, 86254134Strasz LT_SID, 87254134Strasz LT_CLASS 88127412Sgad}; 89127412Sgad 90127412Sgadstruct list { 91127412Sgad SLIST_ENTRY(list) li_chain; 92127412Sgad long li_number; 93254134Strasz char *li_name; 94127412Sgad}; 95127412Sgad 96127412SgadSLIST_HEAD(listhead, list); 97127412Sgad 98152521Spjdstatic struct kinfo_proc *plist; 99152521Spjdstatic char *selected; 100152521Spjdstatic const char *delim = "\n"; 101152521Spjdstatic int nproc; 102152521Spjdstatic int pgrep; 103152521Spjdstatic int signum = SIGTERM; 104152521Spjdstatic int newest; 105152521Spjdstatic int oldest; 106152521Spjdstatic int interactive; 107152521Spjdstatic int inverse; 108152521Spjdstatic int longfmt; 109152521Spjdstatic int matchargs; 110152521Spjdstatic int fullmatch; 111152521Spjdstatic int kthreads; 112152521Spjdstatic int cflags = REG_EXTENDED; 113203802Spjdstatic int quiet; 114152521Spjdstatic kvm_t *kd; 115152521Spjdstatic pid_t mypid; 116127412Sgad 117201145Santoinestatic struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist); 118201145Santoinestatic struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist); 119201145Santoinestatic struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist); 120201145Santoinestatic struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist); 121201145Santoinestatic struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); 122201145Santoinestatic struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); 123201145Santoinestatic struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); 124201145Santoinestatic struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); 125254134Straszstatic struct listhead classlist = SLIST_HEAD_INITIALIZER(classlist); 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; 138209363Sbrian int ancestors, debug_opt, did_action; 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 { 166218285Sjilles 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 189254134Strasz while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ac:d: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; 232254134Strasz case 'c': 233254134Strasz makelist(&classlist, LT_CLASS, optarg); 234254134Strasz criteria = 1; 235254134Strasz break; 236127412Sgad case 'd': 237127412Sgad if (!pgrep) 238127412Sgad usage(); 239127412Sgad delim = optarg; 240127412Sgad break; 241127412Sgad case 'f': 242127412Sgad matchargs = 1; 243127412Sgad break; 244127412Sgad case 'g': 245127412Sgad makelist(&pgrplist, LT_PGRP, optarg); 246127412Sgad criteria = 1; 247127412Sgad break; 248143875Spjd case 'i': 249143875Spjd cflags |= REG_ICASE; 250143875Spjd break; 251143873Spjd case 'j': 252287012Sjamie makelist(&jidlist, LT_JAIL, optarg); 253143873Spjd criteria = 1; 254143873Spjd break; 255127412Sgad case 'l': 256127412Sgad longfmt = 1; 257127412Sgad break; 258127412Sgad case 'n': 259127412Sgad newest = 1; 260127412Sgad criteria = 1; 261127412Sgad break; 262143878Spjd case 'o': 263143878Spjd oldest = 1; 264143878Spjd criteria = 1; 265143878Spjd break; 266203802Spjd case 'q': 267203802Spjd if (!pgrep) 268203802Spjd usage(); 269203802Spjd quiet = 1; 270203802Spjd break; 271127412Sgad case 's': 272127412Sgad makelist(&sidlist, LT_SID, optarg); 273127412Sgad criteria = 1; 274127412Sgad break; 275127412Sgad case 't': 276127412Sgad makelist(&tdevlist, LT_TTY, optarg); 277127412Sgad criteria = 1; 278127412Sgad break; 279127412Sgad case 'u': 280127412Sgad makelist(&euidlist, LT_USER, optarg); 281127412Sgad criteria = 1; 282127412Sgad break; 283127412Sgad case 'v': 284127412Sgad inverse = 1; 285127412Sgad break; 286127412Sgad case 'x': 287127412Sgad fullmatch = 1; 288127412Sgad break; 289127412Sgad default: 290127412Sgad usage(); 291127412Sgad /* NOTREACHED */ 292127412Sgad } 293127412Sgad 294127412Sgad argc -= optind; 295127412Sgad argv += optind; 296127412Sgad if (argc != 0) 297127412Sgad criteria = 1; 298127412Sgad if (!criteria) 299127412Sgad usage(); 300143878Spjd if (newest && oldest) 301152521Spjd errx(STATUS_ERROR, "Options -n and -o are mutually exclusive"); 302149471Spjd if (pidfile != NULL) 303149471Spjd pidfromfile = takepid(pidfile, pidfilelock); 304149471Spjd else { 305152521Spjd if (pidfilelock) { 306152521Spjd errx(STATUS_ERROR, 307152521Spjd "Option -L doesn't make sense without -F"); 308152521Spjd } 309149471Spjd pidfromfile = -1; 310149471Spjd } 311127412Sgad 312127412Sgad mypid = getpid(); 313127412Sgad 314127412Sgad /* 315127412Sgad * Retrieve the list of running processes from the kernel. 316127412Sgad */ 317127462Sgad kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); 318127412Sgad if (kd == NULL) 319152521Spjd errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); 320127412Sgad 321127622Sgad /* 322127622Sgad * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we 323127622Sgad * just want processes and not individual kernel threads. 324127622Sgad */ 325257911Seadler if (pidfromfile >= 0) 326257911Seadler plist = kvm_getprocs(kd, KERN_PROC_PID, pidfromfile, &nproc); 327257911Seadler else 328257911Seadler plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); 329152521Spjd if (plist == NULL) { 330152521Spjd errx(STATUS_ERROR, "Cannot get process list (%s)", 331152521Spjd kvm_geterr(kd)); 332152521Spjd } 333127412Sgad 334127412Sgad /* 335127412Sgad * Allocate memory which will be used to keep track of the 336127412Sgad * selection. 337127412Sgad */ 338152521Spjd if ((selected = malloc(nproc)) == NULL) { 339152521Spjd err(STATUS_ERROR, "Cannot allocate memory for %d processes", 340152521Spjd nproc); 341152521Spjd } 342127412Sgad memset(selected, 0, nproc); 343127412Sgad 344127412Sgad /* 345127412Sgad * Refine the selection. 346127412Sgad */ 347127412Sgad for (; *argv != NULL; argv++) { 348143875Spjd if ((rv = regcomp(®, *argv, cflags)) != 0) { 349127412Sgad regerror(rv, ®, buf, sizeof(buf)); 350152521Spjd errx(STATUS_BADUSAGE, 351152521Spjd "Cannot compile regular expression `%s' (%s)", 352152521Spjd *argv, buf); 353127412Sgad } 354127412Sgad 355127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 356143877Spjd if (PSKIP(kp)) { 357127433Sgad if (debug_opt > 0) 358127434Sgad fprintf(stderr, "* Skipped %5d %3d %s\n", 359127433Sgad kp->ki_pid, kp->ki_uid, kp->ki_comm); 360127412Sgad continue; 361127433Sgad } 362127412Sgad 363143877Spjd if (matchargs && 364143877Spjd (pargv = kvm_getargv(kd, kp, 0)) != NULL) { 365127430Sgad jsz = 0; 366127430Sgad while (jsz < sizeof(buf) && *pargv != NULL) { 367127430Sgad jsz += snprintf(buf + jsz, 368127430Sgad sizeof(buf) - jsz, 369127412Sgad pargv[1] != NULL ? "%s " : "%s", 370127412Sgad pargv[0]); 371127412Sgad pargv++; 372127412Sgad } 373127412Sgad mstr = buf; 374127412Sgad } else 375127425Sgad mstr = kp->ki_comm; 376127412Sgad 377127412Sgad rv = regexec(®, mstr, 1, ®match, 0); 378127412Sgad if (rv == 0) { 379127412Sgad if (fullmatch) { 380127412Sgad if (regmatch.rm_so == 0 && 381127431Sgad regmatch.rm_eo == 382127431Sgad (off_t)strlen(mstr)) 383127412Sgad selected[i] = 1; 384127412Sgad } else 385127412Sgad selected[i] = 1; 386127412Sgad } else if (rv != REG_NOMATCH) { 387127412Sgad regerror(rv, ®, buf, sizeof(buf)); 388152521Spjd errx(STATUS_ERROR, 389152521Spjd "Regular expression evaluation error (%s)", 390152521Spjd buf); 391127412Sgad } 392127433Sgad if (debug_opt > 1) { 393127433Sgad const char *rv_res = "NoMatch"; 394127433Sgad if (selected[i]) 395127433Sgad rv_res = "Matched"; 396127434Sgad fprintf(stderr, "* %s %5d %3d %s\n", rv_res, 397127433Sgad kp->ki_pid, kp->ki_uid, mstr); 398127433Sgad } 399127412Sgad } 400127412Sgad 401127412Sgad regfree(®); 402127412Sgad } 403127412Sgad 404127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 405143877Spjd if (PSKIP(kp)) 406127412Sgad continue; 407127412Sgad 408143874Spjd if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { 409143874Spjd selected[i] = 0; 410143874Spjd continue; 411143874Spjd } 412143874Spjd 413127412Sgad SLIST_FOREACH(li, &ruidlist, li_chain) 414127425Sgad if (kp->ki_ruid == (uid_t)li->li_number) 415127412Sgad break; 416127412Sgad if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 417127412Sgad selected[i] = 0; 418127412Sgad continue; 419127412Sgad } 420127429Sgad 421127412Sgad SLIST_FOREACH(li, &rgidlist, li_chain) 422127425Sgad if (kp->ki_rgid == (gid_t)li->li_number) 423127412Sgad break; 424127412Sgad if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 425127412Sgad selected[i] = 0; 426127412Sgad continue; 427127412Sgad } 428127412Sgad 429127412Sgad SLIST_FOREACH(li, &euidlist, li_chain) 430127425Sgad if (kp->ki_uid == (uid_t)li->li_number) 431127412Sgad break; 432127412Sgad if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 433127412Sgad selected[i] = 0; 434127412Sgad continue; 435127412Sgad } 436127412Sgad 437127412Sgad SLIST_FOREACH(li, &ppidlist, li_chain) 438127426Sgad if (kp->ki_ppid == (pid_t)li->li_number) 439127412Sgad break; 440127412Sgad if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 441127412Sgad selected[i] = 0; 442127412Sgad continue; 443127412Sgad } 444127412Sgad 445127412Sgad SLIST_FOREACH(li, &pgrplist, li_chain) 446127426Sgad if (kp->ki_pgid == (pid_t)li->li_number) 447127412Sgad break; 448127412Sgad if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 449127412Sgad selected[i] = 0; 450127412Sgad continue; 451127412Sgad } 452127412Sgad 453127412Sgad SLIST_FOREACH(li, &tdevlist, li_chain) { 454127412Sgad if (li->li_number == -1 && 455127425Sgad (kp->ki_flag & P_CONTROLT) == 0) 456127412Sgad break; 457130640Sphk if (kp->ki_tdev == (dev_t)li->li_number) 458127412Sgad break; 459127412Sgad } 460127412Sgad if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 461127412Sgad selected[i] = 0; 462127412Sgad continue; 463127412Sgad } 464127412Sgad 465127412Sgad SLIST_FOREACH(li, &sidlist, li_chain) 466127426Sgad if (kp->ki_sid == (pid_t)li->li_number) 467127412Sgad break; 468127412Sgad if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 469127412Sgad selected[i] = 0; 470127412Sgad continue; 471127412Sgad } 472127412Sgad 473143873Spjd SLIST_FOREACH(li, &jidlist, li_chain) { 474164558Syar /* A particular jail ID, including 0 (not in jail) */ 475164558Syar if (kp->ki_jid == (int)li->li_number) 476164558Syar break; 477164558Syar /* Any jail */ 478164558Syar if (kp->ki_jid > 0 && li->li_number == -1) 479164558Syar break; 480143873Spjd } 481143873Spjd if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { 482143873Spjd selected[i] = 0; 483143873Spjd continue; 484143873Spjd } 485143873Spjd 486254134Strasz SLIST_FOREACH(li, &classlist, li_chain) { 487254134Strasz /* 488254134Strasz * We skip P_SYSTEM processes to match ps(1) output. 489254134Strasz */ 490254134Strasz if ((kp->ki_flag & P_SYSTEM) == 0 && 491254134Strasz strcmp(kp->ki_loginclass, li->li_name) == 0) 492254134Strasz break; 493254134Strasz } 494254134Strasz if (SLIST_FIRST(&classlist) != NULL && li == NULL) { 495254134Strasz selected[i] = 0; 496254134Strasz continue; 497254134Strasz } 498254134Strasz 499127412Sgad if (argc == 0) 500127412Sgad selected[i] = 1; 501127412Sgad } 502127412Sgad 503192242Sbrian if (!ancestors) { 504192242Sbrian pid = mypid; 505192242Sbrian while (pid) { 506192242Sbrian for (i = 0, kp = plist; i < nproc; i++, kp++) { 507192242Sbrian if (PSKIP(kp)) 508192242Sbrian continue; 509192242Sbrian if (kp->ki_pid == pid) { 510192242Sbrian selected[i] = 0; 511192242Sbrian pid = kp->ki_ppid; 512192242Sbrian break; 513192242Sbrian } 514192242Sbrian } 515192242Sbrian if (i == nproc) { 516192242Sbrian if (pid == mypid) 517192242Sbrian pid = getppid(); 518192242Sbrian else 519192242Sbrian break; /* Maybe we're in a jail ? */ 520192242Sbrian } 521192242Sbrian } 522192242Sbrian } 523192242Sbrian 524143878Spjd if (newest || oldest) { 525127430Sgad best_tval.tv_sec = 0; 526127430Sgad best_tval.tv_usec = 0; 527127412Sgad bestidx = -1; 528127412Sgad 529127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 530127412Sgad if (!selected[i]) 531127412Sgad continue; 532143878Spjd if (bestidx == -1) { 533143878Spjd /* The first entry of the list which matched. */ 534143878Spjd ; 535143878Spjd } else if (timercmp(&kp->ki_start, &best_tval, >)) { 536143878Spjd /* This entry is newer than previous "best". */ 537143879Spjd if (oldest) /* but we want the oldest */ 538143878Spjd continue; 539143878Spjd } else { 540143878Spjd /* This entry is older than previous "best". */ 541143879Spjd if (newest) /* but we want the newest */ 542143878Spjd continue; 543127412Sgad } 544143878Spjd /* This entry is better than previous "best" entry. */ 545143878Spjd best_tval.tv_sec = kp->ki_start.tv_sec; 546143878Spjd best_tval.tv_usec = kp->ki_start.tv_usec; 547143878Spjd bestidx = i; 548127412Sgad } 549127412Sgad 550127412Sgad memset(selected, 0, nproc); 551127412Sgad if (bestidx != -1) 552127412Sgad selected[bestidx] = 1; 553127412Sgad } 554127412Sgad 555127412Sgad /* 556127412Sgad * Take the appropriate action for each matched process, if any. 557127412Sgad */ 558209363Sbrian did_action = 0; 559127412Sgad for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 560143877Spjd if (PSKIP(kp)) 561127412Sgad continue; 562127412Sgad if (selected[i]) { 563209363Sbrian if (longfmt && !pgrep) { 564209363Sbrian did_action = 1; 565209363Sbrian printf("kill -%d %d\n", signum, kp->ki_pid); 566209363Sbrian } 567127412Sgad if (inverse) 568127412Sgad continue; 569127412Sgad } else if (!inverse) 570127412Sgad continue; 571152521Spjd rv |= (*action)(kp); 572127412Sgad } 573330324Seadler if (rv && pgrep && !quiet) 574330324Seadler putchar('\n'); 575209363Sbrian if (!did_action && !pgrep && longfmt) 576209363Sbrian fprintf(stderr, 577209363Sbrian "No matching processes belonging to you were found\n"); 578127412Sgad 579127412Sgad exit(rv ? STATUS_MATCH : STATUS_NOMATCH); 580127412Sgad} 581127412Sgad 582152521Spjdstatic void 583127412Sgadusage(void) 584127412Sgad{ 585127412Sgad const char *ustr; 586127412Sgad 587127412Sgad if (pgrep) 588203802Spjd ustr = "[-LSfilnoqvx] [-d delim]"; 589127412Sgad else 590209363Sbrian ustr = "[-signal] [-ILfilnovx]"; 591127412Sgad 592127412Sgad fprintf(stderr, 593143874Spjd "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" 594287012Sjamie " [-P ppid] [-U uid] [-c class] [-g pgrp] [-j jail]\n" 595254134Strasz " [-s sid] [-t tty] [-u euid] pattern ...\n", 596254134Strasz getprogname(), ustr); 597127412Sgad 598152521Spjd exit(STATUS_BADUSAGE); 599127412Sgad} 600127412Sgad 601152518Spjdstatic void 602152521Spjdshow_process(const struct kinfo_proc *kp) 603127412Sgad{ 604127412Sgad char **argv; 605127412Sgad 606203802Spjd if (quiet) { 607203802Spjd assert(pgrep); 608203802Spjd return; 609203802Spjd } 610152518Spjd if ((longfmt || !pgrep) && matchargs && 611143877Spjd (argv = kvm_getargv(kd, kp, 0)) != NULL) { 612127425Sgad printf("%d ", (int)kp->ki_pid); 613127412Sgad for (; *argv != NULL; argv++) { 614127412Sgad printf("%s", *argv); 615127412Sgad if (argv[1] != NULL) 616127412Sgad putchar(' '); 617127412Sgad } 618152518Spjd } else if (longfmt || !pgrep) 619127425Sgad printf("%d %s", (int)kp->ki_pid, kp->ki_comm); 620127412Sgad else 621127425Sgad printf("%d", (int)kp->ki_pid); 622152518Spjd} 623127412Sgad 624152521Spjdstatic int 625152521Spjdkillact(const struct kinfo_proc *kp) 626152518Spjd{ 627152518Spjd int ch, first; 628152518Spjd 629152518Spjd if (interactive) { 630152518Spjd /* 631152518Spjd * Be careful, ask before killing. 632152518Spjd */ 633152518Spjd printf("kill "); 634152518Spjd show_process(kp); 635152518Spjd printf("? "); 636152518Spjd fflush(stdout); 637152518Spjd first = ch = getchar(); 638152518Spjd while (ch != '\n' && ch != EOF) 639152518Spjd ch = getchar(); 640152518Spjd if (first != 'y' && first != 'Y') 641152521Spjd return (1); 642152518Spjd } 643152521Spjd if (kill(kp->ki_pid, signum) == -1) { 644152521Spjd /* 645152521Spjd * Check for ESRCH, which indicates that the process 646152521Spjd * disappeared between us matching it and us 647152521Spjd * signalling it; don't issue a warning about it. 648152521Spjd */ 649152521Spjd if (errno != ESRCH) 650152521Spjd warn("signalling pid %d", (int)kp->ki_pid); 651152521Spjd /* 652152521Spjd * Return 0 to indicate that the process should not be 653152521Spjd * considered a match, since we didn't actually get to 654152521Spjd * signal it. 655152521Spjd */ 656152521Spjd return (0); 657152521Spjd } 658152521Spjd return (1); 659152518Spjd} 660152518Spjd 661152521Spjdstatic int 662152521Spjdgrepact(const struct kinfo_proc *kp) 663152518Spjd{ 664330324Seadler static bool first = true; 665152518Spjd 666330324Seadler if (!quiet && !first) 667330324Seadler printf("%s", delim); 668152518Spjd show_process(kp); 669330324Seadler first = false; 670152521Spjd return (1); 671127412Sgad} 672127412Sgad 673152521Spjdstatic void 674127412Sgadmakelist(struct listhead *head, enum listtype type, char *src) 675127412Sgad{ 676127412Sgad struct list *li; 677127412Sgad struct passwd *pw; 678127412Sgad struct group *gr; 679127412Sgad struct stat st; 680183438Sed const char *cp; 681152521Spjd char *sp, *ep, buf[MAXPATHLEN]; 682127412Sgad int empty; 683127412Sgad 684127412Sgad empty = 1; 685127412Sgad 686127412Sgad while ((sp = strsep(&src, ",")) != NULL) { 687127412Sgad if (*sp == '\0') 688127412Sgad usage(); 689127412Sgad 690152521Spjd if ((li = malloc(sizeof(*li))) == NULL) { 691152521Spjd err(STATUS_ERROR, "Cannot allocate %zu bytes", 692152521Spjd sizeof(*li)); 693152521Spjd } 694152521Spjd 695127412Sgad SLIST_INSERT_HEAD(head, li, li_chain); 696127412Sgad empty = 0; 697127412Sgad 698254134Strasz if (type != LT_CLASS) 699254134Strasz li->li_number = (uid_t)strtol(sp, &ep, 0); 700254134Strasz 701254134Strasz if (type != LT_CLASS && *ep == '\0') { 702127412Sgad switch (type) { 703127412Sgad case LT_PGRP: 704127412Sgad if (li->li_number == 0) 705127412Sgad li->li_number = getpgrp(); 706127412Sgad break; 707127412Sgad case LT_SID: 708127412Sgad if (li->li_number == 0) 709127412Sgad li->li_number = getsid(mypid); 710127412Sgad break; 711287012Sjamie case LT_JAIL: 712164558Syar if (li->li_number < 0) 713164558Syar errx(STATUS_BADUSAGE, 714164558Syar "Negative jail ID `%s'", sp); 715164558Syar /* For compatibility with old -j */ 716164558Syar if (li->li_number == 0) 717164558Syar li->li_number = -1; /* any jail */ 718164558Syar break; 719201487Sobrien case LT_TTY: 720201487Sobrien if (li->li_number < 0) 721201487Sobrien errx(STATUS_BADUSAGE, 722201487Sobrien "Negative /dev/pts tty `%s'", sp); 723201487Sobrien snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s", 724201487Sobrien sp); 725201487Sobrien if (stat(buf, &st) != -1) 726201487Sobrien goto foundtty; 727201487Sobrien if (errno == ENOENT) 728201487Sobrien errx(STATUS_BADUSAGE, "No such tty: `" 729201487Sobrien _PATH_DEV "pts/%s'", sp); 730201487Sobrien err(STATUS_ERROR, "Cannot access `" 731201487Sobrien _PATH_DEV "pts/%s'", sp); 732201487Sobrien break; 733127412Sgad default: 734127412Sgad break; 735127412Sgad } 736127412Sgad continue; 737127412Sgad } 738127412Sgad 739127412Sgad switch (type) { 740127412Sgad case LT_USER: 741127412Sgad if ((pw = getpwnam(sp)) == NULL) 742152521Spjd errx(STATUS_BADUSAGE, "Unknown user `%s'", sp); 743127412Sgad li->li_number = pw->pw_uid; 744127412Sgad break; 745127412Sgad case LT_GROUP: 746127412Sgad if ((gr = getgrnam(sp)) == NULL) 747152521Spjd errx(STATUS_BADUSAGE, "Unknown group `%s'", sp); 748127412Sgad li->li_number = gr->gr_gid; 749127412Sgad break; 750127412Sgad case LT_TTY: 751127412Sgad if (strcmp(sp, "-") == 0) { 752127412Sgad li->li_number = -1; 753127412Sgad break; 754152521Spjd } else if (strcmp(sp, "co") == 0) { 755127430Sgad cp = "console"; 756152521Spjd } else { 757127430Sgad cp = sp; 758152521Spjd } 759127412Sgad 760183438Sed snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp); 761183502Sed if (stat(buf, &st) != -1) 762183502Sed goto foundtty; 763127412Sgad 764183502Sed snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp); 765183502Sed if (stat(buf, &st) != -1) 766183502Sed goto foundtty; 767127412Sgad 768183502Sed if (errno == ENOENT) 769183502Sed errx(STATUS_BADUSAGE, "No such tty: `%s'", sp); 770183502Sed err(STATUS_ERROR, "Cannot access `%s'", sp); 771183502Sed 772183502Sedfoundtty: if ((st.st_mode & S_IFCHR) == 0) 773152521Spjd errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp); 774127412Sgad 775127412Sgad li->li_number = st.st_rdev; 776127412Sgad break; 777287012Sjamie case LT_JAIL: { 778287012Sjamie int jid; 779287012Sjamie 780164558Syar if (strcmp(sp, "none") == 0) 781164558Syar li->li_number = 0; 782164558Syar else if (strcmp(sp, "any") == 0) 783164558Syar li->li_number = -1; 784287012Sjamie else if ((jid = jail_getid(sp)) != -1) 785287012Sjamie li->li_number = jid; 786164558Syar else if (*ep != '\0') 787164558Syar errx(STATUS_BADUSAGE, 788287012Sjamie "Invalid jail ID or name `%s'", sp); 789164558Syar break; 790287012Sjamie } 791254134Strasz case LT_CLASS: 792254134Strasz li->li_number = -1; 793254134Strasz li->li_name = strdup(sp); 794254134Strasz if (li->li_name == NULL) 795254134Strasz err(STATUS_ERROR, "Cannot allocate memory"); 796254134Strasz break; 797127412Sgad default: 798127412Sgad usage(); 799152521Spjd } 800127412Sgad } 801127412Sgad 802127412Sgad if (empty) 803127412Sgad usage(); 804127412Sgad} 805143874Spjd 806152521Spjdstatic int 807149471Spjdtakepid(const char *pidfile, int pidfilelock) 808143874Spjd{ 809143874Spjd char *endp, line[BUFSIZ]; 810143874Spjd FILE *fh; 811143874Spjd long rval; 812143879Spjd 813143874Spjd fh = fopen(pidfile, "r"); 814143874Spjd if (fh == NULL) 815152521Spjd err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); 816143879Spjd 817149471Spjd if (pidfilelock) { 818149471Spjd /* 819149471Spjd * If we can lock pidfile, this means that daemon is not 820149471Spjd * running, so would be better not to kill some random process. 821149471Spjd */ 822149471Spjd if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { 823149471Spjd (void)fclose(fh); 824152521Spjd errx(STATUS_ERROR, "File '%s' can be locked", pidfile); 825149471Spjd } else { 826149471Spjd if (errno != EWOULDBLOCK) { 827149471Spjd errx(STATUS_ERROR, 828152521Spjd "Error while locking file '%s'", pidfile); 829149471Spjd } 830149435Spjd } 831149435Spjd } 832149435Spjd 833143874Spjd if (fgets(line, sizeof(line), fh) == NULL) { 834143874Spjd if (feof(fh)) { 835143874Spjd (void)fclose(fh); 836152521Spjd errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); 837143874Spjd } 838143874Spjd (void)fclose(fh); 839152521Spjd err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); 840143874Spjd } 841143874Spjd (void)fclose(fh); 842143879Spjd 843143874Spjd rval = strtol(line, &endp, 10); 844143874Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) 845152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 846143874Spjd else if (rval < MIN_PID || rval > MAX_PID) 847152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 848143874Spjd return (rval); 849143874Spjd} 850