1/*-
2 * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
3 * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: releng/10.3/usr.bin/killall/killall.c 274471 2014-11-13 16:40:15Z smh $");
30
31#include <sys/param.h>
32#include <sys/jail.h>
33#include <sys/stat.h>
34#include <sys/uio.h>
35#include <sys/user.h>
36#include <sys/sysctl.h>
37#include <fcntl.h>
38#include <dirent.h>
39#include <jail.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <pwd.h>
44#include <signal.h>
45#include <regex.h>
46#include <ctype.h>
47#include <err.h>
48#include <errno.h>
49#include <unistd.h>
50#include <locale.h>
51
52static void __dead2
53usage(void)
54{
55
56	fprintf(stderr, "usage: killall [-delmsqvz] [-help] [-I] [-j jail]\n");
57	fprintf(stderr,
58	    "               [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
59	fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
60	exit(1);
61}
62
63
64static void
65printsig(FILE *fp)
66{
67	const char	*const * p;
68	int		cnt;
69	int		offset = 0;
70
71	for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
72		offset += fprintf(fp, "%s ", *p);
73		if (offset >= 75 && cnt > 1) {
74			offset = 0;
75			fprintf(fp, "\n");
76		}
77	}
78	fprintf(fp, "\n");
79}
80
81static void
82nosig(char *name)
83{
84
85	warnx("unknown signal %s; valid signals:", name);
86	printsig(stderr);
87	exit(1);
88}
89
90int
91main(int ac, char **av)
92{
93	char		**saved_av;
94	struct kinfo_proc *procs, *newprocs;
95	struct stat	sb;
96	struct passwd	*pw;
97	regex_t		rgx;
98	regmatch_t	pmatch;
99	int		i, j, ch;
100	char		buf[256];
101	char		first;
102	char		*user = NULL;
103	char		*tty = NULL;
104	char		*cmd = NULL;
105	int		qflag = 0;
106	int		vflag = 0;
107	int		sflag = 0;
108	int		dflag = 0;
109	int		eflag = 0;
110	int		Iflag = 0;
111	int		jflag = 0;
112	int		mflag = 0;
113	int		zflag = 0;
114	uid_t		uid = 0;
115	dev_t		tdev = 0;
116	pid_t		mypid;
117	char		thiscmd[MAXCOMLEN + 1];
118	pid_t		thispid;
119	uid_t		thisuid;
120	dev_t		thistdev;
121	int		sig = SIGTERM;
122	const char *const *p;
123	char		*ep;
124	int		errors = 0;
125	int		jid;
126	int		mib[4];
127	size_t		miblen;
128	int		st, nprocs;
129	size_t		size;
130	int		matched;
131	int		killed = 0;
132
133	setlocale(LC_ALL, "");
134
135	av++;
136	ac--;
137
138	while (ac > 0) {
139		if (strcmp(*av, "-l") == 0) {
140			printsig(stdout);
141			exit(0);
142		}
143		if (strcmp(*av, "-help") == 0)
144			usage();
145		if (**av == '-') {
146			++*av;
147			switch (**av) {
148			case 'j':
149				++*av;
150				if (**av == '\0') {
151					++av;
152					--ac;
153				}
154				jflag++;
155				if (*av == NULL)
156				    	errx(1, "must specify jail");
157				jid = jail_getid(*av);
158				if (jid < 0)
159					errx(1, "%s", jail_errmsg);
160				if (jail_attach(jid) == -1)
161					err(1, "jail_attach(%d)", jid);
162				break;
163			case 'u':
164				++*av;
165				if (**av == '\0') {
166					++av;
167					--ac;
168				}
169				if (*av == NULL)
170				    	errx(1, "must specify user");
171				user = *av;
172				break;
173			case 't':
174				++*av;
175				if (**av == '\0') {
176					++av;
177					--ac;
178				}
179				if (*av == NULL)
180				    	errx(1, "must specify tty");
181				tty = *av;
182				break;
183			case 'c':
184				++*av;
185				if (**av == '\0') {
186					++av;
187					--ac;
188				}
189				if (*av == NULL)
190				    	errx(1, "must specify procname");
191				cmd = *av;
192				break;
193			case 'q':
194				qflag++;
195				break;
196			case 'v':
197				vflag++;
198				break;
199			case 's':
200				sflag++;
201				break;
202			case 'd':
203				dflag++;
204				break;
205			case 'e':
206				eflag++;
207				break;
208			case 'm':
209				mflag++;
210				break;
211			case 'z':
212				zflag++;
213				break;
214			default:
215				saved_av = av;
216				if (isalpha((unsigned char)**av)) {
217					if (strncasecmp(*av, "SIG", 3) == 0)
218						*av += 3;
219					for (sig = NSIG, p = sys_signame + 1;
220					     --sig; ++p)
221						if (strcasecmp(*p, *av) == 0) {
222							sig = p - sys_signame;
223							break;
224						}
225					if (!sig) {
226						if (**saved_av == 'I') {
227							av = saved_av;
228							Iflag = 1;
229							break;
230						} else
231							nosig(*av);
232					}
233				} else if (isdigit((unsigned char)**av)) {
234					sig = strtol(*av, &ep, 10);
235					if (!*av || *ep)
236						errx(1, "illegal signal number: %s", *av);
237					if (sig < 0 || sig >= NSIG)
238						nosig(*av);
239				} else
240					nosig(*av);
241			}
242			++av;
243			--ac;
244		} else {
245			break;
246		}
247	}
248
249	if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
250		usage();
251
252	if (tty) {
253		if (strncmp(tty, "/dev/", 5) == 0)
254			snprintf(buf, sizeof(buf), "%s", tty);
255		else if (strncmp(tty, "tty", 3) == 0)
256			snprintf(buf, sizeof(buf), "/dev/%s", tty);
257		else
258			snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
259		if (stat(buf, &sb) < 0)
260			err(1, "stat(%s)", buf);
261		if (!S_ISCHR(sb.st_mode))
262			errx(1, "%s: not a character device", buf);
263		tdev = sb.st_rdev;
264		if (dflag)
265			printf("ttydev:0x%x\n", tdev);
266	}
267	if (user) {
268		uid = strtol(user, &ep, 10);
269		if (*user == '\0' || *ep != '\0') { /* was it a number? */
270			pw = getpwnam(user);
271			if (pw == NULL)
272				errx(1, "user %s does not exist", user);
273			uid = pw->pw_uid;
274			if (dflag)
275				printf("uid:%d\n", uid);
276		}
277	} else {
278		uid = getuid();
279		if (uid != 0) {
280			pw = getpwuid(uid);
281			if (pw)
282				user = pw->pw_name;
283			if (dflag)
284				printf("uid:%d\n", uid);
285		}
286	}
287	size = 0;
288	mib[0] = CTL_KERN;
289	mib[1] = KERN_PROC;
290
291	if (user) {
292		mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
293		mib[3] = uid;
294		miblen = 4;
295	} else if (tty) {
296		mib[2] = KERN_PROC_TTY;
297		mib[3] = tdev;
298		miblen = 4;
299	} else {
300		mib[2] = KERN_PROC_PROC;
301		mib[3] = 0;
302		miblen = 3;
303	}
304
305	procs = NULL;
306	st = sysctl(mib, miblen, NULL, &size, NULL, 0);
307	do {
308		size += size / 10;
309		newprocs = realloc(procs, size);
310		if (newprocs == NULL) {
311			free(procs);
312			err(1, "could not reallocate memory");
313		}
314		procs = newprocs;
315		st = sysctl(mib, miblen, procs, &size, NULL, 0);
316	} while (st == -1 && errno == ENOMEM);
317	if (st == -1)
318		err(1, "could not sysctl(KERN_PROC)");
319	if (size % sizeof(struct kinfo_proc) != 0) {
320		fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
321			size, sizeof(struct kinfo_proc));
322		fprintf(stderr, "userland out of sync with kernel\n");
323		exit(1);
324	}
325	nprocs = size / sizeof(struct kinfo_proc);
326	if (dflag)
327		printf("nprocs %d\n", nprocs);
328	mypid = getpid();
329
330	for (i = 0; i < nprocs; i++) {
331		if (procs[i].ki_stat == SZOMB && !zflag)
332			continue;
333		thispid = procs[i].ki_pid;
334		strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd));
335		thistdev = procs[i].ki_tdev;
336		if (eflag)
337			thisuid = procs[i].ki_uid;	/* effective uid */
338		else
339			thisuid = procs[i].ki_ruid;	/* real uid */
340
341		if (thispid == mypid)
342			continue;
343		matched = 1;
344		if (user) {
345			if (thisuid != uid)
346				matched = 0;
347		}
348		if (tty) {
349			if (thistdev != tdev)
350				matched = 0;
351		}
352		if (cmd) {
353			if (mflag) {
354				if (regcomp(&rgx, cmd,
355				    REG_EXTENDED|REG_NOSUB) != 0) {
356					mflag = 0;
357					warnx("%s: illegal regexp", cmd);
358				}
359			}
360			if (mflag) {
361				pmatch.rm_so = 0;
362				pmatch.rm_eo = strlen(thiscmd);
363				if (regexec(&rgx, thiscmd, 0, &pmatch,
364				    REG_STARTEND) != 0)
365					matched = 0;
366				regfree(&rgx);
367			} else {
368				if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
369					matched = 0;
370			}
371		}
372		if (jflag && thispid == getpid())
373			matched = 0;
374		if (matched == 0)
375			continue;
376		if (ac > 0)
377			matched = 0;
378		for (j = 0; j < ac; j++) {
379			if (mflag) {
380				if (regcomp(&rgx, av[j],
381				    REG_EXTENDED|REG_NOSUB) != 0) {
382					mflag = 0;
383					warnx("%s: illegal regexp", av[j]);
384				}
385			}
386			if (mflag) {
387				pmatch.rm_so = 0;
388				pmatch.rm_eo = strlen(thiscmd);
389				if (regexec(&rgx, thiscmd, 0, &pmatch,
390				    REG_STARTEND) == 0)
391					matched = 1;
392				regfree(&rgx);
393			} else {
394				if (strcmp(thiscmd, av[j]) == 0)
395					matched = 1;
396			}
397			if (matched)
398				break;
399		}
400		if (matched != 0 && Iflag) {
401			printf("Send signal %d to %s (pid %d uid %d)? ",
402				sig, thiscmd, thispid, thisuid);
403			fflush(stdout);
404			first = ch = getchar();
405			while (ch != '\n' && ch != EOF)
406				ch = getchar();
407			if (first != 'y' && first != 'Y')
408				matched = 0;
409		}
410		if (matched == 0)
411			continue;
412		if (dflag)
413			printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
414			    thiscmd, thispid, thistdev, thisuid);
415
416		if (vflag || sflag)
417			printf("kill -%s %d\n", sys_signame[sig], thispid);
418
419		killed++;
420		if (!dflag && !sflag) {
421			if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
422				warn("warning: kill -%s %d",
423				    sys_signame[sig], thispid);
424				errors = 1;
425			}
426		}
427	}
428	if (killed == 0) {
429		if (!qflag)
430			fprintf(stderr, "No matching processes %swere found\n",
431			    getuid() != 0 ? "belonging to you " : "");
432		errors = 1;
433	}
434	exit(errors);
435}
436