pkill.c revision 143879
1143079Sdelphij/*	$NetBSD: pkill.c,v 1.8 2005/03/02 15:31:44 abs Exp $	*/
2127412Sgad
3127412Sgad/*-
4127412Sgad * Copyright (c) 2002 The NetBSD Foundation, Inc.
5127412Sgad * All rights reserved.
6127412Sgad *
7127412Sgad * This code is derived from software contributed to The NetBSD Foundation
8127412Sgad * by Andrew Doran.
9127412Sgad *
10127412Sgad * Redistribution and use in source and binary forms, with or without
11127412Sgad * modification, are permitted provided that the following conditions
12127412Sgad * are met:
13127412Sgad * 1. Redistributions of source code must retain the above copyright
14127412Sgad *    notice, this list of conditions and the following disclaimer.
15127412Sgad * 2. Redistributions in binary form must reproduce the above copyright
16127412Sgad *    notice, this list of conditions and the following disclaimer in the
17127412Sgad *    documentation and/or other materials provided with the distribution.
18127412Sgad * 3. All advertising materials mentioning features or use of this software
19127412Sgad *    must display the following acknowledgement:
20127412Sgad *	This product includes software developed by the NetBSD
21127412Sgad *	Foundation, Inc. and its contributors.
22127412Sgad * 4. Neither the name of The NetBSD Foundation nor the names of its
23127412Sgad *    contributors may be used to endorse or promote products derived
24127412Sgad *    from this software without specific prior written permission.
25127412Sgad *
26127412Sgad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27127412Sgad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28127412Sgad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29127412Sgad * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30127412Sgad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31127412Sgad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32127412Sgad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33127412Sgad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34127412Sgad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35127412Sgad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36127412Sgad * POSSIBILITY OF SUCH DAMAGE.
37127412Sgad */
38127412Sgad
39127412Sgad#include <sys/cdefs.h>
40127412Sgad__FBSDID("$FreeBSD: head/usr.bin/pkill/pkill.c 143879 2005-03-20 11:47:44Z pjd $");
41127412Sgad
42127412Sgad#include <sys/types.h>
43127412Sgad#include <sys/param.h>
44127412Sgad#include <sys/sysctl.h>
45127412Sgad#include <sys/proc.h>
46127412Sgad#include <sys/queue.h>
47127412Sgad#include <sys/stat.h>
48143878Spjd#include <sys/time.h>
49127425Sgad#include <sys/user.h>
50127412Sgad
51127412Sgad#include <stdio.h>
52127412Sgad#include <stdlib.h>
53127412Sgad#include <limits.h>
54127425Sgad#include <paths.h>
55127412Sgad#include <string.h>
56127412Sgad#include <unistd.h>
57127412Sgad#include <signal.h>
58127412Sgad#include <regex.h>
59127412Sgad#include <ctype.h>
60127425Sgad#include <fcntl.h>
61127412Sgad#include <kvm.h>
62127412Sgad#include <err.h>
63127412Sgad#include <pwd.h>
64127412Sgad#include <grp.h>
65127412Sgad#include <errno.h>
66132198Stjr#include <locale.h>
67127412Sgad
68127412Sgad#define	STATUS_MATCH	0
69127412Sgad#define	STATUS_NOMATCH	1
70127412Sgad#define	STATUS_BADUSAGE	2
71127412Sgad#define	STATUS_ERROR	3
72127412Sgad
73143874Spjd#define	MIN_PID	5
74143874Spjd#define	MAX_PID	99999
75143874Spjd
76143877Spjd/* Ignore system-processes (if '-S' flag is not specified) and myself. */
77143877Spjd#define	PSKIP(kp)	((kp)->ki_pid == mypid ||			\
78143877Spjd			 (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0))
79127425Sgad
80127412Sgadenum listtype {
81127412Sgad	LT_GENERIC,
82127412Sgad	LT_USER,
83127412Sgad	LT_GROUP,
84127412Sgad	LT_TTY,
85127412Sgad	LT_PGRP,
86127412Sgad	LT_SID
87127412Sgad};
88127412Sgad
89127412Sgadstruct list {
90127412Sgad	SLIST_ENTRY(list) li_chain;
91127412Sgad	long	li_number;
92127412Sgad};
93127412Sgad
94127412SgadSLIST_HEAD(listhead, list);
95127412Sgad
96127425Sgadstruct kinfo_proc	*plist;
97127412Sgadchar	*selected;
98127430Sgadconst char	*delim = "\n";
99127412Sgadint	nproc;
100127412Sgadint	pgrep;
101127412Sgadint	signum = SIGTERM;
102127412Sgadint	newest;
103143878Spjdint	oldest;
104127412Sgadint	inverse;
105127412Sgadint	longfmt;
106127412Sgadint	matchargs;
107127412Sgadint	fullmatch;
108143877Spjdint	kthreads;
109143875Spjdint	cflags = REG_EXTENDED;
110127412Sgadkvm_t	*kd;
111127412Sgadpid_t	mypid;
112127412Sgad
113127412Sgadstruct listhead euidlist = SLIST_HEAD_INITIALIZER(list);
114127412Sgadstruct listhead ruidlist = SLIST_HEAD_INITIALIZER(list);
115127412Sgadstruct listhead rgidlist = SLIST_HEAD_INITIALIZER(list);
116127412Sgadstruct listhead pgrplist = SLIST_HEAD_INITIALIZER(list);
117127412Sgadstruct listhead ppidlist = SLIST_HEAD_INITIALIZER(list);
118127412Sgadstruct listhead tdevlist = SLIST_HEAD_INITIALIZER(list);
119127412Sgadstruct listhead sidlist = SLIST_HEAD_INITIALIZER(list);
120143873Spjdstruct listhead jidlist = SLIST_HEAD_INITIALIZER(list);
121127412Sgad
122127412Sgadint	main(int, char **);
123127412Sgadvoid	usage(void);
124127425Sgadvoid	killact(struct kinfo_proc *);
125127425Sgadvoid	grepact(struct kinfo_proc *);
126127412Sgadvoid	makelist(struct listhead *, enum listtype, char *);
127143874Spjdint	takepid(const char *);
128127412Sgad
129127412Sgadint
130127412Sgadmain(int argc, char **argv)
131127412Sgad{
132127412Sgad	extern char *optarg;
133127412Sgad	extern int optind;
134127412Sgad	char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q;
135127462Sgad	const char *execf, *coref;
136127433Sgad	int debug_opt;
137143874Spjd	int i, ch, bestidx, rv, criteria, pidfromfile;
138127430Sgad	size_t jsz;
139127425Sgad	void (*action)(struct kinfo_proc *);
140127425Sgad	struct kinfo_proc *kp;
141127412Sgad	struct list *li;
142127430Sgad	struct timeval best_tval;
143127412Sgad	regex_t reg;
144127412Sgad	regmatch_t regmatch;
145127412Sgad
146132198Stjr	setlocale(LC_ALL, "");
147132198Stjr
148127412Sgad	if (strcmp(getprogname(), "pgrep") == 0) {
149127412Sgad		action = grepact;
150127412Sgad		pgrep = 1;
151127412Sgad	} else {
152127412Sgad		action = killact;
153127412Sgad		p = argv[1];
154127412Sgad
155127412Sgad		if (argc > 1 && p[0] == '-') {
156127412Sgad			p++;
157127412Sgad			i = (int)strtol(p, &q, 10);
158127412Sgad			if (*q == '\0') {
159127412Sgad				signum = i;
160127412Sgad				argv++;
161127412Sgad				argc--;
162127412Sgad			} else {
163127412Sgad				if (strncasecmp(p, "sig", 3) == 0)
164127412Sgad					p += 3;
165127412Sgad				for (i = 1; i < NSIG; i++)
166127412Sgad					if (strcasecmp(sys_signame[i], p) == 0)
167127412Sgad						break;
168127412Sgad				if (i != NSIG) {
169127412Sgad					signum = i;
170127412Sgad					argv++;
171127412Sgad					argc--;
172127412Sgad				}
173127412Sgad			}
174127412Sgad		}
175127412Sgad	}
176127412Sgad
177127412Sgad	criteria = 0;
178127433Sgad	debug_opt = 0;
179143874Spjd	pidfromfile = -1;
180127462Sgad	execf = coref = _PATH_DEVNULL;
181127412Sgad
182143878Spjd	while ((ch = getopt(argc, argv, "DF:G:M:N:P:SU:d:fg:ij:lnos:t:u:vx")) != -1)
183127412Sgad		switch (ch) {
184127433Sgad		case 'D':
185127433Sgad			debug_opt++;
186127433Sgad			break;
187143874Spjd		case 'F':
188143874Spjd			pidfromfile = takepid(optarg);
189143874Spjd			criteria = 1;
190143874Spjd			break;
191127412Sgad		case 'G':
192127412Sgad			makelist(&rgidlist, LT_GROUP, optarg);
193127412Sgad			criteria = 1;
194127412Sgad			break;
195127427Sgad		case 'M':
196127427Sgad			coref = optarg;
197127427Sgad			break;
198127427Sgad		case 'N':
199127427Sgad			execf = optarg;
200127427Sgad			break;
201127412Sgad		case 'P':
202127412Sgad			makelist(&ppidlist, LT_GENERIC, optarg);
203127412Sgad			criteria = 1;
204127412Sgad			break;
205143877Spjd		case 'S':
206143877Spjd			if (!pgrep)
207143877Spjd				usage();
208143877Spjd			kthreads = 1;
209143877Spjd			break;
210127412Sgad		case 'U':
211127412Sgad			makelist(&ruidlist, LT_USER, optarg);
212127412Sgad			criteria = 1;
213127412Sgad			break;
214127412Sgad		case 'd':
215127412Sgad			if (!pgrep)
216127412Sgad				usage();
217127412Sgad			delim = optarg;
218127412Sgad			break;
219127412Sgad		case 'f':
220127412Sgad			matchargs = 1;
221127412Sgad			break;
222127412Sgad		case 'g':
223127412Sgad			makelist(&pgrplist, LT_PGRP, optarg);
224127412Sgad			criteria = 1;
225127412Sgad			break;
226143875Spjd		case 'i':
227143875Spjd			cflags |= REG_ICASE;
228143875Spjd			break;
229143873Spjd		case 'j':
230143873Spjd			makelist(&jidlist, LT_GENERIC, optarg);
231143873Spjd			criteria = 1;
232143873Spjd			break;
233127412Sgad		case 'l':
234127412Sgad			if (!pgrep)
235127412Sgad				usage();
236127412Sgad			longfmt = 1;
237127412Sgad			break;
238127412Sgad		case 'n':
239127412Sgad			newest = 1;
240127412Sgad			criteria = 1;
241127412Sgad			break;
242143878Spjd		case 'o':
243143878Spjd			oldest = 1;
244143878Spjd			criteria = 1;
245143878Spjd			break;
246127412Sgad		case 's':
247127412Sgad			makelist(&sidlist, LT_SID, optarg);
248127412Sgad			criteria = 1;
249127412Sgad			break;
250127412Sgad		case 't':
251127412Sgad			makelist(&tdevlist, LT_TTY, optarg);
252127412Sgad			criteria = 1;
253127412Sgad			break;
254127412Sgad		case 'u':
255127412Sgad			makelist(&euidlist, LT_USER, optarg);
256127412Sgad			criteria = 1;
257127412Sgad			break;
258127412Sgad		case 'v':
259127412Sgad			inverse = 1;
260127412Sgad			break;
261127412Sgad		case 'x':
262127412Sgad			fullmatch = 1;
263127412Sgad			break;
264127412Sgad		default:
265127412Sgad			usage();
266127412Sgad			/* NOTREACHED */
267127412Sgad		}
268127412Sgad
269127412Sgad	argc -= optind;
270127412Sgad	argv += optind;
271127412Sgad	if (argc != 0)
272127412Sgad		criteria = 1;
273127412Sgad	if (!criteria)
274127412Sgad		usage();
275143878Spjd	if (newest && oldest)
276143878Spjd		errx(STATUS_ERROR, "-n and -o are mutually exclusive");
277127412Sgad
278127412Sgad	mypid = getpid();
279127412Sgad
280127412Sgad	/*
281127412Sgad	 * Retrieve the list of running processes from the kernel.
282127412Sgad	 */
283127462Sgad	kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf);
284127412Sgad	if (kd == NULL)
285127412Sgad		errx(STATUS_ERROR, "kvm_openfiles(): %s", buf);
286127412Sgad
287127622Sgad	/*
288127622Sgad	 * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we
289127622Sgad	 * just want processes and not individual kernel threads.
290127622Sgad	 */
291127622Sgad	plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc);
292127412Sgad	if (plist == NULL)
293127425Sgad		errx(STATUS_ERROR, "kvm_getprocs() failed");
294127412Sgad
295127412Sgad	/*
296127412Sgad	 * Allocate memory which will be used to keep track of the
297127412Sgad	 * selection.
298127412Sgad	 */
299127412Sgad	if ((selected = malloc(nproc)) == NULL)
300127412Sgad		errx(STATUS_ERROR, "memory allocation failure");
301127412Sgad	memset(selected, 0, nproc);
302127412Sgad
303127412Sgad	/*
304127412Sgad	 * Refine the selection.
305127412Sgad	 */
306127412Sgad	for (; *argv != NULL; argv++) {
307143875Spjd		if ((rv = regcomp(&reg, *argv, cflags)) != 0) {
308127412Sgad			regerror(rv, &reg, buf, sizeof(buf));
309127412Sgad			errx(STATUS_BADUSAGE, "bad expression: %s", buf);
310127412Sgad		}
311127412Sgad
312127412Sgad		for (i = 0, kp = plist; i < nproc; i++, kp++) {
313143877Spjd			if (PSKIP(kp)) {
314127433Sgad				if (debug_opt > 0)
315127434Sgad				    fprintf(stderr, "* Skipped %5d %3d %s\n",
316127433Sgad					kp->ki_pid, kp->ki_uid, kp->ki_comm);
317127412Sgad				continue;
318127433Sgad			}
319127412Sgad
320143877Spjd			if (matchargs &&
321143877Spjd			    (pargv = kvm_getargv(kd, kp, 0)) != NULL) {
322127430Sgad				jsz = 0;
323127430Sgad				while (jsz < sizeof(buf) && *pargv != NULL) {
324127430Sgad					jsz += snprintf(buf + jsz,
325127430Sgad					    sizeof(buf) - jsz,
326127412Sgad					    pargv[1] != NULL ? "%s " : "%s",
327127412Sgad					    pargv[0]);
328127412Sgad					pargv++;
329127412Sgad				}
330127412Sgad				mstr = buf;
331127412Sgad			} else
332127425Sgad				mstr = kp->ki_comm;
333127412Sgad
334127412Sgad			rv = regexec(&reg, mstr, 1, &regmatch, 0);
335127412Sgad			if (rv == 0) {
336127412Sgad				if (fullmatch) {
337127412Sgad					if (regmatch.rm_so == 0 &&
338127431Sgad					    regmatch.rm_eo ==
339127431Sgad					    (off_t)strlen(mstr))
340127412Sgad						selected[i] = 1;
341127412Sgad				} else
342127412Sgad					selected[i] = 1;
343127412Sgad			} else if (rv != REG_NOMATCH) {
344127412Sgad				regerror(rv, &reg, buf, sizeof(buf));
345127412Sgad				errx(STATUS_ERROR, "regexec(): %s", buf);
346127412Sgad			}
347127433Sgad			if (debug_opt > 1) {
348127433Sgad				const char *rv_res = "NoMatch";
349127433Sgad				if (selected[i])
350127433Sgad					rv_res = "Matched";
351127434Sgad				fprintf(stderr, "* %s %5d %3d %s\n", rv_res,
352127433Sgad				    kp->ki_pid, kp->ki_uid, mstr);
353127433Sgad			}
354127412Sgad		}
355127412Sgad
356127412Sgad		regfree(&reg);
357127412Sgad	}
358127412Sgad
359127412Sgad	for (i = 0, kp = plist; i < nproc; i++, kp++) {
360143877Spjd		if (PSKIP(kp))
361127412Sgad			continue;
362127412Sgad
363143874Spjd		if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) {
364143874Spjd			selected[i] = 0;
365143874Spjd			continue;
366143874Spjd		}
367143874Spjd
368127412Sgad		SLIST_FOREACH(li, &ruidlist, li_chain)
369127425Sgad			if (kp->ki_ruid == (uid_t)li->li_number)
370127412Sgad				break;
371127412Sgad		if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
372127412Sgad			selected[i] = 0;
373127412Sgad			continue;
374127412Sgad		}
375127429Sgad
376127412Sgad		SLIST_FOREACH(li, &rgidlist, li_chain)
377127425Sgad			if (kp->ki_rgid == (gid_t)li->li_number)
378127412Sgad				break;
379127412Sgad		if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
380127412Sgad			selected[i] = 0;
381127412Sgad			continue;
382127412Sgad		}
383127412Sgad
384127412Sgad		SLIST_FOREACH(li, &euidlist, li_chain)
385127425Sgad			if (kp->ki_uid == (uid_t)li->li_number)
386127412Sgad				break;
387127412Sgad		if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
388127412Sgad			selected[i] = 0;
389127412Sgad			continue;
390127412Sgad		}
391127412Sgad
392127412Sgad		SLIST_FOREACH(li, &ppidlist, li_chain)
393127426Sgad			if (kp->ki_ppid == (pid_t)li->li_number)
394127412Sgad				break;
395127412Sgad		if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
396127412Sgad			selected[i] = 0;
397127412Sgad			continue;
398127412Sgad		}
399127412Sgad
400127412Sgad		SLIST_FOREACH(li, &pgrplist, li_chain)
401127426Sgad			if (kp->ki_pgid == (pid_t)li->li_number)
402127412Sgad				break;
403127412Sgad		if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
404127412Sgad			selected[i] = 0;
405127412Sgad			continue;
406127412Sgad		}
407127412Sgad
408127412Sgad		SLIST_FOREACH(li, &tdevlist, li_chain) {
409127412Sgad			if (li->li_number == -1 &&
410127425Sgad			    (kp->ki_flag & P_CONTROLT) == 0)
411127412Sgad				break;
412130640Sphk			if (kp->ki_tdev == (dev_t)li->li_number)
413127412Sgad				break;
414127412Sgad		}
415127412Sgad		if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
416127412Sgad			selected[i] = 0;
417127412Sgad			continue;
418127412Sgad		}
419127412Sgad
420127412Sgad		SLIST_FOREACH(li, &sidlist, li_chain)
421127426Sgad			if (kp->ki_sid == (pid_t)li->li_number)
422127412Sgad				break;
423127412Sgad		if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
424127412Sgad			selected[i] = 0;
425127412Sgad			continue;
426127412Sgad		}
427127412Sgad
428143873Spjd		SLIST_FOREACH(li, &jidlist, li_chain) {
429143873Spjd			if (kp->ki_jid > 0) {
430143873Spjd				if (li->li_number == 0)
431143873Spjd					break;
432143873Spjd				if (kp->ki_jid == (int)li->li_number)
433143873Spjd					break;
434143873Spjd			}
435143873Spjd		}
436143873Spjd		if (SLIST_FIRST(&jidlist) != NULL && li == NULL) {
437143873Spjd			selected[i] = 0;
438143873Spjd			continue;
439143873Spjd		}
440143873Spjd
441127412Sgad		if (argc == 0)
442127412Sgad			selected[i] = 1;
443127412Sgad	}
444127412Sgad
445143878Spjd	if (newest || oldest) {
446127430Sgad		best_tval.tv_sec = 0;
447127430Sgad		best_tval.tv_usec = 0;
448127412Sgad		bestidx = -1;
449127412Sgad
450127412Sgad		for (i = 0, kp = plist; i < nproc; i++, kp++) {
451127412Sgad			if (!selected[i])
452127412Sgad				continue;
453143878Spjd			if (bestidx == -1) {
454143878Spjd				/* The first entry of the list which matched. */
455143878Spjd				;
456143878Spjd			} else if (timercmp(&kp->ki_start, &best_tval, >)) {
457143878Spjd				/* This entry is newer than previous "best". */
458143879Spjd				if (oldest)	/* but we want the oldest */
459143878Spjd					continue;
460143878Spjd			} else {
461143878Spjd				/* This entry is older than previous "best". */
462143879Spjd				if (newest)	/* but we want the newest */
463143878Spjd					continue;
464127412Sgad			}
465143878Spjd			/* This entry is better than previous "best" entry. */
466143878Spjd			best_tval.tv_sec = kp->ki_start.tv_sec;
467143878Spjd			best_tval.tv_usec = kp->ki_start.tv_usec;
468143878Spjd			bestidx = i;
469127412Sgad		}
470127412Sgad
471127412Sgad		memset(selected, 0, nproc);
472127412Sgad		if (bestidx != -1)
473127412Sgad			selected[bestidx] = 1;
474127412Sgad	}
475127412Sgad
476127412Sgad	/*
477127412Sgad	 * Take the appropriate action for each matched process, if any.
478127412Sgad	 */
479127412Sgad	for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) {
480143877Spjd		if (PSKIP(kp))
481127412Sgad			continue;
482127412Sgad		if (selected[i]) {
483127412Sgad			if (inverse)
484127412Sgad				continue;
485127412Sgad		} else if (!inverse)
486127412Sgad			continue;
487127412Sgad		rv = 1;
488127412Sgad		(*action)(kp);
489127412Sgad	}
490127412Sgad
491127412Sgad	exit(rv ? STATUS_MATCH : STATUS_NOMATCH);
492127412Sgad}
493127412Sgad
494127412Sgadvoid
495127412Sgadusage(void)
496127412Sgad{
497127412Sgad	const char *ustr;
498127412Sgad
499127412Sgad	if (pgrep)
500143878Spjd		ustr = "[-Sfilnovx] [-d delim]";
501127412Sgad	else
502143878Spjd		ustr = "[-signal] [-finovx]";
503127412Sgad
504127412Sgad	fprintf(stderr,
505143874Spjd		"usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n"
506143873Spjd		"             [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n"
507143873Spjd		"             [-t tty] [-u euid] pattern ...\n", getprogname(),
508143873Spjd		ustr);
509127412Sgad
510127412Sgad	exit(STATUS_ERROR);
511127412Sgad}
512127412Sgad
513127412Sgadvoid
514127425Sgadkillact(struct kinfo_proc *kp)
515127412Sgad{
516127412Sgad
517127425Sgad	if (kill(kp->ki_pid, signum) == -1)
518127425Sgad		err(STATUS_ERROR, "signalling pid %d", (int)kp->ki_pid);
519127412Sgad}
520127412Sgad
521127412Sgadvoid
522127425Sgadgrepact(struct kinfo_proc *kp)
523127412Sgad{
524127412Sgad	char **argv;
525127412Sgad
526143877Spjd	if (longfmt && matchargs &&
527143877Spjd	    (argv = kvm_getargv(kd, kp, 0)) != NULL) {
528127425Sgad		printf("%d ", (int)kp->ki_pid);
529127412Sgad		for (; *argv != NULL; argv++) {
530127412Sgad			printf("%s", *argv);
531127412Sgad			if (argv[1] != NULL)
532127412Sgad				putchar(' ');
533127412Sgad		}
534127412Sgad	} else if (longfmt)
535127425Sgad		printf("%d %s", (int)kp->ki_pid, kp->ki_comm);
536127412Sgad	else
537127425Sgad		printf("%d", (int)kp->ki_pid);
538127412Sgad
539127412Sgad	printf("%s", delim);
540127412Sgad}
541127412Sgad
542127412Sgadvoid
543127412Sgadmakelist(struct listhead *head, enum listtype type, char *src)
544127412Sgad{
545127412Sgad	struct list *li;
546127412Sgad	struct passwd *pw;
547127412Sgad	struct group *gr;
548127412Sgad	struct stat st;
549127430Sgad	const char *cp;
550127412Sgad	char *sp, *p, buf[MAXPATHLEN];
551127412Sgad	int empty;
552127412Sgad
553127412Sgad	empty = 1;
554127412Sgad
555127412Sgad	while ((sp = strsep(&src, ",")) != NULL) {
556127412Sgad		if (*sp == '\0')
557127412Sgad			usage();
558127412Sgad
559127412Sgad		if ((li = malloc(sizeof(*li))) == NULL)
560127412Sgad			errx(STATUS_ERROR, "memory allocation failure");
561127412Sgad		SLIST_INSERT_HEAD(head, li, li_chain);
562127412Sgad		empty = 0;
563127412Sgad
564127412Sgad		li->li_number = (uid_t)strtol(sp, &p, 0);
565127412Sgad		if (*p == '\0') {
566127412Sgad			switch (type) {
567127412Sgad			case LT_PGRP:
568127412Sgad				if (li->li_number == 0)
569127412Sgad					li->li_number = getpgrp();
570127412Sgad				break;
571127412Sgad			case LT_SID:
572127412Sgad				if (li->li_number == 0)
573127412Sgad					li->li_number = getsid(mypid);
574127412Sgad				break;
575127412Sgad			case LT_TTY:
576127412Sgad				usage();
577127412Sgad			default:
578127412Sgad				break;
579127412Sgad			}
580127412Sgad			continue;
581127412Sgad		}
582127412Sgad
583127412Sgad		switch (type) {
584127412Sgad		case LT_USER:
585127412Sgad			if ((pw = getpwnam(sp)) == NULL)
586127412Sgad				errx(STATUS_BADUSAGE, "unknown user `%s'",
587143079Sdelphij				    sp);
588127412Sgad			li->li_number = pw->pw_uid;
589127412Sgad			break;
590127412Sgad		case LT_GROUP:
591127412Sgad			if ((gr = getgrnam(sp)) == NULL)
592127412Sgad				errx(STATUS_BADUSAGE, "unknown group `%s'",
593143079Sdelphij				    sp);
594127412Sgad			li->li_number = gr->gr_gid;
595127412Sgad			break;
596127412Sgad		case LT_TTY:
597127412Sgad			if (strcmp(sp, "-") == 0) {
598127412Sgad				li->li_number = -1;
599127412Sgad				break;
600127412Sgad			} else if (strcmp(sp, "co") == 0)
601127430Sgad				cp = "console";
602127412Sgad			else if (strncmp(sp, "tty", 3) == 0)
603127430Sgad				cp = sp;
604127412Sgad			else
605127430Sgad				cp = NULL;
606127412Sgad
607127430Sgad			if (cp == NULL)
608127412Sgad				snprintf(buf, sizeof(buf), "/dev/tty%s", sp);
609127412Sgad			else
610127430Sgad				snprintf(buf, sizeof(buf), "/dev/%s", cp);
611127412Sgad
612127412Sgad			if (stat(buf, &st) < 0) {
613127412Sgad				if (errno == ENOENT)
614127412Sgad					errx(STATUS_BADUSAGE,
615127412Sgad					    "no such tty: `%s'", sp);
616127412Sgad				err(STATUS_ERROR, "stat(%s)", sp);
617127412Sgad			}
618127412Sgad
619127412Sgad			if ((st.st_mode & S_IFCHR) == 0)
620127412Sgad				errx(STATUS_BADUSAGE, "not a tty: `%s'", sp);
621127412Sgad
622127412Sgad			li->li_number = st.st_rdev;
623127412Sgad			break;
624127412Sgad		default:
625127412Sgad			usage();
626127412Sgad		};
627127412Sgad	}
628127412Sgad
629127412Sgad	if (empty)
630127412Sgad		usage();
631127412Sgad}
632143874Spjd
633143874Spjdint
634143874Spjdtakepid(const char *pidfile)
635143874Spjd{
636143874Spjd	char *endp, line[BUFSIZ];
637143874Spjd	FILE *fh;
638143874Spjd	long rval;
639143879Spjd
640143874Spjd	fh = fopen(pidfile, "r");
641143874Spjd	if (fh == NULL)
642143874Spjd		err(STATUS_ERROR, "can't open pid file `%s'", pidfile);
643143879Spjd
644143874Spjd	if (fgets(line, sizeof(line), fh) == NULL) {
645143874Spjd		if (feof(fh)) {
646143874Spjd			(void)fclose(fh);
647143874Spjd			errx(STATUS_ERROR, "pid file `%s' is empty", pidfile);
648143874Spjd		}
649143874Spjd		(void)fclose(fh);
650143874Spjd		err(STATUS_ERROR, "can't read from pid file `%s'", pidfile);
651143874Spjd	}
652143874Spjd	(void)fclose(fh);
653143879Spjd
654143874Spjd	rval = strtol(line, &endp, 10);
655143874Spjd	if (*endp != '\0' && !isspace((unsigned char)*endp))
656143874Spjd		errx(STATUS_ERROR, "invalid pid in file `%s'", pidfile);
657143874Spjd	else if (rval < MIN_PID || rval > MAX_PID)
658143874Spjd		errx(STATUS_ERROR, "invalid pid in file `%s'", pidfile);
659143874Spjd	return (rval);
660143874Spjd}
661