pkill.c revision 209363
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: head/bin/pkill/pkill.c 209363 2010-06-20 08:48:30Z brian $"); 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, 82127412Sgad LT_SID 83127412Sgad}; 84127412Sgad 85127412Sgadstruct list { 86127412Sgad SLIST_ENTRY(list) li_chain; 87127412Sgad long li_number; 88127412Sgad}; 89127412Sgad 90127412SgadSLIST_HEAD(listhead, list); 91127412Sgad 92152521Spjdstatic struct kinfo_proc *plist; 93152521Spjdstatic char *selected; 94152521Spjdstatic const char *delim = "\n"; 95152521Spjdstatic int nproc; 96152521Spjdstatic int pgrep; 97152521Spjdstatic int signum = SIGTERM; 98152521Spjdstatic int newest; 99152521Spjdstatic int oldest; 100152521Spjdstatic int interactive; 101152521Spjdstatic int inverse; 102152521Spjdstatic int longfmt; 103152521Spjdstatic int matchargs; 104152521Spjdstatic int fullmatch; 105152521Spjdstatic int kthreads; 106152521Spjdstatic int cflags = REG_EXTENDED; 107203802Spjdstatic int quiet; 108152521Spjdstatic kvm_t *kd; 109152521Spjdstatic pid_t mypid; 110127412Sgad 111201145Santoinestatic struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist); 112201145Santoinestatic struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist); 113201145Santoinestatic struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist); 114201145Santoinestatic struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist); 115201145Santoinestatic struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); 116201145Santoinestatic struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); 117201145Santoinestatic struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); 118201145Santoinestatic struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); 119127412Sgad 120152521Spjdstatic void usage(void) __attribute__((__noreturn__)); 121152521Spjdstatic int killact(const struct kinfo_proc *); 122152521Spjdstatic int grepact(const struct kinfo_proc *); 123152521Spjdstatic void makelist(struct listhead *, enum listtype, char *); 124152521Spjdstatic int takepid(const char *, int); 125127412Sgad 126127412Sgadint 127127412Sgadmain(int argc, char **argv) 128127412Sgad{ 129149471Spjd char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; 130127462Sgad const char *execf, *coref; 131209363Sbrian int ancestors, debug_opt, did_action; 132149471Spjd int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; 133127430Sgad size_t jsz; 134152521Spjd int (*action)(const struct kinfo_proc *); 135127425Sgad struct kinfo_proc *kp; 136127412Sgad struct list *li; 137127430Sgad struct timeval best_tval; 138127412Sgad regex_t reg; 139127412Sgad regmatch_t regmatch; 140192242Sbrian pid_t pid; 141127412Sgad 142132198Stjr setlocale(LC_ALL, ""); 143132198Stjr 144127412Sgad if (strcmp(getprogname(), "pgrep") == 0) { 145127412Sgad action = grepact; 146127412Sgad pgrep = 1; 147127412Sgad } else { 148127412Sgad action = killact; 149127412Sgad p = argv[1]; 150127412Sgad 151127412Sgad if (argc > 1 && p[0] == '-') { 152127412Sgad p++; 153127412Sgad i = (int)strtol(p, &q, 10); 154127412Sgad if (*q == '\0') { 155127412Sgad signum = i; 156127412Sgad argv++; 157127412Sgad argc--; 158127412Sgad } else { 159127412Sgad if (strncasecmp(p, "sig", 3) == 0) 160127412Sgad p += 3; 161127412Sgad for (i = 1; i < NSIG; i++) 162127412Sgad if (strcasecmp(sys_signame[i], p) == 0) 163127412Sgad break; 164127412Sgad if (i != NSIG) { 165127412Sgad signum = i; 166127412Sgad argv++; 167127412Sgad argc--; 168127412Sgad } 169127412Sgad } 170127412Sgad } 171127412Sgad } 172127412Sgad 173192242Sbrian ancestors = 0; 174127412Sgad criteria = 0; 175127433Sgad debug_opt = 0; 176149471Spjd pidfile = NULL; 177149471Spjd pidfilelock = 0; 178203802Spjd quiet = 0; 179203688Sbrucec execf = NULL; 180203688Sbrucec coref = _PATH_DEVNULL; 181127412Sgad 182203802Spjd while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1) 183127412Sgad switch (ch) { 184127433Sgad case 'D': 185127433Sgad debug_opt++; 186127433Sgad break; 187143874Spjd case 'F': 188149471Spjd pidfile = optarg; 189143874Spjd criteria = 1; 190143874Spjd break; 191127412Sgad case 'G': 192127412Sgad makelist(&rgidlist, LT_GROUP, optarg); 193127412Sgad criteria = 1; 194127412Sgad break; 195152518Spjd case 'I': 196152518Spjd if (pgrep) 197152518Spjd usage(); 198152518Spjd interactive = 1; 199152518Spjd break; 200149471Spjd case 'L': 201149471Spjd pidfilelock = 1; 202149471Spjd break; 203127427Sgad case 'M': 204127427Sgad coref = optarg; 205127427Sgad break; 206127427Sgad case 'N': 207127427Sgad execf = optarg; 208127427Sgad break; 209127412Sgad case 'P': 210127412Sgad makelist(&ppidlist, LT_GENERIC, optarg); 211127412Sgad criteria = 1; 212127412Sgad break; 213143877Spjd case 'S': 214143877Spjd if (!pgrep) 215143877Spjd usage(); 216143877Spjd kthreads = 1; 217143877Spjd break; 218127412Sgad case 'U': 219127412Sgad makelist(&ruidlist, LT_USER, optarg); 220127412Sgad criteria = 1; 221127412Sgad break; 222192242Sbrian case 'a': 223192242Sbrian ancestors++; 224192242Sbrian break; 225127412Sgad case 'd': 226127412Sgad if (!pgrep) 227127412Sgad usage(); 228127412Sgad delim = optarg; 229127412Sgad break; 230127412Sgad case 'f': 231127412Sgad matchargs = 1; 232127412Sgad break; 233127412Sgad case 'g': 234127412Sgad makelist(&pgrplist, LT_PGRP, optarg); 235127412Sgad criteria = 1; 236127412Sgad break; 237143875Spjd case 'i': 238143875Spjd cflags |= REG_ICASE; 239143875Spjd break; 240143873Spjd case 'j': 241164558Syar makelist(&jidlist, LT_JID, optarg); 242143873Spjd criteria = 1; 243143873Spjd break; 244127412Sgad case 'l': 245127412Sgad longfmt = 1; 246127412Sgad break; 247127412Sgad case 'n': 248127412Sgad newest = 1; 249127412Sgad criteria = 1; 250127412Sgad break; 251143878Spjd case 'o': 252143878Spjd oldest = 1; 253143878Spjd criteria = 1; 254143878Spjd break; 255203802Spjd case 'q': 256203802Spjd if (!pgrep) 257203802Spjd usage(); 258203802Spjd quiet = 1; 259203802Spjd break; 260127412Sgad case 's': 261127412Sgad makelist(&sidlist, LT_SID, optarg); 262127412Sgad criteria = 1; 263127412Sgad break; 264127412Sgad case 't': 265127412Sgad makelist(&tdevlist, LT_TTY, optarg); 266127412Sgad criteria = 1; 267127412Sgad break; 268127412Sgad case 'u': 269127412Sgad makelist(&euidlist, LT_USER, optarg); 270127412Sgad criteria = 1; 271127412Sgad break; 272127412Sgad case 'v': 273127412Sgad inverse = 1; 274127412Sgad break; 275127412Sgad case 'x': 276127412Sgad fullmatch = 1; 277127412Sgad break; 278127412Sgad default: 279127412Sgad usage(); 280127412Sgad /* NOTREACHED */ 281127412Sgad } 282127412Sgad 283127412Sgad argc -= optind; 284127412Sgad argv += optind; 285127412Sgad if (argc != 0) 286127412Sgad criteria = 1; 287127412Sgad if (!criteria) 288127412Sgad usage(); 289143878Spjd if (newest && oldest) 290152521Spjd errx(STATUS_ERROR, "Options -n and -o are mutually exclusive"); 291149471Spjd if (pidfile != NULL) 292149471Spjd pidfromfile = takepid(pidfile, pidfilelock); 293149471Spjd else { 294152521Spjd if (pidfilelock) { 295152521Spjd errx(STATUS_ERROR, 296152521Spjd "Option -L doesn't make sense without -F"); 297152521Spjd } 298149471Spjd pidfromfile = -1; 299149471Spjd } 300127412Sgad 301127412Sgad mypid = getpid(); 302127412Sgad 303127412Sgad /* 304127412Sgad * Retrieve the list of running processes from the kernel. 305127412Sgad */ 306127462Sgad kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); 307127412Sgad if (kd == NULL) 308152521Spjd errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); 309127412Sgad 310127622Sgad /* 311127622Sgad * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we 312127622Sgad * just want processes and not individual kernel threads. 313127622Sgad */ 314127622Sgad plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); 315152521Spjd if (plist == NULL) { 316152521Spjd errx(STATUS_ERROR, "Cannot get process list (%s)", 317152521Spjd kvm_geterr(kd)); 318152521Spjd } 319127412Sgad 320127412Sgad /* 321127412Sgad * Allocate memory which will be used to keep track of the 322127412Sgad * selection. 323127412Sgad */ 324152521Spjd if ((selected = malloc(nproc)) == NULL) { 325152521Spjd err(STATUS_ERROR, "Cannot allocate memory for %d processes", 326152521Spjd nproc); 327152521Spjd } 328127412Sgad memset(selected, 0, nproc); 329127412Sgad 330127412Sgad /* 331127412Sgad * Refine the selection. 332127412Sgad */ 333127412Sgad for (; *argv != NULL; argv++) { 334143875Spjd if ((rv = regcomp(®, *argv, cflags)) != 0) { 335127412Sgad regerror(rv, ®, buf, sizeof(buf)); 336152521Spjd errx(STATUS_BADUSAGE, 337152521Spjd "Cannot compile regular expression `%s' (%s)", 338152521Spjd *argv, buf); 339127412Sgad } 340127412Sgad 341127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 342143877Spjd if (PSKIP(kp)) { 343127433Sgad if (debug_opt > 0) 344127434Sgad fprintf(stderr, "* Skipped %5d %3d %s\n", 345127433Sgad kp->ki_pid, kp->ki_uid, kp->ki_comm); 346127412Sgad continue; 347127433Sgad } 348127412Sgad 349143877Spjd if (matchargs && 350143877Spjd (pargv = kvm_getargv(kd, kp, 0)) != NULL) { 351127430Sgad jsz = 0; 352127430Sgad while (jsz < sizeof(buf) && *pargv != NULL) { 353127430Sgad jsz += snprintf(buf + jsz, 354127430Sgad sizeof(buf) - jsz, 355127412Sgad pargv[1] != NULL ? "%s " : "%s", 356127412Sgad pargv[0]); 357127412Sgad pargv++; 358127412Sgad } 359127412Sgad mstr = buf; 360127412Sgad } else 361127425Sgad mstr = kp->ki_comm; 362127412Sgad 363127412Sgad rv = regexec(®, mstr, 1, ®match, 0); 364127412Sgad if (rv == 0) { 365127412Sgad if (fullmatch) { 366127412Sgad if (regmatch.rm_so == 0 && 367127431Sgad regmatch.rm_eo == 368127431Sgad (off_t)strlen(mstr)) 369127412Sgad selected[i] = 1; 370127412Sgad } else 371127412Sgad selected[i] = 1; 372127412Sgad } else if (rv != REG_NOMATCH) { 373127412Sgad regerror(rv, ®, buf, sizeof(buf)); 374152521Spjd errx(STATUS_ERROR, 375152521Spjd "Regular expression evaluation error (%s)", 376152521Spjd buf); 377127412Sgad } 378127433Sgad if (debug_opt > 1) { 379127433Sgad const char *rv_res = "NoMatch"; 380127433Sgad if (selected[i]) 381127433Sgad rv_res = "Matched"; 382127434Sgad fprintf(stderr, "* %s %5d %3d %s\n", rv_res, 383127433Sgad kp->ki_pid, kp->ki_uid, mstr); 384127433Sgad } 385127412Sgad } 386127412Sgad 387127412Sgad regfree(®); 388127412Sgad } 389127412Sgad 390127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 391143877Spjd if (PSKIP(kp)) 392127412Sgad continue; 393127412Sgad 394143874Spjd if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { 395143874Spjd selected[i] = 0; 396143874Spjd continue; 397143874Spjd } 398143874Spjd 399127412Sgad SLIST_FOREACH(li, &ruidlist, li_chain) 400127425Sgad if (kp->ki_ruid == (uid_t)li->li_number) 401127412Sgad break; 402127412Sgad if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 403127412Sgad selected[i] = 0; 404127412Sgad continue; 405127412Sgad } 406127429Sgad 407127412Sgad SLIST_FOREACH(li, &rgidlist, li_chain) 408127425Sgad if (kp->ki_rgid == (gid_t)li->li_number) 409127412Sgad break; 410127412Sgad if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 411127412Sgad selected[i] = 0; 412127412Sgad continue; 413127412Sgad } 414127412Sgad 415127412Sgad SLIST_FOREACH(li, &euidlist, li_chain) 416127425Sgad if (kp->ki_uid == (uid_t)li->li_number) 417127412Sgad break; 418127412Sgad if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 419127412Sgad selected[i] = 0; 420127412Sgad continue; 421127412Sgad } 422127412Sgad 423127412Sgad SLIST_FOREACH(li, &ppidlist, li_chain) 424127426Sgad if (kp->ki_ppid == (pid_t)li->li_number) 425127412Sgad break; 426127412Sgad if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 427127412Sgad selected[i] = 0; 428127412Sgad continue; 429127412Sgad } 430127412Sgad 431127412Sgad SLIST_FOREACH(li, &pgrplist, li_chain) 432127426Sgad if (kp->ki_pgid == (pid_t)li->li_number) 433127412Sgad break; 434127412Sgad if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 435127412Sgad selected[i] = 0; 436127412Sgad continue; 437127412Sgad } 438127412Sgad 439127412Sgad SLIST_FOREACH(li, &tdevlist, li_chain) { 440127412Sgad if (li->li_number == -1 && 441127425Sgad (kp->ki_flag & P_CONTROLT) == 0) 442127412Sgad break; 443130640Sphk if (kp->ki_tdev == (dev_t)li->li_number) 444127412Sgad break; 445127412Sgad } 446127412Sgad if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 447127412Sgad selected[i] = 0; 448127412Sgad continue; 449127412Sgad } 450127412Sgad 451127412Sgad SLIST_FOREACH(li, &sidlist, li_chain) 452127426Sgad if (kp->ki_sid == (pid_t)li->li_number) 453127412Sgad break; 454127412Sgad if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 455127412Sgad selected[i] = 0; 456127412Sgad continue; 457127412Sgad } 458127412Sgad 459143873Spjd SLIST_FOREACH(li, &jidlist, li_chain) { 460164558Syar /* A particular jail ID, including 0 (not in jail) */ 461164558Syar if (kp->ki_jid == (int)li->li_number) 462164558Syar break; 463164558Syar /* Any jail */ 464164558Syar if (kp->ki_jid > 0 && li->li_number == -1) 465164558Syar break; 466143873Spjd } 467143873Spjd if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { 468143873Spjd selected[i] = 0; 469143873Spjd continue; 470143873Spjd } 471143873Spjd 472127412Sgad if (argc == 0) 473127412Sgad selected[i] = 1; 474127412Sgad } 475127412Sgad 476192242Sbrian if (!ancestors) { 477192242Sbrian pid = mypid; 478192242Sbrian while (pid) { 479192242Sbrian for (i = 0, kp = plist; i < nproc; i++, kp++) { 480192242Sbrian if (PSKIP(kp)) 481192242Sbrian continue; 482192242Sbrian if (kp->ki_pid == pid) { 483192242Sbrian selected[i] = 0; 484192242Sbrian pid = kp->ki_ppid; 485192242Sbrian break; 486192242Sbrian } 487192242Sbrian } 488192242Sbrian if (i == nproc) { 489192242Sbrian if (pid == mypid) 490192242Sbrian pid = getppid(); 491192242Sbrian else 492192242Sbrian break; /* Maybe we're in a jail ? */ 493192242Sbrian } 494192242Sbrian } 495192242Sbrian } 496192242Sbrian 497143878Spjd if (newest || oldest) { 498127430Sgad best_tval.tv_sec = 0; 499127430Sgad best_tval.tv_usec = 0; 500127412Sgad bestidx = -1; 501127412Sgad 502127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 503127412Sgad if (!selected[i]) 504127412Sgad continue; 505143878Spjd if (bestidx == -1) { 506143878Spjd /* The first entry of the list which matched. */ 507143878Spjd ; 508143878Spjd } else if (timercmp(&kp->ki_start, &best_tval, >)) { 509143878Spjd /* This entry is newer than previous "best". */ 510143879Spjd if (oldest) /* but we want the oldest */ 511143878Spjd continue; 512143878Spjd } else { 513143878Spjd /* This entry is older than previous "best". */ 514143879Spjd if (newest) /* but we want the newest */ 515143878Spjd continue; 516127412Sgad } 517143878Spjd /* This entry is better than previous "best" entry. */ 518143878Spjd best_tval.tv_sec = kp->ki_start.tv_sec; 519143878Spjd best_tval.tv_usec = kp->ki_start.tv_usec; 520143878Spjd bestidx = i; 521127412Sgad } 522127412Sgad 523127412Sgad memset(selected, 0, nproc); 524127412Sgad if (bestidx != -1) 525127412Sgad selected[bestidx] = 1; 526127412Sgad } 527127412Sgad 528127412Sgad /* 529127412Sgad * Take the appropriate action for each matched process, if any. 530127412Sgad */ 531209363Sbrian did_action = 0; 532127412Sgad for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 533143877Spjd if (PSKIP(kp)) 534127412Sgad continue; 535127412Sgad if (selected[i]) { 536209363Sbrian if (longfmt && !pgrep) { 537209363Sbrian did_action = 1; 538209363Sbrian printf("kill -%d %d\n", signum, kp->ki_pid); 539209363Sbrian } 540127412Sgad if (inverse) 541127412Sgad continue; 542127412Sgad } else if (!inverse) 543127412Sgad continue; 544152521Spjd rv |= (*action)(kp); 545127412Sgad } 546209363Sbrian if (!did_action && !pgrep && longfmt) 547209363Sbrian fprintf(stderr, 548209363Sbrian "No matching processes belonging to you were found\n"); 549127412Sgad 550127412Sgad exit(rv ? STATUS_MATCH : STATUS_NOMATCH); 551127412Sgad} 552127412Sgad 553152521Spjdstatic void 554127412Sgadusage(void) 555127412Sgad{ 556127412Sgad const char *ustr; 557127412Sgad 558127412Sgad if (pgrep) 559203802Spjd ustr = "[-LSfilnoqvx] [-d delim]"; 560127412Sgad else 561209363Sbrian ustr = "[-signal] [-ILfilnovx]"; 562127412Sgad 563127412Sgad fprintf(stderr, 564143874Spjd "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" 565143873Spjd " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n" 566143873Spjd " [-t tty] [-u euid] pattern ...\n", getprogname(), 567143873Spjd ustr); 568127412Sgad 569152521Spjd exit(STATUS_BADUSAGE); 570127412Sgad} 571127412Sgad 572152518Spjdstatic void 573152521Spjdshow_process(const struct kinfo_proc *kp) 574127412Sgad{ 575127412Sgad char **argv; 576127412Sgad 577203802Spjd if (quiet) { 578203802Spjd assert(pgrep); 579203802Spjd return; 580203802Spjd } 581152518Spjd if ((longfmt || !pgrep) && matchargs && 582143877Spjd (argv = kvm_getargv(kd, kp, 0)) != NULL) { 583127425Sgad printf("%d ", (int)kp->ki_pid); 584127412Sgad for (; *argv != NULL; argv++) { 585127412Sgad printf("%s", *argv); 586127412Sgad if (argv[1] != NULL) 587127412Sgad putchar(' '); 588127412Sgad } 589152518Spjd } else if (longfmt || !pgrep) 590127425Sgad printf("%d %s", (int)kp->ki_pid, kp->ki_comm); 591127412Sgad else 592127425Sgad printf("%d", (int)kp->ki_pid); 593152518Spjd} 594127412Sgad 595152521Spjdstatic int 596152521Spjdkillact(const struct kinfo_proc *kp) 597152518Spjd{ 598152518Spjd int ch, first; 599152518Spjd 600152518Spjd if (interactive) { 601152518Spjd /* 602152518Spjd * Be careful, ask before killing. 603152518Spjd */ 604152518Spjd printf("kill "); 605152518Spjd show_process(kp); 606152518Spjd printf("? "); 607152518Spjd fflush(stdout); 608152518Spjd first = ch = getchar(); 609152518Spjd while (ch != '\n' && ch != EOF) 610152518Spjd ch = getchar(); 611152518Spjd if (first != 'y' && first != 'Y') 612152521Spjd return (1); 613152518Spjd } 614152521Spjd if (kill(kp->ki_pid, signum) == -1) { 615152521Spjd /* 616152521Spjd * Check for ESRCH, which indicates that the process 617152521Spjd * disappeared between us matching it and us 618152521Spjd * signalling it; don't issue a warning about it. 619152521Spjd */ 620152521Spjd if (errno != ESRCH) 621152521Spjd warn("signalling pid %d", (int)kp->ki_pid); 622152521Spjd /* 623152521Spjd * Return 0 to indicate that the process should not be 624152521Spjd * considered a match, since we didn't actually get to 625152521Spjd * signal it. 626152521Spjd */ 627152521Spjd return (0); 628152521Spjd } 629152521Spjd return (1); 630152518Spjd} 631152518Spjd 632152521Spjdstatic int 633152521Spjdgrepact(const struct kinfo_proc *kp) 634152518Spjd{ 635152518Spjd 636152518Spjd show_process(kp); 637203802Spjd if (!quiet) 638203802Spjd printf("%s", delim); 639152521Spjd return (1); 640127412Sgad} 641127412Sgad 642152521Spjdstatic void 643127412Sgadmakelist(struct listhead *head, enum listtype type, char *src) 644127412Sgad{ 645127412Sgad struct list *li; 646127412Sgad struct passwd *pw; 647127412Sgad struct group *gr; 648127412Sgad struct stat st; 649183438Sed const char *cp; 650152521Spjd char *sp, *ep, buf[MAXPATHLEN]; 651127412Sgad int empty; 652127412Sgad 653127412Sgad empty = 1; 654127412Sgad 655127412Sgad while ((sp = strsep(&src, ",")) != NULL) { 656127412Sgad if (*sp == '\0') 657127412Sgad usage(); 658127412Sgad 659152521Spjd if ((li = malloc(sizeof(*li))) == NULL) { 660152521Spjd err(STATUS_ERROR, "Cannot allocate %zu bytes", 661152521Spjd sizeof(*li)); 662152521Spjd } 663152521Spjd 664127412Sgad SLIST_INSERT_HEAD(head, li, li_chain); 665127412Sgad empty = 0; 666127412Sgad 667152521Spjd li->li_number = (uid_t)strtol(sp, &ep, 0); 668152521Spjd if (*ep == '\0') { 669127412Sgad switch (type) { 670127412Sgad case LT_PGRP: 671127412Sgad if (li->li_number == 0) 672127412Sgad li->li_number = getpgrp(); 673127412Sgad break; 674127412Sgad case LT_SID: 675127412Sgad if (li->li_number == 0) 676127412Sgad li->li_number = getsid(mypid); 677127412Sgad break; 678164558Syar case LT_JID: 679164558Syar if (li->li_number < 0) 680164558Syar errx(STATUS_BADUSAGE, 681164558Syar "Negative jail ID `%s'", sp); 682164558Syar /* For compatibility with old -j */ 683164558Syar if (li->li_number == 0) 684164558Syar li->li_number = -1; /* any jail */ 685164558Syar break; 686201487Sobrien case LT_TTY: 687201487Sobrien if (li->li_number < 0) 688201487Sobrien errx(STATUS_BADUSAGE, 689201487Sobrien "Negative /dev/pts tty `%s'", sp); 690201487Sobrien snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s", 691201487Sobrien sp); 692201487Sobrien if (stat(buf, &st) != -1) 693201487Sobrien goto foundtty; 694201487Sobrien if (errno == ENOENT) 695201487Sobrien errx(STATUS_BADUSAGE, "No such tty: `" 696201487Sobrien _PATH_DEV "pts/%s'", sp); 697201487Sobrien err(STATUS_ERROR, "Cannot access `" 698201487Sobrien _PATH_DEV "pts/%s'", sp); 699201487Sobrien break; 700127412Sgad default: 701127412Sgad break; 702127412Sgad } 703127412Sgad continue; 704127412Sgad } 705127412Sgad 706127412Sgad switch (type) { 707127412Sgad case LT_USER: 708127412Sgad if ((pw = getpwnam(sp)) == NULL) 709152521Spjd errx(STATUS_BADUSAGE, "Unknown user `%s'", sp); 710127412Sgad li->li_number = pw->pw_uid; 711127412Sgad break; 712127412Sgad case LT_GROUP: 713127412Sgad if ((gr = getgrnam(sp)) == NULL) 714152521Spjd errx(STATUS_BADUSAGE, "Unknown group `%s'", sp); 715127412Sgad li->li_number = gr->gr_gid; 716127412Sgad break; 717127412Sgad case LT_TTY: 718127412Sgad if (strcmp(sp, "-") == 0) { 719127412Sgad li->li_number = -1; 720127412Sgad break; 721152521Spjd } else if (strcmp(sp, "co") == 0) { 722127430Sgad cp = "console"; 723152521Spjd } else { 724127430Sgad cp = sp; 725152521Spjd } 726127412Sgad 727183438Sed snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp); 728183502Sed if (stat(buf, &st) != -1) 729183502Sed goto foundtty; 730127412Sgad 731183502Sed snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp); 732183502Sed if (stat(buf, &st) != -1) 733183502Sed goto foundtty; 734127412Sgad 735183502Sed if (errno == ENOENT) 736183502Sed errx(STATUS_BADUSAGE, "No such tty: `%s'", sp); 737183502Sed err(STATUS_ERROR, "Cannot access `%s'", sp); 738183502Sed 739183502Sedfoundtty: if ((st.st_mode & S_IFCHR) == 0) 740152521Spjd errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp); 741127412Sgad 742127412Sgad li->li_number = st.st_rdev; 743127412Sgad break; 744164558Syar case LT_JID: 745164558Syar if (strcmp(sp, "none") == 0) 746164558Syar li->li_number = 0; 747164558Syar else if (strcmp(sp, "any") == 0) 748164558Syar li->li_number = -1; 749164558Syar else if (*ep != '\0') 750164558Syar errx(STATUS_BADUSAGE, 751164558Syar "Invalid jail ID `%s'", sp); 752164558Syar break; 753127412Sgad default: 754127412Sgad usage(); 755152521Spjd } 756127412Sgad } 757127412Sgad 758127412Sgad if (empty) 759127412Sgad usage(); 760127412Sgad} 761143874Spjd 762152521Spjdstatic int 763149471Spjdtakepid(const char *pidfile, int pidfilelock) 764143874Spjd{ 765143874Spjd char *endp, line[BUFSIZ]; 766143874Spjd FILE *fh; 767143874Spjd long rval; 768143879Spjd 769143874Spjd fh = fopen(pidfile, "r"); 770143874Spjd if (fh == NULL) 771152521Spjd err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); 772143879Spjd 773149471Spjd if (pidfilelock) { 774149471Spjd /* 775149471Spjd * If we can lock pidfile, this means that daemon is not 776149471Spjd * running, so would be better not to kill some random process. 777149471Spjd */ 778149471Spjd if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { 779149471Spjd (void)fclose(fh); 780152521Spjd errx(STATUS_ERROR, "File '%s' can be locked", pidfile); 781149471Spjd } else { 782149471Spjd if (errno != EWOULDBLOCK) { 783149471Spjd errx(STATUS_ERROR, 784152521Spjd "Error while locking file '%s'", pidfile); 785149471Spjd } 786149435Spjd } 787149435Spjd } 788149435Spjd 789143874Spjd if (fgets(line, sizeof(line), fh) == NULL) { 790143874Spjd if (feof(fh)) { 791143874Spjd (void)fclose(fh); 792152521Spjd errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); 793143874Spjd } 794143874Spjd (void)fclose(fh); 795152521Spjd err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); 796143874Spjd } 797143874Spjd (void)fclose(fh); 798143879Spjd 799143874Spjd rval = strtol(line, &endp, 10); 800143874Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) 801152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 802143874Spjd else if (rval < MIN_PID || rval > MAX_PID) 803152521Spjd errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 804143874Spjd return (rval); 805143874Spjd} 806