121be3b31SYaroslav Tykhiy /* $NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $ */
221be3b31SYaroslav Tykhiy
321be3b31SYaroslav Tykhiy /*-
4*b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni *
621be3b31SYaroslav Tykhiy * Copyright (c) 2002 The NetBSD Foundation, Inc.
721be3b31SYaroslav Tykhiy * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
821be3b31SYaroslav Tykhiy * All rights reserved.
921be3b31SYaroslav Tykhiy *
1021be3b31SYaroslav Tykhiy * This code is derived from software contributed to The NetBSD Foundation
1121be3b31SYaroslav Tykhiy * by Andrew Doran.
1221be3b31SYaroslav Tykhiy *
1321be3b31SYaroslav Tykhiy * Redistribution and use in source and binary forms, with or without
1421be3b31SYaroslav Tykhiy * modification, are permitted provided that the following conditions
1521be3b31SYaroslav Tykhiy * are met:
1621be3b31SYaroslav Tykhiy * 1. Redistributions of source code must retain the above copyright
1721be3b31SYaroslav Tykhiy * notice, this list of conditions and the following disclaimer.
1821be3b31SYaroslav Tykhiy * 2. Redistributions in binary form must reproduce the above copyright
1921be3b31SYaroslav Tykhiy * notice, this list of conditions and the following disclaimer in the
2021be3b31SYaroslav Tykhiy * documentation and/or other materials provided with the distribution.
2121be3b31SYaroslav Tykhiy *
2221be3b31SYaroslav Tykhiy * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2321be3b31SYaroslav Tykhiy * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2421be3b31SYaroslav Tykhiy * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2521be3b31SYaroslav Tykhiy * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2621be3b31SYaroslav Tykhiy * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2721be3b31SYaroslav Tykhiy * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2821be3b31SYaroslav Tykhiy * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2921be3b31SYaroslav Tykhiy * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3021be3b31SYaroslav Tykhiy * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3121be3b31SYaroslav Tykhiy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3221be3b31SYaroslav Tykhiy * POSSIBILITY OF SUCH DAMAGE.
3321be3b31SYaroslav Tykhiy */
3421be3b31SYaroslav Tykhiy
3521be3b31SYaroslav Tykhiy #include <sys/types.h>
3621be3b31SYaroslav Tykhiy #include <sys/param.h>
3721be3b31SYaroslav Tykhiy #include <sys/sysctl.h>
3821be3b31SYaroslav Tykhiy #include <sys/proc.h>
3921be3b31SYaroslav Tykhiy #include <sys/queue.h>
4021be3b31SYaroslav Tykhiy #include <sys/stat.h>
4121be3b31SYaroslav Tykhiy #include <sys/time.h>
4221be3b31SYaroslav Tykhiy #include <sys/user.h>
4321be3b31SYaroslav Tykhiy
447b0706f6SPawel Jakub Dawidek #include <assert.h>
4527181846SLawrence Stewart #include <stdbool.h>
4621be3b31SYaroslav Tykhiy #include <stdio.h>
4721be3b31SYaroslav Tykhiy #include <stdlib.h>
4821be3b31SYaroslav Tykhiy #include <limits.h>
4921be3b31SYaroslav Tykhiy #include <paths.h>
5021be3b31SYaroslav Tykhiy #include <string.h>
5121be3b31SYaroslav Tykhiy #include <unistd.h>
5221be3b31SYaroslav Tykhiy #include <signal.h>
5321be3b31SYaroslav Tykhiy #include <regex.h>
5421be3b31SYaroslav Tykhiy #include <ctype.h>
5521be3b31SYaroslav Tykhiy #include <fcntl.h>
5621be3b31SYaroslav Tykhiy #include <kvm.h>
5721be3b31SYaroslav Tykhiy #include <err.h>
5821be3b31SYaroslav Tykhiy #include <pwd.h>
5921be3b31SYaroslav Tykhiy #include <grp.h>
6021be3b31SYaroslav Tykhiy #include <errno.h>
6121be3b31SYaroslav Tykhiy #include <locale.h>
62c4f0631fSJamie Gritton #include <jail.h>
6321be3b31SYaroslav Tykhiy
6421be3b31SYaroslav Tykhiy #define STATUS_MATCH 0
6521be3b31SYaroslav Tykhiy #define STATUS_NOMATCH 1
6621be3b31SYaroslav Tykhiy #define STATUS_BADUSAGE 2
6721be3b31SYaroslav Tykhiy #define STATUS_ERROR 3
6821be3b31SYaroslav Tykhiy
6921be3b31SYaroslav Tykhiy #define MIN_PID 5
7021be3b31SYaroslav Tykhiy #define MAX_PID 99999
7121be3b31SYaroslav Tykhiy
7221be3b31SYaroslav Tykhiy /* Ignore system-processes (if '-S' flag is not specified) and myself. */
7321be3b31SYaroslav Tykhiy #define PSKIP(kp) ((kp)->ki_pid == mypid || \
74db57c70aSKonstantin Belousov (!kthreads && ((kp)->ki_flag & P_KPROC) != 0))
7521be3b31SYaroslav Tykhiy
7621be3b31SYaroslav Tykhiy enum listtype {
7721be3b31SYaroslav Tykhiy LT_GENERIC,
7821be3b31SYaroslav Tykhiy LT_USER,
7921be3b31SYaroslav Tykhiy LT_GROUP,
8021be3b31SYaroslav Tykhiy LT_TTY,
8121be3b31SYaroslav Tykhiy LT_PGRP,
82c4f0631fSJamie Gritton LT_JAIL,
83cc55ad3dSEdward Tomasz Napierala LT_SID,
84cc55ad3dSEdward Tomasz Napierala LT_CLASS
8521be3b31SYaroslav Tykhiy };
8621be3b31SYaroslav Tykhiy
8721be3b31SYaroslav Tykhiy struct list {
8821be3b31SYaroslav Tykhiy SLIST_ENTRY(list) li_chain;
8921be3b31SYaroslav Tykhiy long li_number;
90cc55ad3dSEdward Tomasz Napierala char *li_name;
9121be3b31SYaroslav Tykhiy };
9221be3b31SYaroslav Tykhiy
9321be3b31SYaroslav Tykhiy SLIST_HEAD(listhead, list);
9421be3b31SYaroslav Tykhiy
9521be3b31SYaroslav Tykhiy static struct kinfo_proc *plist;
9621be3b31SYaroslav Tykhiy static char *selected;
9721be3b31SYaroslav Tykhiy static const char *delim = "\n";
9821be3b31SYaroslav Tykhiy static int nproc;
9921be3b31SYaroslav Tykhiy static int pgrep;
10021be3b31SYaroslav Tykhiy static int signum = SIGTERM;
10121be3b31SYaroslav Tykhiy static int newest;
10221be3b31SYaroslav Tykhiy static int oldest;
10321be3b31SYaroslav Tykhiy static int interactive;
10421be3b31SYaroslav Tykhiy static int inverse;
10521be3b31SYaroslav Tykhiy static int longfmt;
10621be3b31SYaroslav Tykhiy static int matchargs;
10721be3b31SYaroslav Tykhiy static int fullmatch;
10821be3b31SYaroslav Tykhiy static int kthreads;
10921be3b31SYaroslav Tykhiy static int cflags = REG_EXTENDED;
1107b0706f6SPawel Jakub Dawidek static int quiet;
11121be3b31SYaroslav Tykhiy static kvm_t *kd;
11221be3b31SYaroslav Tykhiy static pid_t mypid;
11321be3b31SYaroslav Tykhiy
11413e403fdSAntoine Brodin static struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist);
11513e403fdSAntoine Brodin static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist);
11613e403fdSAntoine Brodin static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist);
11713e403fdSAntoine Brodin static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist);
11813e403fdSAntoine Brodin static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist);
11913e403fdSAntoine Brodin static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist);
12013e403fdSAntoine Brodin static struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist);
12113e403fdSAntoine Brodin static struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist);
122cc55ad3dSEdward Tomasz Napierala static struct listhead classlist = SLIST_HEAD_INITIALIZER(classlist);
12321be3b31SYaroslav Tykhiy
12421be3b31SYaroslav Tykhiy static void usage(void) __attribute__((__noreturn__));
12521be3b31SYaroslav Tykhiy static int killact(const struct kinfo_proc *);
12621be3b31SYaroslav Tykhiy static int grepact(const struct kinfo_proc *);
12721be3b31SYaroslav Tykhiy static void makelist(struct listhead *, enum listtype, char *);
12821be3b31SYaroslav Tykhiy static int takepid(const char *, int);
12921be3b31SYaroslav Tykhiy
13021be3b31SYaroslav Tykhiy int
main(int argc,char ** argv)13121be3b31SYaroslav Tykhiy main(int argc, char **argv)
13221be3b31SYaroslav Tykhiy {
1333610bffdSKyle Evans char *buf, *mstr, **pargv, *p, *q, *pidfile;
13421be3b31SYaroslav Tykhiy const char *execf, *coref;
1353610bffdSKyle Evans size_t bufsz;
1363ba0e470SBrian Somers int ancestors, debug_opt, did_action;
13721be3b31SYaroslav Tykhiy int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock;
13821be3b31SYaroslav Tykhiy size_t jsz;
13921be3b31SYaroslav Tykhiy int (*action)(const struct kinfo_proc *);
14021be3b31SYaroslav Tykhiy struct kinfo_proc *kp;
14121be3b31SYaroslav Tykhiy struct list *li;
14221be3b31SYaroslav Tykhiy struct timeval best_tval;
14321be3b31SYaroslav Tykhiy regex_t reg;
14421be3b31SYaroslav Tykhiy regmatch_t regmatch;
1450a091aebSBrian Somers pid_t pid;
14621be3b31SYaroslav Tykhiy
14721be3b31SYaroslav Tykhiy setlocale(LC_ALL, "");
14821be3b31SYaroslav Tykhiy
14921be3b31SYaroslav Tykhiy if (strcmp(getprogname(), "pgrep") == 0) {
15021be3b31SYaroslav Tykhiy action = grepact;
15121be3b31SYaroslav Tykhiy pgrep = 1;
15221be3b31SYaroslav Tykhiy } else {
15321be3b31SYaroslav Tykhiy action = killact;
15421be3b31SYaroslav Tykhiy p = argv[1];
15521be3b31SYaroslav Tykhiy
15621be3b31SYaroslav Tykhiy if (argc > 1 && p[0] == '-') {
15721be3b31SYaroslav Tykhiy p++;
15821be3b31SYaroslav Tykhiy i = (int)strtol(p, &q, 10);
15921be3b31SYaroslav Tykhiy if (*q == '\0') {
16021be3b31SYaroslav Tykhiy signum = i;
16121be3b31SYaroslav Tykhiy argv++;
16221be3b31SYaroslav Tykhiy argc--;
16321be3b31SYaroslav Tykhiy } else {
16412dacf62SJilles Tjoelker if (strncasecmp(p, "SIG", 3) == 0)
16521be3b31SYaroslav Tykhiy p += 3;
16621be3b31SYaroslav Tykhiy for (i = 1; i < NSIG; i++)
16721be3b31SYaroslav Tykhiy if (strcasecmp(sys_signame[i], p) == 0)
16821be3b31SYaroslav Tykhiy break;
16921be3b31SYaroslav Tykhiy if (i != NSIG) {
17021be3b31SYaroslav Tykhiy signum = i;
17121be3b31SYaroslav Tykhiy argv++;
17221be3b31SYaroslav Tykhiy argc--;
17321be3b31SYaroslav Tykhiy }
17421be3b31SYaroslav Tykhiy }
17521be3b31SYaroslav Tykhiy }
17621be3b31SYaroslav Tykhiy }
17721be3b31SYaroslav Tykhiy
1783610bffdSKyle Evans buf = NULL;
1790a091aebSBrian Somers ancestors = 0;
18021be3b31SYaroslav Tykhiy criteria = 0;
18121be3b31SYaroslav Tykhiy debug_opt = 0;
18221be3b31SYaroslav Tykhiy pidfile = NULL;
18321be3b31SYaroslav Tykhiy pidfilelock = 0;
1847b0706f6SPawel Jakub Dawidek quiet = 0;
185c08dcaf1SRebecca Cran execf = NULL;
186c08dcaf1SRebecca Cran coref = _PATH_DEVNULL;
18721be3b31SYaroslav Tykhiy
188cc55ad3dSEdward Tomasz Napierala while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ac:d:fg:ij:lnoqs:t:u:vx")) != -1)
18921be3b31SYaroslav Tykhiy switch (ch) {
19021be3b31SYaroslav Tykhiy case 'D':
19121be3b31SYaroslav Tykhiy debug_opt++;
19221be3b31SYaroslav Tykhiy break;
19321be3b31SYaroslav Tykhiy case 'F':
19421be3b31SYaroslav Tykhiy pidfile = optarg;
19521be3b31SYaroslav Tykhiy criteria = 1;
19621be3b31SYaroslav Tykhiy break;
19721be3b31SYaroslav Tykhiy case 'G':
19821be3b31SYaroslav Tykhiy makelist(&rgidlist, LT_GROUP, optarg);
19921be3b31SYaroslav Tykhiy criteria = 1;
20021be3b31SYaroslav Tykhiy break;
20121be3b31SYaroslav Tykhiy case 'I':
20221be3b31SYaroslav Tykhiy if (pgrep)
20321be3b31SYaroslav Tykhiy usage();
20421be3b31SYaroslav Tykhiy interactive = 1;
20521be3b31SYaroslav Tykhiy break;
20621be3b31SYaroslav Tykhiy case 'L':
20721be3b31SYaroslav Tykhiy pidfilelock = 1;
20821be3b31SYaroslav Tykhiy break;
20921be3b31SYaroslav Tykhiy case 'M':
21021be3b31SYaroslav Tykhiy coref = optarg;
21121be3b31SYaroslav Tykhiy break;
21221be3b31SYaroslav Tykhiy case 'N':
21321be3b31SYaroslav Tykhiy execf = optarg;
21421be3b31SYaroslav Tykhiy break;
21521be3b31SYaroslav Tykhiy case 'P':
21621be3b31SYaroslav Tykhiy makelist(&ppidlist, LT_GENERIC, optarg);
21721be3b31SYaroslav Tykhiy criteria = 1;
21821be3b31SYaroslav Tykhiy break;
21921be3b31SYaroslav Tykhiy case 'S':
22021be3b31SYaroslav Tykhiy if (!pgrep)
22121be3b31SYaroslav Tykhiy usage();
22221be3b31SYaroslav Tykhiy kthreads = 1;
22321be3b31SYaroslav Tykhiy break;
22421be3b31SYaroslav Tykhiy case 'U':
22521be3b31SYaroslav Tykhiy makelist(&ruidlist, LT_USER, optarg);
22621be3b31SYaroslav Tykhiy criteria = 1;
22721be3b31SYaroslav Tykhiy break;
2280a091aebSBrian Somers case 'a':
2290a091aebSBrian Somers ancestors++;
2300a091aebSBrian Somers break;
231cc55ad3dSEdward Tomasz Napierala case 'c':
232cc55ad3dSEdward Tomasz Napierala makelist(&classlist, LT_CLASS, optarg);
233cc55ad3dSEdward Tomasz Napierala criteria = 1;
234cc55ad3dSEdward Tomasz Napierala break;
23521be3b31SYaroslav Tykhiy case 'd':
23621be3b31SYaroslav Tykhiy if (!pgrep)
23721be3b31SYaroslav Tykhiy usage();
23821be3b31SYaroslav Tykhiy delim = optarg;
23921be3b31SYaroslav Tykhiy break;
24021be3b31SYaroslav Tykhiy case 'f':
24121be3b31SYaroslav Tykhiy matchargs = 1;
24221be3b31SYaroslav Tykhiy break;
24321be3b31SYaroslav Tykhiy case 'g':
24421be3b31SYaroslav Tykhiy makelist(&pgrplist, LT_PGRP, optarg);
24521be3b31SYaroslav Tykhiy criteria = 1;
24621be3b31SYaroslav Tykhiy break;
24721be3b31SYaroslav Tykhiy case 'i':
24821be3b31SYaroslav Tykhiy cflags |= REG_ICASE;
24921be3b31SYaroslav Tykhiy break;
25021be3b31SYaroslav Tykhiy case 'j':
251c4f0631fSJamie Gritton makelist(&jidlist, LT_JAIL, optarg);
25221be3b31SYaroslav Tykhiy criteria = 1;
25321be3b31SYaroslav Tykhiy break;
25421be3b31SYaroslav Tykhiy case 'l':
25521be3b31SYaroslav Tykhiy longfmt = 1;
25621be3b31SYaroslav Tykhiy break;
25721be3b31SYaroslav Tykhiy case 'n':
25821be3b31SYaroslav Tykhiy newest = 1;
25921be3b31SYaroslav Tykhiy criteria = 1;
26021be3b31SYaroslav Tykhiy break;
26121be3b31SYaroslav Tykhiy case 'o':
26221be3b31SYaroslav Tykhiy oldest = 1;
26321be3b31SYaroslav Tykhiy criteria = 1;
26421be3b31SYaroslav Tykhiy break;
2657b0706f6SPawel Jakub Dawidek case 'q':
2667b0706f6SPawel Jakub Dawidek if (!pgrep)
2677b0706f6SPawel Jakub Dawidek usage();
2687b0706f6SPawel Jakub Dawidek quiet = 1;
2697b0706f6SPawel Jakub Dawidek break;
27021be3b31SYaroslav Tykhiy case 's':
27121be3b31SYaroslav Tykhiy makelist(&sidlist, LT_SID, optarg);
27221be3b31SYaroslav Tykhiy criteria = 1;
27321be3b31SYaroslav Tykhiy break;
27421be3b31SYaroslav Tykhiy case 't':
27521be3b31SYaroslav Tykhiy makelist(&tdevlist, LT_TTY, optarg);
27621be3b31SYaroslav Tykhiy criteria = 1;
27721be3b31SYaroslav Tykhiy break;
27821be3b31SYaroslav Tykhiy case 'u':
27921be3b31SYaroslav Tykhiy makelist(&euidlist, LT_USER, optarg);
28021be3b31SYaroslav Tykhiy criteria = 1;
28121be3b31SYaroslav Tykhiy break;
28221be3b31SYaroslav Tykhiy case 'v':
28321be3b31SYaroslav Tykhiy inverse = 1;
28421be3b31SYaroslav Tykhiy break;
28521be3b31SYaroslav Tykhiy case 'x':
28621be3b31SYaroslav Tykhiy fullmatch = 1;
28721be3b31SYaroslav Tykhiy break;
28821be3b31SYaroslav Tykhiy default:
28921be3b31SYaroslav Tykhiy usage();
29021be3b31SYaroslav Tykhiy /* NOTREACHED */
29121be3b31SYaroslav Tykhiy }
29221be3b31SYaroslav Tykhiy
29321be3b31SYaroslav Tykhiy argc -= optind;
29421be3b31SYaroslav Tykhiy argv += optind;
29521be3b31SYaroslav Tykhiy if (argc != 0)
29621be3b31SYaroslav Tykhiy criteria = 1;
29721be3b31SYaroslav Tykhiy if (!criteria)
29821be3b31SYaroslav Tykhiy usage();
29921be3b31SYaroslav Tykhiy if (newest && oldest)
30021be3b31SYaroslav Tykhiy errx(STATUS_ERROR, "Options -n and -o are mutually exclusive");
30121be3b31SYaroslav Tykhiy if (pidfile != NULL)
30221be3b31SYaroslav Tykhiy pidfromfile = takepid(pidfile, pidfilelock);
30321be3b31SYaroslav Tykhiy else {
30421be3b31SYaroslav Tykhiy if (pidfilelock) {
30521be3b31SYaroslav Tykhiy errx(STATUS_ERROR,
30621be3b31SYaroslav Tykhiy "Option -L doesn't make sense without -F");
30721be3b31SYaroslav Tykhiy }
30821be3b31SYaroslav Tykhiy pidfromfile = -1;
30921be3b31SYaroslav Tykhiy }
31021be3b31SYaroslav Tykhiy
31121be3b31SYaroslav Tykhiy mypid = getpid();
31221be3b31SYaroslav Tykhiy
31321be3b31SYaroslav Tykhiy /*
3143610bffdSKyle Evans * If we're not matching args, we only need a buffer large enough to
3153610bffdSKyle Evans * hold some relatively short error strings. Otherwise, we have to
3163610bffdSKyle Evans * assume we'll need up to ARG_MAX bytes for arguments.
3173610bffdSKyle Evans */
3183610bffdSKyle Evans bufsz = _POSIX2_LINE_MAX;
3193610bffdSKyle Evans if (matchargs) {
3203610bffdSKyle Evans long arg_max;
3213610bffdSKyle Evans
3223610bffdSKyle Evans arg_max = sysconf(_SC_ARG_MAX);
3233610bffdSKyle Evans if (arg_max == -1)
3243610bffdSKyle Evans arg_max = ARG_MAX;
3253610bffdSKyle Evans
3263610bffdSKyle Evans /*
3273610bffdSKyle Evans * The absolute worst case scenario is ARG_MAX single-byte
3283610bffdSKyle Evans * arguments which we'll then separate with spaces and NUL
3293610bffdSKyle Evans * terminate.
3303610bffdSKyle Evans */
3313610bffdSKyle Evans bufsz = (arg_max * 2) + 1;
3323610bffdSKyle Evans }
3333610bffdSKyle Evans
3343610bffdSKyle Evans buf = malloc(bufsz);
3353610bffdSKyle Evans if (buf == NULL)
3363610bffdSKyle Evans err(STATUS_ERROR, "malloc");
3373610bffdSKyle Evans
3383610bffdSKyle Evans /*
33921be3b31SYaroslav Tykhiy * Retrieve the list of running processes from the kernel.
34021be3b31SYaroslav Tykhiy */
34121be3b31SYaroslav Tykhiy kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf);
34221be3b31SYaroslav Tykhiy if (kd == NULL)
34321be3b31SYaroslav Tykhiy errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf);
34421be3b31SYaroslav Tykhiy
34521be3b31SYaroslav Tykhiy /*
34621be3b31SYaroslav Tykhiy * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we
34721be3b31SYaroslav Tykhiy * just want processes and not individual kernel threads.
34821be3b31SYaroslav Tykhiy */
34903eea902SEitan Adler if (pidfromfile >= 0)
35003eea902SEitan Adler plist = kvm_getprocs(kd, KERN_PROC_PID, pidfromfile, &nproc);
35103eea902SEitan Adler else
35221be3b31SYaroslav Tykhiy plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc);
35321be3b31SYaroslav Tykhiy if (plist == NULL) {
35421be3b31SYaroslav Tykhiy errx(STATUS_ERROR, "Cannot get process list (%s)",
35521be3b31SYaroslav Tykhiy kvm_geterr(kd));
35621be3b31SYaroslav Tykhiy }
35721be3b31SYaroslav Tykhiy
35821be3b31SYaroslav Tykhiy /*
35921be3b31SYaroslav Tykhiy * Allocate memory which will be used to keep track of the
36021be3b31SYaroslav Tykhiy * selection.
36121be3b31SYaroslav Tykhiy */
36221be3b31SYaroslav Tykhiy if ((selected = malloc(nproc)) == NULL) {
36321be3b31SYaroslav Tykhiy err(STATUS_ERROR, "Cannot allocate memory for %d processes",
36421be3b31SYaroslav Tykhiy nproc);
36521be3b31SYaroslav Tykhiy }
36621be3b31SYaroslav Tykhiy memset(selected, 0, nproc);
36721be3b31SYaroslav Tykhiy
36821be3b31SYaroslav Tykhiy /*
36921be3b31SYaroslav Tykhiy * Refine the selection.
37021be3b31SYaroslav Tykhiy */
37121be3b31SYaroslav Tykhiy for (; *argv != NULL; argv++) {
37221be3b31SYaroslav Tykhiy if ((rv = regcomp(®, *argv, cflags)) != 0) {
3733610bffdSKyle Evans regerror(rv, ®, buf, bufsz);
37421be3b31SYaroslav Tykhiy errx(STATUS_BADUSAGE,
37521be3b31SYaroslav Tykhiy "Cannot compile regular expression `%s' (%s)",
37621be3b31SYaroslav Tykhiy *argv, buf);
37721be3b31SYaroslav Tykhiy }
37821be3b31SYaroslav Tykhiy
37921be3b31SYaroslav Tykhiy for (i = 0, kp = plist; i < nproc; i++, kp++) {
38021be3b31SYaroslav Tykhiy if (PSKIP(kp)) {
38121be3b31SYaroslav Tykhiy if (debug_opt > 0)
38221be3b31SYaroslav Tykhiy fprintf(stderr, "* Skipped %5d %3d %s\n",
38321be3b31SYaroslav Tykhiy kp->ki_pid, kp->ki_uid, kp->ki_comm);
38421be3b31SYaroslav Tykhiy continue;
38521be3b31SYaroslav Tykhiy }
38621be3b31SYaroslav Tykhiy
38721be3b31SYaroslav Tykhiy if (matchargs &&
38821be3b31SYaroslav Tykhiy (pargv = kvm_getargv(kd, kp, 0)) != NULL) {
38921be3b31SYaroslav Tykhiy jsz = 0;
3903610bffdSKyle Evans while (jsz < bufsz && *pargv != NULL) {
39121be3b31SYaroslav Tykhiy jsz += snprintf(buf + jsz,
3923610bffdSKyle Evans bufsz - jsz,
39321be3b31SYaroslav Tykhiy pargv[1] != NULL ? "%s " : "%s",
39421be3b31SYaroslav Tykhiy pargv[0]);
39521be3b31SYaroslav Tykhiy pargv++;
39621be3b31SYaroslav Tykhiy }
39721be3b31SYaroslav Tykhiy mstr = buf;
39821be3b31SYaroslav Tykhiy } else
39921be3b31SYaroslav Tykhiy mstr = kp->ki_comm;
40021be3b31SYaroslav Tykhiy
40121be3b31SYaroslav Tykhiy rv = regexec(®, mstr, 1, ®match, 0);
40221be3b31SYaroslav Tykhiy if (rv == 0) {
40321be3b31SYaroslav Tykhiy if (fullmatch) {
40421be3b31SYaroslav Tykhiy if (regmatch.rm_so == 0 &&
40521be3b31SYaroslav Tykhiy regmatch.rm_eo ==
40621be3b31SYaroslav Tykhiy (off_t)strlen(mstr))
40721be3b31SYaroslav Tykhiy selected[i] = 1;
40821be3b31SYaroslav Tykhiy } else
40921be3b31SYaroslav Tykhiy selected[i] = 1;
41021be3b31SYaroslav Tykhiy } else if (rv != REG_NOMATCH) {
4113610bffdSKyle Evans regerror(rv, ®, buf, bufsz);
41221be3b31SYaroslav Tykhiy errx(STATUS_ERROR,
41321be3b31SYaroslav Tykhiy "Regular expression evaluation error (%s)",
41421be3b31SYaroslav Tykhiy buf);
41521be3b31SYaroslav Tykhiy }
41621be3b31SYaroslav Tykhiy if (debug_opt > 1) {
41721be3b31SYaroslav Tykhiy const char *rv_res = "NoMatch";
41821be3b31SYaroslav Tykhiy if (selected[i])
41921be3b31SYaroslav Tykhiy rv_res = "Matched";
42021be3b31SYaroslav Tykhiy fprintf(stderr, "* %s %5d %3d %s\n", rv_res,
42121be3b31SYaroslav Tykhiy kp->ki_pid, kp->ki_uid, mstr);
42221be3b31SYaroslav Tykhiy }
42321be3b31SYaroslav Tykhiy }
42421be3b31SYaroslav Tykhiy
42521be3b31SYaroslav Tykhiy regfree(®);
42621be3b31SYaroslav Tykhiy }
42721be3b31SYaroslav Tykhiy
42821be3b31SYaroslav Tykhiy for (i = 0, kp = plist; i < nproc; i++, kp++) {
42921be3b31SYaroslav Tykhiy if (PSKIP(kp))
43021be3b31SYaroslav Tykhiy continue;
43121be3b31SYaroslav Tykhiy
43221be3b31SYaroslav Tykhiy if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) {
43321be3b31SYaroslav Tykhiy selected[i] = 0;
43421be3b31SYaroslav Tykhiy continue;
43521be3b31SYaroslav Tykhiy }
43621be3b31SYaroslav Tykhiy
43721be3b31SYaroslav Tykhiy SLIST_FOREACH(li, &ruidlist, li_chain)
43821be3b31SYaroslav Tykhiy if (kp->ki_ruid == (uid_t)li->li_number)
43921be3b31SYaroslav Tykhiy break;
44021be3b31SYaroslav Tykhiy if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
44121be3b31SYaroslav Tykhiy selected[i] = 0;
44221be3b31SYaroslav Tykhiy continue;
44321be3b31SYaroslav Tykhiy }
44421be3b31SYaroslav Tykhiy
44521be3b31SYaroslav Tykhiy SLIST_FOREACH(li, &rgidlist, li_chain)
44621be3b31SYaroslav Tykhiy if (kp->ki_rgid == (gid_t)li->li_number)
44721be3b31SYaroslav Tykhiy break;
44821be3b31SYaroslav Tykhiy if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
44921be3b31SYaroslav Tykhiy selected[i] = 0;
45021be3b31SYaroslav Tykhiy continue;
45121be3b31SYaroslav Tykhiy }
45221be3b31SYaroslav Tykhiy
45321be3b31SYaroslav Tykhiy SLIST_FOREACH(li, &euidlist, li_chain)
45421be3b31SYaroslav Tykhiy if (kp->ki_uid == (uid_t)li->li_number)
45521be3b31SYaroslav Tykhiy break;
45621be3b31SYaroslav Tykhiy if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
45721be3b31SYaroslav Tykhiy selected[i] = 0;
45821be3b31SYaroslav Tykhiy continue;
45921be3b31SYaroslav Tykhiy }
46021be3b31SYaroslav Tykhiy
46121be3b31SYaroslav Tykhiy SLIST_FOREACH(li, &ppidlist, li_chain)
46221be3b31SYaroslav Tykhiy if (kp->ki_ppid == (pid_t)li->li_number)
46321be3b31SYaroslav Tykhiy break;
46421be3b31SYaroslav Tykhiy if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
46521be3b31SYaroslav Tykhiy selected[i] = 0;
46621be3b31SYaroslav Tykhiy continue;
46721be3b31SYaroslav Tykhiy }
46821be3b31SYaroslav Tykhiy
46921be3b31SYaroslav Tykhiy SLIST_FOREACH(li, &pgrplist, li_chain)
47021be3b31SYaroslav Tykhiy if (kp->ki_pgid == (pid_t)li->li_number)
47121be3b31SYaroslav Tykhiy break;
47221be3b31SYaroslav Tykhiy if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
47321be3b31SYaroslav Tykhiy selected[i] = 0;
47421be3b31SYaroslav Tykhiy continue;
47521be3b31SYaroslav Tykhiy }
47621be3b31SYaroslav Tykhiy
47721be3b31SYaroslav Tykhiy SLIST_FOREACH(li, &tdevlist, li_chain) {
47821be3b31SYaroslav Tykhiy if (li->li_number == -1 &&
47921be3b31SYaroslav Tykhiy (kp->ki_flag & P_CONTROLT) == 0)
48021be3b31SYaroslav Tykhiy break;
48121be3b31SYaroslav Tykhiy if (kp->ki_tdev == (dev_t)li->li_number)
48221be3b31SYaroslav Tykhiy break;
48321be3b31SYaroslav Tykhiy }
48421be3b31SYaroslav Tykhiy if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
48521be3b31SYaroslav Tykhiy selected[i] = 0;
48621be3b31SYaroslav Tykhiy continue;
48721be3b31SYaroslav Tykhiy }
48821be3b31SYaroslav Tykhiy
48921be3b31SYaroslav Tykhiy SLIST_FOREACH(li, &sidlist, li_chain)
49021be3b31SYaroslav Tykhiy if (kp->ki_sid == (pid_t)li->li_number)
49121be3b31SYaroslav Tykhiy break;
49221be3b31SYaroslav Tykhiy if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
49321be3b31SYaroslav Tykhiy selected[i] = 0;
49421be3b31SYaroslav Tykhiy continue;
49521be3b31SYaroslav Tykhiy }
49621be3b31SYaroslav Tykhiy
49721be3b31SYaroslav Tykhiy SLIST_FOREACH(li, &jidlist, li_chain) {
49821be3b31SYaroslav Tykhiy /* A particular jail ID, including 0 (not in jail) */
49921be3b31SYaroslav Tykhiy if (kp->ki_jid == (int)li->li_number)
50021be3b31SYaroslav Tykhiy break;
50121be3b31SYaroslav Tykhiy /* Any jail */
50221be3b31SYaroslav Tykhiy if (kp->ki_jid > 0 && li->li_number == -1)
50321be3b31SYaroslav Tykhiy break;
50421be3b31SYaroslav Tykhiy }
50521be3b31SYaroslav Tykhiy if (SLIST_FIRST(&jidlist) != NULL && li == NULL) {
50621be3b31SYaroslav Tykhiy selected[i] = 0;
50721be3b31SYaroslav Tykhiy continue;
50821be3b31SYaroslav Tykhiy }
50921be3b31SYaroslav Tykhiy
510cc55ad3dSEdward Tomasz Napierala SLIST_FOREACH(li, &classlist, li_chain) {
511cc55ad3dSEdward Tomasz Napierala /*
512cc55ad3dSEdward Tomasz Napierala * We skip P_SYSTEM processes to match ps(1) output.
513cc55ad3dSEdward Tomasz Napierala */
514cc55ad3dSEdward Tomasz Napierala if ((kp->ki_flag & P_SYSTEM) == 0 &&
515cc55ad3dSEdward Tomasz Napierala strcmp(kp->ki_loginclass, li->li_name) == 0)
516cc55ad3dSEdward Tomasz Napierala break;
517cc55ad3dSEdward Tomasz Napierala }
518cc55ad3dSEdward Tomasz Napierala if (SLIST_FIRST(&classlist) != NULL && li == NULL) {
519cc55ad3dSEdward Tomasz Napierala selected[i] = 0;
520cc55ad3dSEdward Tomasz Napierala continue;
521cc55ad3dSEdward Tomasz Napierala }
522cc55ad3dSEdward Tomasz Napierala
52321be3b31SYaroslav Tykhiy if (argc == 0)
52421be3b31SYaroslav Tykhiy selected[i] = 1;
52521be3b31SYaroslav Tykhiy }
52621be3b31SYaroslav Tykhiy
5270a091aebSBrian Somers if (!ancestors) {
5280a091aebSBrian Somers pid = mypid;
5290a091aebSBrian Somers while (pid) {
5300a091aebSBrian Somers for (i = 0, kp = plist; i < nproc; i++, kp++) {
5310a091aebSBrian Somers if (PSKIP(kp))
5320a091aebSBrian Somers continue;
5330a091aebSBrian Somers if (kp->ki_pid == pid) {
5340a091aebSBrian Somers selected[i] = 0;
5350a091aebSBrian Somers pid = kp->ki_ppid;
5360a091aebSBrian Somers break;
5370a091aebSBrian Somers }
5380a091aebSBrian Somers }
5390a091aebSBrian Somers if (i == nproc) {
5400a091aebSBrian Somers if (pid == mypid)
5410a091aebSBrian Somers pid = getppid();
5420a091aebSBrian Somers else
5430a091aebSBrian Somers break; /* Maybe we're in a jail ? */
5440a091aebSBrian Somers }
5450a091aebSBrian Somers }
5460a091aebSBrian Somers }
5470a091aebSBrian Somers
54821be3b31SYaroslav Tykhiy if (newest || oldest) {
54921be3b31SYaroslav Tykhiy best_tval.tv_sec = 0;
55021be3b31SYaroslav Tykhiy best_tval.tv_usec = 0;
55121be3b31SYaroslav Tykhiy bestidx = -1;
55221be3b31SYaroslav Tykhiy
55321be3b31SYaroslav Tykhiy for (i = 0, kp = plist; i < nproc; i++, kp++) {
55421be3b31SYaroslav Tykhiy if (!selected[i])
55521be3b31SYaroslav Tykhiy continue;
55621be3b31SYaroslav Tykhiy if (bestidx == -1) {
55721be3b31SYaroslav Tykhiy /* The first entry of the list which matched. */
55821be3b31SYaroslav Tykhiy ;
55921be3b31SYaroslav Tykhiy } else if (timercmp(&kp->ki_start, &best_tval, >)) {
56021be3b31SYaroslav Tykhiy /* This entry is newer than previous "best". */
56121be3b31SYaroslav Tykhiy if (oldest) /* but we want the oldest */
56221be3b31SYaroslav Tykhiy continue;
56321be3b31SYaroslav Tykhiy } else {
56421be3b31SYaroslav Tykhiy /* This entry is older than previous "best". */
56521be3b31SYaroslav Tykhiy if (newest) /* but we want the newest */
56621be3b31SYaroslav Tykhiy continue;
56721be3b31SYaroslav Tykhiy }
56821be3b31SYaroslav Tykhiy /* This entry is better than previous "best" entry. */
56921be3b31SYaroslav Tykhiy best_tval.tv_sec = kp->ki_start.tv_sec;
57021be3b31SYaroslav Tykhiy best_tval.tv_usec = kp->ki_start.tv_usec;
57121be3b31SYaroslav Tykhiy bestidx = i;
57221be3b31SYaroslav Tykhiy }
57321be3b31SYaroslav Tykhiy
57421be3b31SYaroslav Tykhiy memset(selected, 0, nproc);
57521be3b31SYaroslav Tykhiy if (bestidx != -1)
57621be3b31SYaroslav Tykhiy selected[bestidx] = 1;
57721be3b31SYaroslav Tykhiy }
57821be3b31SYaroslav Tykhiy
57921be3b31SYaroslav Tykhiy /*
58021be3b31SYaroslav Tykhiy * Take the appropriate action for each matched process, if any.
58121be3b31SYaroslav Tykhiy */
5823ba0e470SBrian Somers did_action = 0;
58321be3b31SYaroslav Tykhiy for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) {
58421be3b31SYaroslav Tykhiy if (PSKIP(kp))
58521be3b31SYaroslav Tykhiy continue;
58621be3b31SYaroslav Tykhiy if (selected[i]) {
5873ba0e470SBrian Somers if (longfmt && !pgrep) {
5883ba0e470SBrian Somers did_action = 1;
5893ba0e470SBrian Somers printf("kill -%d %d\n", signum, kp->ki_pid);
5903ba0e470SBrian Somers }
59121be3b31SYaroslav Tykhiy if (inverse)
59221be3b31SYaroslav Tykhiy continue;
59321be3b31SYaroslav Tykhiy } else if (!inverse)
59421be3b31SYaroslav Tykhiy continue;
59521be3b31SYaroslav Tykhiy rv |= (*action)(kp);
59621be3b31SYaroslav Tykhiy }
597cf182be5SLawrence Stewart if (rv && pgrep && !quiet)
5981e781c6fSLawrence Stewart putchar('\n');
5993ba0e470SBrian Somers if (!did_action && !pgrep && longfmt)
6003ba0e470SBrian Somers fprintf(stderr,
6013ba0e470SBrian Somers "No matching processes belonging to you were found\n");
60221be3b31SYaroslav Tykhiy
6033610bffdSKyle Evans free(buf);
60421be3b31SYaroslav Tykhiy exit(rv ? STATUS_MATCH : STATUS_NOMATCH);
60521be3b31SYaroslav Tykhiy }
60621be3b31SYaroslav Tykhiy
60721be3b31SYaroslav Tykhiy static void
usage(void)60821be3b31SYaroslav Tykhiy usage(void)
60921be3b31SYaroslav Tykhiy {
61021be3b31SYaroslav Tykhiy const char *ustr;
61121be3b31SYaroslav Tykhiy
61221be3b31SYaroslav Tykhiy if (pgrep)
6137b0706f6SPawel Jakub Dawidek ustr = "[-LSfilnoqvx] [-d delim]";
61421be3b31SYaroslav Tykhiy else
6153ba0e470SBrian Somers ustr = "[-signal] [-ILfilnovx]";
61621be3b31SYaroslav Tykhiy
61721be3b31SYaroslav Tykhiy fprintf(stderr,
61821be3b31SYaroslav Tykhiy "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n"
619c4f0631fSJamie Gritton " [-P ppid] [-U uid] [-c class] [-g pgrp] [-j jail]\n"
620cc55ad3dSEdward Tomasz Napierala " [-s sid] [-t tty] [-u euid] pattern ...\n",
621cc55ad3dSEdward Tomasz Napierala getprogname(), ustr);
62221be3b31SYaroslav Tykhiy
62321be3b31SYaroslav Tykhiy exit(STATUS_BADUSAGE);
62421be3b31SYaroslav Tykhiy }
62521be3b31SYaroslav Tykhiy
62621be3b31SYaroslav Tykhiy static void
show_process(const struct kinfo_proc * kp)62721be3b31SYaroslav Tykhiy show_process(const struct kinfo_proc *kp)
62821be3b31SYaroslav Tykhiy {
62921be3b31SYaroslav Tykhiy char **argv;
63021be3b31SYaroslav Tykhiy
6317b0706f6SPawel Jakub Dawidek if (quiet) {
6327b0706f6SPawel Jakub Dawidek assert(pgrep);
6337b0706f6SPawel Jakub Dawidek return;
6347b0706f6SPawel Jakub Dawidek }
63521be3b31SYaroslav Tykhiy if ((longfmt || !pgrep) && matchargs &&
63621be3b31SYaroslav Tykhiy (argv = kvm_getargv(kd, kp, 0)) != NULL) {
63721be3b31SYaroslav Tykhiy printf("%d ", (int)kp->ki_pid);
63821be3b31SYaroslav Tykhiy for (; *argv != NULL; argv++) {
63921be3b31SYaroslav Tykhiy printf("%s", *argv);
64021be3b31SYaroslav Tykhiy if (argv[1] != NULL)
64121be3b31SYaroslav Tykhiy putchar(' ');
64221be3b31SYaroslav Tykhiy }
64321be3b31SYaroslav Tykhiy } else if (longfmt || !pgrep)
64421be3b31SYaroslav Tykhiy printf("%d %s", (int)kp->ki_pid, kp->ki_comm);
64521be3b31SYaroslav Tykhiy else
64621be3b31SYaroslav Tykhiy printf("%d", (int)kp->ki_pid);
64721be3b31SYaroslav Tykhiy }
64821be3b31SYaroslav Tykhiy
64921be3b31SYaroslav Tykhiy static int
killact(const struct kinfo_proc * kp)65021be3b31SYaroslav Tykhiy killact(const struct kinfo_proc *kp)
65121be3b31SYaroslav Tykhiy {
65221be3b31SYaroslav Tykhiy int ch, first;
65321be3b31SYaroslav Tykhiy
65421be3b31SYaroslav Tykhiy if (interactive) {
65521be3b31SYaroslav Tykhiy /*
65621be3b31SYaroslav Tykhiy * Be careful, ask before killing.
65721be3b31SYaroslav Tykhiy */
65821be3b31SYaroslav Tykhiy printf("kill ");
65921be3b31SYaroslav Tykhiy show_process(kp);
66021be3b31SYaroslav Tykhiy printf("? ");
66121be3b31SYaroslav Tykhiy fflush(stdout);
66221be3b31SYaroslav Tykhiy first = ch = getchar();
66321be3b31SYaroslav Tykhiy while (ch != '\n' && ch != EOF)
66421be3b31SYaroslav Tykhiy ch = getchar();
66521be3b31SYaroslav Tykhiy if (first != 'y' && first != 'Y')
66621be3b31SYaroslav Tykhiy return (1);
66721be3b31SYaroslav Tykhiy }
66821be3b31SYaroslav Tykhiy if (kill(kp->ki_pid, signum) == -1) {
66921be3b31SYaroslav Tykhiy /*
67021be3b31SYaroslav Tykhiy * Check for ESRCH, which indicates that the process
67121be3b31SYaroslav Tykhiy * disappeared between us matching it and us
67221be3b31SYaroslav Tykhiy * signalling it; don't issue a warning about it.
67321be3b31SYaroslav Tykhiy */
67421be3b31SYaroslav Tykhiy if (errno != ESRCH)
67521be3b31SYaroslav Tykhiy warn("signalling pid %d", (int)kp->ki_pid);
67621be3b31SYaroslav Tykhiy /*
67721be3b31SYaroslav Tykhiy * Return 0 to indicate that the process should not be
67821be3b31SYaroslav Tykhiy * considered a match, since we didn't actually get to
67921be3b31SYaroslav Tykhiy * signal it.
68021be3b31SYaroslav Tykhiy */
68121be3b31SYaroslav Tykhiy return (0);
68221be3b31SYaroslav Tykhiy }
68321be3b31SYaroslav Tykhiy return (1);
68421be3b31SYaroslav Tykhiy }
68521be3b31SYaroslav Tykhiy
68621be3b31SYaroslav Tykhiy static int
grepact(const struct kinfo_proc * kp)68721be3b31SYaroslav Tykhiy grepact(const struct kinfo_proc *kp)
68821be3b31SYaroslav Tykhiy {
68927181846SLawrence Stewart static bool first = true;
69021be3b31SYaroslav Tykhiy
69127181846SLawrence Stewart if (!quiet && !first)
69221be3b31SYaroslav Tykhiy printf("%s", delim);
69327181846SLawrence Stewart show_process(kp);
69427181846SLawrence Stewart first = false;
69521be3b31SYaroslav Tykhiy return (1);
69621be3b31SYaroslav Tykhiy }
69721be3b31SYaroslav Tykhiy
69821be3b31SYaroslav Tykhiy static void
makelist(struct listhead * head,enum listtype type,char * src)69921be3b31SYaroslav Tykhiy makelist(struct listhead *head, enum listtype type, char *src)
70021be3b31SYaroslav Tykhiy {
70121be3b31SYaroslav Tykhiy struct list *li;
70221be3b31SYaroslav Tykhiy struct passwd *pw;
70321be3b31SYaroslav Tykhiy struct group *gr;
70421be3b31SYaroslav Tykhiy struct stat st;
705eb948eacSEd Schouten const char *cp;
70621be3b31SYaroslav Tykhiy char *sp, *ep, buf[MAXPATHLEN];
70721be3b31SYaroslav Tykhiy int empty;
70821be3b31SYaroslav Tykhiy
70921be3b31SYaroslav Tykhiy empty = 1;
71021be3b31SYaroslav Tykhiy
71121be3b31SYaroslav Tykhiy while ((sp = strsep(&src, ",")) != NULL) {
71221be3b31SYaroslav Tykhiy if (*sp == '\0')
71321be3b31SYaroslav Tykhiy usage();
71421be3b31SYaroslav Tykhiy
71521be3b31SYaroslav Tykhiy if ((li = malloc(sizeof(*li))) == NULL) {
71621be3b31SYaroslav Tykhiy err(STATUS_ERROR, "Cannot allocate %zu bytes",
71721be3b31SYaroslav Tykhiy sizeof(*li));
71821be3b31SYaroslav Tykhiy }
71921be3b31SYaroslav Tykhiy
72021be3b31SYaroslav Tykhiy SLIST_INSERT_HEAD(head, li, li_chain);
72121be3b31SYaroslav Tykhiy empty = 0;
72221be3b31SYaroslav Tykhiy
723cc55ad3dSEdward Tomasz Napierala if (type != LT_CLASS)
72421be3b31SYaroslav Tykhiy li->li_number = (uid_t)strtol(sp, &ep, 0);
725cc55ad3dSEdward Tomasz Napierala
726cc55ad3dSEdward Tomasz Napierala if (type != LT_CLASS && *ep == '\0') {
72721be3b31SYaroslav Tykhiy switch (type) {
72821be3b31SYaroslav Tykhiy case LT_PGRP:
72921be3b31SYaroslav Tykhiy if (li->li_number == 0)
73021be3b31SYaroslav Tykhiy li->li_number = getpgrp();
73121be3b31SYaroslav Tykhiy break;
73221be3b31SYaroslav Tykhiy case LT_SID:
73321be3b31SYaroslav Tykhiy if (li->li_number == 0)
73421be3b31SYaroslav Tykhiy li->li_number = getsid(mypid);
73521be3b31SYaroslav Tykhiy break;
736c4f0631fSJamie Gritton case LT_JAIL:
73721be3b31SYaroslav Tykhiy if (li->li_number < 0)
73821be3b31SYaroslav Tykhiy errx(STATUS_BADUSAGE,
73921be3b31SYaroslav Tykhiy "Negative jail ID `%s'", sp);
74021be3b31SYaroslav Tykhiy /* For compatibility with old -j */
74121be3b31SYaroslav Tykhiy if (li->li_number == 0)
74221be3b31SYaroslav Tykhiy li->li_number = -1; /* any jail */
74321be3b31SYaroslav Tykhiy break;
7442a546db8SDavid E. O'Brien case LT_TTY:
7452a546db8SDavid E. O'Brien if (li->li_number < 0)
7462a546db8SDavid E. O'Brien errx(STATUS_BADUSAGE,
7472a546db8SDavid E. O'Brien "Negative /dev/pts tty `%s'", sp);
7482a546db8SDavid E. O'Brien snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s",
7492a546db8SDavid E. O'Brien sp);
7502a546db8SDavid E. O'Brien if (stat(buf, &st) != -1)
7512a546db8SDavid E. O'Brien goto foundtty;
7522a546db8SDavid E. O'Brien if (errno == ENOENT)
7532a546db8SDavid E. O'Brien errx(STATUS_BADUSAGE, "No such tty: `"
7542a546db8SDavid E. O'Brien _PATH_DEV "pts/%s'", sp);
7552a546db8SDavid E. O'Brien err(STATUS_ERROR, "Cannot access `"
7562a546db8SDavid E. O'Brien _PATH_DEV "pts/%s'", sp);
7572a546db8SDavid E. O'Brien break;
75821be3b31SYaroslav Tykhiy default:
75921be3b31SYaroslav Tykhiy break;
76021be3b31SYaroslav Tykhiy }
76121be3b31SYaroslav Tykhiy continue;
76221be3b31SYaroslav Tykhiy }
76321be3b31SYaroslav Tykhiy
76421be3b31SYaroslav Tykhiy switch (type) {
76521be3b31SYaroslav Tykhiy case LT_USER:
76621be3b31SYaroslav Tykhiy if ((pw = getpwnam(sp)) == NULL)
76721be3b31SYaroslav Tykhiy errx(STATUS_BADUSAGE, "Unknown user `%s'", sp);
76821be3b31SYaroslav Tykhiy li->li_number = pw->pw_uid;
76921be3b31SYaroslav Tykhiy break;
77021be3b31SYaroslav Tykhiy case LT_GROUP:
77121be3b31SYaroslav Tykhiy if ((gr = getgrnam(sp)) == NULL)
77221be3b31SYaroslav Tykhiy errx(STATUS_BADUSAGE, "Unknown group `%s'", sp);
77321be3b31SYaroslav Tykhiy li->li_number = gr->gr_gid;
77421be3b31SYaroslav Tykhiy break;
77521be3b31SYaroslav Tykhiy case LT_TTY:
77621be3b31SYaroslav Tykhiy if (strcmp(sp, "-") == 0) {
77721be3b31SYaroslav Tykhiy li->li_number = -1;
77821be3b31SYaroslav Tykhiy break;
77921be3b31SYaroslav Tykhiy } else if (strcmp(sp, "co") == 0) {
78021be3b31SYaroslav Tykhiy cp = "console";
78121be3b31SYaroslav Tykhiy } else {
78221be3b31SYaroslav Tykhiy cp = sp;
78321be3b31SYaroslav Tykhiy }
78421be3b31SYaroslav Tykhiy
785eb948eacSEd Schouten snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp);
78618aa158fSEd Schouten if (stat(buf, &st) != -1)
78718aa158fSEd Schouten goto foundtty;
78821be3b31SYaroslav Tykhiy
78918aa158fSEd Schouten snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp);
79018aa158fSEd Schouten if (stat(buf, &st) != -1)
79118aa158fSEd Schouten goto foundtty;
79218aa158fSEd Schouten
79318aa158fSEd Schouten if (errno == ENOENT)
79418aa158fSEd Schouten errx(STATUS_BADUSAGE, "No such tty: `%s'", sp);
79521be3b31SYaroslav Tykhiy err(STATUS_ERROR, "Cannot access `%s'", sp);
79621be3b31SYaroslav Tykhiy
79718aa158fSEd Schouten foundtty: if ((st.st_mode & S_IFCHR) == 0)
79821be3b31SYaroslav Tykhiy errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp);
79921be3b31SYaroslav Tykhiy
80021be3b31SYaroslav Tykhiy li->li_number = st.st_rdev;
80121be3b31SYaroslav Tykhiy break;
802c4f0631fSJamie Gritton case LT_JAIL: {
803c4f0631fSJamie Gritton int jid;
804c4f0631fSJamie Gritton
80521be3b31SYaroslav Tykhiy if (strcmp(sp, "none") == 0)
80621be3b31SYaroslav Tykhiy li->li_number = 0;
80721be3b31SYaroslav Tykhiy else if (strcmp(sp, "any") == 0)
80821be3b31SYaroslav Tykhiy li->li_number = -1;
809c4f0631fSJamie Gritton else if ((jid = jail_getid(sp)) != -1)
810c4f0631fSJamie Gritton li->li_number = jid;
81121be3b31SYaroslav Tykhiy else if (*ep != '\0')
81221be3b31SYaroslav Tykhiy errx(STATUS_BADUSAGE,
813c4f0631fSJamie Gritton "Invalid jail ID or name `%s'", sp);
81421be3b31SYaroslav Tykhiy break;
815c4f0631fSJamie Gritton }
816cc55ad3dSEdward Tomasz Napierala case LT_CLASS:
817cc55ad3dSEdward Tomasz Napierala li->li_number = -1;
818cc55ad3dSEdward Tomasz Napierala li->li_name = strdup(sp);
819cc55ad3dSEdward Tomasz Napierala if (li->li_name == NULL)
820cc55ad3dSEdward Tomasz Napierala err(STATUS_ERROR, "Cannot allocate memory");
821cc55ad3dSEdward Tomasz Napierala break;
82221be3b31SYaroslav Tykhiy default:
82321be3b31SYaroslav Tykhiy usage();
82421be3b31SYaroslav Tykhiy }
82521be3b31SYaroslav Tykhiy }
82621be3b31SYaroslav Tykhiy
82721be3b31SYaroslav Tykhiy if (empty)
82821be3b31SYaroslav Tykhiy usage();
82921be3b31SYaroslav Tykhiy }
83021be3b31SYaroslav Tykhiy
83121be3b31SYaroslav Tykhiy static int
takepid(const char * pidfile,int pidfilelock)83221be3b31SYaroslav Tykhiy takepid(const char *pidfile, int pidfilelock)
83321be3b31SYaroslav Tykhiy {
83421be3b31SYaroslav Tykhiy char *endp, line[BUFSIZ];
83521be3b31SYaroslav Tykhiy FILE *fh;
83621be3b31SYaroslav Tykhiy long rval;
83721be3b31SYaroslav Tykhiy
83821be3b31SYaroslav Tykhiy fh = fopen(pidfile, "r");
83921be3b31SYaroslav Tykhiy if (fh == NULL)
84021be3b31SYaroslav Tykhiy err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile);
84121be3b31SYaroslav Tykhiy
84221be3b31SYaroslav Tykhiy if (pidfilelock) {
84321be3b31SYaroslav Tykhiy /*
84421be3b31SYaroslav Tykhiy * If we can lock pidfile, this means that daemon is not
84521be3b31SYaroslav Tykhiy * running, so would be better not to kill some random process.
84621be3b31SYaroslav Tykhiy */
84721be3b31SYaroslav Tykhiy if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) {
84821be3b31SYaroslav Tykhiy (void)fclose(fh);
84921be3b31SYaroslav Tykhiy errx(STATUS_ERROR, "File '%s' can be locked", pidfile);
85021be3b31SYaroslav Tykhiy } else {
85121be3b31SYaroslav Tykhiy if (errno != EWOULDBLOCK) {
85221be3b31SYaroslav Tykhiy errx(STATUS_ERROR,
85321be3b31SYaroslav Tykhiy "Error while locking file '%s'", pidfile);
85421be3b31SYaroslav Tykhiy }
85521be3b31SYaroslav Tykhiy }
85621be3b31SYaroslav Tykhiy }
85721be3b31SYaroslav Tykhiy
85821be3b31SYaroslav Tykhiy if (fgets(line, sizeof(line), fh) == NULL) {
85921be3b31SYaroslav Tykhiy if (feof(fh)) {
86021be3b31SYaroslav Tykhiy (void)fclose(fh);
86121be3b31SYaroslav Tykhiy errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile);
86221be3b31SYaroslav Tykhiy }
86321be3b31SYaroslav Tykhiy (void)fclose(fh);
86421be3b31SYaroslav Tykhiy err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile);
86521be3b31SYaroslav Tykhiy }
86621be3b31SYaroslav Tykhiy (void)fclose(fh);
86721be3b31SYaroslav Tykhiy
86821be3b31SYaroslav Tykhiy rval = strtol(line, &endp, 10);
86921be3b31SYaroslav Tykhiy if (*endp != '\0' && !isspace((unsigned char)*endp))
87021be3b31SYaroslav Tykhiy errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
87121be3b31SYaroslav Tykhiy else if (rval < MIN_PID || rval > MAX_PID)
87221be3b31SYaroslav Tykhiy errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
87321be3b31SYaroslav Tykhiy return (rval);
87421be3b31SYaroslav Tykhiy }
875