pkill.c revision 203802
1152521Spjd/*	$NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $	*/
2127412Sgad
3127412Sgad/*-
4127412Sgad * Copyright (c) 2002 The NetBSD Foundation, Inc.
5152518Spjd * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
6127412Sgad * All rights reserved.
7127412Sgad *
8127412Sgad * This code is derived from software contributed to The NetBSD Foundation
9127412Sgad * by Andrew Doran.
10127412Sgad *
11127412Sgad * Redistribution and use in source and binary forms, with or without
12127412Sgad * modification, are permitted provided that the following conditions
13127412Sgad * are met:
14127412Sgad * 1. Redistributions of source code must retain the above copyright
15127412Sgad *    notice, this list of conditions and the following disclaimer.
16127412Sgad * 2. Redistributions in binary form must reproduce the above copyright
17127412Sgad *    notice, this list of conditions and the following disclaimer in the
18127412Sgad *    documentation and/or other materials provided with the distribution.
19127412Sgad * 3. All advertising materials mentioning features or use of this software
20127412Sgad *    must display the following acknowledgement:
21127412Sgad *	This product includes software developed by the NetBSD
22127412Sgad *	Foundation, Inc. and its contributors.
23127412Sgad * 4. Neither the name of The NetBSD Foundation nor the names of its
24127412Sgad *    contributors may be used to endorse or promote products derived
25127412Sgad *    from this software without specific prior written permission.
26127412Sgad *
27127412Sgad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28127412Sgad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29127412Sgad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30127412Sgad * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31127412Sgad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32127412Sgad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33127412Sgad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34127412Sgad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35127412Sgad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36127412Sgad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37127412Sgad * POSSIBILITY OF SUCH DAMAGE.
38127412Sgad */
39127412Sgad
40127412Sgad#include <sys/cdefs.h>
41127412Sgad__FBSDID("$FreeBSD: head/bin/pkill/pkill.c 203802 2010-02-12 18:52:24Z pjd $");
42127412Sgad
43127412Sgad#include <sys/types.h>
44127412Sgad#include <sys/param.h>
45127412Sgad#include <sys/sysctl.h>
46127412Sgad#include <sys/proc.h>
47127412Sgad#include <sys/queue.h>
48127412Sgad#include <sys/stat.h>
49143878Spjd#include <sys/time.h>
50127425Sgad#include <sys/user.h>
51127412Sgad
52203802Spjd#include <assert.h>
53127412Sgad#include <stdio.h>
54127412Sgad#include <stdlib.h>
55127412Sgad#include <limits.h>
56127425Sgad#include <paths.h>
57127412Sgad#include <string.h>
58127412Sgad#include <unistd.h>
59127412Sgad#include <signal.h>
60127412Sgad#include <regex.h>
61127412Sgad#include <ctype.h>
62127425Sgad#include <fcntl.h>
63127412Sgad#include <kvm.h>
64127412Sgad#include <err.h>
65127412Sgad#include <pwd.h>
66127412Sgad#include <grp.h>
67127412Sgad#include <errno.h>
68132198Stjr#include <locale.h>
69127412Sgad
70127412Sgad#define	STATUS_MATCH	0
71127412Sgad#define	STATUS_NOMATCH	1
72127412Sgad#define	STATUS_BADUSAGE	2
73127412Sgad#define	STATUS_ERROR	3
74127412Sgad
75143874Spjd#define	MIN_PID	5
76143874Spjd#define	MAX_PID	99999
77143874Spjd
78143877Spjd/* Ignore system-processes (if '-S' flag is not specified) and myself. */
79143877Spjd#define	PSKIP(kp)	((kp)->ki_pid == mypid ||			\
80143877Spjd			 (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0))
81127425Sgad
82127412Sgadenum listtype {
83127412Sgad	LT_GENERIC,
84127412Sgad	LT_USER,
85127412Sgad	LT_GROUP,
86127412Sgad	LT_TTY,
87127412Sgad	LT_PGRP,
88164558Syar	LT_JID,
89127412Sgad	LT_SID
90127412Sgad};
91127412Sgad
92127412Sgadstruct list {
93127412Sgad	SLIST_ENTRY(list) li_chain;
94127412Sgad	long	li_number;
95127412Sgad};
96127412Sgad
97127412SgadSLIST_HEAD(listhead, list);
98127412Sgad
99152521Spjdstatic struct kinfo_proc *plist;
100152521Spjdstatic char	*selected;
101152521Spjdstatic const char *delim = "\n";
102152521Spjdstatic int	nproc;
103152521Spjdstatic int	pgrep;
104152521Spjdstatic int	signum = SIGTERM;
105152521Spjdstatic int	newest;
106152521Spjdstatic int	oldest;
107152521Spjdstatic int	interactive;
108152521Spjdstatic int	inverse;
109152521Spjdstatic int	longfmt;
110152521Spjdstatic int	matchargs;
111152521Spjdstatic int	fullmatch;
112152521Spjdstatic int	kthreads;
113152521Spjdstatic int	cflags = REG_EXTENDED;
114203802Spjdstatic int	quiet;
115152521Spjdstatic kvm_t	*kd;
116152521Spjdstatic pid_t	mypid;
117127412Sgad
118201145Santoinestatic struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist);
119201145Santoinestatic struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist);
120201145Santoinestatic struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist);
121201145Santoinestatic struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist);
122201145Santoinestatic struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist);
123201145Santoinestatic struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist);
124201145Santoinestatic struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist);
125201145Santoinestatic struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist);
126127412Sgad
127152521Spjdstatic void	usage(void) __attribute__((__noreturn__));
128152521Spjdstatic int	killact(const struct kinfo_proc *);
129152521Spjdstatic int	grepact(const struct kinfo_proc *);
130152521Spjdstatic void	makelist(struct listhead *, enum listtype, char *);
131152521Spjdstatic int	takepid(const char *, int);
132127412Sgad
133127412Sgadint
134127412Sgadmain(int argc, char **argv)
135127412Sgad{
136149471Spjd	char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile;
137127462Sgad	const char *execf, *coref;
138192242Sbrian	int ancestors, debug_opt;
139149471Spjd	int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock;
140127430Sgad	size_t jsz;
141152521Spjd	int (*action)(const struct kinfo_proc *);
142127425Sgad	struct kinfo_proc *kp;
143127412Sgad	struct list *li;
144127430Sgad	struct timeval best_tval;
145127412Sgad	regex_t reg;
146127412Sgad	regmatch_t regmatch;
147192242Sbrian	pid_t pid;
148127412Sgad
149132198Stjr	setlocale(LC_ALL, "");
150132198Stjr
151127412Sgad	if (strcmp(getprogname(), "pgrep") == 0) {
152127412Sgad		action = grepact;
153127412Sgad		pgrep = 1;
154127412Sgad	} else {
155127412Sgad		action = killact;
156127412Sgad		p = argv[1];
157127412Sgad
158127412Sgad		if (argc > 1 && p[0] == '-') {
159127412Sgad			p++;
160127412Sgad			i = (int)strtol(p, &q, 10);
161127412Sgad			if (*q == '\0') {
162127412Sgad				signum = i;
163127412Sgad				argv++;
164127412Sgad				argc--;
165127412Sgad			} else {
166127412Sgad				if (strncasecmp(p, "sig", 3) == 0)
167127412Sgad					p += 3;
168127412Sgad				for (i = 1; i < NSIG; i++)
169127412Sgad					if (strcasecmp(sys_signame[i], p) == 0)
170127412Sgad						break;
171127412Sgad				if (i != NSIG) {
172127412Sgad					signum = i;
173127412Sgad					argv++;
174127412Sgad					argc--;
175127412Sgad				}
176127412Sgad			}
177127412Sgad		}
178127412Sgad	}
179127412Sgad
180192242Sbrian	ancestors = 0;
181127412Sgad	criteria = 0;
182127433Sgad	debug_opt = 0;
183149471Spjd	pidfile = NULL;
184149471Spjd	pidfilelock = 0;
185203802Spjd	quiet = 0;
186203688Sbrucec	execf = NULL;
187203688Sbrucec	coref = _PATH_DEVNULL;
188127412Sgad
189203802Spjd	while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1)
190127412Sgad		switch (ch) {
191127433Sgad		case 'D':
192127433Sgad			debug_opt++;
193127433Sgad			break;
194143874Spjd		case 'F':
195149471Spjd			pidfile = optarg;
196143874Spjd			criteria = 1;
197143874Spjd			break;
198127412Sgad		case 'G':
199127412Sgad			makelist(&rgidlist, LT_GROUP, optarg);
200127412Sgad			criteria = 1;
201127412Sgad			break;
202152518Spjd		case 'I':
203152518Spjd			if (pgrep)
204152518Spjd				usage();
205152518Spjd			interactive = 1;
206152518Spjd			break;
207149471Spjd		case 'L':
208149471Spjd			pidfilelock = 1;
209149471Spjd			break;
210127427Sgad		case 'M':
211127427Sgad			coref = optarg;
212127427Sgad			break;
213127427Sgad		case 'N':
214127427Sgad			execf = optarg;
215127427Sgad			break;
216127412Sgad		case 'P':
217127412Sgad			makelist(&ppidlist, LT_GENERIC, optarg);
218127412Sgad			criteria = 1;
219127412Sgad			break;
220143877Spjd		case 'S':
221143877Spjd			if (!pgrep)
222143877Spjd				usage();
223143877Spjd			kthreads = 1;
224143877Spjd			break;
225127412Sgad		case 'U':
226127412Sgad			makelist(&ruidlist, LT_USER, optarg);
227127412Sgad			criteria = 1;
228127412Sgad			break;
229192242Sbrian		case 'a':
230192242Sbrian			ancestors++;
231192242Sbrian			break;
232127412Sgad		case 'd':
233127412Sgad			if (!pgrep)
234127412Sgad				usage();
235127412Sgad			delim = optarg;
236127412Sgad			break;
237127412Sgad		case 'f':
238127412Sgad			matchargs = 1;
239127412Sgad			break;
240127412Sgad		case 'g':
241127412Sgad			makelist(&pgrplist, LT_PGRP, optarg);
242127412Sgad			criteria = 1;
243127412Sgad			break;
244143875Spjd		case 'i':
245143875Spjd			cflags |= REG_ICASE;
246143875Spjd			break;
247143873Spjd		case 'j':
248164558Syar			makelist(&jidlist, LT_JID, optarg);
249143873Spjd			criteria = 1;
250143873Spjd			break;
251127412Sgad		case 'l':
252127412Sgad			if (!pgrep)
253127412Sgad				usage();
254127412Sgad			longfmt = 1;
255127412Sgad			break;
256127412Sgad		case 'n':
257127412Sgad			newest = 1;
258127412Sgad			criteria = 1;
259127412Sgad			break;
260143878Spjd		case 'o':
261143878Spjd			oldest = 1;
262143878Spjd			criteria = 1;
263143878Spjd			break;
264203802Spjd		case 'q':
265203802Spjd			if (!pgrep)
266203802Spjd				usage();
267203802Spjd			quiet = 1;
268203802Spjd			break;
269127412Sgad		case 's':
270127412Sgad			makelist(&sidlist, LT_SID, optarg);
271127412Sgad			criteria = 1;
272127412Sgad			break;
273127412Sgad		case 't':
274127412Sgad			makelist(&tdevlist, LT_TTY, optarg);
275127412Sgad			criteria = 1;
276127412Sgad			break;
277127412Sgad		case 'u':
278127412Sgad			makelist(&euidlist, LT_USER, optarg);
279127412Sgad			criteria = 1;
280127412Sgad			break;
281127412Sgad		case 'v':
282127412Sgad			inverse = 1;
283127412Sgad			break;
284127412Sgad		case 'x':
285127412Sgad			fullmatch = 1;
286127412Sgad			break;
287127412Sgad		default:
288127412Sgad			usage();
289127412Sgad			/* NOTREACHED */
290127412Sgad		}
291127412Sgad
292127412Sgad	argc -= optind;
293127412Sgad	argv += optind;
294127412Sgad	if (argc != 0)
295127412Sgad		criteria = 1;
296127412Sgad	if (!criteria)
297127412Sgad		usage();
298143878Spjd	if (newest && oldest)
299152521Spjd		errx(STATUS_ERROR, "Options -n and -o are mutually exclusive");
300149471Spjd	if (pidfile != NULL)
301149471Spjd		pidfromfile = takepid(pidfile, pidfilelock);
302149471Spjd	else {
303152521Spjd		if (pidfilelock) {
304152521Spjd			errx(STATUS_ERROR,
305152521Spjd			    "Option -L doesn't make sense without -F");
306152521Spjd		}
307149471Spjd		pidfromfile = -1;
308149471Spjd	}
309127412Sgad
310127412Sgad	mypid = getpid();
311127412Sgad
312127412Sgad	/*
313127412Sgad	 * Retrieve the list of running processes from the kernel.
314127412Sgad	 */
315127462Sgad	kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf);
316127412Sgad	if (kd == NULL)
317152521Spjd		errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf);
318127412Sgad
319127622Sgad	/*
320127622Sgad	 * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we
321127622Sgad	 * just want processes and not individual kernel threads.
322127622Sgad	 */
323127622Sgad	plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc);
324152521Spjd	if (plist == NULL) {
325152521Spjd		errx(STATUS_ERROR, "Cannot get process list (%s)",
326152521Spjd		    kvm_geterr(kd));
327152521Spjd	}
328127412Sgad
329127412Sgad	/*
330127412Sgad	 * Allocate memory which will be used to keep track of the
331127412Sgad	 * selection.
332127412Sgad	 */
333152521Spjd	if ((selected = malloc(nproc)) == NULL) {
334152521Spjd		err(STATUS_ERROR, "Cannot allocate memory for %d processes",
335152521Spjd		    nproc);
336152521Spjd	}
337127412Sgad	memset(selected, 0, nproc);
338127412Sgad
339127412Sgad	/*
340127412Sgad	 * Refine the selection.
341127412Sgad	 */
342127412Sgad	for (; *argv != NULL; argv++) {
343143875Spjd		if ((rv = regcomp(&reg, *argv, cflags)) != 0) {
344127412Sgad			regerror(rv, &reg, buf, sizeof(buf));
345152521Spjd			errx(STATUS_BADUSAGE,
346152521Spjd			    "Cannot compile regular expression `%s' (%s)",
347152521Spjd			    *argv, buf);
348127412Sgad		}
349127412Sgad
350127412Sgad		for (i = 0, kp = plist; i < nproc; i++, kp++) {
351143877Spjd			if (PSKIP(kp)) {
352127433Sgad				if (debug_opt > 0)
353127434Sgad				    fprintf(stderr, "* Skipped %5d %3d %s\n",
354127433Sgad					kp->ki_pid, kp->ki_uid, kp->ki_comm);
355127412Sgad				continue;
356127433Sgad			}
357127412Sgad
358143877Spjd			if (matchargs &&
359143877Spjd			    (pargv = kvm_getargv(kd, kp, 0)) != NULL) {
360127430Sgad				jsz = 0;
361127430Sgad				while (jsz < sizeof(buf) && *pargv != NULL) {
362127430Sgad					jsz += snprintf(buf + jsz,
363127430Sgad					    sizeof(buf) - jsz,
364127412Sgad					    pargv[1] != NULL ? "%s " : "%s",
365127412Sgad					    pargv[0]);
366127412Sgad					pargv++;
367127412Sgad				}
368127412Sgad				mstr = buf;
369127412Sgad			} else
370127425Sgad				mstr = kp->ki_comm;
371127412Sgad
372127412Sgad			rv = regexec(&reg, mstr, 1, &regmatch, 0);
373127412Sgad			if (rv == 0) {
374127412Sgad				if (fullmatch) {
375127412Sgad					if (regmatch.rm_so == 0 &&
376127431Sgad					    regmatch.rm_eo ==
377127431Sgad					    (off_t)strlen(mstr))
378127412Sgad						selected[i] = 1;
379127412Sgad				} else
380127412Sgad					selected[i] = 1;
381127412Sgad			} else if (rv != REG_NOMATCH) {
382127412Sgad				regerror(rv, &reg, buf, sizeof(buf));
383152521Spjd				errx(STATUS_ERROR,
384152521Spjd				    "Regular expression evaluation error (%s)",
385152521Spjd				    buf);
386127412Sgad			}
387127433Sgad			if (debug_opt > 1) {
388127433Sgad				const char *rv_res = "NoMatch";
389127433Sgad				if (selected[i])
390127433Sgad					rv_res = "Matched";
391127434Sgad				fprintf(stderr, "* %s %5d %3d %s\n", rv_res,
392127433Sgad				    kp->ki_pid, kp->ki_uid, mstr);
393127433Sgad			}
394127412Sgad		}
395127412Sgad
396127412Sgad		regfree(&reg);
397127412Sgad	}
398127412Sgad
399127412Sgad	for (i = 0, kp = plist; i < nproc; i++, kp++) {
400143877Spjd		if (PSKIP(kp))
401127412Sgad			continue;
402127412Sgad
403143874Spjd		if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) {
404143874Spjd			selected[i] = 0;
405143874Spjd			continue;
406143874Spjd		}
407143874Spjd
408127412Sgad		SLIST_FOREACH(li, &ruidlist, li_chain)
409127425Sgad			if (kp->ki_ruid == (uid_t)li->li_number)
410127412Sgad				break;
411127412Sgad		if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
412127412Sgad			selected[i] = 0;
413127412Sgad			continue;
414127412Sgad		}
415127429Sgad
416127412Sgad		SLIST_FOREACH(li, &rgidlist, li_chain)
417127425Sgad			if (kp->ki_rgid == (gid_t)li->li_number)
418127412Sgad				break;
419127412Sgad		if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
420127412Sgad			selected[i] = 0;
421127412Sgad			continue;
422127412Sgad		}
423127412Sgad
424127412Sgad		SLIST_FOREACH(li, &euidlist, li_chain)
425127425Sgad			if (kp->ki_uid == (uid_t)li->li_number)
426127412Sgad				break;
427127412Sgad		if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
428127412Sgad			selected[i] = 0;
429127412Sgad			continue;
430127412Sgad		}
431127412Sgad
432127412Sgad		SLIST_FOREACH(li, &ppidlist, li_chain)
433127426Sgad			if (kp->ki_ppid == (pid_t)li->li_number)
434127412Sgad				break;
435127412Sgad		if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
436127412Sgad			selected[i] = 0;
437127412Sgad			continue;
438127412Sgad		}
439127412Sgad
440127412Sgad		SLIST_FOREACH(li, &pgrplist, li_chain)
441127426Sgad			if (kp->ki_pgid == (pid_t)li->li_number)
442127412Sgad				break;
443127412Sgad		if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
444127412Sgad			selected[i] = 0;
445127412Sgad			continue;
446127412Sgad		}
447127412Sgad
448127412Sgad		SLIST_FOREACH(li, &tdevlist, li_chain) {
449127412Sgad			if (li->li_number == -1 &&
450127425Sgad			    (kp->ki_flag & P_CONTROLT) == 0)
451127412Sgad				break;
452130640Sphk			if (kp->ki_tdev == (dev_t)li->li_number)
453127412Sgad				break;
454127412Sgad		}
455127412Sgad		if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
456127412Sgad			selected[i] = 0;
457127412Sgad			continue;
458127412Sgad		}
459127412Sgad
460127412Sgad		SLIST_FOREACH(li, &sidlist, li_chain)
461127426Sgad			if (kp->ki_sid == (pid_t)li->li_number)
462127412Sgad				break;
463127412Sgad		if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
464127412Sgad			selected[i] = 0;
465127412Sgad			continue;
466127412Sgad		}
467127412Sgad
468143873Spjd		SLIST_FOREACH(li, &jidlist, li_chain) {
469164558Syar			/* A particular jail ID, including 0 (not in jail) */
470164558Syar			if (kp->ki_jid == (int)li->li_number)
471164558Syar				break;
472164558Syar			/* Any jail */
473164558Syar			if (kp->ki_jid > 0 && li->li_number == -1)
474164558Syar				break;
475143873Spjd		}
476143873Spjd		if (SLIST_FIRST(&jidlist) != NULL && li == NULL) {
477143873Spjd			selected[i] = 0;
478143873Spjd			continue;
479143873Spjd		}
480143873Spjd
481127412Sgad		if (argc == 0)
482127412Sgad			selected[i] = 1;
483127412Sgad	}
484127412Sgad
485192242Sbrian	if (!ancestors) {
486192242Sbrian		pid = mypid;
487192242Sbrian		while (pid) {
488192242Sbrian			for (i = 0, kp = plist; i < nproc; i++, kp++) {
489192242Sbrian				if (PSKIP(kp))
490192242Sbrian					continue;
491192242Sbrian				if (kp->ki_pid == pid) {
492192242Sbrian					selected[i] = 0;
493192242Sbrian					pid = kp->ki_ppid;
494192242Sbrian					break;
495192242Sbrian				}
496192242Sbrian			}
497192242Sbrian			if (i == nproc) {
498192242Sbrian				if (pid == mypid)
499192242Sbrian					pid = getppid();
500192242Sbrian				else
501192242Sbrian					break;	/* Maybe we're in a jail ? */
502192242Sbrian			}
503192242Sbrian		}
504192242Sbrian	}
505192242Sbrian
506143878Spjd	if (newest || oldest) {
507127430Sgad		best_tval.tv_sec = 0;
508127430Sgad		best_tval.tv_usec = 0;
509127412Sgad		bestidx = -1;
510127412Sgad
511127412Sgad		for (i = 0, kp = plist; i < nproc; i++, kp++) {
512127412Sgad			if (!selected[i])
513127412Sgad				continue;
514143878Spjd			if (bestidx == -1) {
515143878Spjd				/* The first entry of the list which matched. */
516143878Spjd				;
517143878Spjd			} else if (timercmp(&kp->ki_start, &best_tval, >)) {
518143878Spjd				/* This entry is newer than previous "best". */
519143879Spjd				if (oldest)	/* but we want the oldest */
520143878Spjd					continue;
521143878Spjd			} else {
522143878Spjd				/* This entry is older than previous "best". */
523143879Spjd				if (newest)	/* but we want the newest */
524143878Spjd					continue;
525127412Sgad			}
526143878Spjd			/* This entry is better than previous "best" entry. */
527143878Spjd			best_tval.tv_sec = kp->ki_start.tv_sec;
528143878Spjd			best_tval.tv_usec = kp->ki_start.tv_usec;
529143878Spjd			bestidx = i;
530127412Sgad		}
531127412Sgad
532127412Sgad		memset(selected, 0, nproc);
533127412Sgad		if (bestidx != -1)
534127412Sgad			selected[bestidx] = 1;
535127412Sgad	}
536127412Sgad
537127412Sgad	/*
538127412Sgad	 * Take the appropriate action for each matched process, if any.
539127412Sgad	 */
540127412Sgad	for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) {
541143877Spjd		if (PSKIP(kp))
542127412Sgad			continue;
543127412Sgad		if (selected[i]) {
544127412Sgad			if (inverse)
545127412Sgad				continue;
546127412Sgad		} else if (!inverse)
547127412Sgad			continue;
548152521Spjd		rv |= (*action)(kp);
549127412Sgad	}
550127412Sgad
551127412Sgad	exit(rv ? STATUS_MATCH : STATUS_NOMATCH);
552127412Sgad}
553127412Sgad
554152521Spjdstatic void
555127412Sgadusage(void)
556127412Sgad{
557127412Sgad	const char *ustr;
558127412Sgad
559127412Sgad	if (pgrep)
560203802Spjd		ustr = "[-LSfilnoqvx] [-d delim]";
561127412Sgad	else
562152518Spjd		ustr = "[-signal] [-ILfinovx]";
563127412Sgad
564127412Sgad	fprintf(stderr,
565143874Spjd		"usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n"
566143873Spjd		"             [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n"
567143873Spjd		"             [-t tty] [-u euid] pattern ...\n", getprogname(),
568143873Spjd		ustr);
569127412Sgad
570152521Spjd	exit(STATUS_BADUSAGE);
571127412Sgad}
572127412Sgad
573152518Spjdstatic void
574152521Spjdshow_process(const struct kinfo_proc *kp)
575127412Sgad{
576127412Sgad	char **argv;
577127412Sgad
578203802Spjd	if (quiet) {
579203802Spjd		assert(pgrep);
580203802Spjd		return;
581203802Spjd	}
582152518Spjd	if ((longfmt || !pgrep) && matchargs &&
583143877Spjd	    (argv = kvm_getargv(kd, kp, 0)) != NULL) {
584127425Sgad		printf("%d ", (int)kp->ki_pid);
585127412Sgad		for (; *argv != NULL; argv++) {
586127412Sgad			printf("%s", *argv);
587127412Sgad			if (argv[1] != NULL)
588127412Sgad				putchar(' ');
589127412Sgad		}
590152518Spjd	} else if (longfmt || !pgrep)
591127425Sgad		printf("%d %s", (int)kp->ki_pid, kp->ki_comm);
592127412Sgad	else
593127425Sgad		printf("%d", (int)kp->ki_pid);
594152518Spjd}
595127412Sgad
596152521Spjdstatic int
597152521Spjdkillact(const struct kinfo_proc *kp)
598152518Spjd{
599152518Spjd	int ch, first;
600152518Spjd
601152518Spjd	if (interactive) {
602152518Spjd		/*
603152518Spjd		 * Be careful, ask before killing.
604152518Spjd		 */
605152518Spjd		printf("kill ");
606152518Spjd		show_process(kp);
607152518Spjd		printf("? ");
608152518Spjd		fflush(stdout);
609152518Spjd		first = ch = getchar();
610152518Spjd		while (ch != '\n' && ch != EOF)
611152518Spjd			ch = getchar();
612152518Spjd		if (first != 'y' && first != 'Y')
613152521Spjd			return (1);
614152518Spjd	}
615152521Spjd	if (kill(kp->ki_pid, signum) == -1) {
616152521Spjd		/*
617152521Spjd		 * Check for ESRCH, which indicates that the process
618152521Spjd		 * disappeared between us matching it and us
619152521Spjd		 * signalling it; don't issue a warning about it.
620152521Spjd		 */
621152521Spjd		if (errno != ESRCH)
622152521Spjd			warn("signalling pid %d", (int)kp->ki_pid);
623152521Spjd		/*
624152521Spjd		 * Return 0 to indicate that the process should not be
625152521Spjd		 * considered a match, since we didn't actually get to
626152521Spjd		 * signal it.
627152521Spjd		 */
628152521Spjd		return (0);
629152521Spjd	}
630152521Spjd	return (1);
631152518Spjd}
632152518Spjd
633152521Spjdstatic int
634152521Spjdgrepact(const struct kinfo_proc *kp)
635152518Spjd{
636152518Spjd
637152518Spjd	show_process(kp);
638203802Spjd	if (!quiet)
639203802Spjd		printf("%s", delim);
640152521Spjd	return (1);
641127412Sgad}
642127412Sgad
643152521Spjdstatic void
644127412Sgadmakelist(struct listhead *head, enum listtype type, char *src)
645127412Sgad{
646127412Sgad	struct list *li;
647127412Sgad	struct passwd *pw;
648127412Sgad	struct group *gr;
649127412Sgad	struct stat st;
650183438Sed	const char *cp;
651152521Spjd	char *sp, *ep, buf[MAXPATHLEN];
652127412Sgad	int empty;
653127412Sgad
654127412Sgad	empty = 1;
655127412Sgad
656127412Sgad	while ((sp = strsep(&src, ",")) != NULL) {
657127412Sgad		if (*sp == '\0')
658127412Sgad			usage();
659127412Sgad
660152521Spjd		if ((li = malloc(sizeof(*li))) == NULL) {
661152521Spjd			err(STATUS_ERROR, "Cannot allocate %zu bytes",
662152521Spjd			    sizeof(*li));
663152521Spjd		}
664152521Spjd
665127412Sgad		SLIST_INSERT_HEAD(head, li, li_chain);
666127412Sgad		empty = 0;
667127412Sgad
668152521Spjd		li->li_number = (uid_t)strtol(sp, &ep, 0);
669152521Spjd		if (*ep == '\0') {
670127412Sgad			switch (type) {
671127412Sgad			case LT_PGRP:
672127412Sgad				if (li->li_number == 0)
673127412Sgad					li->li_number = getpgrp();
674127412Sgad				break;
675127412Sgad			case LT_SID:
676127412Sgad				if (li->li_number == 0)
677127412Sgad					li->li_number = getsid(mypid);
678127412Sgad				break;
679164558Syar			case LT_JID:
680164558Syar				if (li->li_number < 0)
681164558Syar					errx(STATUS_BADUSAGE,
682164558Syar					     "Negative jail ID `%s'", sp);
683164558Syar				/* For compatibility with old -j */
684164558Syar				if (li->li_number == 0)
685164558Syar					li->li_number = -1;	/* any jail */
686164558Syar				break;
687201487Sobrien			case LT_TTY:
688201487Sobrien				if (li->li_number < 0)
689201487Sobrien					errx(STATUS_BADUSAGE,
690201487Sobrien					     "Negative /dev/pts tty `%s'", sp);
691201487Sobrien				snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s",
692201487Sobrien				    sp);
693201487Sobrien				if (stat(buf, &st) != -1)
694201487Sobrien					goto foundtty;
695201487Sobrien				if (errno == ENOENT)
696201487Sobrien					errx(STATUS_BADUSAGE, "No such tty: `"
697201487Sobrien					    _PATH_DEV "pts/%s'", sp);
698201487Sobrien				err(STATUS_ERROR, "Cannot access `"
699201487Sobrien				    _PATH_DEV "pts/%s'", sp);
700201487Sobrien				break;
701127412Sgad			default:
702127412Sgad				break;
703127412Sgad			}
704127412Sgad			continue;
705127412Sgad		}
706127412Sgad
707127412Sgad		switch (type) {
708127412Sgad		case LT_USER:
709127412Sgad			if ((pw = getpwnam(sp)) == NULL)
710152521Spjd				errx(STATUS_BADUSAGE, "Unknown user `%s'", sp);
711127412Sgad			li->li_number = pw->pw_uid;
712127412Sgad			break;
713127412Sgad		case LT_GROUP:
714127412Sgad			if ((gr = getgrnam(sp)) == NULL)
715152521Spjd				errx(STATUS_BADUSAGE, "Unknown group `%s'", sp);
716127412Sgad			li->li_number = gr->gr_gid;
717127412Sgad			break;
718127412Sgad		case LT_TTY:
719127412Sgad			if (strcmp(sp, "-") == 0) {
720127412Sgad				li->li_number = -1;
721127412Sgad				break;
722152521Spjd			} else if (strcmp(sp, "co") == 0) {
723127430Sgad				cp = "console";
724152521Spjd			} else {
725127430Sgad				cp = sp;
726152521Spjd			}
727127412Sgad
728183438Sed			snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp);
729183502Sed			if (stat(buf, &st) != -1)
730183502Sed				goto foundtty;
731127412Sgad
732183502Sed			snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp);
733183502Sed			if (stat(buf, &st) != -1)
734183502Sed				goto foundtty;
735127412Sgad
736183502Sed			if (errno == ENOENT)
737183502Sed				errx(STATUS_BADUSAGE, "No such tty: `%s'", sp);
738183502Sed			err(STATUS_ERROR, "Cannot access `%s'", sp);
739183502Sed
740183502Sedfoundtty:		if ((st.st_mode & S_IFCHR) == 0)
741152521Spjd				errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp);
742127412Sgad
743127412Sgad			li->li_number = st.st_rdev;
744127412Sgad			break;
745164558Syar		case LT_JID:
746164558Syar			if (strcmp(sp, "none") == 0)
747164558Syar				li->li_number = 0;
748164558Syar			else if (strcmp(sp, "any") == 0)
749164558Syar				li->li_number = -1;
750164558Syar			else if (*ep != '\0')
751164558Syar				errx(STATUS_BADUSAGE,
752164558Syar				     "Invalid jail ID `%s'", sp);
753164558Syar			break;
754127412Sgad		default:
755127412Sgad			usage();
756152521Spjd		}
757127412Sgad	}
758127412Sgad
759127412Sgad	if (empty)
760127412Sgad		usage();
761127412Sgad}
762143874Spjd
763152521Spjdstatic int
764149471Spjdtakepid(const char *pidfile, int pidfilelock)
765143874Spjd{
766143874Spjd	char *endp, line[BUFSIZ];
767143874Spjd	FILE *fh;
768143874Spjd	long rval;
769143879Spjd
770143874Spjd	fh = fopen(pidfile, "r");
771143874Spjd	if (fh == NULL)
772152521Spjd		err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile);
773143879Spjd
774149471Spjd	if (pidfilelock) {
775149471Spjd		/*
776149471Spjd		 * If we can lock pidfile, this means that daemon is not
777149471Spjd		 * running, so would be better not to kill some random process.
778149471Spjd		 */
779149471Spjd		if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) {
780149471Spjd			(void)fclose(fh);
781152521Spjd			errx(STATUS_ERROR, "File '%s' can be locked", pidfile);
782149471Spjd		} else {
783149471Spjd			if (errno != EWOULDBLOCK) {
784149471Spjd				errx(STATUS_ERROR,
785152521Spjd				    "Error while locking file '%s'", pidfile);
786149471Spjd			}
787149435Spjd		}
788149435Spjd	}
789149435Spjd
790143874Spjd	if (fgets(line, sizeof(line), fh) == NULL) {
791143874Spjd		if (feof(fh)) {
792143874Spjd			(void)fclose(fh);
793152521Spjd			errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile);
794143874Spjd		}
795143874Spjd		(void)fclose(fh);
796152521Spjd		err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile);
797143874Spjd	}
798143874Spjd	(void)fclose(fh);
799143879Spjd
800143874Spjd	rval = strtol(line, &endp, 10);
801143874Spjd	if (*endp != '\0' && !isspace((unsigned char)*endp))
802152521Spjd		errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
803143874Spjd	else if (rval < MIN_PID || rval > MAX_PID)
804152521Spjd		errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
805143874Spjd	return (rval);
806143874Spjd}
807