1*9d92ab4fSroy /* $NetBSD: pkill.c,v 1.34 2024/10/07 06:14:05 roy Exp $ */ 23b8a0d4fSad 33b8a0d4fSad /*- 46b00e6e9Sad * Copyright (c) 2002, 2022 The NetBSD Foundation, Inc. 53b8a0d4fSad * All rights reserved. 63b8a0d4fSad * 73b8a0d4fSad * This code is derived from software contributed to The NetBSD Foundation 83b8a0d4fSad * by Andrew Doran. 93b8a0d4fSad * 103b8a0d4fSad * Redistribution and use in source and binary forms, with or without 113b8a0d4fSad * modification, are permitted provided that the following conditions 123b8a0d4fSad * are met: 133b8a0d4fSad * 1. Redistributions of source code must retain the above copyright 143b8a0d4fSad * notice, this list of conditions and the following disclaimer. 153b8a0d4fSad * 2. Redistributions in binary form must reproduce the above copyright 163b8a0d4fSad * notice, this list of conditions and the following disclaimer in the 173b8a0d4fSad * documentation and/or other materials provided with the distribution. 183b8a0d4fSad * 193b8a0d4fSad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 203b8a0d4fSad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 213b8a0d4fSad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 223b8a0d4fSad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 233b8a0d4fSad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 243b8a0d4fSad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 253b8a0d4fSad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 263b8a0d4fSad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 273b8a0d4fSad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 283b8a0d4fSad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 293b8a0d4fSad * POSSIBILITY OF SUCH DAMAGE. 303b8a0d4fSad */ 313b8a0d4fSad 323b8a0d4fSad #include <sys/cdefs.h> 3338b296bfSad #ifndef lint 34*9d92ab4fSroy __RCSID("$NetBSD: pkill.c,v 1.34 2024/10/07 06:14:05 roy Exp $"); 3538b296bfSad #endif /* !lint */ 363b8a0d4fSad 373b8a0d4fSad #include <sys/types.h> 383b8a0d4fSad #include <sys/param.h> 393b8a0d4fSad #include <sys/sysctl.h> 403b8a0d4fSad #include <sys/proc.h> 413b8a0d4fSad #include <sys/queue.h> 42b374a568Sdsl #include <sys/resource.h> 433b8a0d4fSad #include <sys/stat.h> 443b8a0d4fSad 453b8a0d4fSad #include <stdio.h> 463b8a0d4fSad #include <stdlib.h> 473b8a0d4fSad #include <limits.h> 483b8a0d4fSad #include <string.h> 493b8a0d4fSad #include <unistd.h> 503b8a0d4fSad #include <signal.h> 513b8a0d4fSad #include <regex.h> 523b8a0d4fSad #include <ctype.h> 533b8a0d4fSad #include <kvm.h> 543b8a0d4fSad #include <err.h> 55*9d92ab4fSroy #include <fcntl.h> 563b8a0d4fSad #include <pwd.h> 573b8a0d4fSad #include <grp.h> 583b8a0d4fSad #include <errno.h> 59140eaa6eSchristos #include <paths.h> 603b8a0d4fSad 613b8a0d4fSad #define STATUS_MATCH 0 623b8a0d4fSad #define STATUS_NOMATCH 1 633b8a0d4fSad #define STATUS_BADUSAGE 2 643b8a0d4fSad #define STATUS_ERROR 3 653b8a0d4fSad 66*9d92ab4fSroy #define MIN_PID 5 67*9d92ab4fSroy #define MAX_PID 30000 // XXX PID_MAX from sys/proc.h? 68*9d92ab4fSroy 693b8a0d4fSad enum listtype { 703b8a0d4fSad LT_GENERIC, 713b8a0d4fSad LT_USER, 723b8a0d4fSad LT_GROUP, 733b8a0d4fSad LT_TTY, 743b8a0d4fSad LT_PGRP, 753b8a0d4fSad LT_SID 763b8a0d4fSad }; 773b8a0d4fSad 783b8a0d4fSad struct list { 793b8a0d4fSad SLIST_ENTRY(list) li_chain; 803b8a0d4fSad long li_number; 813b8a0d4fSad }; 823b8a0d4fSad 833b8a0d4fSad SLIST_HEAD(listhead, list); 843b8a0d4fSad 85140eaa6eSchristos static struct kinfo_proc2 *plist; 86140eaa6eSchristos static char *selected; 87140eaa6eSchristos static const char *delim = "\n"; 88140eaa6eSchristos static int nproc; 89140eaa6eSchristos static int pgrep; 9079ffd9c9Smrg static int prenice; 91140eaa6eSchristos static int signum = SIGTERM; 9279ffd9c9Smrg static int nicenum; 93140eaa6eSchristos static int newest; 9449ef36ceSsimonb static int quiet; 95140eaa6eSchristos static int inverse; 96140eaa6eSchristos static int longfmt; 97140eaa6eSchristos static int matchargs; 98140eaa6eSchristos static int fullmatch; 99140eaa6eSchristos static int cflags = REG_EXTENDED; 100140eaa6eSchristos static kvm_t *kd; 101140eaa6eSchristos static pid_t mypid; 1023b8a0d4fSad 103140eaa6eSchristos static struct listhead euidlist = SLIST_HEAD_INITIALIZER(list); 104140eaa6eSchristos static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list); 105140eaa6eSchristos static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list); 106140eaa6eSchristos static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list); 107140eaa6eSchristos static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list); 108140eaa6eSchristos static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list); 109140eaa6eSchristos static struct listhead sidlist = SLIST_HEAD_INITIALIZER(list); 1103b8a0d4fSad 1118b0f9554Sperry static void usage(void) __dead; 112de094613Sdsainty static int killact(const struct kinfo_proc2 *); 11379ffd9c9Smrg static int reniceact(const struct kinfo_proc2 *); 114de094613Sdsainty static int grepact(const struct kinfo_proc2 *); 115140eaa6eSchristos static void makelist(struct listhead *, enum listtype, char *); 116*9d92ab4fSroy static int takepid(const char *, int); 1173b8a0d4fSad 1183b8a0d4fSad int 1193b8a0d4fSad main(int argc, char **argv) 1203b8a0d4fSad { 121*9d92ab4fSroy char buf[_POSIX2_LINE_MAX], **pargv, *q, *pidfile = NULL; 122*9d92ab4fSroy int i, j, ch, bestidx, rv, criteria, pidfromfile, pidfilelock = 0; 123de094613Sdsainty int (*action)(const struct kinfo_proc2 *); 124de094613Sdsainty const struct kinfo_proc2 *kp; 1253b8a0d4fSad struct list *li; 1261524d388Schristos const char *p; 1273b8a0d4fSad u_int32_t bestsec, bestusec; 1283b8a0d4fSad regex_t reg; 1293b8a0d4fSad regmatch_t regmatch; 1303b8a0d4fSad 131140eaa6eSchristos setprogname(argv[0]); 132140eaa6eSchristos 1333b8a0d4fSad if (strcmp(getprogname(), "pgrep") == 0) { 1343b8a0d4fSad action = grepact; 1353b8a0d4fSad pgrep = 1; 13679ffd9c9Smrg } else if (strcmp(getprogname(), "prenice") == 0) { 1378707c3a3Sprlw1 action = reniceact; 13879ffd9c9Smrg prenice = 1; 1393b8a0d4fSad } else { 1403b8a0d4fSad action = killact; 1413b8a0d4fSad p = argv[1]; 1423b8a0d4fSad 143ee19c521Saugustss if (argc > 1 && p[0] == '-') { 1443b8a0d4fSad p++; 145ee19c521Saugustss i = (int)strtol(p, &q, 10); 146ee19c521Saugustss if (*q == '\0') { 1473b8a0d4fSad signum = i; 1483b8a0d4fSad argv++; 149ee19c521Saugustss argc--; 1503b8a0d4fSad } else { 1513b8a0d4fSad if (strncasecmp(p, "sig", 3) == 0) 1523b8a0d4fSad p += 3; 1533b8a0d4fSad for (i = 1; i < NSIG; i++) 1543b8a0d4fSad if (strcasecmp(sys_signame[i], p) == 0) 1553b8a0d4fSad break; 1563b8a0d4fSad if (i != NSIG) { 1573b8a0d4fSad signum = i; 1583b8a0d4fSad argv++; 159ee19c521Saugustss argc--; 1603b8a0d4fSad } 1613b8a0d4fSad } 1623b8a0d4fSad } 1633b8a0d4fSad } 1643b8a0d4fSad 1653b8a0d4fSad criteria = 0; 1663b8a0d4fSad 167f2e89618Smrg if (prenice) { 168f2e89618Smrg if (argc < 2) 169f2e89618Smrg usage(); 170f2e89618Smrg 171f2e89618Smrg if (strcmp(argv[1], "-l") == 0) { 172f2e89618Smrg longfmt = 1; 173f2e89618Smrg argv++; 174f2e89618Smrg argc--; 175f2e89618Smrg } 176f2e89618Smrg 177f2e89618Smrg if (argc < 2) 178f2e89618Smrg usage(); 179f2e89618Smrg 180f2e89618Smrg p = argv[1]; 181f2e89618Smrg 182f2e89618Smrg i = (int)strtol(p, &q, 10); 183f2e89618Smrg if (*q == '\0') { 184f2e89618Smrg nicenum = i; 185f2e89618Smrg argv++; 186f2e89618Smrg argc--; 187f2e89618Smrg } else 188f2e89618Smrg usage(); 189f2e89618Smrg } else { 190*9d92ab4fSroy while ((ch = getopt(argc, argv, "F:G:LP:U:d:fg:ilnqs:t:u:vx")) != -1) 1913b8a0d4fSad switch (ch) { 192*9d92ab4fSroy case 'F': 193*9d92ab4fSroy pidfile = optarg; 194*9d92ab4fSroy criteria = 1; 195*9d92ab4fSroy break; 1963b8a0d4fSad case 'G': 1973b8a0d4fSad makelist(&rgidlist, LT_GROUP, optarg); 1983b8a0d4fSad criteria = 1; 1993b8a0d4fSad break; 200*9d92ab4fSroy case 'L': 201*9d92ab4fSroy pidfilelock = 1; 202*9d92ab4fSroy break; 2033b8a0d4fSad case 'P': 2043b8a0d4fSad makelist(&ppidlist, LT_GENERIC, optarg); 2053b8a0d4fSad criteria = 1; 2063b8a0d4fSad break; 2073b8a0d4fSad case 'U': 2083b8a0d4fSad makelist(&ruidlist, LT_USER, optarg); 2093b8a0d4fSad criteria = 1; 2103b8a0d4fSad break; 2113b8a0d4fSad case 'd': 2123b8a0d4fSad if (!pgrep) 2133b8a0d4fSad usage(); 2143b8a0d4fSad delim = optarg; 2153b8a0d4fSad break; 2163b8a0d4fSad case 'f': 2173b8a0d4fSad matchargs = 1; 2183b8a0d4fSad break; 2193b8a0d4fSad case 'g': 2203b8a0d4fSad makelist(&pgrplist, LT_PGRP, optarg); 2213b8a0d4fSad criteria = 1; 2223b8a0d4fSad break; 2238e587b4cSsketch case 'i': 2248e587b4cSsketch cflags |= REG_ICASE; 2258e587b4cSsketch break; 2263b8a0d4fSad case 'l': 2273b8a0d4fSad longfmt = 1; 2283b8a0d4fSad break; 2293b8a0d4fSad case 'n': 2303b8a0d4fSad newest = 1; 2313b8a0d4fSad criteria = 1; 2323b8a0d4fSad break; 23349ef36ceSsimonb case 'q': 23449ef36ceSsimonb if (!pgrep) 23549ef36ceSsimonb usage(); 23649ef36ceSsimonb quiet = 1; 23749ef36ceSsimonb break; 2383b8a0d4fSad case 's': 2393b8a0d4fSad makelist(&sidlist, LT_SID, optarg); 2403b8a0d4fSad criteria = 1; 2413b8a0d4fSad break; 2423b8a0d4fSad case 't': 2433b8a0d4fSad makelist(&tdevlist, LT_TTY, optarg); 2443b8a0d4fSad criteria = 1; 2453b8a0d4fSad break; 2463b8a0d4fSad case 'u': 2473b8a0d4fSad makelist(&euidlist, LT_USER, optarg); 2483b8a0d4fSad criteria = 1; 2493b8a0d4fSad break; 2503b8a0d4fSad case 'v': 2513b8a0d4fSad inverse = 1; 2523b8a0d4fSad break; 2533b8a0d4fSad case 'x': 2543b8a0d4fSad fullmatch = 1; 2553b8a0d4fSad break; 2563b8a0d4fSad default: 2573b8a0d4fSad usage(); 2583b8a0d4fSad /* NOTREACHED */ 2593b8a0d4fSad } 2603b8a0d4fSad argc -= optind; 2613b8a0d4fSad argv += optind; 262f2e89618Smrg } 263f2e89618Smrg 2643b8a0d4fSad if (argc != 0) 2653b8a0d4fSad criteria = 1; 2663b8a0d4fSad if (!criteria) 2673b8a0d4fSad usage(); 268*9d92ab4fSroy if (pidfile != NULL) 269*9d92ab4fSroy pidfromfile = takepid(pidfile, pidfilelock); 270*9d92ab4fSroy else { 271*9d92ab4fSroy if (pidfilelock) { 272*9d92ab4fSroy errx(STATUS_ERROR, 273*9d92ab4fSroy "Option -L doesn't make sense without -F"); 274*9d92ab4fSroy } 275*9d92ab4fSroy pidfromfile = -1; 276*9d92ab4fSroy } 2773b8a0d4fSad 2783b8a0d4fSad mypid = getpid(); 2793b8a0d4fSad 2803b8a0d4fSad /* 2813b8a0d4fSad * Retrieve the list of running processes from the kernel. 2823b8a0d4fSad */ 2833b8a0d4fSad kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf); 2843b8a0d4fSad if (kd == NULL) 285140eaa6eSchristos errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); 2863b8a0d4fSad 2873b8a0d4fSad plist = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc); 2883b8a0d4fSad if (plist == NULL) 289140eaa6eSchristos errx(STATUS_ERROR, "Cannot get process list (%s)", 290140eaa6eSchristos kvm_geterr(kd)); 2913b8a0d4fSad 2923b8a0d4fSad /* 2933b8a0d4fSad * Allocate memory which will be used to keep track of the 2943b8a0d4fSad * selection. 2953b8a0d4fSad */ 2966b00e6e9Sad if ((selected = calloc(sizeof(*selected), (size_t)nproc)) == NULL) 297140eaa6eSchristos err(STATUS_ERROR, "Cannot allocate memory for %d processes", 298140eaa6eSchristos nproc); 2993b8a0d4fSad 3003b8a0d4fSad /* 3013b8a0d4fSad * Refine the selection. 3023b8a0d4fSad */ 3033b8a0d4fSad for (; *argv != NULL; argv++) { 3048e587b4cSsketch if ((rv = regcomp(®, *argv, cflags)) != 0) { 30541d3ce98Schristos (void)regerror(rv, ®, buf, sizeof(buf)); 306140eaa6eSchristos errx(STATUS_BADUSAGE, 307140eaa6eSchristos "Cannot compile regular expression `%s' (%s)", 308140eaa6eSchristos *argv, buf); 3093b8a0d4fSad } 3103b8a0d4fSad 3113b8a0d4fSad for (i = 0, kp = plist; i < nproc; i++, kp++) { 312f5e7ca24Spavel if ((kp->p_flag & P_SYSTEM) != 0 || kp->p_pid == mypid) 3133b8a0d4fSad continue; 3143b8a0d4fSad 3153b8a0d4fSad if ((pargv = kvm_getargv2(kd, kp, 0)) == NULL) 3163b8a0d4fSad continue; 3171524d388Schristos if (matchargs) { 3183b8a0d4fSad 3193b8a0d4fSad j = 0; 320ba2ed01cSlukem while (j < (int)sizeof(buf) && *pargv != NULL) { 3213b8a0d4fSad j += snprintf(buf + j, sizeof(buf) - j, 3223b8a0d4fSad pargv[1] != NULL ? "%s " : "%s", 3233b8a0d4fSad pargv[0]); 3243b8a0d4fSad pargv++; 3253b8a0d4fSad } 326d7b1a047Skre } else if (pargv[0] != NULL) 3271524d388Schristos strlcpy(buf, pargv[0], sizeof(buf)); 328d7b1a047Skre else 329d7b1a047Skre strlcpy(buf, kp->p_comm, sizeof(buf)); 3303b8a0d4fSad 3311524d388Schristos rv = regexec(®, buf, 1, ®match, 0); 3323b8a0d4fSad if (rv == 0) { 3333b8a0d4fSad if (fullmatch) { 3343b8a0d4fSad if (regmatch.rm_so == 0 && 3351524d388Schristos regmatch.rm_eo == 3361524d388Schristos (regoff_t)strlen(buf)) 3373b8a0d4fSad selected[i] = 1; 3383b8a0d4fSad } else 3393b8a0d4fSad selected[i] = 1; 3403b8a0d4fSad } else if (rv != REG_NOMATCH) { 34141d3ce98Schristos (void)regerror(rv, ®, buf, sizeof(buf)); 342140eaa6eSchristos errx(STATUS_ERROR, 343140eaa6eSchristos "Regular expression evaluation error (%s)", 344140eaa6eSchristos buf); 3453b8a0d4fSad } 3463b8a0d4fSad } 3473b8a0d4fSad 3483b8a0d4fSad regfree(®); 3493b8a0d4fSad } 3503b8a0d4fSad 3513b8a0d4fSad for (i = 0, kp = plist; i < nproc; i++, kp++) { 352f5e7ca24Spavel if ((kp->p_flag & P_SYSTEM) != 0) 3533b8a0d4fSad continue; 3543b8a0d4fSad 355*9d92ab4fSroy if (pidfromfile >= 0 && kp->p_pid != pidfromfile) { 356*9d92ab4fSroy selected[i] = 0; 357*9d92ab4fSroy continue; 358*9d92ab4fSroy } 359*9d92ab4fSroy 3603b8a0d4fSad SLIST_FOREACH(li, &ruidlist, li_chain) 3613b8a0d4fSad if (kp->p_ruid == (uid_t)li->li_number) 3623b8a0d4fSad break; 3633b8a0d4fSad if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 3643b8a0d4fSad selected[i] = 0; 3653b8a0d4fSad continue; 3663b8a0d4fSad } 3673b8a0d4fSad 3683b8a0d4fSad SLIST_FOREACH(li, &rgidlist, li_chain) 3693b8a0d4fSad if (kp->p_rgid == (gid_t)li->li_number) 3703b8a0d4fSad break; 3713b8a0d4fSad if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 3723b8a0d4fSad selected[i] = 0; 3733b8a0d4fSad continue; 3743b8a0d4fSad } 3753b8a0d4fSad 3763b8a0d4fSad SLIST_FOREACH(li, &euidlist, li_chain) 3773b8a0d4fSad if (kp->p_uid == (uid_t)li->li_number) 3783b8a0d4fSad break; 3793b8a0d4fSad if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 3803b8a0d4fSad selected[i] = 0; 3813b8a0d4fSad continue; 3823b8a0d4fSad } 3833b8a0d4fSad 3843b8a0d4fSad SLIST_FOREACH(li, &ppidlist, li_chain) 385ba2ed01cSlukem if ((uid_t)kp->p_ppid == (uid_t)li->li_number) 3863b8a0d4fSad break; 3873b8a0d4fSad if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 3883b8a0d4fSad selected[i] = 0; 3893b8a0d4fSad continue; 3903b8a0d4fSad } 3913b8a0d4fSad 3923b8a0d4fSad SLIST_FOREACH(li, &pgrplist, li_chain) 393ba2ed01cSlukem if (kp->p__pgid == (pid_t)li->li_number) 3943b8a0d4fSad break; 3953b8a0d4fSad if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 3963b8a0d4fSad selected[i] = 0; 3973b8a0d4fSad continue; 3983b8a0d4fSad } 3993b8a0d4fSad 4003b8a0d4fSad SLIST_FOREACH(li, &tdevlist, li_chain) { 4013b8a0d4fSad if (li->li_number == -1 && 402f5e7ca24Spavel (kp->p_flag & P_CONTROLT) == 0) 4033b8a0d4fSad break; 4043b8a0d4fSad if (kp->p_tdev == (uid_t)li->li_number) 4053b8a0d4fSad break; 4063b8a0d4fSad } 4073b8a0d4fSad if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 4083b8a0d4fSad selected[i] = 0; 4093b8a0d4fSad continue; 4103b8a0d4fSad } 4113b8a0d4fSad 4123b8a0d4fSad SLIST_FOREACH(li, &sidlist, li_chain) 413ba2ed01cSlukem if (kp->p_sid == (pid_t)li->li_number) 4143b8a0d4fSad break; 4153b8a0d4fSad if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 4163b8a0d4fSad selected[i] = 0; 4173b8a0d4fSad continue; 4183b8a0d4fSad } 4193b8a0d4fSad 4203b8a0d4fSad if (argc == 0) 4213b8a0d4fSad selected[i] = 1; 4223b8a0d4fSad } 4233b8a0d4fSad 4243b8a0d4fSad if (newest) { 4253b8a0d4fSad bestsec = 0; 4263b8a0d4fSad bestusec = 0; 4273b8a0d4fSad bestidx = -1; 4283b8a0d4fSad 4293b8a0d4fSad for (i = 0, kp = plist; i < nproc; i++, kp++) { 4303b8a0d4fSad if (!selected[i]) 4313b8a0d4fSad continue; 4323b8a0d4fSad 4333b8a0d4fSad if (kp->p_ustart_sec > bestsec || 4343b8a0d4fSad (kp->p_ustart_sec == bestsec 4353b8a0d4fSad && kp->p_ustart_usec > bestusec)) { 4363b8a0d4fSad bestsec = kp->p_ustart_sec; 4373b8a0d4fSad bestusec = kp->p_ustart_usec; 4383b8a0d4fSad bestidx = i; 4393b8a0d4fSad } 4403b8a0d4fSad } 4413b8a0d4fSad 44241d3ce98Schristos (void)memset(selected, 0, (size_t)nproc); 4433b8a0d4fSad if (bestidx != -1) 4443b8a0d4fSad selected[bestidx] = 1; 4453b8a0d4fSad } 4463b8a0d4fSad 4473b8a0d4fSad /* 4483b8a0d4fSad * Take the appropriate action for each matched process, if any. 4493b8a0d4fSad */ 4503b8a0d4fSad for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 4513b8a0d4fSad if (kp->p_pid == mypid) 4523b8a0d4fSad continue; 4533b8a0d4fSad if (selected[i]) { 4543b8a0d4fSad if (inverse) 4553b8a0d4fSad continue; 4563b8a0d4fSad } else if (!inverse) 4573b8a0d4fSad continue; 4583b8a0d4fSad 459f5e7ca24Spavel if ((kp->p_flag & P_SYSTEM) != 0) 460eabe280bSad continue; 461eabe280bSad 462078c5c1aSchristos rv |= (*action)(kp); 4633b8a0d4fSad } 4643b8a0d4fSad 46541d3ce98Schristos return rv ? STATUS_MATCH : STATUS_NOMATCH; 4663b8a0d4fSad } 4673b8a0d4fSad 468140eaa6eSchristos static void 4693b8a0d4fSad usage(void) 4703b8a0d4fSad { 4713b8a0d4fSad const char *ustr; 4723b8a0d4fSad 47379ffd9c9Smrg if (prenice) 474f2e89618Smrg fprintf(stderr, "Usage: %s [-l] priority pattern ...\n", 47579ffd9c9Smrg getprogname()); 47679ffd9c9Smrg else { 4773b8a0d4fSad if (pgrep) 478*9d92ab4fSroy ustr = "[-Lfilnqvx] [-d delim]"; 4793b8a0d4fSad else 480*9d92ab4fSroy ustr = "[-signal] [-Lfilnvx]"; 4813b8a0d4fSad 482140eaa6eSchristos (void)fprintf(stderr, 483*9d92ab4fSroy "Usage: %s %s [-F pidfile] [-G gid] [-g pgrp] [-P ppid] [-s sid] " 48479ffd9c9Smrg "[-t tty]\n" 48579ffd9c9Smrg " [-U uid] [-u euid] pattern ...\n", 48679ffd9c9Smrg getprogname(), ustr); 48779ffd9c9Smrg } 4883b8a0d4fSad 48970316522Skleink exit(STATUS_BADUSAGE); 4903b8a0d4fSad } 4913b8a0d4fSad 492140eaa6eSchristos static int 493de094613Sdsainty killact(const struct kinfo_proc2 *kp) 4943b8a0d4fSad { 495de96a26eSerh if (longfmt) 496de96a26eSerh grepact(kp); 497078c5c1aSchristos if (kill(kp->p_pid, signum) == -1) { 4980de40530Sdsainty 499078c5c1aSchristos /* 5000de40530Sdsainty * Check for ESRCH, which indicates that the process 5010de40530Sdsainty * disappeared between us matching it and us 502a050a273Skleink * signalling it; don't issue a warning about it. 503078c5c1aSchristos */ 504a050a273Skleink if (errno != ESRCH) 505a050a273Skleink warn("signalling pid %d", (int)kp->p_pid); 5063b8a0d4fSad 507a050a273Skleink /* 508a050a273Skleink * Return 0 to indicate that the process should not be 509a050a273Skleink * considered a match, since we didn't actually get to 510a050a273Skleink * signal it. 511a050a273Skleink */ 512a050a273Skleink return 0; 5133b8a0d4fSad } 5143b8a0d4fSad 515078c5c1aSchristos return 1; 516078c5c1aSchristos } 517078c5c1aSchristos 518140eaa6eSchristos static int 51979ffd9c9Smrg reniceact(const struct kinfo_proc2 *kp) 52079ffd9c9Smrg { 52179ffd9c9Smrg int oldprio; 52279ffd9c9Smrg 52379ffd9c9Smrg if (longfmt) 52479ffd9c9Smrg grepact(kp); 52579ffd9c9Smrg 52679ffd9c9Smrg errno = 0; 52779ffd9c9Smrg if ((oldprio = getpriority(PRIO_PROCESS, kp->p_pid)) == -1 && 52879ffd9c9Smrg errno != 0) { 52979ffd9c9Smrg warn("%d: getpriority", kp->p_pid); 53079ffd9c9Smrg return 0; 53179ffd9c9Smrg } 53279ffd9c9Smrg 53379ffd9c9Smrg if (setpriority(PRIO_PROCESS, kp->p_pid, nicenum) == -1) { 53479ffd9c9Smrg warn("%d: setpriority", kp->p_pid); 53579ffd9c9Smrg return 0; 53679ffd9c9Smrg } 53779ffd9c9Smrg 53879ffd9c9Smrg (void)printf("%d: old priority %d, new priority %d\n", 53979ffd9c9Smrg kp->p_pid, oldprio, nicenum); 54079ffd9c9Smrg 54179ffd9c9Smrg return 1; 54279ffd9c9Smrg } 54379ffd9c9Smrg 54479ffd9c9Smrg static int 545de094613Sdsainty grepact(const struct kinfo_proc2 *kp) 5463b8a0d4fSad { 5473b8a0d4fSad char **argv; 5483b8a0d4fSad 54949ef36ceSsimonb if (quiet) 55049ef36ceSsimonb return 1; 55149ef36ceSsimonb 5523b8a0d4fSad if (longfmt && matchargs) { 5530de40530Sdsainty 554078c5c1aSchristos /* 5550de40530Sdsainty * If kvm_getargv2() failed the process has probably 5560de40530Sdsainty * disappeared. Return 0 to indicate that the process 5570de40530Sdsainty * should not be considered a match, since we are no 5580de40530Sdsainty * longer in a position to output it as a match. 559078c5c1aSchristos */ 5600de40530Sdsainty if ((argv = kvm_getargv2(kd, kp, 0)) == NULL) 561078c5c1aSchristos return 0; 5623b8a0d4fSad 563140eaa6eSchristos (void)printf("%d ", (int)kp->p_pid); 5643b8a0d4fSad for (; *argv != NULL; argv++) { 565140eaa6eSchristos (void)printf("%s", *argv); 5663b8a0d4fSad if (argv[1] != NULL) 567140eaa6eSchristos (void)putchar(' '); 5683b8a0d4fSad } 5693b8a0d4fSad } else if (longfmt) 570140eaa6eSchristos (void)printf("%d %s", (int)kp->p_pid, kp->p_comm); 5713b8a0d4fSad else 572140eaa6eSchristos (void)printf("%d", (int)kp->p_pid); 5733b8a0d4fSad 574140eaa6eSchristos (void)printf("%s", delim); 575078c5c1aSchristos 576078c5c1aSchristos return 1; 5773b8a0d4fSad } 5783b8a0d4fSad 579140eaa6eSchristos static void 5803b8a0d4fSad makelist(struct listhead *head, enum listtype type, char *src) 5813b8a0d4fSad { 5823b8a0d4fSad struct list *li; 5833b8a0d4fSad struct passwd *pw; 5843b8a0d4fSad struct group *gr; 5853b8a0d4fSad struct stat st; 586140eaa6eSchristos char *sp, *ep, buf[MAXPATHLEN]; 587140eaa6eSchristos const char *p; 5883b8a0d4fSad int empty; 589140eaa6eSchristos const char *prefix = _PATH_DEV; 5903b8a0d4fSad 5913b8a0d4fSad empty = 1; 5923b8a0d4fSad 5933b8a0d4fSad while ((sp = strsep(&src, ",")) != NULL) { 5943b8a0d4fSad if (*sp == '\0') 5953b8a0d4fSad usage(); 5963b8a0d4fSad 5973b8a0d4fSad if ((li = malloc(sizeof(*li))) == NULL) 5981524d388Schristos err(STATUS_ERROR, "Cannot allocate %zu bytes", 599140eaa6eSchristos sizeof(*li)); 6003b8a0d4fSad SLIST_INSERT_HEAD(head, li, li_chain); 6013b8a0d4fSad empty = 0; 6023b8a0d4fSad 603140eaa6eSchristos li->li_number = (uid_t)strtol(sp, &ep, 0); 604b90f233bSchristos if (*ep == '\0' && type != LT_TTY) { 6053b8a0d4fSad switch (type) { 6063b8a0d4fSad case LT_PGRP: 6073b8a0d4fSad if (li->li_number == 0) 6083b8a0d4fSad li->li_number = getpgrp(); 6093b8a0d4fSad break; 6103b8a0d4fSad case LT_SID: 6113b8a0d4fSad if (li->li_number == 0) 6123b8a0d4fSad li->li_number = getsid(mypid); 6133b8a0d4fSad break; 6143b8a0d4fSad default: 6153b8a0d4fSad break; 6163b8a0d4fSad } 6173b8a0d4fSad continue; 6183b8a0d4fSad } 6193b8a0d4fSad 6203b8a0d4fSad switch (type) { 6213b8a0d4fSad case LT_USER: 6223b8a0d4fSad if ((pw = getpwnam(sp)) == NULL) 623140eaa6eSchristos errx(STATUS_BADUSAGE, "Unknown user `%s'", 62424cba1acSabs sp); 6253b8a0d4fSad li->li_number = pw->pw_uid; 6263b8a0d4fSad break; 6273b8a0d4fSad case LT_GROUP: 6283b8a0d4fSad if ((gr = getgrnam(sp)) == NULL) 629140eaa6eSchristos errx(STATUS_BADUSAGE, "Unknown group `%s'", 63024cba1acSabs sp); 6313b8a0d4fSad li->li_number = gr->gr_gid; 6323b8a0d4fSad break; 6333b8a0d4fSad case LT_TTY: 634b90f233bSchristos p = sp; 635b90f233bSchristos if (*sp == '/') 636b90f233bSchristos prefix = ""; 637b90f233bSchristos else if (strcmp(sp, "-") == 0) { 6383b8a0d4fSad li->li_number = -1; 6393b8a0d4fSad break; 6403b8a0d4fSad } else if (strcmp(sp, "co") == 0) 6413b8a0d4fSad p = "console"; 6423b8a0d4fSad else if (strncmp(sp, "tty", 3) == 0) 643b90f233bSchristos /* all set */; 644b90f233bSchristos else if (strncmp(sp, "pts/", 4) == 0) 645b90f233bSchristos /* all set */; 646b90f233bSchristos else if (*ep != '\0' || (strlen(sp) == 2 && *sp == '0')) 647140eaa6eSchristos prefix = _PATH_TTY; 648b90f233bSchristos else 649b90f233bSchristos prefix = _PATH_DEV_PTS; 6503b8a0d4fSad 651140eaa6eSchristos (void)snprintf(buf, sizeof(buf), "%s%s", prefix, p); 6523b8a0d4fSad 653140eaa6eSchristos if (stat(buf, &st) == -1) { 6543b8a0d4fSad if (errno == ENOENT) 6553b8a0d4fSad errx(STATUS_BADUSAGE, 656b90f233bSchristos "No such tty: `%s'", buf); 657b90f233bSchristos err(STATUS_ERROR, "Cannot access `%s'", buf); 6583b8a0d4fSad } 6593b8a0d4fSad 6603b8a0d4fSad if ((st.st_mode & S_IFCHR) == 0) 661b90f233bSchristos errx(STATUS_BADUSAGE, "Not a tty: `%s'", buf); 6623b8a0d4fSad 6633b8a0d4fSad li->li_number = st.st_rdev; 6643b8a0d4fSad break; 6653b8a0d4fSad default: 6663b8a0d4fSad usage(); 667140eaa6eSchristos } 6683b8a0d4fSad } 6693b8a0d4fSad 6703b8a0d4fSad if (empty) 6713b8a0d4fSad usage(); 6723b8a0d4fSad } 673*9d92ab4fSroy 674*9d92ab4fSroy static int 675*9d92ab4fSroy takepid(const char *pidfile, int pidfilelock) 676*9d92ab4fSroy { 677*9d92ab4fSroy char *endp, line[BUFSIZ]; 678*9d92ab4fSroy FILE *fh; 679*9d92ab4fSroy long rval; 680*9d92ab4fSroy 681*9d92ab4fSroy fh = fopen(pidfile, "r"); 682*9d92ab4fSroy if (fh == NULL) 683*9d92ab4fSroy err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); 684*9d92ab4fSroy 685*9d92ab4fSroy if (pidfilelock) { 686*9d92ab4fSroy /* 687*9d92ab4fSroy * If we can lock pidfile, this means that daemon is not 688*9d92ab4fSroy * running, so would be better not to kill some random process. 689*9d92ab4fSroy */ 690*9d92ab4fSroy if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { 691*9d92ab4fSroy (void)fclose(fh); 692*9d92ab4fSroy errx(STATUS_ERROR, "File '%s' can be locked", pidfile); 693*9d92ab4fSroy } else { 694*9d92ab4fSroy if (errno != EWOULDBLOCK) { 695*9d92ab4fSroy errx(STATUS_ERROR, 696*9d92ab4fSroy "Error while locking file '%s'", pidfile); 697*9d92ab4fSroy } 698*9d92ab4fSroy } 699*9d92ab4fSroy } 700*9d92ab4fSroy 701*9d92ab4fSroy if (fgets(line, sizeof(line), fh) == NULL) { 702*9d92ab4fSroy if (feof(fh)) { 703*9d92ab4fSroy (void)fclose(fh); 704*9d92ab4fSroy errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); 705*9d92ab4fSroy } 706*9d92ab4fSroy (void)fclose(fh); 707*9d92ab4fSroy err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); 708*9d92ab4fSroy } 709*9d92ab4fSroy (void)fclose(fh); 710*9d92ab4fSroy 711*9d92ab4fSroy rval = strtol(line, &endp, 10); 712*9d92ab4fSroy if (*endp != '\0' && !isspace((unsigned char)*endp)) 713*9d92ab4fSroy errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 714*9d92ab4fSroy else if (rval < MIN_PID || rval > MAX_PID) 715*9d92ab4fSroy errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 716*9d92ab4fSroy return (rval); 717*9d92ab4fSroy } 718