165123Speter/*-
265123Speter * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
365123Speter * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
465123Speter * All rights reserved.
565123Speter *
665123Speter * Redistribution and use in source and binary forms, with or without
765123Speter * modification, are permitted provided that the following conditions
865123Speter * are met:
965123Speter * 1. Redistributions of source code must retain the above copyright
1065123Speter *    notice, this list of conditions and the following disclaimer.
1165123Speter * 2. Redistributions in binary form must reproduce the above copyright
1265123Speter *    notice, this list of conditions and the following disclaimer in the
1365123Speter *    documentation and/or other materials provided with the distribution.
1465123Speter *
1565123Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1665123Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1765123Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1865123Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1965123Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2065123Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2165123Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2265123Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2365123Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2465123Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2565123Speter * SUCH DAMAGE.
2665123Speter */
2765123Speter
2865177Speter#include <sys/cdefs.h>
2999112Sobrien__FBSDID("$FreeBSD: releng/10.2/usr.bin/killall/killall.c 274471 2014-11-13 16:40:15Z smh $");
3099112Sobrien
3165123Speter#include <sys/param.h>
32113277Smike#include <sys/jail.h>
3365123Speter#include <sys/stat.h>
34192896Sjamie#include <sys/uio.h>
3565123Speter#include <sys/user.h>
3665123Speter#include <sys/sysctl.h>
37200462Sdelphij#include <fcntl.h>
38200462Sdelphij#include <dirent.h>
39194869Sjamie#include <jail.h>
4065123Speter#include <stdio.h>
4165123Speter#include <stdlib.h>
4265123Speter#include <string.h>
4365123Speter#include <pwd.h>
4465123Speter#include <signal.h>
4565123Speter#include <regex.h>
4665123Speter#include <ctype.h>
4765123Speter#include <err.h>
4865123Speter#include <errno.h>
4965123Speter#include <unistd.h>
50132191Stjr#include <locale.h>
5165123Speter
5265177Speterstatic void __dead2
5365123Speterusage(void)
5465123Speter{
5565123Speter
56252428Smjg	fprintf(stderr, "usage: killall [-delmsqvz] [-help] [-I] [-j jail]\n");
57113277Smike	fprintf(stderr,
58124681Smaxim	    "               [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
5965123Speter	fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
6065123Speter	exit(1);
6165123Speter}
6265123Speter
6365123Speter
6465123Speterstatic void
6565123Speterprintsig(FILE *fp)
6665123Speter{
6765123Speter	const char	*const * p;
6865123Speter	int		cnt;
6965123Speter	int		offset = 0;
7065123Speter
7165123Speter	for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
72219347Sjilles		offset += fprintf(fp, "%s ", *p);
7365123Speter		if (offset >= 75 && cnt > 1) {
7465123Speter			offset = 0;
7565123Speter			fprintf(fp, "\n");
7665123Speter		}
7765123Speter	}
7865123Speter	fprintf(fp, "\n");
7965123Speter}
8065123Speter
8165123Speterstatic void
8265123Speternosig(char *name)
8365123Speter{
8465123Speter
8565123Speter	warnx("unknown signal %s; valid signals:", name);
8665123Speter	printsig(stderr);
8765123Speter	exit(1);
8865123Speter}
8965123Speter
9065123Speterint
9165123Spetermain(int ac, char **av)
9265123Speter{
93274471Ssmh	char		**saved_av;
94237844Skib	struct kinfo_proc *procs, *newprocs;
9565123Speter	struct stat	sb;
9665127Speter	struct passwd	*pw;
9765123Speter	regex_t		rgx;
9865123Speter	regmatch_t	pmatch;
99237618Sdelphij	int		i, j, ch;
10065123Speter	char		buf[256];
101237618Sdelphij	char		first;
10265123Speter	char		*user = NULL;
10365123Speter	char		*tty = NULL;
10465123Speter	char		*cmd = NULL;
105252428Smjg	int		qflag = 0;
10665123Speter	int		vflag = 0;
10765123Speter	int		sflag = 0;
10865123Speter	int		dflag = 0;
109125013Sdds	int		eflag = 0;
110237618Sdelphij	int		Iflag = 0;
111113277Smike	int		jflag = 0;
11265123Speter	int		mflag = 0;
11394689Sdes	int		zflag = 0;
11465123Speter	uid_t		uid = 0;
11565123Speter	dev_t		tdev = 0;
116124844Scperciva	pid_t		mypid;
11765123Speter	char		thiscmd[MAXCOMLEN + 1];
11865123Speter	pid_t		thispid;
11965123Speter	uid_t		thisuid;
12065123Speter	dev_t		thistdev;
12165123Speter	int		sig = SIGTERM;
12265127Speter	const char *const *p;
12365123Speter	char		*ep;
12465123Speter	int		errors = 0;
125113277Smike	int		jid;
12676678Sphk	int		mib[4];
12765123Speter	size_t		miblen;
12865123Speter	int		st, nprocs;
12965123Speter	size_t		size;
13065123Speter	int		matched;
13165123Speter	int		killed = 0;
13265123Speter
133132191Stjr	setlocale(LC_ALL, "");
134132191Stjr
13565123Speter	av++;
13665123Speter	ac--;
13765123Speter
13865123Speter	while (ac > 0) {
13965123Speter		if (strcmp(*av, "-l") == 0) {
14065123Speter			printsig(stdout);
14165123Speter			exit(0);
14265123Speter		}
14365177Speter		if (strcmp(*av, "-help") == 0)
14465177Speter			usage();
14565123Speter		if (**av == '-') {
14665123Speter			++*av;
14765123Speter			switch (**av) {
148113277Smike			case 'j':
149113277Smike				++*av;
150173502Sru				if (**av == '\0') {
151113277Smike					++av;
152173502Sru					--ac;
153173502Sru				}
154113277Smike				jflag++;
155173502Sru				if (*av == NULL)
156192896Sjamie				    	errx(1, "must specify jail");
157194869Sjamie				jid = jail_getid(*av);
158194869Sjamie				if (jid < 0)
159194869Sjamie					errx(1, "%s", jail_errmsg);
160113277Smike				if (jail_attach(jid) == -1)
161192896Sjamie					err(1, "jail_attach(%d)", jid);
162113277Smike				break;
16365123Speter			case 'u':
16465123Speter				++*av;
165173502Sru				if (**av == '\0') {
16665123Speter					++av;
167173502Sru					--ac;
168173502Sru				}
169173502Sru				if (*av == NULL)
170173502Sru				    	errx(1, "must specify user");
17165123Speter				user = *av;
17265123Speter				break;
17365123Speter			case 't':
17465123Speter				++*av;
175173502Sru				if (**av == '\0') {
17665123Speter					++av;
177173502Sru					--ac;
178173502Sru				}
179173502Sru				if (*av == NULL)
180173502Sru				    	errx(1, "must specify tty");
18165123Speter				tty = *av;
18265123Speter				break;
18365123Speter			case 'c':
18465123Speter				++*av;
185173502Sru				if (**av == '\0') {
18665123Speter					++av;
187173502Sru					--ac;
188173502Sru				}
189173502Sru				if (*av == NULL)
190173502Sru				    	errx(1, "must specify procname");
19165123Speter				cmd = *av;
19265123Speter				break;
193252428Smjg			case 'q':
194252428Smjg				qflag++;
195252428Smjg				break;
19665123Speter			case 'v':
19765123Speter				vflag++;
19865123Speter				break;
19965123Speter			case 's':
20065123Speter				sflag++;
20165123Speter				break;
20265123Speter			case 'd':
20365123Speter				dflag++;
20465123Speter				break;
205125013Sdds			case 'e':
206125013Sdds				eflag++;
207125013Sdds				break;
20865123Speter			case 'm':
20965123Speter				mflag++;
21065123Speter				break;
21194689Sdes			case 'z':
21294689Sdes				zflag++;
21394689Sdes				break;
21465123Speter			default:
215274471Ssmh				saved_av = av;
216132193Stjr				if (isalpha((unsigned char)**av)) {
217218285Sjilles					if (strncasecmp(*av, "SIG", 3) == 0)
21865123Speter						*av += 3;
21965123Speter					for (sig = NSIG, p = sys_signame + 1;
22065123Speter					     --sig; ++p)
22165123Speter						if (strcasecmp(*p, *av) == 0) {
22265123Speter							sig = p - sys_signame;
22365123Speter							break;
22465123Speter						}
225274471Ssmh					if (!sig) {
226274471Ssmh						if (**saved_av == 'I') {
227274471Ssmh							av = saved_av;
228274471Ssmh							Iflag = 1;
229274471Ssmh							break;
230274471Ssmh						} else
231274471Ssmh							nosig(*av);
232274471Ssmh					}
233132193Stjr				} else if (isdigit((unsigned char)**av)) {
23465123Speter					sig = strtol(*av, &ep, 10);
23565123Speter					if (!*av || *ep)
23665123Speter						errx(1, "illegal signal number: %s", *av);
237132851Smaxim					if (sig < 0 || sig >= NSIG)
23865123Speter						nosig(*av);
23965123Speter				} else
24065123Speter					nosig(*av);
24165123Speter			}
24265123Speter			++av;
24365123Speter			--ac;
24465123Speter		} else {
24565123Speter			break;
24665123Speter		}
24765123Speter	}
24865123Speter
249113277Smike	if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
25065123Speter		usage();
25165123Speter
25265123Speter	if (tty) {
25365123Speter		if (strncmp(tty, "/dev/", 5) == 0)
25465123Speter			snprintf(buf, sizeof(buf), "%s", tty);
25565123Speter		else if (strncmp(tty, "tty", 3) == 0)
25665123Speter			snprintf(buf, sizeof(buf), "/dev/%s", tty);
25765123Speter		else
25865123Speter			snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
25965123Speter		if (stat(buf, &sb) < 0)
26065123Speter			err(1, "stat(%s)", buf);
26165123Speter		if (!S_ISCHR(sb.st_mode))
26265123Speter			errx(1, "%s: not a character device", buf);
26365123Speter		tdev = sb.st_rdev;
26465123Speter		if (dflag)
26565123Speter			printf("ttydev:0x%x\n", tdev);
26665123Speter	}
26765123Speter	if (user) {
26878144Sobrien		uid = strtol(user, &ep, 10);
26993432Sdwmalone		if (*user == '\0' || *ep != '\0') { /* was it a number? */
27078144Sobrien			pw = getpwnam(user);
27178144Sobrien			if (pw == NULL)
27278144Sobrien				errx(1, "user %s does not exist", user);
27378144Sobrien			uid = pw->pw_uid;
27478144Sobrien			if (dflag)
27578144Sobrien				printf("uid:%d\n", uid);
27678144Sobrien		}
27765123Speter	} else {
27865123Speter		uid = getuid();
27965123Speter		if (uid != 0) {
28065123Speter			pw = getpwuid(uid);
28165123Speter			if (pw)
28265123Speter				user = pw->pw_name;
28365123Speter			if (dflag)
28465123Speter				printf("uid:%d\n", uid);
28565123Speter		}
28665123Speter	}
28765123Speter	size = 0;
28865123Speter	mib[0] = CTL_KERN;
28965123Speter	mib[1] = KERN_PROC;
29065123Speter
291119834Stjr	if (user) {
292125013Sdds		mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
29365123Speter		mib[3] = uid;
294120500Stjr		miblen = 4;
295119834Stjr	} else if (tty) {
29665123Speter		mib[2] = KERN_PROC_TTY;
29765123Speter		mib[3] = tdev;
298120500Stjr		miblen = 4;
299237845Skib	} else {
300237845Skib		mib[2] = KERN_PROC_PROC;
301237845Skib		mib[3] = 0;
302237845Skib		miblen = 3;
30365123Speter	}
30465123Speter
305237844Skib	procs = NULL;
30665123Speter	st = sysctl(mib, miblen, NULL, &size, NULL, 0);
30765123Speter	do {
30865123Speter		size += size / 10;
30965123Speter		newprocs = realloc(procs, size);
310237844Skib		if (newprocs == NULL) {
311237844Skib			free(procs);
312237844Skib			err(1, "could not reallocate memory");
31365123Speter		}
31465123Speter		procs = newprocs;
31565123Speter		st = sysctl(mib, miblen, procs, &size, NULL, 0);
31665123Speter	} while (st == -1 && errno == ENOMEM);
31765123Speter	if (st == -1)
31865123Speter		err(1, "could not sysctl(KERN_PROC)");
31965123Speter	if (size % sizeof(struct kinfo_proc) != 0) {
320132192Stjr		fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
32165123Speter			size, sizeof(struct kinfo_proc));
322237846Skib		fprintf(stderr, "userland out of sync with kernel\n");
32365123Speter		exit(1);
32465123Speter	}
32565123Speter	nprocs = size / sizeof(struct kinfo_proc);
32665123Speter	if (dflag)
32765123Speter		printf("nprocs %d\n", nprocs);
328124844Scperciva	mypid = getpid();
32965123Speter
33065123Speter	for (i = 0; i < nprocs; i++) {
331237847Skib		if (procs[i].ki_stat == SZOMB && !zflag)
33294689Sdes			continue;
33369941Sjhb		thispid = procs[i].ki_pid;
334185074Sdelphij		strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd));
33569941Sjhb		thistdev = procs[i].ki_tdev;
336125013Sdds		if (eflag)
337125013Sdds			thisuid = procs[i].ki_uid;	/* effective uid */
338125013Sdds		else
339125013Sdds			thisuid = procs[i].ki_ruid;	/* real uid */
34065123Speter
341124844Scperciva		if (thispid == mypid)
342124844Scperciva			continue;
34365123Speter		matched = 1;
34465123Speter		if (user) {
34565123Speter			if (thisuid != uid)
34665123Speter				matched = 0;
34765123Speter		}
34865123Speter		if (tty) {
34965123Speter			if (thistdev != tdev)
35065123Speter				matched = 0;
35165123Speter		}
35265123Speter		if (cmd) {
35365123Speter			if (mflag) {
35465123Speter				if (regcomp(&rgx, cmd,
35565123Speter				    REG_EXTENDED|REG_NOSUB) != 0) {
35665123Speter					mflag = 0;
35765123Speter					warnx("%s: illegal regexp", cmd);
35865123Speter				}
35965123Speter			}
36065123Speter			if (mflag) {
36165123Speter				pmatch.rm_so = 0;
36265123Speter				pmatch.rm_eo = strlen(thiscmd);
36365123Speter				if (regexec(&rgx, thiscmd, 0, &pmatch,
36465123Speter				    REG_STARTEND) != 0)
36565123Speter					matched = 0;
36665123Speter				regfree(&rgx);
36765123Speter			} else {
36872497Speter				if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
36965123Speter					matched = 0;
37065123Speter			}
37165123Speter		}
372113277Smike		if (jflag && thispid == getpid())
373113277Smike			matched = 0;
37465123Speter		if (matched == 0)
37565123Speter			continue;
37671309Sache		if (ac > 0)
37771309Sache			matched = 0;
37865123Speter		for (j = 0; j < ac; j++) {
37965123Speter			if (mflag) {
38065123Speter				if (regcomp(&rgx, av[j],
38165123Speter				    REG_EXTENDED|REG_NOSUB) != 0) {
38265123Speter					mflag = 0;
38365123Speter					warnx("%s: illegal regexp", av[j]);
38465123Speter				}
38565123Speter			}
38665123Speter			if (mflag) {
38765123Speter				pmatch.rm_so = 0;
38865123Speter				pmatch.rm_eo = strlen(thiscmd);
38965123Speter				if (regexec(&rgx, thiscmd, 0, &pmatch,
39065123Speter				    REG_STARTEND) == 0)
39165123Speter					matched = 1;
39265123Speter				regfree(&rgx);
39365123Speter			} else {
39465123Speter				if (strcmp(thiscmd, av[j]) == 0)
39565123Speter					matched = 1;
39665123Speter			}
39765123Speter			if (matched)
39865123Speter				break;
39965123Speter		}
400237618Sdelphij		if (matched != 0 && Iflag) {
401237618Sdelphij			printf("Send signal %d to %s (pid %d uid %d)? ",
402237618Sdelphij				sig, thiscmd, thispid, thisuid);
403237618Sdelphij			fflush(stdout);
404237618Sdelphij			first = ch = getchar();
405237618Sdelphij			while (ch != '\n' && ch != EOF)
406237618Sdelphij				ch = getchar();
407237618Sdelphij			if (first != 'y' && first != 'Y')
408237618Sdelphij				matched = 0;
409237618Sdelphij		}
41065123Speter		if (matched == 0)
41165123Speter			continue;
41265123Speter		if (dflag)
41365123Speter			printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
41465123Speter			    thiscmd, thispid, thistdev, thisuid);
41565123Speter
41665123Speter		if (vflag || sflag)
417219347Sjilles			printf("kill -%s %d\n", sys_signame[sig], thispid);
41865123Speter
41965123Speter		killed++;
42065123Speter		if (!dflag && !sflag) {
42165123Speter			if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
42296976Sdd				warn("warning: kill -%s %d",
423219347Sjilles				    sys_signame[sig], thispid);
42465123Speter				errors = 1;
42565123Speter			}
42665123Speter		}
42765123Speter	}
42865123Speter	if (killed == 0) {
429252428Smjg		if (!qflag)
430252428Smjg			fprintf(stderr, "No matching processes %swere found\n",
431252428Smjg			    getuid() != 0 ? "belonging to you " : "");
43265123Speter		errors = 1;
43365123Speter	}
43465123Speter	exit(errors);
43565123Speter}
436