killall.c revision 218285
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: head/usr.bin/killall/killall.c 218285 2011-02-04 16:40:50Z jilles $");
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
56237618Sdelphij	fprintf(stderr, "usage: killall [-delmsvz] [-help] [-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
6365123Speterstatic char *
6465123Speterupper(const char *str)
6565123Speter{
6665123Speter	static char buf[80];
6765123Speter	char *s;
6865123Speter
6965123Speter	strlcpy(buf, str, sizeof(buf));
7065123Speter	for (s = buf; *s; s++)
7165123Speter		*s = toupper((unsigned char)*s);
72219347Sjilles	return buf;
7365123Speter}
7465123Speter
7565123Speter
7665123Speterstatic void
7765123Speterprintsig(FILE *fp)
7865123Speter{
7965123Speter	const char	*const * p;
8065123Speter	int		cnt;
8165123Speter	int		offset = 0;
8265123Speter
8365123Speter	for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
8465123Speter		offset += fprintf(fp, "%s ", upper(*p));
8565123Speter		if (offset >= 75 && cnt > 1) {
8665123Speter			offset = 0;
8765123Speter			fprintf(fp, "\n");
8865123Speter		}
8965123Speter	}
9065123Speter	fprintf(fp, "\n");
9165123Speter}
9265123Speter
93237844Skibstatic void
9465123Speternosig(char *name)
9565127Speter{
9665123Speter
9765123Speter	warnx("unknown signal %s; valid signals:", name);
98237618Sdelphij	printsig(stderr);
9965123Speter	exit(1);
100237618Sdelphij}
10165123Speter
10265123Speterint
10365123Spetermain(int ac, char **av)
10465123Speter{
10565123Speter	struct kinfo_proc *procs = NULL, *newprocs;
10665123Speter	struct stat	sb;
107125013Sdds	struct passwd	*pw;
108237618Sdelphij	regex_t		rgx;
109113277Smike	regmatch_t	pmatch;
11065123Speter	int		i, j;
11194689Sdes	char		buf[256];
11265123Speter	char		*user = NULL;
11365123Speter	char		*tty = NULL;
114124844Scperciva	char		*cmd = NULL;
11565123Speter	int		vflag = 0;
11665123Speter	int		sflag = 0;
11765123Speter	int		dflag = 0;
11865123Speter	int		eflag = 0;
11965123Speter	int		jflag = 0;
12065127Speter	int		mflag = 0;
12165123Speter	int		zflag = 0;
12265123Speter	uid_t		uid = 0;
123113277Smike	dev_t		tdev = 0;
12476678Sphk	pid_t		mypid;
12565123Speter	char		thiscmd[MAXCOMLEN + 1];
12665123Speter	pid_t		thispid;
12765123Speter	uid_t		thisuid;
12865123Speter	dev_t		thistdev;
12965123Speter	int		sig = SIGTERM;
13065123Speter	const char *const *p;
131132191Stjr	char		*ep;
132132191Stjr	int		errors = 0;
13365123Speter	int		jid;
13465123Speter	int		mib[4];
13565123Speter	size_t		miblen;
13665123Speter	int		st, nprocs;
13765123Speter	size_t		size;
13865123Speter	int		matched;
13965123Speter	int		killed = 0;
14065123Speter
14165177Speter	setlocale(LC_ALL, "");
14265177Speter
14365123Speter	av++;
14465123Speter	ac--;
14565123Speter
146237618Sdelphij	while (ac > 0) {
147237618Sdelphij		if (strcmp(*av, "-l") == 0) {
148237618Sdelphij			printsig(stdout);
149113277Smike			exit(0);
150113277Smike		}
151173502Sru		if (strcmp(*av, "-help") == 0)
152113277Smike			usage();
153173502Sru		if (**av == '-') {
154173502Sru			++*av;
155113277Smike			switch (**av) {
156173502Sru			case 'j':
157192896Sjamie				++*av;
158194869Sjamie				if (**av == '\0') {
159194869Sjamie					++av;
160194869Sjamie					--ac;
161113277Smike				}
162192896Sjamie				jflag++;
163113277Smike				if (*av == NULL)
16465123Speter				    	errx(1, "must specify jail");
16565123Speter				jid = jail_getid(*av);
166173502Sru				if (jid < 0)
16765123Speter					errx(1, "%s", jail_errmsg);
168173502Sru				if (jail_attach(jid) == -1)
169173502Sru					err(1, "jail_attach(%d)", jid);
170173502Sru				break;
171173502Sru			case 'u':
17265123Speter				++*av;
17365123Speter				if (**av == '\0') {
17465123Speter					++av;
17565123Speter					--ac;
176173502Sru				}
17765123Speter				if (*av == NULL)
178173502Sru				    	errx(1, "must specify user");
179173502Sru				user = *av;
180173502Sru				break;
181173502Sru			case 't':
18265123Speter				++*av;
18365123Speter				if (**av == '\0') {
18465123Speter					++av;
18565123Speter					--ac;
186173502Sru				}
18765123Speter				if (*av == NULL)
188173502Sru				    	errx(1, "must specify tty");
189173502Sru				tty = *av;
190173502Sru				break;
191173502Sru			case 'c':
19265123Speter				++*av;
19365123Speter				if (**av == '\0') {
19465123Speter					++av;
19565123Speter					--ac;
19665123Speter				}
19765123Speter				if (*av == NULL)
19865123Speter				    	errx(1, "must specify procname");
19965123Speter				cmd = *av;
20065123Speter				break;
20165123Speter			case 'v':
20265123Speter				vflag++;
203125013Sdds				break;
204125013Sdds			case 's':
205125013Sdds				sflag++;
20665123Speter				break;
20765123Speter			case 'd':
20865123Speter				dflag++;
20994689Sdes				break;
21094689Sdes			case 'e':
21194689Sdes				eflag++;
21265123Speter				break;
213132193Stjr			case 'm':
214218285Sjilles				mflag++;
21565123Speter				break;
21665123Speter			case 'z':
21765123Speter				zflag++;
21865123Speter				break;
21965123Speter			default:
22065123Speter				if (isalpha((unsigned char)**av)) {
22165123Speter					if (strncasecmp(*av, "SIG", 3) == 0)
22265123Speter						*av += 3;
22365123Speter					for (sig = NSIG, p = sys_signame + 1;
224132193Stjr					     --sig; ++p)
22565123Speter						if (strcasecmp(*p, *av) == 0) {
22665123Speter							sig = p - sys_signame;
22765123Speter							break;
228132851Smaxim						}
22965123Speter					if (!sig)
23065123Speter						nosig(*av);
23165123Speter				} else if (isdigit((unsigned char)**av)) {
23265123Speter					sig = strtol(*av, &ep, 10);
23365123Speter					if (!*av || *ep)
23465123Speter						errx(1, "illegal signal number: %s", *av);
23565123Speter					if (sig < 0 || sig >= NSIG)
23665123Speter						nosig(*av);
23765123Speter				} else
23865123Speter					nosig(*av);
23965123Speter			}
240113277Smike			++av;
24165123Speter			--ac;
24265123Speter		} else {
24365123Speter			break;
24465123Speter		}
24565123Speter	}
24665123Speter
24765123Speter	if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
24865123Speter		usage();
24965123Speter
25065123Speter	if (tty) {
25165123Speter		if (strncmp(tty, "/dev/", 5) == 0)
25265123Speter			snprintf(buf, sizeof(buf), "%s", tty);
25365123Speter		else if (strncmp(tty, "tty", 3) == 0)
25465123Speter			snprintf(buf, sizeof(buf), "/dev/%s", tty);
25565123Speter		else
25665123Speter			snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
25765123Speter		if (stat(buf, &sb) < 0)
25865123Speter			err(1, "stat(%s)", buf);
25978144Sobrien		if (!S_ISCHR(sb.st_mode))
26093432Sdwmalone			errx(1, "%s: not a character device", buf);
26178144Sobrien		tdev = sb.st_rdev;
26278144Sobrien		if (dflag)
26378144Sobrien			printf("ttydev:0x%x\n", tdev);
26478144Sobrien	}
26578144Sobrien	if (user) {
26678144Sobrien		uid = strtol(user, &ep, 10);
26778144Sobrien		if (*user == '\0' || *ep != '\0') { /* was it a number? */
26865123Speter			pw = getpwnam(user);
26965123Speter			if (pw == NULL)
27065123Speter				errx(1, "user %s does not exist", user);
27165123Speter			uid = pw->pw_uid;
27265123Speter			if (dflag)
27365123Speter				printf("uid:%d\n", uid);
27465123Speter		}
27565123Speter	} else {
27665123Speter		uid = getuid();
27765123Speter		if (uid != 0) {
27865123Speter			pw = getpwuid(uid);
27965123Speter			if (pw)
28065123Speter				user = pw->pw_name;
281119834Stjr			if (dflag)
28265123Speter				printf("uid:%d\n", uid);
283120500Stjr		}
28465123Speter	}
285119834Stjr	size = 0;
286125013Sdds	mib[0] = CTL_KERN;
28765123Speter	mib[1] = KERN_PROC;
288120500Stjr	mib[2] = KERN_PROC_PROC;
289119834Stjr	mib[3] = 0;
29065123Speter	miblen = 3;
29165123Speter
292120500Stjr	if (user) {
29365123Speter		mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
29465123Speter		mib[3] = uid;
295237844Skib		miblen = 4;
29665123Speter	} else if (tty) {
29765123Speter		mib[2] = KERN_PROC_TTY;
29865123Speter		mib[3] = tdev;
29965123Speter		miblen = 4;
300237844Skib	}
301237844Skib
302237844Skib	st = sysctl(mib, miblen, NULL, &size, NULL, 0);
30365123Speter	do {
30465123Speter		size += size / 10;
30565123Speter		newprocs = realloc(procs, size);
30665123Speter		if (newprocs == 0) {
30765123Speter			if (procs)
30865123Speter				free(procs);
30965123Speter			errx(1, "could not reallocate memory");
310132192Stjr		}
31165123Speter		procs = newprocs;
31265123Speter		st = sysctl(mib, miblen, procs, &size, NULL, 0);
31365123Speter	} while (st == -1 && errno == ENOMEM);
31465123Speter	if (st == -1)
31565123Speter		err(1, "could not sysctl(KERN_PROC)");
31665123Speter	if (size % sizeof(struct kinfo_proc) != 0) {
31765123Speter		fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
318124844Scperciva			size, sizeof(struct kinfo_proc));
31965123Speter		fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
32065123Speter		exit(1);
32194689Sdes	}
32294689Sdes	nprocs = size / sizeof(struct kinfo_proc);
32369941Sjhb	if (dflag)
324185074Sdelphij		printf("nprocs %d\n", nprocs);
32569941Sjhb	mypid = getpid();
326125013Sdds
327125013Sdds	for (i = 0; i < nprocs; i++) {
328125013Sdds		if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
329125013Sdds			continue;
33065123Speter		thispid = procs[i].ki_pid;
331124844Scperciva		strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd));
332124844Scperciva		thistdev = procs[i].ki_tdev;
33365123Speter		if (eflag)
33465123Speter			thisuid = procs[i].ki_uid;	/* effective uid */
33565123Speter		else
33665123Speter			thisuid = procs[i].ki_ruid;	/* real uid */
33765123Speter
33865123Speter		if (thispid == mypid)
33965123Speter			continue;
34065123Speter		matched = 1;
34165123Speter		if (user) {
34265123Speter			if (thisuid != uid)
34365123Speter				matched = 0;
34465123Speter		}
34565123Speter		if (tty) {
34665123Speter			if (thistdev != tdev)
34765123Speter				matched = 0;
34865123Speter		}
34965123Speter		if (cmd) {
35065123Speter			if (mflag) {
35165123Speter				if (regcomp(&rgx, cmd,
35265123Speter				    REG_EXTENDED|REG_NOSUB) != 0) {
35365123Speter					mflag = 0;
35465123Speter					warnx("%s: illegal regexp", cmd);
35565123Speter				}
35665123Speter			}
35765123Speter			if (mflag) {
35872497Speter				pmatch.rm_so = 0;
35965123Speter				pmatch.rm_eo = strlen(thiscmd);
36065123Speter				if (regexec(&rgx, thiscmd, 0, &pmatch,
36165123Speter				    REG_STARTEND) != 0)
362113277Smike					matched = 0;
363113277Smike				regfree(&rgx);
36465123Speter			} else {
36565123Speter				if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
36671309Sache					matched = 0;
36771309Sache			}
36865123Speter		}
36965123Speter		if (jflag && thispid == getpid())
37065123Speter			matched = 0;
37165123Speter		if (matched == 0)
37265123Speter			continue;
37365123Speter		if (ac > 0)
37465123Speter			matched = 0;
37565123Speter		for (j = 0; j < ac; j++) {
37665123Speter			if (mflag) {
37765123Speter				if (regcomp(&rgx, av[j],
37865123Speter				    REG_EXTENDED|REG_NOSUB) != 0) {
37965123Speter					mflag = 0;
38065123Speter					warnx("%s: illegal regexp", av[j]);
38165123Speter				}
38265123Speter			}
38365123Speter			if (mflag) {
38465123Speter				pmatch.rm_so = 0;
38565123Speter				pmatch.rm_eo = strlen(thiscmd);
38665123Speter				if (regexec(&rgx, thiscmd, 0, &pmatch,
38765123Speter				    REG_STARTEND) == 0)
38865123Speter					matched = 1;
38965123Speter				regfree(&rgx);
390237618Sdelphij			} else {
391237618Sdelphij				if (strcmp(thiscmd, av[j]) == 0)
392237618Sdelphij					matched = 1;
393237618Sdelphij			}
394237618Sdelphij			if (matched)
395237618Sdelphij				break;
396237618Sdelphij		}
397237618Sdelphij		if (matched == 0)
398237618Sdelphij			continue;
399237618Sdelphij		if (dflag)
40065123Speter			printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
40165123Speter			    thiscmd, thispid, thistdev, thisuid);
40265123Speter
40365123Speter		if (vflag || sflag)
40465123Speter			printf("kill -%s %d\n", upper(sys_signame[sig]),
40565123Speter			    thispid);
40665123Speter
407219347Sjilles		killed++;
40865123Speter		if (!dflag && !sflag) {
40965123Speter			if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
41065123Speter				warn("warning: kill -%s %d",
41165123Speter				    upper(sys_signame[sig]), thispid);
41296976Sdd				errors = 1;
413219347Sjilles			}
41465123Speter		}
41565123Speter	}
41665123Speter	if (killed == 0) {
41765123Speter		fprintf(stderr, "No matching processes %swere found\n",
41865123Speter		    getuid() != 0 ? "belonging to you " : "");
41965123Speter		errors = 1;
42065123Speter	}
42165123Speter	exit(errors);
42265123Speter}
42365123Speter