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