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