pkill.c revision 152521
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 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the NetBSD
22 *	Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 *    contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD: head/usr.bin/pkill/pkill.c 152521 2005-11-16 11:03:00Z pjd $");
42
43#include <sys/types.h>
44#include <sys/param.h>
45#include <sys/sysctl.h>
46#include <sys/proc.h>
47#include <sys/queue.h>
48#include <sys/stat.h>
49#include <sys/time.h>
50#include <sys/user.h>
51
52#include <stdio.h>
53#include <stdlib.h>
54#include <limits.h>
55#include <paths.h>
56#include <string.h>
57#include <unistd.h>
58#include <signal.h>
59#include <regex.h>
60#include <ctype.h>
61#include <fcntl.h>
62#include <kvm.h>
63#include <err.h>
64#include <pwd.h>
65#include <grp.h>
66#include <errno.h>
67#include <locale.h>
68
69#define	STATUS_MATCH	0
70#define	STATUS_NOMATCH	1
71#define	STATUS_BADUSAGE	2
72#define	STATUS_ERROR	3
73
74#define	MIN_PID	5
75#define	MAX_PID	99999
76
77/* Ignore system-processes (if '-S' flag is not specified) and myself. */
78#define	PSKIP(kp)	((kp)->ki_pid == mypid ||			\
79			 (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0))
80
81enum listtype {
82	LT_GENERIC,
83	LT_USER,
84	LT_GROUP,
85	LT_TTY,
86	LT_PGRP,
87	LT_SID
88};
89
90struct list {
91	SLIST_ENTRY(list) li_chain;
92	long	li_number;
93};
94
95SLIST_HEAD(listhead, list);
96
97static struct kinfo_proc *plist;
98static char	*selected;
99static const char *delim = "\n";
100static int	nproc;
101static int	pgrep;
102static int	signum = SIGTERM;
103static int	newest;
104static int	oldest;
105static int	interactive;
106static int	inverse;
107static int	longfmt;
108static int	matchargs;
109static int	fullmatch;
110static int	kthreads;
111static int	cflags = REG_EXTENDED;
112static kvm_t	*kd;
113static pid_t	mypid;
114
115static struct listhead euidlist = SLIST_HEAD_INITIALIZER(list);
116static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list);
117static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list);
118static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list);
119static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list);
120static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list);
121static struct listhead sidlist = SLIST_HEAD_INITIALIZER(list);
122static struct listhead jidlist = SLIST_HEAD_INITIALIZER(list);
123
124static void	usage(void) __attribute__((__noreturn__));
125static int	killact(const struct kinfo_proc *);
126static int	grepact(const struct kinfo_proc *);
127static void	makelist(struct listhead *, enum listtype, char *);
128static int	takepid(const char *, int);
129
130int
131main(int argc, char **argv)
132{
133	char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile;
134	const char *execf, *coref;
135	int debug_opt;
136	int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock;
137	size_t jsz;
138	int (*action)(const struct kinfo_proc *);
139	struct kinfo_proc *kp;
140	struct list *li;
141	struct timeval best_tval;
142	regex_t reg;
143	regmatch_t regmatch;
144
145	setlocale(LC_ALL, "");
146
147	if (strcmp(getprogname(), "pgrep") == 0) {
148		action = grepact;
149		pgrep = 1;
150	} else {
151		action = killact;
152		p = argv[1];
153
154		if (argc > 1 && p[0] == '-') {
155			p++;
156			i = (int)strtol(p, &q, 10);
157			if (*q == '\0') {
158				signum = i;
159				argv++;
160				argc--;
161			} else {
162				if (strncasecmp(p, "sig", 3) == 0)
163					p += 3;
164				for (i = 1; i < NSIG; i++)
165					if (strcasecmp(sys_signame[i], p) == 0)
166						break;
167				if (i != NSIG) {
168					signum = i;
169					argv++;
170					argc--;
171				}
172			}
173		}
174	}
175
176	criteria = 0;
177	debug_opt = 0;
178	pidfile = NULL;
179	pidfilelock = 0;
180	execf = coref = _PATH_DEVNULL;
181
182	while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:d:fg:ij:lnos:t:u:vx")) != -1)
183		switch (ch) {
184		case 'D':
185			debug_opt++;
186			break;
187		case 'F':
188			pidfile = optarg;
189			criteria = 1;
190			break;
191		case 'G':
192			makelist(&rgidlist, LT_GROUP, optarg);
193			criteria = 1;
194			break;
195		case 'I':
196			if (pgrep)
197				usage();
198			interactive = 1;
199			break;
200		case 'L':
201			pidfilelock = 1;
202			break;
203		case 'M':
204			coref = optarg;
205			break;
206		case 'N':
207			execf = optarg;
208			break;
209		case 'P':
210			makelist(&ppidlist, LT_GENERIC, optarg);
211			criteria = 1;
212			break;
213		case 'S':
214			if (!pgrep)
215				usage();
216			kthreads = 1;
217			break;
218		case 'U':
219			makelist(&ruidlist, LT_USER, optarg);
220			criteria = 1;
221			break;
222		case 'd':
223			if (!pgrep)
224				usage();
225			delim = optarg;
226			break;
227		case 'f':
228			matchargs = 1;
229			break;
230		case 'g':
231			makelist(&pgrplist, LT_PGRP, optarg);
232			criteria = 1;
233			break;
234		case 'i':
235			cflags |= REG_ICASE;
236			break;
237		case 'j':
238			makelist(&jidlist, LT_GENERIC, optarg);
239			criteria = 1;
240			break;
241		case 'l':
242			if (!pgrep)
243				usage();
244			longfmt = 1;
245			break;
246		case 'n':
247			newest = 1;
248			criteria = 1;
249			break;
250		case 'o':
251			oldest = 1;
252			criteria = 1;
253			break;
254		case 's':
255			makelist(&sidlist, LT_SID, optarg);
256			criteria = 1;
257			break;
258		case 't':
259			makelist(&tdevlist, LT_TTY, optarg);
260			criteria = 1;
261			break;
262		case 'u':
263			makelist(&euidlist, LT_USER, optarg);
264			criteria = 1;
265			break;
266		case 'v':
267			inverse = 1;
268			break;
269		case 'x':
270			fullmatch = 1;
271			break;
272		default:
273			usage();
274			/* NOTREACHED */
275		}
276
277	argc -= optind;
278	argv += optind;
279	if (argc != 0)
280		criteria = 1;
281	if (!criteria)
282		usage();
283	if (newest && oldest)
284		errx(STATUS_ERROR, "Options -n and -o are mutually exclusive");
285	if (pidfile != NULL)
286		pidfromfile = takepid(pidfile, pidfilelock);
287	else {
288		if (pidfilelock) {
289			errx(STATUS_ERROR,
290			    "Option -L doesn't make sense without -F");
291		}
292		pidfromfile = -1;
293	}
294
295	mypid = getpid();
296
297	/*
298	 * Retrieve the list of running processes from the kernel.
299	 */
300	kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf);
301	if (kd == NULL)
302		errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf);
303
304	/*
305	 * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we
306	 * just want processes and not individual kernel threads.
307	 */
308	plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc);
309	if (plist == NULL) {
310		errx(STATUS_ERROR, "Cannot get process list (%s)",
311		    kvm_geterr(kd));
312	}
313
314	/*
315	 * Allocate memory which will be used to keep track of the
316	 * selection.
317	 */
318	if ((selected = malloc(nproc)) == NULL) {
319		err(STATUS_ERROR, "Cannot allocate memory for %d processes",
320		    nproc);
321	}
322	memset(selected, 0, nproc);
323
324	/*
325	 * Refine the selection.
326	 */
327	for (; *argv != NULL; argv++) {
328		if ((rv = regcomp(&reg, *argv, cflags)) != 0) {
329			regerror(rv, &reg, buf, sizeof(buf));
330			errx(STATUS_BADUSAGE,
331			    "Cannot compile regular expression `%s' (%s)",
332			    *argv, buf);
333		}
334
335		for (i = 0, kp = plist; i < nproc; i++, kp++) {
336			if (PSKIP(kp)) {
337				if (debug_opt > 0)
338				    fprintf(stderr, "* Skipped %5d %3d %s\n",
339					kp->ki_pid, kp->ki_uid, kp->ki_comm);
340				continue;
341			}
342
343			if (matchargs &&
344			    (pargv = kvm_getargv(kd, kp, 0)) != NULL) {
345				jsz = 0;
346				while (jsz < sizeof(buf) && *pargv != NULL) {
347					jsz += snprintf(buf + jsz,
348					    sizeof(buf) - jsz,
349					    pargv[1] != NULL ? "%s " : "%s",
350					    pargv[0]);
351					pargv++;
352				}
353				mstr = buf;
354			} else
355				mstr = kp->ki_comm;
356
357			rv = regexec(&reg, mstr, 1, &regmatch, 0);
358			if (rv == 0) {
359				if (fullmatch) {
360					if (regmatch.rm_so == 0 &&
361					    regmatch.rm_eo ==
362					    (off_t)strlen(mstr))
363						selected[i] = 1;
364				} else
365					selected[i] = 1;
366			} else if (rv != REG_NOMATCH) {
367				regerror(rv, &reg, buf, sizeof(buf));
368				errx(STATUS_ERROR,
369				    "Regular expression evaluation error (%s)",
370				    buf);
371			}
372			if (debug_opt > 1) {
373				const char *rv_res = "NoMatch";
374				if (selected[i])
375					rv_res = "Matched";
376				fprintf(stderr, "* %s %5d %3d %s\n", rv_res,
377				    kp->ki_pid, kp->ki_uid, mstr);
378			}
379		}
380
381		regfree(&reg);
382	}
383
384	for (i = 0, kp = plist; i < nproc; i++, kp++) {
385		if (PSKIP(kp))
386			continue;
387
388		if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) {
389			selected[i] = 0;
390			continue;
391		}
392
393		SLIST_FOREACH(li, &ruidlist, li_chain)
394			if (kp->ki_ruid == (uid_t)li->li_number)
395				break;
396		if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
397			selected[i] = 0;
398			continue;
399		}
400
401		SLIST_FOREACH(li, &rgidlist, li_chain)
402			if (kp->ki_rgid == (gid_t)li->li_number)
403				break;
404		if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
405			selected[i] = 0;
406			continue;
407		}
408
409		SLIST_FOREACH(li, &euidlist, li_chain)
410			if (kp->ki_uid == (uid_t)li->li_number)
411				break;
412		if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
413			selected[i] = 0;
414			continue;
415		}
416
417		SLIST_FOREACH(li, &ppidlist, li_chain)
418			if (kp->ki_ppid == (pid_t)li->li_number)
419				break;
420		if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
421			selected[i] = 0;
422			continue;
423		}
424
425		SLIST_FOREACH(li, &pgrplist, li_chain)
426			if (kp->ki_pgid == (pid_t)li->li_number)
427				break;
428		if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
429			selected[i] = 0;
430			continue;
431		}
432
433		SLIST_FOREACH(li, &tdevlist, li_chain) {
434			if (li->li_number == -1 &&
435			    (kp->ki_flag & P_CONTROLT) == 0)
436				break;
437			if (kp->ki_tdev == (dev_t)li->li_number)
438				break;
439		}
440		if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
441			selected[i] = 0;
442			continue;
443		}
444
445		SLIST_FOREACH(li, &sidlist, li_chain)
446			if (kp->ki_sid == (pid_t)li->li_number)
447				break;
448		if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
449			selected[i] = 0;
450			continue;
451		}
452
453		SLIST_FOREACH(li, &jidlist, li_chain) {
454			if (kp->ki_jid > 0) {
455				if (li->li_number == 0)
456					break;
457				if (kp->ki_jid == (int)li->li_number)
458					break;
459			}
460		}
461		if (SLIST_FIRST(&jidlist) != NULL && li == NULL) {
462			selected[i] = 0;
463			continue;
464		}
465
466		if (argc == 0)
467			selected[i] = 1;
468	}
469
470	if (newest || oldest) {
471		best_tval.tv_sec = 0;
472		best_tval.tv_usec = 0;
473		bestidx = -1;
474
475		for (i = 0, kp = plist; i < nproc; i++, kp++) {
476			if (!selected[i])
477				continue;
478			if (bestidx == -1) {
479				/* The first entry of the list which matched. */
480				;
481			} else if (timercmp(&kp->ki_start, &best_tval, >)) {
482				/* This entry is newer than previous "best". */
483				if (oldest)	/* but we want the oldest */
484					continue;
485			} else {
486				/* This entry is older than previous "best". */
487				if (newest)	/* but we want the newest */
488					continue;
489			}
490			/* This entry is better than previous "best" entry. */
491			best_tval.tv_sec = kp->ki_start.tv_sec;
492			best_tval.tv_usec = kp->ki_start.tv_usec;
493			bestidx = i;
494		}
495
496		memset(selected, 0, nproc);
497		if (bestidx != -1)
498			selected[bestidx] = 1;
499	}
500
501	/*
502	 * Take the appropriate action for each matched process, if any.
503	 */
504	for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) {
505		if (PSKIP(kp))
506			continue;
507		if (selected[i]) {
508			if (inverse)
509				continue;
510		} else if (!inverse)
511			continue;
512		rv |= (*action)(kp);
513	}
514
515	exit(rv ? STATUS_MATCH : STATUS_NOMATCH);
516}
517
518static void
519usage(void)
520{
521	const char *ustr;
522
523	if (pgrep)
524		ustr = "[-LSfilnovx] [-d delim]";
525	else
526		ustr = "[-signal] [-ILfinovx]";
527
528	fprintf(stderr,
529		"usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n"
530		"             [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n"
531		"             [-t tty] [-u euid] pattern ...\n", getprogname(),
532		ustr);
533
534	exit(STATUS_BADUSAGE);
535}
536
537static void
538show_process(const struct kinfo_proc *kp)
539{
540	char **argv;
541
542	if ((longfmt || !pgrep) && matchargs &&
543	    (argv = kvm_getargv(kd, kp, 0)) != NULL) {
544		printf("%d ", (int)kp->ki_pid);
545		for (; *argv != NULL; argv++) {
546			printf("%s", *argv);
547			if (argv[1] != NULL)
548				putchar(' ');
549		}
550	} else if (longfmt || !pgrep)
551		printf("%d %s", (int)kp->ki_pid, kp->ki_comm);
552	else
553		printf("%d", (int)kp->ki_pid);
554}
555
556static int
557killact(const struct kinfo_proc *kp)
558{
559	int ch, first;
560
561	if (interactive) {
562		/*
563		 * Be careful, ask before killing.
564		 */
565		printf("kill ");
566		show_process(kp);
567		printf("? ");
568		fflush(stdout);
569		first = ch = getchar();
570		while (ch != '\n' && ch != EOF)
571			ch = getchar();
572		if (first != 'y' && first != 'Y')
573			return (1);
574	}
575	if (kill(kp->ki_pid, signum) == -1) {
576		/*
577		 * Check for ESRCH, which indicates that the process
578		 * disappeared between us matching it and us
579		 * signalling it; don't issue a warning about it.
580		 */
581		if (errno != ESRCH)
582			warn("signalling pid %d", (int)kp->ki_pid);
583		/*
584		 * Return 0 to indicate that the process should not be
585		 * considered a match, since we didn't actually get to
586		 * signal it.
587		 */
588		return (0);
589	}
590	return (1);
591}
592
593static int
594grepact(const struct kinfo_proc *kp)
595{
596
597	show_process(kp);
598	printf("%s", delim);
599	return (1);
600}
601
602static void
603makelist(struct listhead *head, enum listtype type, char *src)
604{
605	struct list *li;
606	struct passwd *pw;
607	struct group *gr;
608	struct stat st;
609	const char *cp, *prefix;
610	char *sp, *ep, buf[MAXPATHLEN];
611	int empty;
612
613	empty = 1;
614	prefix = _PATH_DEV;
615
616	while ((sp = strsep(&src, ",")) != NULL) {
617		if (*sp == '\0')
618			usage();
619
620		if ((li = malloc(sizeof(*li))) == NULL) {
621			err(STATUS_ERROR, "Cannot allocate %zu bytes",
622			    sizeof(*li));
623		}
624
625		SLIST_INSERT_HEAD(head, li, li_chain);
626		empty = 0;
627
628		li->li_number = (uid_t)strtol(sp, &ep, 0);
629		if (*ep == '\0') {
630			switch (type) {
631			case LT_PGRP:
632				if (li->li_number == 0)
633					li->li_number = getpgrp();
634				break;
635			case LT_SID:
636				if (li->li_number == 0)
637					li->li_number = getsid(mypid);
638				break;
639			case LT_TTY:
640				usage();
641				/* NOTREACHED */
642			default:
643				break;
644			}
645			continue;
646		}
647
648		switch (type) {
649		case LT_USER:
650			if ((pw = getpwnam(sp)) == NULL)
651				errx(STATUS_BADUSAGE, "Unknown user `%s'", sp);
652			li->li_number = pw->pw_uid;
653			break;
654		case LT_GROUP:
655			if ((gr = getgrnam(sp)) == NULL)
656				errx(STATUS_BADUSAGE, "Unknown group `%s'", sp);
657			li->li_number = gr->gr_gid;
658			break;
659		case LT_TTY:
660			if (strcmp(sp, "-") == 0) {
661				li->li_number = -1;
662				break;
663			} else if (strcmp(sp, "co") == 0) {
664				cp = "console";
665			} else {
666				cp = sp;
667				if (strncmp(sp, "tty", 3) != 0)
668					prefix = _PATH_TTY;
669			}
670
671			snprintf(buf, sizeof(buf), "%s%s", prefix, cp);
672
673			if (stat(buf, &st) == -1) {
674				if (errno == ENOENT) {
675					errx(STATUS_BADUSAGE,
676					    "No such tty: `%s'", sp);
677				}
678				err(STATUS_ERROR, "Cannot access `%s'", sp);
679			}
680
681			if ((st.st_mode & S_IFCHR) == 0)
682				errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp);
683
684			li->li_number = st.st_rdev;
685			break;
686		default:
687			usage();
688		}
689	}
690
691	if (empty)
692		usage();
693}
694
695static int
696takepid(const char *pidfile, int pidfilelock)
697{
698	char *endp, line[BUFSIZ];
699	FILE *fh;
700	long rval;
701
702	fh = fopen(pidfile, "r");
703	if (fh == NULL)
704		err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile);
705
706	if (pidfilelock) {
707		/*
708		 * If we can lock pidfile, this means that daemon is not
709		 * running, so would be better not to kill some random process.
710		 */
711		if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) {
712			(void)fclose(fh);
713			errx(STATUS_ERROR, "File '%s' can be locked", pidfile);
714		} else {
715			if (errno != EWOULDBLOCK) {
716				errx(STATUS_ERROR,
717				    "Error while locking file '%s'", pidfile);
718			}
719		}
720	}
721
722	if (fgets(line, sizeof(line), fh) == NULL) {
723		if (feof(fh)) {
724			(void)fclose(fh);
725			errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile);
726		}
727		(void)fclose(fh);
728		err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile);
729	}
730	(void)fclose(fh);
731
732	rval = strtol(line, &endp, 10);
733	if (*endp != '\0' && !isspace((unsigned char)*endp))
734		errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
735	else if (rval < MIN_PID || rval > MAX_PID)
736		errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
737	return (rval);
738}
739