killall.c revision 96976
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 * $FreeBSD: head/usr.bin/killall/killall.c 96976 2002-05-20 07:17:22Z dd $
2865123Speter */
2965123Speter
3065177Speter#include <sys/cdefs.h>
3165123Speter#include <sys/param.h>
3265123Speter#include <sys/stat.h>
3365123Speter#include <sys/user.h>
3465123Speter#include <sys/sysctl.h>
3565123Speter#include <fcntl.h>
3665123Speter#include <dirent.h>
3765123Speter#include <stdio.h>
3865123Speter#include <stdlib.h>
3965123Speter#include <string.h>
4065123Speter#include <pwd.h>
4165123Speter#include <signal.h>
4265123Speter#include <regex.h>
4365123Speter#include <ctype.h>
4465123Speter#include <err.h>
4565123Speter#include <errno.h>
4665123Speter#include <unistd.h>
4765123Speter
4865123Speterstatic char	*prog;
4965123Speter
5065177Speterstatic void __dead2
5165123Speterusage(void)
5265123Speter{
5365123Speter
5465123Speter	fprintf(stderr, "usage: %s [-l] [-v] [-m] [-sig] [-u user] [-t tty] [-c cmd] [cmd]...\n", prog);
5565123Speter	fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
5665123Speter	exit(1);
5765123Speter}
5865123Speter
5965123Speterstatic char *
6065123Speterupper(const char *str)
6165123Speter{
6265123Speter	static char buf[80];
6365123Speter	char *s;
6465123Speter
6565123Speter	strncpy(buf, str, sizeof(buf));
6665123Speter	buf[sizeof(buf) - 1] = '\0';
6765126Speter	for (s = buf; *s; s++)
6865123Speter		*s = toupper(*s);
6965123Speter	return buf;
7065123Speter}
7165123Speter
7265123Speter
7365123Speterstatic void
7465123Speterprintsig(FILE *fp)
7565123Speter{
7665123Speter	const char	*const * p;
7765123Speter	int		cnt;
7865123Speter	int		offset = 0;
7965123Speter
8065123Speter	for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
8165123Speter		offset += fprintf(fp, "%s ", upper(*p));
8265123Speter		if (offset >= 75 && cnt > 1) {
8365123Speter			offset = 0;
8465123Speter			fprintf(fp, "\n");
8565123Speter		}
8665123Speter	}
8765123Speter	fprintf(fp, "\n");
8865123Speter}
8965123Speter
9065123Speterstatic void
9165123Speternosig(char *name)
9265123Speter{
9365123Speter
9465123Speter	warnx("unknown signal %s; valid signals:", name);
9565123Speter	printsig(stderr);
9665123Speter	exit(1);
9765123Speter}
9865123Speter
9965123Speterint
10065123Spetermain(int ac, char **av)
10165123Speter{
10265123Speter	struct kinfo_proc *procs = NULL, *newprocs;
10365123Speter	struct stat	sb;
10465127Speter	struct passwd	*pw;
10565123Speter	regex_t		rgx;
10665123Speter	regmatch_t	pmatch;
10765123Speter	int		i, j;
10865123Speter	char		buf[256];
10965123Speter	char		*user = NULL;
11065123Speter	char		*tty = NULL;
11165123Speter	char		*cmd = NULL;
11265123Speter	int		vflag = 0;
11365123Speter	int		sflag = 0;
11465123Speter	int		dflag = 0;
11565123Speter	int		mflag = 0;
11694689Sdes	int		zflag = 0;
11765123Speter	uid_t		uid = 0;
11865123Speter	dev_t		tdev = 0;
11965123Speter	char		thiscmd[MAXCOMLEN + 1];
12065123Speter	pid_t		thispid;
12165123Speter	uid_t		thisuid;
12265123Speter	dev_t		thistdev;
12365123Speter	int		sig = SIGTERM;
12465127Speter	const char *const *p;
12565123Speter	char		*ep;
12665123Speter	int		errors = 0;
12776678Sphk	int		mib[4];
12865123Speter	size_t		miblen;
12965123Speter	int		st, nprocs;
13065123Speter	size_t		size;
13165123Speter	int		matched;
13265123Speter	int		killed = 0;
13365123Speter
13465123Speter	prog = av[0];
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) {
14865123Speter			case 'u':
14965123Speter				++*av;
15065123Speter				if (**av == '\0')
15165123Speter					++av;
15265123Speter				--ac;
15365123Speter				user = *av;
15465123Speter				break;
15565123Speter			case 't':
15665123Speter				++*av;
15765123Speter				if (**av == '\0')
15865123Speter					++av;
15965123Speter				--ac;
16065123Speter				tty = *av;
16165123Speter				break;
16265123Speter			case 'c':
16365123Speter				++*av;
16465123Speter				if (**av == '\0')
16565123Speter					++av;
16665123Speter				--ac;
16765123Speter				cmd = *av;
16865123Speter				break;
16965123Speter			case 'v':
17065123Speter				vflag++;
17165123Speter				break;
17265123Speter			case 's':
17365123Speter				sflag++;
17465123Speter				break;
17565123Speter			case 'd':
17665123Speter				dflag++;
17765123Speter				break;
17865123Speter			case 'm':
17965123Speter				mflag++;
18065123Speter				break;
18194689Sdes			case 'z':
18294689Sdes				zflag++;
18394689Sdes				break;
18465123Speter			default:
18565123Speter				if (isalpha(**av)) {
18665123Speter					if (strncasecmp(*av, "sig", 3) == 0)
18765123Speter						*av += 3;
18865123Speter					for (sig = NSIG, p = sys_signame + 1;
18965123Speter					     --sig; ++p)
19065123Speter						if (strcasecmp(*p, *av) == 0) {
19165123Speter							sig = p - sys_signame;
19265123Speter							break;
19365123Speter						}
19465123Speter					if (!sig)
19565123Speter						nosig(*av);
19665123Speter				} else if (isdigit(**av)) {
19765123Speter					sig = strtol(*av, &ep, 10);
19865123Speter					if (!*av || *ep)
19965123Speter						errx(1, "illegal signal number: %s", *av);
20065123Speter					if (sig < 0 || sig > NSIG)
20165123Speter						nosig(*av);
20265123Speter				} else
20365123Speter					nosig(*av);
20465123Speter			}
20565123Speter			++av;
20665123Speter			--ac;
20765123Speter		} else {
20865123Speter			break;
20965123Speter		}
21065123Speter	}
21165123Speter
21265123Speter	if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
21365123Speter		usage();
21465123Speter
21565123Speter	if (tty) {
21665123Speter		if (strncmp(tty, "/dev/", 5) == 0)
21765123Speter			snprintf(buf, sizeof(buf), "%s", tty);
21865123Speter		else if (strncmp(tty, "tty", 3) == 0)
21965123Speter			snprintf(buf, sizeof(buf), "/dev/%s", tty);
22065123Speter		else
22165123Speter			snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
22265123Speter		if (stat(buf, &sb) < 0)
22365123Speter			err(1, "stat(%s)", buf);
22465123Speter		if (!S_ISCHR(sb.st_mode))
22565123Speter			errx(1, "%s: not a character device", buf);
22665123Speter		tdev = sb.st_rdev;
22765123Speter		if (dflag)
22865123Speter			printf("ttydev:0x%x\n", tdev);
22965123Speter	}
23065123Speter	if (user) {
23178144Sobrien		uid = strtol(user, &ep, 10);
23293432Sdwmalone		if (*user == '\0' || *ep != '\0') { /* was it a number? */
23378144Sobrien			pw = getpwnam(user);
23478144Sobrien			if (pw == NULL)
23578144Sobrien				errx(1, "user %s does not exist", user);
23678144Sobrien			uid = pw->pw_uid;
23778144Sobrien			if (dflag)
23878144Sobrien				printf("uid:%d\n", uid);
23978144Sobrien		}
24065123Speter	} else {
24165123Speter		uid = getuid();
24265123Speter		if (uid != 0) {
24365123Speter			pw = getpwuid(uid);
24465123Speter			if (pw)
24565123Speter				user = pw->pw_name;
24665123Speter			if (dflag)
24765123Speter				printf("uid:%d\n", uid);
24865123Speter		}
24965123Speter	}
25065123Speter	size = 0;
25165123Speter	mib[0] = CTL_KERN;
25265123Speter	mib[1] = KERN_PROC;
25365123Speter	mib[2] = KERN_PROC_ALL;
25465123Speter	mib[3] = 0;
25565123Speter	miblen = 3;
25665123Speter
25765123Speter	if (user && mib[2] == KERN_PROC_ALL) {
25870350Sps		mib[2] = KERN_PROC_RUID;
25965123Speter		mib[3] = uid;
26065123Speter		miblen = 4;
26165123Speter	}
26265123Speter	if (tty && mib[2] == KERN_PROC_ALL) {
26365123Speter		mib[2] = KERN_PROC_TTY;
26465123Speter		mib[3] = tdev;
26565123Speter		miblen = 4;
26665123Speter	}
26765123Speter
26865123Speter	st = sysctl(mib, miblen, NULL, &size, NULL, 0);
26965123Speter	do {
27065123Speter		size += size / 10;
27165123Speter		newprocs = realloc(procs, size);
27265123Speter		if (newprocs == 0) {
27365123Speter			if (procs)
27465123Speter				free(procs);
27565123Speter			errx(1, "could not reallocate memory");
27665123Speter		}
27765123Speter		procs = newprocs;
27865123Speter		st = sysctl(mib, miblen, procs, &size, NULL, 0);
27965123Speter	} while (st == -1 && errno == ENOMEM);
28065123Speter	if (st == -1)
28165123Speter		err(1, "could not sysctl(KERN_PROC)");
28265123Speter	if (size % sizeof(struct kinfo_proc) != 0) {
28365123Speter		fprintf(stderr, "proc size mismatch (%d total, %d chunks)\n",
28465123Speter			size, sizeof(struct kinfo_proc));
28565123Speter		fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
28665123Speter		exit(1);
28765123Speter	}
28865123Speter	nprocs = size / sizeof(struct kinfo_proc);
28965123Speter	if (dflag)
29065123Speter		printf("nprocs %d\n", nprocs);
29165123Speter
29265123Speter	for (i = 0; i < nprocs; i++) {
29394689Sdes		if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
29494689Sdes			continue;
29569941Sjhb		thispid = procs[i].ki_pid;
29669941Sjhb		strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
29765123Speter		thiscmd[MAXCOMLEN] = '\0';
29869941Sjhb		thistdev = procs[i].ki_tdev;
29969941Sjhb		thisuid = procs[i].ki_ruid;	/* real uid */
30065123Speter
30165123Speter		matched = 1;
30265123Speter		if (user) {
30365123Speter			if (thisuid != uid)
30465123Speter				matched = 0;
30565123Speter		}
30665123Speter		if (tty) {
30765123Speter			if (thistdev != tdev)
30865123Speter				matched = 0;
30965123Speter		}
31065123Speter		if (cmd) {
31165123Speter			if (mflag) {
31265123Speter				if (regcomp(&rgx, cmd,
31365123Speter				    REG_EXTENDED|REG_NOSUB) != 0) {
31465123Speter					mflag = 0;
31565123Speter					warnx("%s: illegal regexp", cmd);
31665123Speter				}
31765123Speter			}
31865123Speter			if (mflag) {
31965123Speter				pmatch.rm_so = 0;
32065123Speter				pmatch.rm_eo = strlen(thiscmd);
32165123Speter				if (regexec(&rgx, thiscmd, 0, &pmatch,
32265123Speter				    REG_STARTEND) != 0)
32365123Speter					matched = 0;
32465123Speter				regfree(&rgx);
32565123Speter			} else {
32672497Speter				if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
32765123Speter					matched = 0;
32865123Speter			}
32965123Speter		}
33065123Speter		if (matched == 0)
33165123Speter			continue;
33271309Sache		if (ac > 0)
33371309Sache			matched = 0;
33465123Speter		for (j = 0; j < ac; j++) {
33565123Speter			if (mflag) {
33665123Speter				if (regcomp(&rgx, av[j],
33765123Speter				    REG_EXTENDED|REG_NOSUB) != 0) {
33865123Speter					mflag = 0;
33965123Speter					warnx("%s: illegal regexp", av[j]);
34065123Speter				}
34165123Speter			}
34265123Speter			if (mflag) {
34365123Speter				pmatch.rm_so = 0;
34465123Speter				pmatch.rm_eo = strlen(thiscmd);
34565123Speter				if (regexec(&rgx, thiscmd, 0, &pmatch,
34665123Speter				    REG_STARTEND) == 0)
34765123Speter					matched = 1;
34865123Speter				regfree(&rgx);
34965123Speter			} else {
35065123Speter				if (strcmp(thiscmd, av[j]) == 0)
35165123Speter					matched = 1;
35265123Speter			}
35365123Speter			if (matched)
35465123Speter				break;
35565123Speter		}
35665123Speter		if (matched == 0)
35765123Speter			continue;
35865123Speter		if (dflag)
35965123Speter			printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
36065123Speter			    thiscmd, thispid, thistdev, thisuid);
36165123Speter
36265123Speter		if (vflag || sflag)
36365123Speter			printf("kill -%s %d\n", upper(sys_signame[sig]),
36465123Speter			    thispid);
36565123Speter
36665123Speter		killed++;
36765123Speter		if (!dflag && !sflag) {
36865123Speter			if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
36996976Sdd				warn("warning: kill -%s %d",
37096976Sdd				    upper(sys_signame[sig]), thispid);
37165123Speter				errors = 1;
37265123Speter			}
37365123Speter		}
37465123Speter	}
37565123Speter	if (killed == 0) {
37665123Speter		fprintf(stderr, "No matching processes %swere found\n",
37765123Speter		    getuid() != 0 ? "belonging to you " : "");
37865123Speter		errors = 1;
37965123Speter	}
38065123Speter	exit(errors);
38165123Speter}
382