1/*- 2 * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org> 3 * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: src/usr.bin/killall/killall.c,v 1.31 2004/07/29 18:36:35 maxim Exp $"); 30 31#include <sys/param.h> 32#ifndef __APPLE__ 33#include <sys/jail.h> 34#endif /* !__APPLE__ */ 35#include <sys/stat.h> 36#include <sys/user.h> 37#include <sys/sysctl.h> 38#include <fcntl.h> 39#include <dirent.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <pwd.h> 44#include <signal.h> 45#include <regex.h> 46#include <ctype.h> 47#include <err.h> 48#include <errno.h> 49#include <unistd.h> 50#include <locale.h> 51 52#include <getopt.h> 53#define OPTIONS ("c:dej:lmst:u:vz") 54 55#ifdef __APPLE__ 56#include <TargetConditionals.h> 57#endif 58 59static void __dead2 60usage(void) 61{ 62 63#ifdef __APPLE__ 64 fprintf(stderr, "usage: killall [-delmsvz] [-help]\n"); 65#else /* !__APPLE__ */ 66 fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jid]\n"); 67#endif /* __APPLE__ */ 68 fprintf(stderr, 69 " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n"); 70 fprintf(stderr, "At least one option or argument to specify processes must be given.\n"); 71 exit(1); 72} 73 74static char * 75upper(const char *str) 76{ 77 static char buf[80]; 78 char *s; 79 80 strncpy(buf, str, sizeof(buf)); 81 buf[sizeof(buf) - 1] = '\0'; 82 for (s = buf; *s; s++) 83 *s = toupper((unsigned char)*s); 84 return buf; 85} 86 87 88static void 89printsig(FILE *fp) 90{ 91 const char *const * p; 92 int cnt; 93 int offset = 0; 94 95 for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) { 96 offset += fprintf(fp, "%s ", upper(*p)); 97 if (offset >= 75 && cnt > 1) { 98 offset = 0; 99 fprintf(fp, "\n"); 100 } 101 } 102 fprintf(fp, "\n"); 103} 104 105static void 106nosig(char *name) 107{ 108 109 warnx("unknown signal %s; valid signals:", name); 110 printsig(stderr); 111 exit(1); 112} 113 114/* 115 * kludge_signal_args - remove any signal option (-SIGXXX, -##) from the argv array. 116 */ 117void 118kludge_signal_args(int *argc, char **argv, int *sig) 119{ 120 int i; 121 int shift = 0; 122 int kludge = 1; 123 char *ptr; 124 const char *const *p; 125 char *ep; 126 127 /* i = 1, skip program name */ 128 for (i = 1; i < *argc; i++) { 129 /* Stop kludging if we encounter -- */ 130 if (strcmp(argv[i], "--") == 0) 131 kludge = 0; 132 ptr = argv[i] + 1; 133 /* Only process arguments that start with - and do not look like an existing option. */ 134 if (kludge && *argv[i] == '-' && *ptr && strchr(OPTIONS, *ptr) == NULL) { 135 if (isalpha(*ptr)) { 136 if (strcmp(ptr, "help") == 0) 137 usage(); 138 if (strncasecmp(ptr, "sig", 3) == 0) 139 ptr += 3; 140 for (*sig = NSIG, p = sys_signame + 1; --*sig; ++p) 141 if (strcasecmp(*p, ptr) == 0) { 142 *sig = p - sys_signame; 143 break; 144 } 145 if (!*sig) 146 nosig(ptr); 147 } else if (isdigit(*ptr)) { 148 *sig = strtol(ptr, &ep, 10); 149 if (*ep) 150 errx(1, "illegal signal number: %s", ptr); 151 if (*sig < 0 || *sig >= NSIG) 152 nosig(ptr); 153 } else 154 nosig(ptr); 155 156 shift++; 157 continue; 158 } 159 160 argv[i - shift] = argv[i]; 161 } 162 163 for (i = *argc - shift; i < *argc; i++) { 164 argv[i] = NULL; 165 } 166 167 *argc -= shift; 168} 169 170int 171main(int ac, char **av) 172{ 173 struct kinfo_proc *procs = NULL, *newprocs; 174 struct stat sb; 175 struct passwd *pw; 176 regex_t rgx; 177 regmatch_t pmatch; 178 int i, j; 179 char buf[256]; 180 char *user = NULL; 181 char *tty = NULL; 182 char *cmd = NULL; 183 int vflag = 0; 184 int sflag = 0; 185 int dflag = 0; 186 int eflag = 0; 187#ifndef __APPLE__ 188 int jflag = 0; 189#endif /* !__APPLE__*/ 190 int mflag = 0; 191 int zflag = 0; 192 uid_t uid = 0; 193 dev_t tdev = 0; 194 pid_t mypid; 195#ifdef __APPLE__ 196 char *thiscmd; 197#else /* !__APPLE__ */ 198 char thiscmd[MAXCOMLEN + 1]; 199#endif /* __APPLE__ */ 200 pid_t thispid; 201#ifndef __APPLE__ 202 uid_t thisuid; 203#endif /* !__APPLE__ */ 204 dev_t thistdev; 205 int sig = SIGTERM; 206 char *ep; 207 int errors = 0; 208#ifndef __APPLE__ 209 int jid; 210#endif /* !__APPLE__ */ 211 int mib[4]; 212 size_t miblen; 213 int st, nprocs; 214 size_t size; 215 int matched; 216 int killed = 0; 217 int ch; 218 219 setlocale(LC_ALL, ""); 220 221 kludge_signal_args(&ac, av, &sig); 222 223 while ((ch = getopt(ac, av, OPTIONS)) != -1) { 224 switch (ch) { 225 case 'c': 226 cmd = optarg; 227 break; 228 case 'd': 229 dflag++; 230 break; 231 case 'e': 232 eflag++; 233 break; 234#ifndef __APPLE__ 235 case 'j': 236 jflag++; 237 jid = strtol(optarg, &ep, 10); 238 if (*ep) 239 errx(1, "illegal jid: %s", optarg); 240 if (jail_attach(jid) == -1) 241 err(1, "jail_attach(): %d", jid); 242 break; 243#endif /* __APPLE__ */ 244 case 'l': 245 printsig(stdout); 246 exit(0); 247 case 'm': 248 mflag++; 249 break; 250 case 's': 251 sflag++; 252 break; 253 case 't': 254 tty = optarg; 255 break; 256 case 'u': 257 user = optarg; 258 break; 259 case 'v': 260 vflag++; 261 break; 262 case 'z': 263 zflag++; 264 break; 265 default: 266 usage(); 267 } 268 } 269 270 ac -= optind; 271 av += optind; 272 273#ifdef __APPLE__ 274 if (user == NULL && tty == NULL && cmd == NULL && ac == 0) 275#else /* !__APPLE__*/ 276 if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0) 277#endif /* __APPLE__ */ 278 usage(); 279 280 if (tty) { 281 if (strncmp(tty, "/dev/", 5) == 0) 282 snprintf(buf, sizeof(buf), "%s", tty); 283 else if (strncmp(tty, "tty", 3) == 0) 284 snprintf(buf, sizeof(buf), "/dev/%s", tty); 285 else 286 snprintf(buf, sizeof(buf), "/dev/tty%s", tty); 287 if (stat(buf, &sb) < 0) 288 err(1, "stat(%s)", buf); 289 if (!S_ISCHR(sb.st_mode)) 290 errx(1, "%s: not a character device", buf); 291 tdev = sb.st_rdev; 292 if (dflag) 293 printf("ttydev:0x%x\n", tdev); 294 } 295 if (user) { 296 uid = strtol(user, &ep, 10); 297 if (*user == '\0' || *ep != '\0') { /* was it a number? */ 298 pw = getpwnam(user); 299 if (pw == NULL) 300 errx(1, "user %s does not exist", user); 301 uid = pw->pw_uid; 302 if (dflag) 303 printf("uid:%d\n", uid); 304 } 305 } else { 306 uid = getuid(); 307 if (uid != 0) { 308 pw = getpwuid(uid); 309 if (pw) 310 user = pw->pw_name; 311 if (dflag) 312 printf("uid:%d\n", uid); 313 } 314 } 315 size = 0; 316 mib[0] = CTL_KERN; 317 mib[1] = KERN_PROC; 318#ifdef __APPLE__ 319 mib[2] = KERN_PROC_ALL; 320#else /* !__APPLE__ */ 321 mib[2] = KERN_PROC_PROC; 322#endif /* __APPLE__ */ 323 mib[3] = 0; 324 miblen = 3; 325 326 if (user) { 327 mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID; 328 mib[3] = uid; 329 miblen = 4; 330 } else if (tty) { 331 mib[2] = KERN_PROC_TTY; 332 mib[3] = tdev; 333 miblen = 4; 334 } 335 336 st = sysctl(mib, miblen, NULL, &size, NULL, 0); 337 do { 338 size += size / 10; 339 newprocs = realloc(procs, size); 340 if (newprocs == 0) { 341 if (procs) 342 free(procs); 343 errx(1, "could not reallocate memory"); 344 } 345 procs = newprocs; 346 st = sysctl(mib, miblen, procs, &size, NULL, 0); 347 } while (st == -1 && errno == ENOMEM); 348 if (st == -1) 349 err(1, "could not sysctl(KERN_PROC)"); 350 if (size % sizeof(struct kinfo_proc) != 0) { 351 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n", 352 size, sizeof(struct kinfo_proc)); 353 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n"); 354 exit(1); 355 } 356 nprocs = size / sizeof(struct kinfo_proc); 357 if (dflag) 358 printf("nprocs %d\n", nprocs); 359 mypid = getpid(); 360 361 for (i = 0; i < nprocs; i++) { 362#ifdef __APPLE__ 363 if (procs[i].kp_proc.p_stat == SZOMB && !zflag) 364 continue; 365 thispid = procs[i].kp_proc.p_pid; 366 367 int mib[3], argmax; 368 size_t syssize; 369 char *procargs, *cp; 370 371 mib[0] = CTL_KERN; 372 mib[1] = KERN_ARGMAX; 373 374 syssize = sizeof(argmax); 375 if (sysctl(mib, 2, &argmax, &syssize, NULL, 0) == -1) 376 continue; 377 378 procargs = malloc(argmax); 379 if (procargs == NULL) 380 continue; 381 382 mib[0] = CTL_KERN; 383#if defined(__APPLE__) && TARGET_OS_EMBEDDED 384 mib[1] = KERN_PROCARGS2; 385#else 386 mib[1] = KERN_PROCARGS; 387#endif 388 mib[2] = thispid; 389 390 syssize = (size_t)argmax; 391 if (sysctl(mib, 3, procargs, &syssize, NULL, 0) == -1) { 392 free(procargs); 393 continue; 394 } 395 396 for (cp = procargs; cp < &procargs[syssize]; cp++) { 397 if (*cp == '\0') { 398 break; 399 } 400 } 401 402 if (cp == &procargs[syssize]) { 403 free(procargs); 404 continue; 405 } 406 407 for (; cp < &procargs[syssize]; cp++) { 408 if (*cp != '\0') { 409 break; 410 } 411 } 412 413 if (cp == &procargs[syssize]) { 414 free(procargs); 415 continue; 416 } 417 418 /* Strip off any path that was specified */ 419 for (thiscmd = cp; (cp < &procargs[syssize]) && (*cp != '\0'); cp++) { 420 if (*cp == '/') { 421 thiscmd = cp + 1; 422 } 423 } 424 425 thistdev = procs[i].kp_eproc.e_tdev; 426#else /* !__APPLE__ */ 427 if (procs[i].ki_stat == SZOMB && !zflag) 428 continue; 429 thispid = procs[i].ki_pid; 430 strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN); 431 thiscmd[MAXCOMLEN] = '\0'; 432 thistdev = procs[i].ki_tdev; 433#endif /* __APPLE__ */ 434#ifndef __APPLE__ 435 if (eflag) 436 thisuid = procs[i].ki_uid; /* effective uid */ 437 else 438 thisuid = procs[i].ki_ruid; /* real uid */ 439#endif /* !__APPLE__ */ 440 441 if (thispid == mypid) { 442#ifdef __APPLE__ 443 free(procargs); 444#endif /* __APPLE__ */ 445 continue; 446 } 447 matched = 1; 448#ifndef __APPLE__ 449 if (user) { 450 if (thisuid != uid) 451 matched = 0; 452 } 453#endif /* !__APPLE__ */ 454 if (tty) { 455 if (thistdev != tdev) 456 matched = 0; 457 } 458 if (cmd) { 459 if (mflag) { 460 if (regcomp(&rgx, cmd, 461 REG_EXTENDED|REG_NOSUB) != 0) { 462 mflag = 0; 463 warnx("%s: illegal regexp", cmd); 464 } 465 } 466 if (mflag) { 467 pmatch.rm_so = 0; 468 pmatch.rm_eo = strlen(thiscmd); 469 if (regexec(&rgx, thiscmd, 0, &pmatch, 470 REG_STARTEND) != 0) 471 matched = 0; 472 regfree(&rgx); 473 } else { 474 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0) 475 matched = 0; 476 } 477 } 478#ifndef __APPLE__ 479 if (jflag && thispid == getpid()) 480 matched = 0; 481#endif /* !__APPLE__ */ 482 if (matched == 0) { 483#ifdef __APPLE__ 484 free(procargs); 485#endif /* !__APPLE__ */ 486 continue; 487 } 488 if (ac > 0) 489 matched = 0; 490 for (j = 0; j < ac; j++) { 491 if (mflag) { 492 if (regcomp(&rgx, av[j], 493 REG_EXTENDED|REG_NOSUB) != 0) { 494 mflag = 0; 495 warnx("%s: illegal regexp", av[j]); 496 } 497 } 498 if (mflag) { 499 pmatch.rm_so = 0; 500 pmatch.rm_eo = strlen(thiscmd); 501 if (regexec(&rgx, thiscmd, 0, &pmatch, 502 REG_STARTEND) == 0) 503 matched = 1; 504 regfree(&rgx); 505 } else { 506 if (strcmp(thiscmd, av[j]) == 0) 507 matched = 1; 508 } 509 if (matched) 510 break; 511 } 512 if (matched == 0) { 513#ifdef __APPLE__ 514 free(procargs); 515#endif /* __APPLE__ */ 516 continue; 517 } 518 if (dflag) 519#ifdef __APPLE__ 520 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x\n", sig, 521 thiscmd, thispid, thistdev); 522#else /* !__APPLE__ */ 523 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig, 524 thiscmd, thispid, thistdev, thisuid); 525#endif /* __APPLE__ */ 526 527 if (vflag || sflag) 528 printf("kill -%s %d\n", upper(sys_signame[sig]), 529 thispid); 530 531 killed++; 532 if (!dflag && !sflag) { 533 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) { 534 warn("warning: kill -%s %d", 535 upper(sys_signame[sig]), thispid); 536 errors = 1; 537 } 538 } 539#ifdef __APPLE__ 540 free(procargs); 541#endif /* __APPLE__ */ 542 } 543 if (killed == 0) { 544 fprintf(stderr, "No matching processes %swere found\n", 545 getuid() != 0 ? "belonging to you " : ""); 546 errors = 1; 547 } 548 exit(errors); 549} 550