xref: /openbsd-src/usr.bin/pkill/pkill.c (revision cb3e16ae1034a2c4961aa569840dd72050cf92de)
1*cb3e16aeSderaadt /*	$OpenBSD: pkill.c,v 1.43 2021/09/01 15:54:40 deraadt Exp $	*/
245580423Smillert /*	$NetBSD: pkill.c,v 1.5 2002/10/27 11:49:34 kleink Exp $	*/
345580423Smillert 
445580423Smillert /*-
545580423Smillert  * Copyright (c) 2002 The NetBSD Foundation, Inc.
645580423Smillert  * All rights reserved.
745580423Smillert  *
845580423Smillert  * This code is derived from software contributed to The NetBSD Foundation
945580423Smillert  * by Andrew Doran.
1045580423Smillert  *
1145580423Smillert  * Redistribution and use in source and binary forms, with or without
1245580423Smillert  * modification, are permitted provided that the following conditions
1345580423Smillert  * are met:
1445580423Smillert  * 1. Redistributions of source code must retain the above copyright
1545580423Smillert  *    notice, this list of conditions and the following disclaimer.
1645580423Smillert  * 2. Redistributions in binary form must reproduce the above copyright
1745580423Smillert  *    notice, this list of conditions and the following disclaimer in the
1845580423Smillert  *    documentation and/or other materials provided with the distribution.
1945580423Smillert  *
2045580423Smillert  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2145580423Smillert  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2245580423Smillert  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2345580423Smillert  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2445580423Smillert  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2545580423Smillert  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2645580423Smillert  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2745580423Smillert  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2845580423Smillert  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2945580423Smillert  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3045580423Smillert  * POSSIBILITY OF SUCH DAMAGE.
3145580423Smillert  */
3245580423Smillert 
3345580423Smillert #include <sys/types.h>
3445580423Smillert #include <sys/sysctl.h>
35*cb3e16aeSderaadt #include <sys/signal.h>
3645580423Smillert #include <sys/proc.h>
3745580423Smillert #include <sys/queue.h>
3845580423Smillert #include <sys/stat.h>
391b2463c8Smarkus #include <sys/socket.h>
4045580423Smillert 
4145580423Smillert #include <stdio.h>
4245580423Smillert #include <stdlib.h>
4383d16d5cSmillert #include <stdint.h>
4445580423Smillert #include <limits.h>
4545580423Smillert #include <string.h>
4645580423Smillert #include <unistd.h>
4745580423Smillert #include <signal.h>
4845580423Smillert #include <regex.h>
4945580423Smillert #include <ctype.h>
5045580423Smillert #include <kvm.h>
5145580423Smillert #include <err.h>
5245580423Smillert #include <pwd.h>
5345580423Smillert #include <grp.h>
5445580423Smillert #include <errno.h>
5545580423Smillert 
5645580423Smillert #define	STATUS_MATCH	0
5745580423Smillert #define	STATUS_NOMATCH	1
5845580423Smillert #define	STATUS_BADUSAGE	2
5945580423Smillert #define	STATUS_ERROR	3
6045580423Smillert 
6145580423Smillert enum listtype {
6245580423Smillert 	LT_GENERIC,
6345580423Smillert 	LT_USER,
6445580423Smillert 	LT_GROUP,
6545580423Smillert 	LT_TTY,
6645580423Smillert 	LT_PGRP,
671b2463c8Smarkus 	LT_SID,
681b2463c8Smarkus 	LT_RTABLE
6945580423Smillert };
7045580423Smillert 
7145580423Smillert struct list {
7245580423Smillert 	SLIST_ENTRY(list) li_chain;
7345580423Smillert 	long	li_number;
7445580423Smillert };
7545580423Smillert 
7645580423Smillert SLIST_HEAD(listhead, list);
7745580423Smillert 
785027561dSguenther struct kinfo_proc	*plist;
7945580423Smillert char	*selected;
8065e8c1ceSgsoares const char	*delim = "\n";
8145580423Smillert int	nproc;
8245580423Smillert int	pgrep;
8345580423Smillert int	signum = SIGTERM;
8445580423Smillert int	newest;
8583d16d5cSmillert int	oldest;
86d2e6cab4Sespie int 	quiet;
8745580423Smillert int	inverse;
8845580423Smillert int	longfmt;
8945580423Smillert int	matchargs;
9045580423Smillert int	fullmatch;
91e880abb2Stedu int	confirmkill;
9245580423Smillert kvm_t	*kd;
9345580423Smillert pid_t	mypid;
9445580423Smillert 
9545580423Smillert struct listhead euidlist = SLIST_HEAD_INITIALIZER(list);
9645580423Smillert struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list);
9745580423Smillert struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list);
9845580423Smillert struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list);
9945580423Smillert struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list);
10045580423Smillert struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list);
10145580423Smillert struct listhead sidlist = SLIST_HEAD_INITIALIZER(list);
1021b2463c8Smarkus struct listhead rtablist = SLIST_HEAD_INITIALIZER(list);
10345580423Smillert 
10465e8c1ceSgsoares static void __dead	usage(void);
10565e8c1ceSgsoares static int	killact(struct kinfo_proc *, int);
10665e8c1ceSgsoares static int	grepact(struct kinfo_proc *, int);
10765e8c1ceSgsoares static void	makelist(struct listhead *, enum listtype, char *);
10865e8c1ceSgsoares static char	*getargv(struct kinfo_proc *);
10965e8c1ceSgsoares static int	askyn(struct kinfo_proc *);
11045580423Smillert 
11145580423Smillert extern char *__progname;
11245580423Smillert 
11365e8c1ceSgsoares static char *
getargv(struct kinfo_proc * kp)114e880abb2Stedu getargv(struct kinfo_proc *kp)
115e880abb2Stedu {
116e880abb2Stedu 	static char buf[_POSIX2_LINE_MAX];
117e880abb2Stedu 	char **pargv;
118e880abb2Stedu 	size_t j;
119e880abb2Stedu 
120e880abb2Stedu 	if ((pargv = kvm_getargv(kd, kp, 0)) == NULL) {
121e880abb2Stedu 		strlcpy(buf, kp->p_comm, sizeof(buf));
122e880abb2Stedu 		return buf;
123e880abb2Stedu 	}
124e880abb2Stedu 
125e880abb2Stedu 	j = 0;
126e880abb2Stedu 	while (j < sizeof(buf) && *pargv != NULL) {
127e880abb2Stedu 		int ret;
128e880abb2Stedu 
129e880abb2Stedu 		ret = snprintf(buf + j, sizeof(buf) - j,
130e880abb2Stedu 		    pargv[1] != NULL ? "%s " : "%s", pargv[0]);
131e880abb2Stedu 		if (ret >= sizeof(buf) - j)
132e880abb2Stedu 			j += sizeof(buf) - j - 1;
133e880abb2Stedu 		else if (ret > 0)
134e880abb2Stedu 			j += ret;
135e880abb2Stedu 		pargv++;
136e880abb2Stedu 	}
137e880abb2Stedu 	return buf;
138e880abb2Stedu }
139e880abb2Stedu 
14045580423Smillert int
main(int argc,char ** argv)14145580423Smillert main(int argc, char **argv)
14245580423Smillert {
143e880abb2Stedu 	char buf[_POSIX2_LINE_MAX], *mstr, *p, *q;
14445580423Smillert 	int i, j, ch, bestidx, rv, criteria;
1455027561dSguenther 	int (*action)(struct kinfo_proc *, int);
1465027561dSguenther 	struct kinfo_proc *kp;
14745580423Smillert 	struct list *li;
1481bbd613dSmillert 	u_int32_t bestsec, bestusec;
14945580423Smillert 	regex_t reg;
15045580423Smillert 	regmatch_t regmatch;
15145580423Smillert 
15245580423Smillert 	if (strcmp(__progname, "pgrep") == 0) {
15345580423Smillert 		action = grepact;
15445580423Smillert 		pgrep = 1;
15545580423Smillert 	} else {
15645580423Smillert 		action = killact;
1571bbd613dSmillert 		p = argv[1];
15845580423Smillert 
1591bbd613dSmillert 		if (argc > 1 && p[0] == '-') {
1601bbd613dSmillert 			p++;
1611bbd613dSmillert 			i = (int)strtol(p, &q, 10);
16245580423Smillert 			if (*q == '\0') {
16345580423Smillert 				signum = i;
16445580423Smillert 				argv++;
16545580423Smillert 				argc--;
16645580423Smillert 			} else {
1671bbd613dSmillert 				if (strncasecmp(p, "sig", 3) == 0)
1681bbd613dSmillert 					p += 3;
16945580423Smillert 				for (i = 1; i < NSIG; i++)
1701bbd613dSmillert 					if (strcasecmp(sys_signame[i], p) == 0)
17145580423Smillert 						break;
17245580423Smillert 				if (i != NSIG) {
17345580423Smillert 					signum = i;
17445580423Smillert 					argv++;
17545580423Smillert 					argc--;
17645580423Smillert 				}
17745580423Smillert 			}
17845580423Smillert 		}
17945580423Smillert 	}
18045580423Smillert 
18145580423Smillert 	criteria = 0;
18245580423Smillert 
183e880abb2Stedu 	while ((ch = getopt(argc, argv, "G:P:T:U:d:fg:Ilnoqs:t:u:vx")) != -1)
18445580423Smillert 		switch (ch) {
18545580423Smillert 		case 'G':
18645580423Smillert 			makelist(&rgidlist, LT_GROUP, optarg);
18745580423Smillert 			criteria = 1;
18845580423Smillert 			break;
18945580423Smillert 		case 'P':
19045580423Smillert 			makelist(&ppidlist, LT_GENERIC, optarg);
19145580423Smillert 			criteria = 1;
19245580423Smillert 			break;
1931b2463c8Smarkus 		case 'T':
1941b2463c8Smarkus 			makelist(&rtablist, LT_RTABLE, optarg);
1951b2463c8Smarkus 			criteria = 1;
1961b2463c8Smarkus 			break;
19745580423Smillert 		case 'U':
19845580423Smillert 			makelist(&ruidlist, LT_USER, optarg);
19945580423Smillert 			criteria = 1;
20045580423Smillert 			break;
20145580423Smillert 		case 'd':
20245580423Smillert 			if (!pgrep)
20345580423Smillert 				usage();
20445580423Smillert 			delim = optarg;
20545580423Smillert 			break;
20645580423Smillert 		case 'f':
20745580423Smillert 			matchargs = 1;
20845580423Smillert 			break;
20945580423Smillert 		case 'g':
21045580423Smillert 			makelist(&pgrplist, LT_PGRP, optarg);
21145580423Smillert 			criteria = 1;
21245580423Smillert 			break;
213e880abb2Stedu 		case 'I':
214e880abb2Stedu 			confirmkill = 1;
215e880abb2Stedu 			break;
21645580423Smillert 		case 'l':
21745580423Smillert 			longfmt = 1;
21845580423Smillert 			break;
21945580423Smillert 		case 'n':
22045580423Smillert 			newest = 1;
22145580423Smillert 			criteria = 1;
22245580423Smillert 			break;
22383d16d5cSmillert 		case 'o':
22483d16d5cSmillert 			oldest = 1;
22583d16d5cSmillert 			criteria = 1;
22683d16d5cSmillert 			break;
227d2e6cab4Sespie 		case 'q':
228d2e6cab4Sespie 			quiet = 1;
229d2e6cab4Sespie 			break;
23045580423Smillert 		case 's':
23145580423Smillert 			makelist(&sidlist, LT_SID, optarg);
23245580423Smillert 			criteria = 1;
23345580423Smillert 			break;
23445580423Smillert 		case 't':
23545580423Smillert 			makelist(&tdevlist, LT_TTY, optarg);
23645580423Smillert 			criteria = 1;
23745580423Smillert 			break;
23845580423Smillert 		case 'u':
23945580423Smillert 			makelist(&euidlist, LT_USER, optarg);
24045580423Smillert 			criteria = 1;
24145580423Smillert 			break;
24245580423Smillert 		case 'v':
24345580423Smillert 			inverse = 1;
24445580423Smillert 			break;
24545580423Smillert 		case 'x':
24645580423Smillert 			fullmatch = 1;
24745580423Smillert 			break;
24845580423Smillert 		default:
24945580423Smillert 			usage();
25045580423Smillert 			/* NOTREACHED */
25145580423Smillert 		}
25245580423Smillert 
25345580423Smillert 	argc -= optind;
25445580423Smillert 	argv += optind;
25545580423Smillert 	if (argc != 0)
25645580423Smillert 		criteria = 1;
25783d16d5cSmillert 	if (!criteria || (newest && oldest))
25845580423Smillert 		usage();
25945580423Smillert 
26045580423Smillert 	mypid = getpid();
26145580423Smillert 
26245580423Smillert 	/*
26345580423Smillert 	 * Retrieve the list of running processes from the kernel.
26445580423Smillert 	 */
26545580423Smillert 	kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf);
26645580423Smillert 	if (kd == NULL)
26745580423Smillert 		errx(STATUS_ERROR, "kvm_openfiles(): %s", buf);
26845580423Smillert 
2695027561dSguenther 	plist = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc);
27045580423Smillert 	if (plist == NULL)
2715027561dSguenther 		errx(STATUS_ERROR, "kvm_getprocs() failed");
27245580423Smillert 
2735c17cc01Sderaadt 	if (matchargs == 0 && confirmkill == 0) {
2745c17cc01Sderaadt 		if (action == killact) {
2755c17cc01Sderaadt 			if (pledge("stdio proc", NULL) == -1)
27665e8c1ceSgsoares 				err(STATUS_ERROR, "pledge");
2775c17cc01Sderaadt 		} else if (action == grepact) {
2785c17cc01Sderaadt 			if (pledge("stdio", NULL) == -1)
27965e8c1ceSgsoares 				err(STATUS_ERROR, "pledge");
2805c17cc01Sderaadt 		}
2815c17cc01Sderaadt 	}
282814f35abSderaadt 
28345580423Smillert 	/*
28445580423Smillert 	 * Allocate memory which will be used to keep track of the
28545580423Smillert 	 * selection.
28645580423Smillert 	 */
287db4177c9Stedu 	if ((selected = calloc(nproc, 1)) == NULL)
28845580423Smillert 		errx(STATUS_ERROR, "memory allocation failure");
28945580423Smillert 
29045580423Smillert 	/*
29145580423Smillert 	 * Refine the selection.
29245580423Smillert 	 */
29345580423Smillert 	for (; *argv != NULL; argv++) {
294e2f012a0Srobert 		if ((rv = regcomp(&reg, *argv, REG_EXTENDED)) != 0) {
29545580423Smillert 			regerror(rv, &reg, buf, sizeof(buf));
29645580423Smillert 			errx(STATUS_BADUSAGE, "bad expression: %s", buf);
29745580423Smillert 		}
29845580423Smillert 
29945580423Smillert 		for (i = 0, kp = plist; i < nproc; i++, kp++) {
3000f1976c8Sguenther 			if (kp->p_pid == mypid)
30145580423Smillert 				continue;
30245580423Smillert 
303e880abb2Stedu 			if (matchargs)
304e880abb2Stedu 				mstr = getargv(kp);
305e880abb2Stedu 			else
3061bbd613dSmillert 				mstr = kp->p_comm;
30745580423Smillert 
30845580423Smillert 			rv = regexec(&reg, mstr, 1, &regmatch, 0);
30945580423Smillert 			if (rv == 0) {
31045580423Smillert 				if (fullmatch) {
31145580423Smillert 					if (regmatch.rm_so == 0 &&
31245580423Smillert 					    regmatch.rm_eo == strlen(mstr))
31345580423Smillert 						selected[i] = 1;
31445580423Smillert 				} else
31545580423Smillert 					selected[i] = 1;
31645580423Smillert 			} else if (rv != REG_NOMATCH) {
31745580423Smillert 				regerror(rv, &reg, buf, sizeof(buf));
31845580423Smillert 				errx(STATUS_ERROR, "regexec(): %s", buf);
31945580423Smillert 			}
32045580423Smillert 		}
32145580423Smillert 
32245580423Smillert 		regfree(&reg);
32345580423Smillert 	}
32445580423Smillert 
32545580423Smillert 	for (i = 0, kp = plist; i < nproc; i++, kp++) {
3260f1976c8Sguenther 		if (kp->p_pid == mypid)
32745580423Smillert 			continue;
32845580423Smillert 
32945580423Smillert 		SLIST_FOREACH(li, &ruidlist, li_chain)
3301bbd613dSmillert 			if (kp->p_ruid == (uid_t)li->li_number)
33145580423Smillert 				break;
33245580423Smillert 		if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
33345580423Smillert 			selected[i] = 0;
33445580423Smillert 			continue;
33545580423Smillert 		}
33645580423Smillert 
33745580423Smillert 		SLIST_FOREACH(li, &rgidlist, li_chain)
3381bbd613dSmillert 			if (kp->p_rgid == (gid_t)li->li_number)
33945580423Smillert 				break;
34045580423Smillert 		if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
34145580423Smillert 			selected[i] = 0;
34245580423Smillert 			continue;
34345580423Smillert 		}
34445580423Smillert 
34545580423Smillert 		SLIST_FOREACH(li, &euidlist, li_chain)
3461bbd613dSmillert 			if (kp->p_uid == (uid_t)li->li_number)
34745580423Smillert 				break;
34845580423Smillert 		if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
34945580423Smillert 			selected[i] = 0;
35045580423Smillert 			continue;
35145580423Smillert 		}
35245580423Smillert 
35345580423Smillert 		SLIST_FOREACH(li, &ppidlist, li_chain)
3541bbd613dSmillert 			if (kp->p_ppid == (uid_t)li->li_number)
35545580423Smillert 				break;
35645580423Smillert 		if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
35745580423Smillert 			selected[i] = 0;
35845580423Smillert 			continue;
35945580423Smillert 		}
36045580423Smillert 
36145580423Smillert 		SLIST_FOREACH(li, &pgrplist, li_chain)
3621bbd613dSmillert 			if (kp->p__pgid == (uid_t)li->li_number)
36345580423Smillert 				break;
36445580423Smillert 		if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
36545580423Smillert 			selected[i] = 0;
36645580423Smillert 			continue;
36745580423Smillert 		}
36845580423Smillert 
36945580423Smillert 		SLIST_FOREACH(li, &tdevlist, li_chain) {
37045580423Smillert 			if (li->li_number == -1 &&
371447f61ceSguenther 			    (kp->p_psflags & PS_CONTROLT) == 0)
37245580423Smillert 				break;
3731bbd613dSmillert 			if (kp->p_tdev == (uid_t)li->li_number)
37445580423Smillert 				break;
37545580423Smillert 		}
37645580423Smillert 		if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
37745580423Smillert 			selected[i] = 0;
37845580423Smillert 			continue;
37945580423Smillert 		}
38045580423Smillert 
38145580423Smillert 		SLIST_FOREACH(li, &sidlist, li_chain)
3821bbd613dSmillert 			if (kp->p_sid == (uid_t)li->li_number)
38345580423Smillert 				break;
38445580423Smillert 		if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
38545580423Smillert 			selected[i] = 0;
38645580423Smillert 			continue;
38745580423Smillert 		}
38845580423Smillert 
3891b2463c8Smarkus 		SLIST_FOREACH(li, &rtablist, li_chain)
3901b2463c8Smarkus 			if (kp->p_rtableid == (u_int32_t)li->li_number)
3911b2463c8Smarkus 				break;
3921b2463c8Smarkus 		if (SLIST_FIRST(&rtablist) != NULL && li == NULL) {
3931b2463c8Smarkus 			selected[i] = 0;
3941b2463c8Smarkus 			continue;
3951b2463c8Smarkus 		}
3961b2463c8Smarkus 
39745580423Smillert 		if (argc == 0)
39845580423Smillert 			selected[i] = 1;
39945580423Smillert 	}
40045580423Smillert 
40183d16d5cSmillert 	if (newest || oldest) {
40245580423Smillert 		bestidx = -1;
40345580423Smillert 
40483d16d5cSmillert 		if (newest)
40583d16d5cSmillert 			bestsec = bestusec = 0;
40683d16d5cSmillert 		else
40783d16d5cSmillert 			bestsec = bestusec = UINT32_MAX;
40883d16d5cSmillert 
40945580423Smillert 		for (i = 0, kp = plist; i < nproc; i++, kp++) {
41045580423Smillert 			if (!selected[i])
41145580423Smillert 				continue;
41245580423Smillert 
41383d16d5cSmillert 			if ((newest && (kp->p_ustart_sec > bestsec ||
4141bbd613dSmillert 			    (kp->p_ustart_sec == bestsec
41583d16d5cSmillert 			    && kp->p_ustart_usec > bestusec)))
41683d16d5cSmillert 			|| (oldest && (kp->p_ustart_sec < bestsec ||
41783d16d5cSmillert                             (kp->p_ustart_sec == bestsec
41883d16d5cSmillert                             && kp->p_ustart_usec < bestusec)))) {
41983d16d5cSmillert 
4201bbd613dSmillert 				bestsec = kp->p_ustart_sec;
4211bbd613dSmillert 				bestusec = kp->p_ustart_usec;
42245580423Smillert 				bestidx = i;
42345580423Smillert 			}
42445580423Smillert 		}
42545580423Smillert 
42645580423Smillert 		memset(selected, 0, nproc);
42745580423Smillert 		if (bestidx != -1)
42845580423Smillert 			selected[bestidx] = 1;
42945580423Smillert 	}
43045580423Smillert 
43145580423Smillert 	/*
43245580423Smillert 	 * Take the appropriate action for each matched process, if any.
43345580423Smillert 	 */
434b6c33612Smillert 	rv = STATUS_NOMATCH;
435b6c33612Smillert 	for (i = 0, j = 0, kp = plist; i < nproc; i++, kp++) {
4360f1976c8Sguenther 		if (kp->p_pid == mypid)
43745580423Smillert 			continue;
43804bf3307Shalex 		if (selected[i] == inverse)
43945580423Smillert 			continue;
44045580423Smillert 
441a33a3c03Shalex 		switch ((*action)(kp, j++)) {
442a33a3c03Shalex 		case STATUS_MATCH:
443a33a3c03Shalex 			if (rv != STATUS_ERROR)
4440f5777d4Smillert 				rv = STATUS_MATCH;
445a33a3c03Shalex 			break;
446a33a3c03Shalex 		case STATUS_NOMATCH:
447a33a3c03Shalex 			j--;
448a33a3c03Shalex 			break;
449a33a3c03Shalex 		case STATUS_ERROR:
450a33a3c03Shalex 			rv = STATUS_ERROR;
451a33a3c03Shalex 			break;
452a33a3c03Shalex 		}
45345580423Smillert 	}
454d2e6cab4Sespie 	if (pgrep && j && !quiet)
455b6c33612Smillert 		putchar('\n');
45645580423Smillert 
45765e8c1ceSgsoares 	return(rv);
45845580423Smillert }
45945580423Smillert 
46065e8c1ceSgsoares static void __dead
usage(void)46145580423Smillert usage(void)
46245580423Smillert {
46345580423Smillert 	const char *ustr;
46445580423Smillert 
46545580423Smillert 	if (pgrep)
466dbc30627Sajacoutot 		ustr = "[-flnoqvx] [-d delim]";
46745580423Smillert 	else
468e880abb2Stedu 		ustr = "[-signal] [-fIlnoqvx]";
46945580423Smillert 
4700ecd6060Sjmc 	fprintf(stderr, "usage: %s %s [-G gid] [-g pgrp] [-P ppid] [-s sid]"
4712e74a01cSjmc 	    "\n\t[-T rtable] [-t tty] [-U uid] [-u euid] [pattern ...]\n",
4721b2463c8Smarkus 	    __progname, ustr);
47345580423Smillert 
4741e77ae25Sjmc 	exit(STATUS_BADUSAGE);
47545580423Smillert }
47645580423Smillert 
47765e8c1ceSgsoares static int
askyn(struct kinfo_proc * kp)478e880abb2Stedu askyn(struct kinfo_proc *kp)
479e880abb2Stedu {
480e880abb2Stedu 	int first, ch;
481e880abb2Stedu 
482e880abb2Stedu 	printf("kill %d %.60s? ", (int)kp->p_pid, getargv(kp));
483e880abb2Stedu 	fflush(stdout);
484e880abb2Stedu 
485e880abb2Stedu 	first = ch = getchar();
486e880abb2Stedu 	while (ch != '\n' && ch != EOF)
487e880abb2Stedu 		ch = getchar();
488e880abb2Stedu 	return (first == 'y' || first == 'Y');
489e880abb2Stedu }
490e880abb2Stedu 
49165e8c1ceSgsoares static int
killact(struct kinfo_proc * kp,int dummy)4925027561dSguenther killact(struct kinfo_proc *kp, int dummy)
49345580423Smillert {
494e880abb2Stedu 	int doit;
495e880abb2Stedu 
496e880abb2Stedu 	if (confirmkill) {
497e880abb2Stedu 		doit = askyn(kp);
498e880abb2Stedu 	} else {
499d2e6cab4Sespie 		if (longfmt && !quiet)
50004bf3307Shalex 			printf("%d %s\n", (int)kp->p_pid, kp->p_comm);
501e880abb2Stedu 		doit = 1;
502e880abb2Stedu 	}
50345580423Smillert 
504e880abb2Stedu 	if (doit && kill(kp->p_pid, signum) == -1) {
505a33a3c03Shalex 		if (errno == ESRCH)
506a33a3c03Shalex 			return (STATUS_NOMATCH);
5070f5777d4Smillert 		warn("signalling pid %d", (int)kp->p_pid);
508a33a3c03Shalex 		return (STATUS_ERROR);
5090f5777d4Smillert 	}
510a33a3c03Shalex 	return (STATUS_MATCH);
51145580423Smillert }
51245580423Smillert 
51365e8c1ceSgsoares static int
grepact(struct kinfo_proc * kp,int printdelim)5145027561dSguenther grepact(struct kinfo_proc *kp, int printdelim)
51545580423Smillert {
51645580423Smillert 	char **argv;
51745580423Smillert 
518d2e6cab4Sespie 	if (quiet)
519a33a3c03Shalex 		return (STATUS_MATCH);
520a33a3c03Shalex 	if (longfmt && matchargs)
521a33a3c03Shalex 		if ((argv = kvm_getargv(kd, kp, 0)) == NULL)
522a33a3c03Shalex 			return (errno == ESRCH ? STATUS_NOMATCH : STATUS_ERROR);
523b6c33612Smillert 	if (printdelim)
524b6c33612Smillert 		fputs(delim, stdout);
52545580423Smillert 	if (longfmt && matchargs) {
5261bbd613dSmillert 		printf("%d ", (int)kp->p_pid);
52745580423Smillert 		for (; *argv != NULL; argv++) {
52845580423Smillert 			printf("%s", *argv);
52945580423Smillert 			if (argv[1] != NULL)
53045580423Smillert 				putchar(' ');
53145580423Smillert 		}
53245580423Smillert 	} else if (longfmt)
5331bbd613dSmillert 		printf("%d %s", (int)kp->p_pid, kp->p_comm);
53445580423Smillert 	else
5351bbd613dSmillert 		printf("%d", (int)kp->p_pid);
53645580423Smillert 
537a33a3c03Shalex 	return (STATUS_MATCH);
53845580423Smillert }
53945580423Smillert 
54065e8c1ceSgsoares static void
makelist(struct listhead * head,enum listtype type,char * src)54145580423Smillert makelist(struct listhead *head, enum listtype type, char *src)
54245580423Smillert {
54345580423Smillert 	struct list *li;
54445580423Smillert 	struct stat st;
545b9fc9a72Sderaadt 	char *sp, *p, buf[PATH_MAX];
546a0f924b8Smillert 	uid_t uid;
547a0f924b8Smillert 	gid_t gid;
54845580423Smillert 	int empty;
54945580423Smillert 
55045580423Smillert 	empty = 1;
55145580423Smillert 
55245580423Smillert 	while ((sp = strsep(&src, ",")) != NULL) {
55345580423Smillert 		if (*sp == '\0')
55445580423Smillert 			usage();
55545580423Smillert 
55645580423Smillert 		if ((li = malloc(sizeof(*li))) == NULL)
55745580423Smillert 			errx(STATUS_ERROR, "memory allocation failure");
55845580423Smillert 		SLIST_INSERT_HEAD(head, li, li_chain);
55945580423Smillert 		empty = 0;
56045580423Smillert 
5611b2463c8Smarkus 		li->li_number = strtol(sp, &p, 0);
56245580423Smillert 		if (*p == '\0') {
56345580423Smillert 			switch (type) {
56445580423Smillert 			case LT_PGRP:
56545580423Smillert 				if (li->li_number == 0)
56645580423Smillert 					li->li_number = getpgrp();
56745580423Smillert 				break;
56845580423Smillert 			case LT_SID:
56945580423Smillert 				if (li->li_number == 0)
57045580423Smillert 					li->li_number = getsid(mypid);
57145580423Smillert 				break;
5721b2463c8Smarkus 			case LT_RTABLE:
5731b2463c8Smarkus 				if (li->li_number < 0 ||
5741b2463c8Smarkus 				    li->li_number > RT_TABLEID_MAX)
5751b2463c8Smarkus 					errx(STATUS_BADUSAGE,
5761b2463c8Smarkus 					    "rtable out of range");
5771b2463c8Smarkus 				break;
57845580423Smillert 			case LT_TTY:
57945580423Smillert 				usage();
58045580423Smillert 			default:
58145580423Smillert 				break;
58245580423Smillert 			}
58345580423Smillert 			continue;
58445580423Smillert 		}
58545580423Smillert 
58645580423Smillert 		switch (type) {
58745580423Smillert 		case LT_USER:
588a0f924b8Smillert 			if (uid_from_user(sp, &uid) == -1)
58985308c32Sotto 				errx(STATUS_BADUSAGE, "unknown user `%s'", sp);
590a0f924b8Smillert 			li->li_number = uid;
59145580423Smillert 			break;
59245580423Smillert 		case LT_GROUP:
593a0f924b8Smillert 			if (gid_from_group(sp, &gid) == -1)
59485308c32Sotto 				errx(STATUS_BADUSAGE, "unknown group `%s'", sp);
595a0f924b8Smillert 			li->li_number = gid;
59645580423Smillert 			break;
59745580423Smillert 		case LT_TTY:
59845580423Smillert 			if (strcmp(sp, "-") == 0) {
59945580423Smillert 				li->li_number = -1;
60045580423Smillert 				break;
60145580423Smillert 			} else if (strcmp(sp, "co") == 0)
60245580423Smillert 				p = "console";
60345580423Smillert 			else if (strncmp(sp, "tty", 3) == 0)
60445580423Smillert 				p = sp;
60545580423Smillert 			else
60645580423Smillert 				p = NULL;
60745580423Smillert 
60845580423Smillert 			if (p == NULL)
60945580423Smillert 				snprintf(buf, sizeof(buf), "/dev/tty%s", sp);
61045580423Smillert 			else
61145580423Smillert 				snprintf(buf, sizeof(buf), "/dev/%s", p);
61245580423Smillert 
6133aaa63ebSderaadt 			if (stat(buf, &st) == -1) {
61445580423Smillert 				if (errno == ENOENT)
61545580423Smillert 					errx(STATUS_BADUSAGE,
61645580423Smillert 					    "no such tty: `%s'", sp);
61745580423Smillert 				err(STATUS_ERROR, "stat(%s)", sp);
61845580423Smillert 			}
61945580423Smillert 
620dc8143a2Sotto 			if (!S_ISCHR(st.st_mode))
62145580423Smillert 				errx(STATUS_BADUSAGE, "not a tty: `%s'", sp);
62245580423Smillert 
62345580423Smillert 			li->li_number = st.st_rdev;
62445580423Smillert 			break;
62545580423Smillert 		default:
62645580423Smillert 			usage();
627522cf29cSderaadt 		}
62845580423Smillert 	}
62945580423Smillert 
63045580423Smillert 	if (empty)
63145580423Smillert 		usage();
63245580423Smillert }
633