1/*	$NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $	*/
2
3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Andrew Doran.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: src/bin/pkill/pkill.c,v 1.12 2011/02/04 16:40:50 jilles Exp $");
35
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/sysctl.h>
39#include <sys/proc.h>
40#include <sys/queue.h>
41#include <sys/stat.h>
42#include <sys/time.h>
43#include <sys/user.h>
44
45#include <assert.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <limits.h>
49#include <paths.h>
50#include <string.h>
51#include <unistd.h>
52#include <signal.h>
53#include <regex.h>
54#include <ctype.h>
55#include <fcntl.h>
56#ifndef __APPLE__
57#include <kvm.h>
58#endif
59#include <err.h>
60#include <pwd.h>
61#include <grp.h>
62#include <errno.h>
63#include <locale.h>
64
65#ifdef __APPLE__
66#include <xpc/xpc.h>
67#include <sys/proc_info.h>
68#include <os/assumes.h>
69#include <sysmon.h>
70#endif
71
72#define	STATUS_MATCH	0
73#define	STATUS_NOMATCH	1
74#define	STATUS_BADUSAGE	2
75#define	STATUS_ERROR	3
76
77#define	MIN_PID	5
78#define	MAX_PID	99999
79
80#ifdef __APPLE__
81/* Ignore system processes and myself. */
82#define	PSKIP(kp)	((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == mypid ||			\
83			 ((xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_SYSTEM) != 0))
84#else
85/* Ignore system-processes (if '-S' flag is not specified) and myself. */
86#define	PSKIP(kp)	((kp)->ki_pid == mypid ||			\
87			 (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0))
88#endif
89
90enum listtype {
91	LT_GENERIC,
92	LT_USER,
93	LT_GROUP,
94	LT_TTY,
95	LT_PGRP,
96#ifndef __APPLE__
97	LT_JID,
98#endif
99	LT_SID
100};
101
102struct list {
103	SLIST_ENTRY(list) li_chain;
104	long	li_number;
105};
106
107SLIST_HEAD(listhead, list);
108
109#ifdef __APPLE__
110static sysmon_table_t plist;
111#else
112static struct kinfo_proc *plist;
113#endif
114static char	*selected;
115static const char *delim = "\n";
116static int	nproc;
117static int	pgrep;
118static int	signum = SIGTERM;
119static int	newest;
120static int	oldest;
121static int	interactive;
122static int	inverse;
123static int	longfmt;
124static int	matchargs;
125static int	fullmatch;
126#ifndef __APPLE__
127static int	kthreads;
128#endif
129static int	cflags = REG_EXTENDED;
130static int	quiet;
131#ifndef __APPLE__
132static kvm_t	*kd;
133#endif
134static pid_t	mypid;
135
136static struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist);
137static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist);
138static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist);
139static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist);
140static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist);
141static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist);
142#ifndef __APPLE__
143static struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist);
144static struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist);
145#endif
146
147static void	usage(void) __attribute__((__noreturn__));
148#ifdef __APPLE__
149static int	killact(const sysmon_row_t);
150static int	grepact(const sysmon_row_t);
151#else
152static int	killact(const struct kinfo_proc *);
153static int	grepact(const struct kinfo_proc *);
154#endif
155static void	makelist(struct listhead *, enum listtype, char *);
156static int	takepid(const char *, int);
157
158#ifdef __APPLE__
159static sysmon_table_t
160copy_process_info(void)
161{
162	dispatch_semaphore_t sema;
163	sysmon_request_t request;
164	__block sysmon_table_t result = NULL;
165
166	sema = dispatch_semaphore_create(0);
167	request = sysmon_request_create(SYSMON_REQUEST_TYPE_PROCESS, ^(sysmon_table_t table) {
168		result = sysmon_retain(table);
169		dispatch_semaphore_signal(sema);
170	});
171	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PID);
172	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_FLAGS);
173	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_UID);
174	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_COMM);
175	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_ARGUMENTS);
176	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RUID);
177	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RGID);
178	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PPID);
179	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PGID);
180	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_TDEV);
181	sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_START);
182	sysmon_request_execute(request);
183	dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
184	dispatch_release(sema);
185	sysmon_release(request);
186
187	return result;
188}
189#endif /* __APPLE__ */
190
191int
192main(int argc, char **argv)
193{
194#ifdef __APPLE__
195	char buf[_POSIX2_LINE_MAX], *bufp, *mstr, *p, *q, *pidfile;
196	xpc_object_t pargv;
197#else
198	char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile;
199	const char *execf, *coref;
200#endif
201	int ancestors, debug_opt, did_action;
202	int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock;
203#ifdef __APPLE__
204	__block size_t jsz;
205	int (*action)(const sysmon_row_t);
206	sysmon_row_t kp;
207#else
208	size_t jsz;
209	int (*action)(const struct kinfo_proc *);
210	struct kinfo_proc *kp;
211#endif
212	struct list *li;
213#ifdef __APPLE__
214	int64_t best_tval;
215#else
216	struct timeval best_tval;
217#endif
218	regex_t reg;
219	regmatch_t regmatch;
220	pid_t pid;
221
222	setlocale(LC_ALL, "");
223
224	if (strcmp(getprogname(), "pgrep") == 0) {
225		action = grepact;
226		pgrep = 1;
227	} else {
228		action = killact;
229		p = argv[1];
230
231		if (argc > 1 && p[0] == '-') {
232			p++;
233			i = (int)strtol(p, &q, 10);
234			if (*q == '\0') {
235				signum = i;
236				argv++;
237				argc--;
238			} else {
239				if (strncasecmp(p, "SIG", 3) == 0)
240					p += 3;
241				for (i = 1; i < NSIG; i++)
242					if (strcasecmp(sys_signame[i], p) == 0)
243						break;
244				if (i != NSIG) {
245					signum = i;
246					argv++;
247					argc--;
248				}
249			}
250		}
251	}
252
253	ancestors = 0;
254	criteria = 0;
255	debug_opt = 0;
256	pidfile = NULL;
257	pidfilelock = 0;
258	quiet = 0;
259#ifndef __APPLE__
260	execf = NULL;
261	coref = _PATH_DEVNULL;
262#endif
263
264#ifdef __APPLE__
265	while ((ch = getopt(argc, argv, "DF:G:ILP:U:ad:fg:ilnoqt:u:vx")) != -1)
266#else
267	while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1)
268#endif
269		switch (ch) {
270		case 'D':
271			debug_opt++;
272			break;
273		case 'F':
274			pidfile = optarg;
275			criteria = 1;
276			break;
277		case 'G':
278			makelist(&rgidlist, LT_GROUP, optarg);
279			criteria = 1;
280			break;
281		case 'I':
282			if (pgrep)
283				usage();
284			interactive = 1;
285			break;
286		case 'L':
287			pidfilelock = 1;
288			break;
289#ifndef __APPLE__
290		case 'M':
291			coref = optarg;
292			break;
293		case 'N':
294			execf = optarg;
295			break;
296#endif
297		case 'P':
298			makelist(&ppidlist, LT_GENERIC, optarg);
299			criteria = 1;
300			break;
301#ifndef __APPLE__
302		case 'S':
303			if (!pgrep)
304				usage();
305			kthreads = 1;
306			break;
307#endif
308		case 'U':
309			makelist(&ruidlist, LT_USER, optarg);
310			criteria = 1;
311			break;
312		case 'a':
313			ancestors++;
314			break;
315		case 'd':
316			if (!pgrep)
317				usage();
318			delim = optarg;
319			break;
320		case 'f':
321			matchargs = 1;
322			break;
323		case 'g':
324			makelist(&pgrplist, LT_PGRP, optarg);
325			criteria = 1;
326			break;
327		case 'i':
328			cflags |= REG_ICASE;
329			break;
330#ifndef __APPLE__
331		case 'j':
332			makelist(&jidlist, LT_JID, optarg);
333			criteria = 1;
334			break;
335#endif
336		case 'l':
337			longfmt = 1;
338			break;
339		case 'n':
340			newest = 1;
341			criteria = 1;
342			break;
343		case 'o':
344			oldest = 1;
345			criteria = 1;
346			break;
347		case 'q':
348			if (!pgrep)
349				usage();
350			quiet = 1;
351			break;
352#ifndef __APPLE__
353		case 's':
354			makelist(&sidlist, LT_SID, optarg);
355			criteria = 1;
356			break;
357#endif /* !__APPLE__ */
358		case 't':
359			makelist(&tdevlist, LT_TTY, optarg);
360			criteria = 1;
361			break;
362		case 'u':
363			makelist(&euidlist, LT_USER, optarg);
364			criteria = 1;
365			break;
366		case 'v':
367			inverse = 1;
368			break;
369		case 'x':
370			fullmatch = 1;
371			break;
372		default:
373			usage();
374			/* NOTREACHED */
375		}
376
377	argc -= optind;
378	argv += optind;
379	if (argc != 0)
380		criteria = 1;
381	if (!criteria)
382		usage();
383	if (newest && oldest)
384		errx(STATUS_ERROR, "Options -n and -o are mutually exclusive");
385	if (pidfile != NULL)
386		pidfromfile = takepid(pidfile, pidfilelock);
387	else {
388		if (pidfilelock) {
389			errx(STATUS_ERROR,
390			    "Option -L doesn't make sense without -F");
391		}
392		pidfromfile = -1;
393	}
394
395	mypid = getpid();
396
397#ifdef __APPLE__
398	plist = copy_process_info();
399	if (plist == NULL) {
400		errx(STATUS_ERROR, "Cannot get process list");
401	}
402	nproc = sysmon_table_get_count(plist);
403#else
404	/*
405	 * Retrieve the list of running processes from the kernel.
406	 */
407	kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf);
408	if (kd == NULL)
409		errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf);
410
411	/*
412	 * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we
413	 * just want processes and not individual kernel threads.
414	 */
415	plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc);
416	if (plist == NULL) {
417		errx(STATUS_ERROR, "Cannot get process list (%s)",
418		    kvm_geterr(kd));
419	}
420#endif
421
422	/*
423	 * Allocate memory which will be used to keep track of the
424	 * selection.
425	 */
426	if ((selected = malloc(nproc)) == NULL) {
427		err(STATUS_ERROR, "Cannot allocate memory for %d processes",
428		    nproc);
429	}
430	memset(selected, 0, nproc);
431
432	/*
433	 * Refine the selection.
434	 */
435	for (; *argv != NULL; argv++) {
436		if ((rv = regcomp(&reg, *argv, cflags)) != 0) {
437			regerror(rv, &reg, buf, sizeof(buf));
438			errx(STATUS_BADUSAGE,
439			    "Cannot compile regular expression `%s' (%s)",
440			    *argv, buf);
441		}
442
443#ifdef __APPLE__
444		for (i = 0; i < nproc; i++) {
445			kp = sysmon_table_get_row(plist, i);
446#else
447		for (i = 0, kp = plist; i < nproc; i++, kp++) {
448#endif
449			if (PSKIP(kp)) {
450				if (debug_opt > 0)
451				    fprintf(stderr, "* Skipped %5d %3d %s\n",
452#ifdef __APPLE__
453					(pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
454					(uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)),
455					xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM)));
456#else
457					kp->ki_pid, kp->ki_uid, kp->ki_comm);
458#endif
459				continue;
460			}
461
462#ifdef __APPLE__
463			if (matchargs &&
464			    (pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) {
465				jsz = 0;
466				os_assert(sizeof(buf) == _POSIX2_LINE_MAX);
467				bufp = buf;
468				xpc_array_apply(pargv, ^(size_t index, xpc_object_t value) {
469					if (jsz >= _POSIX2_LINE_MAX) {
470						return (bool)false;
471					}
472					jsz += snprintf(bufp + jsz,
473					    _POSIX2_LINE_MAX - jsz,
474					    index < xpc_array_get_count(pargv) - 1 ? "%s " : "%s",
475					    xpc_string_get_string_ptr(value));
476					return (bool)true;
477				});
478#else
479			if (matchargs &&
480			    (pargv = kvm_getargv(kd, kp, 0)) != NULL) {
481				jsz = 0;
482				while (jsz < sizeof(buf) && *pargv != NULL) {
483					jsz += snprintf(buf + jsz,
484					    sizeof(buf) - jsz,
485					    pargv[1] != NULL ? "%s " : "%s",
486					    pargv[0]);
487					pargv++;
488				}
489#endif
490				mstr = buf;
491			} else
492#ifdef __APPLE__
493			{
494				/*
495				 * comm is limited to 15 bytes (MAXCOMLEN - 1).
496				 * Try to use argv[0] (trimmed) if available.
497				 */
498				mstr = NULL;
499				pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS);
500				if (pargv != NULL && xpc_array_get_count(pargv) > 0) {
501					const char *tmp = xpc_array_get_string(pargv, 0);
502					if (tmp != NULL) {
503						mstr = strrchr(tmp, '/');
504						if (mstr != NULL) {
505							mstr++;
506						} else {
507							mstr = (char *)tmp;
508						}
509					}
510				}
511
512				/* Fall back to "comm" if we failed to get argv[0]. */
513				if (mstr == NULL || *mstr == '\0') {
514					mstr = (char *)xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM));
515				}
516
517				/* Couldn't find process name, it probably exited. */
518				if (mstr == NULL) {
519					continue;
520				}
521			}
522#else
523				mstr = kp->ki_comm;
524#endif
525
526			rv = regexec(&reg, mstr, 1, &regmatch, 0);
527			if (rv == 0) {
528				if (fullmatch) {
529					if (regmatch.rm_so == 0 &&
530					    regmatch.rm_eo ==
531					    (off_t)strlen(mstr))
532						selected[i] = 1;
533				} else
534					selected[i] = 1;
535			} else if (rv != REG_NOMATCH) {
536				regerror(rv, &reg, buf, sizeof(buf));
537				errx(STATUS_ERROR,
538				    "Regular expression evaluation error (%s)",
539				    buf);
540			}
541			if (debug_opt > 1) {
542				const char *rv_res = "NoMatch";
543				if (selected[i])
544					rv_res = "Matched";
545				fprintf(stderr, "* %s %5d %3d %s\n", rv_res,
546#ifdef __APPLE__
547				    (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
548				    (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)),
549				    mstr);
550#else
551				    kp->ki_pid, kp->ki_uid, mstr);
552#endif
553			}
554		}
555
556		regfree(&reg);
557	}
558
559#ifdef __APPLE__
560	for (i = 0; i < nproc; i++) {
561		kp = sysmon_table_get_row(plist, i);
562#else
563	for (i = 0, kp = plist; i < nproc; i++, kp++) {
564#endif
565		if (PSKIP(kp))
566			continue;
567
568#ifdef __APPLE__
569		if (pidfromfile >= 0 && (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) != pidfromfile) {
570#else
571		if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) {
572#endif
573			selected[i] = 0;
574			continue;
575		}
576
577		SLIST_FOREACH(li, &ruidlist, li_chain)
578#ifdef __APPLE__
579			if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RUID)) == (uid_t)li->li_number)
580#else
581			if (kp->ki_ruid == (uid_t)li->li_number)
582#endif
583				break;
584		if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
585			selected[i] = 0;
586			continue;
587		}
588
589		SLIST_FOREACH(li, &rgidlist, li_chain)
590#ifdef __APPLE__
591			if ((gid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RGID)) == (gid_t)li->li_number)
592#else
593			if (kp->ki_rgid == (gid_t)li->li_number)
594#endif
595				break;
596		if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
597			selected[i] = 0;
598			continue;
599		}
600
601		SLIST_FOREACH(li, &euidlist, li_chain)
602#ifdef __APPLE__
603			if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)) == (uid_t)li->li_number)
604#else
605			if (kp->ki_uid == (uid_t)li->li_number)
606#endif
607				break;
608		if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
609			selected[i] = 0;
610			continue;
611		}
612
613		SLIST_FOREACH(li, &ppidlist, li_chain)
614#ifdef __APPLE__
615			if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID)) == (pid_t)li->li_number)
616#else
617			if (kp->ki_ppid == (pid_t)li->li_number)
618#endif
619				break;
620		if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
621			selected[i] = 0;
622			continue;
623		}
624
625		SLIST_FOREACH(li, &pgrplist, li_chain)
626#ifdef __APPLE__
627			if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PGID)) == (pid_t)li->li_number)
628#else
629			if (kp->ki_pgid == (pid_t)li->li_number)
630#endif
631				break;
632		if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
633			selected[i] = 0;
634			continue;
635		}
636
637		SLIST_FOREACH(li, &tdevlist, li_chain) {
638			if (li->li_number == -1 &&
639#ifdef __APPLE__
640			    (xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_CONTROLT) == 0)
641#else
642			    (kp->ki_flag & P_CONTROLT) == 0)
643#endif
644				break;
645#ifdef __APPLE__
646			if ((dev_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_TDEV)) == (dev_t)li->li_number)
647#else
648			if (kp->ki_tdev == (dev_t)li->li_number)
649#endif
650				break;
651		}
652		if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
653			selected[i] = 0;
654			continue;
655		}
656
657#ifndef __APPLE__
658		SLIST_FOREACH(li, &sidlist, li_chain)
659			if (kp->ki_sid == (pid_t)li->li_number)
660				break;
661		if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
662			selected[i] = 0;
663			continue;
664		}
665
666		SLIST_FOREACH(li, &jidlist, li_chain) {
667			/* A particular jail ID, including 0 (not in jail) */
668			if (kp->ki_jid == (int)li->li_number)
669				break;
670			/* Any jail */
671			if (kp->ki_jid > 0 && li->li_number == -1)
672				break;
673		}
674		if (SLIST_FIRST(&jidlist) != NULL && li == NULL) {
675			selected[i] = 0;
676			continue;
677		}
678#endif /* !__APPLE__ */
679
680		if (argc == 0)
681			selected[i] = 1;
682	}
683
684	if (!ancestors) {
685		pid = mypid;
686		while (pid) {
687#ifdef __APPLE__
688			for (i = 0; i < nproc; i++) {
689				kp = sysmon_table_get_row(plist, i);
690#else
691			for (i = 0, kp = plist; i < nproc; i++, kp++) {
692#endif
693				if (PSKIP(kp))
694					continue;
695#ifdef __APPLE__
696				if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == pid) {
697					selected[i] = 0;
698					pid = (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID));
699					break;
700				}
701#else
702				if (kp->ki_pid == pid) {
703					selected[i] = 0;
704					pid = kp->ki_ppid;
705					break;
706				}
707#endif
708			}
709			if (i == nproc) {
710				if (pid == mypid)
711					pid = getppid();
712				else
713					break;	/* Maybe we're in a jail ? */
714			}
715		}
716	}
717
718	if (newest || oldest) {
719#ifdef __APPLE__
720		best_tval = 0;
721#else
722		best_tval.tv_sec = 0;
723		best_tval.tv_usec = 0;
724#endif
725		bestidx = -1;
726
727#ifdef __APPLE__
728		for (i = 0; i < nproc; i++) {
729			kp = sysmon_table_get_row(plist, i);
730#else
731		for (i = 0, kp = plist; i < nproc; i++, kp++) {
732#endif
733			if (!selected[i])
734				continue;
735			if (bestidx == -1) {
736				/* The first entry of the list which matched. */
737				;
738#ifdef __APPLE__
739			} else if (xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START)) > best_tval) {
740#else
741			} else if (timercmp(&kp->ki_start, &best_tval, >)) {
742#endif
743				/* This entry is newer than previous "best". */
744				if (oldest)	/* but we want the oldest */
745					continue;
746			} else {
747				/* This entry is older than previous "best". */
748				if (newest)	/* but we want the newest */
749					continue;
750			}
751			/* This entry is better than previous "best" entry. */
752#ifdef __APPLE__
753			best_tval = xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START));
754#else
755			best_tval.tv_sec = kp->ki_start.tv_sec;
756			best_tval.tv_usec = kp->ki_start.tv_usec;
757#endif
758			bestidx = i;
759		}
760
761		memset(selected, 0, nproc);
762		if (bestidx != -1)
763			selected[bestidx] = 1;
764	}
765
766	/*
767	 * Take the appropriate action for each matched process, if any.
768	 */
769	did_action = 0;
770#ifdef __APPLE__
771	for (i = 0, rv = 0; i < nproc; i++) {
772		kp = sysmon_table_get_row(plist, i);
773#else
774	for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) {
775#endif
776		if (PSKIP(kp))
777			continue;
778		if (selected[i]) {
779			if (longfmt && !pgrep) {
780				did_action = 1;
781#ifdef __APPLE__
782				printf("kill -%d %d\n", signum, (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
783#else
784				printf("kill -%d %d\n", signum, kp->ki_pid);
785#endif
786			}
787			if (inverse)
788				continue;
789		} else if (!inverse)
790			continue;
791		rv |= (*action)(kp);
792	}
793	if (!did_action && !pgrep && longfmt)
794		fprintf(stderr,
795		    "No matching processes belonging to you were found\n");
796
797	exit(rv ? STATUS_MATCH : STATUS_NOMATCH);
798}
799
800static void
801usage(void)
802{
803	const char *ustr;
804
805	if (pgrep)
806#ifdef __APPLE__
807		ustr = "[-Lfilnoqvx] [-d delim]";
808#else
809		ustr = "[-LSfilnoqvx] [-d delim]";
810#endif
811	else
812		ustr = "[-signal] [-ILfilnovx]";
813
814	fprintf(stderr,
815#ifdef __APPLE__
816		"usage: %s %s [-F pidfile] [-G gid]\n"
817		"             [-P ppid] [-U uid] [-g pgrp]\n"
818#else
819		"usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n"
820		"             [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n"
821#endif
822		"             [-t tty] [-u euid] pattern ...\n", getprogname(),
823		ustr);
824
825	exit(STATUS_BADUSAGE);
826}
827
828static void
829#ifdef __APPLE__
830show_process(const sysmon_row_t kp)
831#else
832show_process(const struct kinfo_proc *kp)
833#endif
834{
835#ifdef __APPLE__
836	xpc_object_t argv;
837#else
838	char **argv;
839#endif
840
841	if (quiet) {
842		assert(pgrep);
843		return;
844	}
845#ifdef __APPLE__
846	if ((longfmt || !pgrep) && matchargs &&
847	    (argv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) {
848		printf("%d ", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
849		(void)xpc_array_apply(argv, ^(size_t index, xpc_object_t value) {
850			printf("%s", xpc_string_get_string_ptr(value));
851			if (index < xpc_array_get_count(argv) - 1)
852				putchar(' ');
853			return (bool)true;
854		});
855	} else if (longfmt || !pgrep)
856		printf("%d %s",
857		    (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
858		    xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM)));
859	else
860		printf("%d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
861#else
862	if ((longfmt || !pgrep) && matchargs &&
863	    (argv = kvm_getargv(kd, kp, 0)) != NULL) {
864		printf("%d ", (int)kp->ki_pid);
865		for (; *argv != NULL; argv++) {
866			printf("%s", *argv);
867			if (argv[1] != NULL)
868				putchar(' ');
869		}
870	} else if (longfmt || !pgrep)
871		printf("%d %s", (int)kp->ki_pid, kp->ki_comm);
872	else
873		printf("%d", (int)kp->ki_pid);
874#endif
875}
876
877static int
878#ifdef __APPLE__
879killact(const sysmon_row_t kp)
880#else
881killact(const struct kinfo_proc *kp)
882#endif
883{
884	int ch, first;
885
886	if (interactive) {
887		/*
888		 * Be careful, ask before killing.
889		 */
890		printf("kill ");
891		show_process(kp);
892		printf("? ");
893		fflush(stdout);
894		first = ch = getchar();
895		while (ch != '\n' && ch != EOF)
896			ch = getchar();
897		if (first != 'y' && first != 'Y')
898			return (1);
899	}
900#ifdef __APPLE__
901	if (kill((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), signum) == -1) {
902#else
903	if (kill(kp->ki_pid, signum) == -1) {
904#endif
905		/*
906		 * Check for ESRCH, which indicates that the process
907		 * disappeared between us matching it and us
908		 * signalling it; don't issue a warning about it.
909		 */
910		if (errno != ESRCH)
911#ifdef __APPLE__
912			warn("signalling pid %d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
913#else
914			warn("signalling pid %d", (int)kp->ki_pid);
915#endif
916		/*
917		 * Return 0 to indicate that the process should not be
918		 * considered a match, since we didn't actually get to
919		 * signal it.
920		 */
921		return (0);
922	}
923	return (1);
924}
925
926static int
927#ifdef __APPLE__
928grepact(const sysmon_row_t kp)
929#else
930grepact(const struct kinfo_proc *kp)
931#endif
932{
933
934	show_process(kp);
935	if (!quiet)
936		printf("%s", delim);
937	return (1);
938}
939
940static void
941makelist(struct listhead *head, enum listtype type, char *src)
942{
943	struct list *li;
944	struct passwd *pw;
945	struct group *gr;
946	struct stat st;
947	const char *cp;
948	char *sp, *ep, buf[MAXPATHLEN];
949	int empty;
950
951	empty = 1;
952
953	while ((sp = strsep(&src, ",")) != NULL) {
954		if (*sp == '\0')
955			usage();
956
957		if ((li = malloc(sizeof(*li))) == NULL) {
958			err(STATUS_ERROR, "Cannot allocate %zu bytes",
959			    sizeof(*li));
960		}
961
962		SLIST_INSERT_HEAD(head, li, li_chain);
963		empty = 0;
964
965		li->li_number = (uid_t)strtol(sp, &ep, 0);
966		if (*ep == '\0') {
967			switch (type) {
968			case LT_PGRP:
969				if (li->li_number == 0)
970					li->li_number = getpgrp();
971				break;
972#ifndef __APPLE__
973			case LT_SID:
974				if (li->li_number == 0)
975					li->li_number = getsid(mypid);
976				break;
977			case LT_JID:
978				if (li->li_number < 0)
979					errx(STATUS_BADUSAGE,
980					     "Negative jail ID `%s'", sp);
981				/* For compatibility with old -j */
982				if (li->li_number == 0)
983					li->li_number = -1;	/* any jail */
984				break;
985#endif /* !__APPLE__ */
986			case LT_TTY:
987				if (li->li_number < 0)
988					errx(STATUS_BADUSAGE,
989					     "Negative /dev/pts tty `%s'", sp);
990				snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s",
991				    sp);
992				if (stat(buf, &st) != -1)
993					goto foundtty;
994				if (errno == ENOENT)
995					errx(STATUS_BADUSAGE, "No such tty: `"
996					    _PATH_DEV "pts/%s'", sp);
997				err(STATUS_ERROR, "Cannot access `"
998				    _PATH_DEV "pts/%s'", sp);
999				break;
1000			default:
1001				break;
1002			}
1003			continue;
1004		}
1005
1006		switch (type) {
1007		case LT_USER:
1008			if ((pw = getpwnam(sp)) == NULL)
1009				errx(STATUS_BADUSAGE, "Unknown user `%s'", sp);
1010			li->li_number = pw->pw_uid;
1011			break;
1012		case LT_GROUP:
1013			if ((gr = getgrnam(sp)) == NULL)
1014				errx(STATUS_BADUSAGE, "Unknown group `%s'", sp);
1015			li->li_number = gr->gr_gid;
1016			break;
1017		case LT_TTY:
1018			if (strcmp(sp, "-") == 0) {
1019				li->li_number = -1;
1020				break;
1021			} else if (strcmp(sp, "co") == 0) {
1022				cp = "console";
1023			} else {
1024				cp = sp;
1025			}
1026
1027			snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp);
1028			if (stat(buf, &st) != -1)
1029				goto foundtty;
1030
1031			snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp);
1032			if (stat(buf, &st) != -1)
1033				goto foundtty;
1034
1035			if (errno == ENOENT)
1036				errx(STATUS_BADUSAGE, "No such tty: `%s'", sp);
1037			err(STATUS_ERROR, "Cannot access `%s'", sp);
1038
1039foundtty:		if ((st.st_mode & S_IFCHR) == 0)
1040				errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp);
1041
1042			li->li_number = st.st_rdev;
1043			break;
1044#ifndef __APPLE__
1045		case LT_JID:
1046			if (strcmp(sp, "none") == 0)
1047				li->li_number = 0;
1048			else if (strcmp(sp, "any") == 0)
1049				li->li_number = -1;
1050			else if (*ep != '\0')
1051				errx(STATUS_BADUSAGE,
1052				     "Invalid jail ID `%s'", sp);
1053			break;
1054#endif /* !__APPLE__ */
1055		default:
1056			usage();
1057		}
1058	}
1059
1060	if (empty)
1061		usage();
1062}
1063
1064static int
1065takepid(const char *pidfile, int pidfilelock)
1066{
1067	char *endp, line[BUFSIZ];
1068	FILE *fh;
1069	long rval;
1070
1071	fh = fopen(pidfile, "r");
1072	if (fh == NULL)
1073		err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile);
1074
1075	if (pidfilelock) {
1076		/*
1077		 * If we can lock pidfile, this means that daemon is not
1078		 * running, so would be better not to kill some random process.
1079		 */
1080		if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) {
1081			(void)fclose(fh);
1082			errx(STATUS_ERROR, "File '%s' can be locked", pidfile);
1083		} else {
1084			if (errno != EWOULDBLOCK) {
1085				errx(STATUS_ERROR,
1086				    "Error while locking file '%s'", pidfile);
1087			}
1088		}
1089	}
1090
1091	if (fgets(line, sizeof(line), fh) == NULL) {
1092		if (feof(fh)) {
1093			(void)fclose(fh);
1094			errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile);
1095		}
1096		(void)fclose(fh);
1097		err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile);
1098	}
1099	(void)fclose(fh);
1100
1101	rval = strtol(line, &endp, 10);
1102	if (*endp != '\0' && !isspace((unsigned char)*endp))
1103		errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
1104	else if (rval < MIN_PID || rval > MAX_PID)
1105		errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
1106	return (rval);
1107}
1108