killall.c revision 274471
1254721Semaste/*- 2254721Semaste * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org> 3254721Semaste * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org> 4254721Semaste * All rights reserved. 5254721Semaste * 6254721Semaste * Redistribution and use in source and binary forms, with or without 7254721Semaste * modification, are permitted provided that the following conditions 8254721Semaste * are met: 9254721Semaste * 1. Redistributions of source code must retain the above copyright 10254721Semaste * notice, this list of conditions and the following disclaimer. 11254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 12254721Semaste * notice, this list of conditions and the following disclaimer in the 13254721Semaste * documentation and/or other materials provided with the distribution. 14254721Semaste * 15254721Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18254721Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20254721Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22254721Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24254721Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25254721Semaste * SUCH DAMAGE. 26254721Semaste */ 27254721Semaste 28254721Semaste#include <sys/cdefs.h> 29254721Semaste__FBSDID("$FreeBSD: stable/10/usr.bin/killall/killall.c 274471 2014-11-13 16:40:15Z smh $"); 30254721Semaste 31254721Semaste#include <sys/param.h> 32254721Semaste#include <sys/jail.h> 33254721Semaste#include <sys/stat.h> 34254721Semaste#include <sys/uio.h> 35254721Semaste#include <sys/user.h> 36254721Semaste#include <sys/sysctl.h> 37254721Semaste#include <fcntl.h> 38254721Semaste#include <dirent.h> 39254721Semaste#include <jail.h> 40254721Semaste#include <stdio.h> 41254721Semaste#include <stdlib.h> 42254721Semaste#include <string.h> 43254721Semaste#include <pwd.h> 44254721Semaste#include <signal.h> 45254721Semaste#include <regex.h> 46254721Semaste#include <ctype.h> 47254721Semaste#include <err.h> 48254721Semaste#include <errno.h> 49254721Semaste#include <unistd.h> 50254721Semaste#include <locale.h> 51254721Semaste 52254721Semastestatic void __dead2 53254721Semasteusage(void) 54254721Semaste{ 55254721Semaste 56254721Semaste fprintf(stderr, "usage: killall [-delmsqvz] [-help] [-I] [-j jail]\n"); 57254721Semaste fprintf(stderr, 58254721Semaste " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n"); 59254721Semaste fprintf(stderr, "At least one option or argument to specify processes must be given.\n"); 60254721Semaste exit(1); 61254721Semaste} 62254721Semaste 63254721Semaste 64254721Semastestatic void 65254721Semasteprintsig(FILE *fp) 66254721Semaste{ 67254721Semaste const char *const * p; 68254721Semaste int cnt; 69254721Semaste int offset = 0; 70254721Semaste 71254721Semaste for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) { 72254721Semaste offset += fprintf(fp, "%s ", *p); 73254721Semaste if (offset >= 75 && cnt > 1) { 74254721Semaste offset = 0; 75254721Semaste fprintf(fp, "\n"); 76254721Semaste } 77254721Semaste } 78254721Semaste fprintf(fp, "\n"); 79254721Semaste} 80254721Semaste 81254721Semastestatic void 82254721Semastenosig(char *name) 83254721Semaste{ 84254721Semaste 85254721Semaste warnx("unknown signal %s; valid signals:", name); 86254721Semaste printsig(stderr); 87254721Semaste exit(1); 88254721Semaste} 89254721Semaste 90254721Semasteint 91254721Semastemain(int ac, char **av) 92254721Semaste{ 93254721Semaste char **saved_av; 94254721Semaste struct kinfo_proc *procs, *newprocs; 95254721Semaste struct stat sb; 96254721Semaste struct passwd *pw; 97254721Semaste regex_t rgx; 98254721Semaste regmatch_t pmatch; 99254721Semaste int i, j, ch; 100254721Semaste char buf[256]; 101254721Semaste char first; 102254721Semaste char *user = NULL; 103254721Semaste char *tty = NULL; 104254721Semaste char *cmd = NULL; 105254721Semaste int qflag = 0; 106254721Semaste int vflag = 0; 107254721Semaste int sflag = 0; 108254721Semaste int dflag = 0; 109254721Semaste int eflag = 0; 110254721Semaste int Iflag = 0; 111254721Semaste int jflag = 0; 112254721Semaste int mflag = 0; 113254721Semaste int zflag = 0; 114254721Semaste uid_t uid = 0; 115254721Semaste dev_t tdev = 0; 116254721Semaste pid_t mypid; 117254721Semaste char thiscmd[MAXCOMLEN + 1]; 118254721Semaste pid_t thispid; 119254721Semaste uid_t thisuid; 120254721Semaste dev_t thistdev; 121254721Semaste int sig = SIGTERM; 122254721Semaste const char *const *p; 123254721Semaste char *ep; 124254721Semaste int errors = 0; 125254721Semaste int jid; 126254721Semaste int mib[4]; 127254721Semaste size_t miblen; 128254721Semaste int st, nprocs; 129254721Semaste size_t size; 130254721Semaste int matched; 131254721Semaste int killed = 0; 132254721Semaste 133254721Semaste setlocale(LC_ALL, ""); 134254721Semaste 135254721Semaste av++; 136254721Semaste ac--; 137254721Semaste 138254721Semaste while (ac > 0) { 139254721Semaste if (strcmp(*av, "-l") == 0) { 140254721Semaste printsig(stdout); 141254721Semaste exit(0); 142254721Semaste } 143254721Semaste if (strcmp(*av, "-help") == 0) 144254721Semaste usage(); 145254721Semaste if (**av == '-') { 146254721Semaste ++*av; 147254721Semaste switch (**av) { 148254721Semaste case 'j': 149254721Semaste ++*av; 150254721Semaste if (**av == '\0') { 151254721Semaste ++av; 152254721Semaste --ac; 153254721Semaste } 154254721Semaste jflag++; 155254721Semaste if (*av == NULL) 156254721Semaste errx(1, "must specify jail"); 157254721Semaste jid = jail_getid(*av); 158254721Semaste if (jid < 0) 159254721Semaste errx(1, "%s", jail_errmsg); 160254721Semaste if (jail_attach(jid) == -1) 161254721Semaste err(1, "jail_attach(%d)", jid); 162254721Semaste break; 163254721Semaste case 'u': 164254721Semaste ++*av; 165254721Semaste if (**av == '\0') { 166254721Semaste ++av; 167254721Semaste --ac; 168254721Semaste } 169254721Semaste if (*av == NULL) 170254721Semaste errx(1, "must specify user"); 171254721Semaste user = *av; 172254721Semaste break; 173254721Semaste case 't': 174254721Semaste ++*av; 175254721Semaste if (**av == '\0') { 176254721Semaste ++av; 177254721Semaste --ac; 178254721Semaste } 179254721Semaste if (*av == NULL) 180254721Semaste errx(1, "must specify tty"); 181254721Semaste tty = *av; 182254721Semaste break; 183254721Semaste case 'c': 184254721Semaste ++*av; 185254721Semaste if (**av == '\0') { 186254721Semaste ++av; 187254721Semaste --ac; 188254721Semaste } 189254721Semaste if (*av == NULL) 190254721Semaste errx(1, "must specify procname"); 191254721Semaste cmd = *av; 192254721Semaste break; 193254721Semaste case 'q': 194254721Semaste qflag++; 195254721Semaste break; 196254721Semaste case 'v': 197254721Semaste vflag++; 198254721Semaste break; 199254721Semaste case 's': 200254721Semaste sflag++; 201254721Semaste break; 202254721Semaste case 'd': 203254721Semaste dflag++; 204254721Semaste break; 205254721Semaste case 'e': 206254721Semaste eflag++; 207254721Semaste break; 208254721Semaste case 'm': 209254721Semaste mflag++; 210254721Semaste break; 211254721Semaste case 'z': 212254721Semaste zflag++; 213254721Semaste break; 214254721Semaste default: 215254721Semaste saved_av = av; 216254721Semaste if (isalpha((unsigned char)**av)) { 217254721Semaste if (strncasecmp(*av, "SIG", 3) == 0) 218254721Semaste *av += 3; 219254721Semaste for (sig = NSIG, p = sys_signame + 1; 220254721Semaste --sig; ++p) 221254721Semaste if (strcasecmp(*p, *av) == 0) { 222254721Semaste sig = p - sys_signame; 223254721Semaste break; 224254721Semaste } 225254721Semaste if (!sig) { 226254721Semaste if (**saved_av == 'I') { 227254721Semaste av = saved_av; 228254721Semaste Iflag = 1; 229254721Semaste break; 230254721Semaste } else 231254721Semaste nosig(*av); 232254721Semaste } 233254721Semaste } else if (isdigit((unsigned char)**av)) { 234254721Semaste sig = strtol(*av, &ep, 10); 235254721Semaste if (!*av || *ep) 236254721Semaste errx(1, "illegal signal number: %s", *av); 237254721Semaste if (sig < 0 || sig >= NSIG) 238254721Semaste nosig(*av); 239254721Semaste } else 240254721Semaste nosig(*av); 241254721Semaste } 242254721Semaste ++av; 243254721Semaste --ac; 244254721Semaste } else { 245254721Semaste break; 246254721Semaste } 247254721Semaste } 248254721Semaste 249254721Semaste if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0) 250254721Semaste usage(); 251254721Semaste 252254721Semaste if (tty) { 253254721Semaste if (strncmp(tty, "/dev/", 5) == 0) 254254721Semaste snprintf(buf, sizeof(buf), "%s", tty); 255254721Semaste else if (strncmp(tty, "tty", 3) == 0) 256254721Semaste snprintf(buf, sizeof(buf), "/dev/%s", tty); 257254721Semaste else 258254721Semaste snprintf(buf, sizeof(buf), "/dev/tty%s", tty); 259254721Semaste if (stat(buf, &sb) < 0) 260254721Semaste err(1, "stat(%s)", buf); 261254721Semaste if (!S_ISCHR(sb.st_mode)) 262254721Semaste errx(1, "%s: not a character device", buf); 263254721Semaste tdev = sb.st_rdev; 264254721Semaste if (dflag) 265254721Semaste printf("ttydev:0x%x\n", tdev); 266254721Semaste } 267254721Semaste if (user) { 268254721Semaste uid = strtol(user, &ep, 10); 269254721Semaste if (*user == '\0' || *ep != '\0') { /* was it a number? */ 270254721Semaste pw = getpwnam(user); 271254721Semaste if (pw == NULL) 272254721Semaste errx(1, "user %s does not exist", user); 273254721Semaste uid = pw->pw_uid; 274254721Semaste if (dflag) 275254721Semaste printf("uid:%d\n", uid); 276254721Semaste } 277254721Semaste } else { 278254721Semaste uid = getuid(); 279254721Semaste if (uid != 0) { 280254721Semaste pw = getpwuid(uid); 281254721Semaste if (pw) 282254721Semaste user = pw->pw_name; 283254721Semaste if (dflag) 284254721Semaste printf("uid:%d\n", uid); 285254721Semaste } 286254721Semaste } 287254721Semaste size = 0; 288254721Semaste mib[0] = CTL_KERN; 289254721Semaste mib[1] = KERN_PROC; 290254721Semaste 291254721Semaste if (user) { 292254721Semaste mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID; 293254721Semaste mib[3] = uid; 294254721Semaste miblen = 4; 295254721Semaste } else if (tty) { 296254721Semaste mib[2] = KERN_PROC_TTY; 297254721Semaste mib[3] = tdev; 298254721Semaste miblen = 4; 299254721Semaste } else { 300254721Semaste mib[2] = KERN_PROC_PROC; 301254721Semaste mib[3] = 0; 302254721Semaste miblen = 3; 303254721Semaste } 304254721Semaste 305254721Semaste procs = NULL; 306254721Semaste st = sysctl(mib, miblen, NULL, &size, NULL, 0); 307254721Semaste do { 308254721Semaste size += size / 10; 309254721Semaste newprocs = realloc(procs, size); 310254721Semaste if (newprocs == NULL) { 311254721Semaste free(procs); 312254721Semaste err(1, "could not reallocate memory"); 313254721Semaste } 314254721Semaste procs = newprocs; 315254721Semaste st = sysctl(mib, miblen, procs, &size, NULL, 0); 316254721Semaste } while (st == -1 && errno == ENOMEM); 317254721Semaste if (st == -1) 318254721Semaste err(1, "could not sysctl(KERN_PROC)"); 319254721Semaste if (size % sizeof(struct kinfo_proc) != 0) { 320254721Semaste fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n", 321254721Semaste size, sizeof(struct kinfo_proc)); 322254721Semaste fprintf(stderr, "userland out of sync with kernel\n"); 323254721Semaste exit(1); 324254721Semaste } 325254721Semaste nprocs = size / sizeof(struct kinfo_proc); 326254721Semaste if (dflag) 327254721Semaste printf("nprocs %d\n", nprocs); 328254721Semaste mypid = getpid(); 329254721Semaste 330254721Semaste for (i = 0; i < nprocs; i++) { 331254721Semaste if (procs[i].ki_stat == SZOMB && !zflag) 332254721Semaste continue; 333254721Semaste thispid = procs[i].ki_pid; 334254721Semaste strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd)); 335254721Semaste thistdev = procs[i].ki_tdev; 336254721Semaste if (eflag) 337254721Semaste thisuid = procs[i].ki_uid; /* effective uid */ 338254721Semaste else 339254721Semaste thisuid = procs[i].ki_ruid; /* real uid */ 340254721Semaste 341254721Semaste if (thispid == mypid) 342254721Semaste continue; 343254721Semaste matched = 1; 344254721Semaste if (user) { 345254721Semaste if (thisuid != uid) 346254721Semaste matched = 0; 347254721Semaste } 348254721Semaste if (tty) { 349254721Semaste if (thistdev != tdev) 350254721Semaste matched = 0; 351254721Semaste } 352254721Semaste if (cmd) { 353254721Semaste if (mflag) { 354254721Semaste if (regcomp(&rgx, cmd, 355254721Semaste REG_EXTENDED|REG_NOSUB) != 0) { 356254721Semaste mflag = 0; 357254721Semaste warnx("%s: illegal regexp", cmd); 358254721Semaste } 359254721Semaste } 360254721Semaste if (mflag) { 361254721Semaste pmatch.rm_so = 0; 362 pmatch.rm_eo = strlen(thiscmd); 363 if (regexec(&rgx, thiscmd, 0, &pmatch, 364 REG_STARTEND) != 0) 365 matched = 0; 366 regfree(&rgx); 367 } else { 368 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0) 369 matched = 0; 370 } 371 } 372 if (jflag && thispid == getpid()) 373 matched = 0; 374 if (matched == 0) 375 continue; 376 if (ac > 0) 377 matched = 0; 378 for (j = 0; j < ac; j++) { 379 if (mflag) { 380 if (regcomp(&rgx, av[j], 381 REG_EXTENDED|REG_NOSUB) != 0) { 382 mflag = 0; 383 warnx("%s: illegal regexp", av[j]); 384 } 385 } 386 if (mflag) { 387 pmatch.rm_so = 0; 388 pmatch.rm_eo = strlen(thiscmd); 389 if (regexec(&rgx, thiscmd, 0, &pmatch, 390 REG_STARTEND) == 0) 391 matched = 1; 392 regfree(&rgx); 393 } else { 394 if (strcmp(thiscmd, av[j]) == 0) 395 matched = 1; 396 } 397 if (matched) 398 break; 399 } 400 if (matched != 0 && Iflag) { 401 printf("Send signal %d to %s (pid %d uid %d)? ", 402 sig, thiscmd, thispid, thisuid); 403 fflush(stdout); 404 first = ch = getchar(); 405 while (ch != '\n' && ch != EOF) 406 ch = getchar(); 407 if (first != 'y' && first != 'Y') 408 matched = 0; 409 } 410 if (matched == 0) 411 continue; 412 if (dflag) 413 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig, 414 thiscmd, thispid, thistdev, thisuid); 415 416 if (vflag || sflag) 417 printf("kill -%s %d\n", sys_signame[sig], thispid); 418 419 killed++; 420 if (!dflag && !sflag) { 421 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) { 422 warn("warning: kill -%s %d", 423 sys_signame[sig], thispid); 424 errors = 1; 425 } 426 } 427 } 428 if (killed == 0) { 429 if (!qflag) 430 fprintf(stderr, "No matching processes %swere found\n", 431 getuid() != 0 ? "belonging to you " : ""); 432 errors = 1; 433 } 434 exit(errors); 435} 436