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$"); 30 31 #include <sys/param.h> 32 #include <sys/jail.h> 33 #include <sys/stat.h> 34 #include <sys/uio.h> 35 #include <sys/user.h> 36 #include <sys/sysctl.h> 37 #include <fcntl.h> 38 #include <dirent.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <pwd.h> 43 #include <signal.h> 44 #include <regex.h> 45 #include <ctype.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <unistd.h> 49 #include <locale.h> 50 51 static void __dead2 52 usage(void) 53 { 54 55 fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jail]\n"); 56 fprintf(stderr, 57 " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n"); 58 fprintf(stderr, "At least one option or argument to specify processes must be given.\n"); 59 exit(1); 60 } 61 62 static char * 63 upper(const char *str) 64 { 65 static char buf[80]; 66 char *s; 67 68 strlcpy(buf, str, sizeof(buf)); 69 for (s = buf; *s; s++) 70 *s = toupper((unsigned char)*s); 71 return buf; 72 } 73 74 75 static void 76 printsig(FILE *fp) 77 { 78 const char *const * p; 79 int cnt; 80 int offset = 0; 81 82 for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) { 83 offset += fprintf(fp, "%s ", upper(*p)); 84 if (offset >= 75 && cnt > 1) { 85 offset = 0; 86 fprintf(fp, "\n"); 87 } 88 } 89 fprintf(fp, "\n"); 90 } 91 92 static void 93 nosig(char *name) 94 { 95 96 warnx("unknown signal %s; valid signals:", name); 97 printsig(stderr); 98 exit(1); 99 } 100 101 int 102 main(int ac, char **av) 103 { 104 struct iovec jparams[2]; 105 struct kinfo_proc *procs = NULL, *newprocs; 106 struct stat sb; 107 struct passwd *pw; 108 regex_t rgx; 109 regmatch_t pmatch; 110 int i, j; 111 char buf[256]; 112 char *user = NULL; 113 char *tty = NULL; 114 char *cmd = NULL; 115 int vflag = 0; 116 int sflag = 0; 117 int dflag = 0; 118 int eflag = 0; 119 int jflag = 0; 120 int mflag = 0; 121 int zflag = 0; 122 uid_t uid = 0; 123 dev_t tdev = 0; 124 pid_t mypid; 125 char thiscmd[MAXCOMLEN + 1]; 126 pid_t thispid; 127 uid_t thisuid; 128 dev_t thistdev; 129 int sig = SIGTERM; 130 const char *const *p; 131 char *ep; 132 int errors = 0; 133 int jid; 134 int mib[4]; 135 size_t miblen; 136 int st, nprocs; 137 size_t size; 138 int matched; 139 int killed = 0; 140 141 setlocale(LC_ALL, ""); 142 143 av++; 144 ac--; 145 146 while (ac > 0) { 147 if (strcmp(*av, "-l") == 0) { 148 printsig(stdout); 149 exit(0); 150 } 151 if (strcmp(*av, "-help") == 0) 152 usage(); 153 if (**av == '-') { 154 ++*av; 155 switch (**av) { 156 case 'j': 157 ++*av; 158 if (**av == '\0') { 159 ++av; 160 --ac; 161 } 162 jflag++; 163 if (*av == NULL) 164 errx(1, "must specify jail"); 165 jid = strtoul(*av, &ep, 10); 166 if (!**av || *ep) { 167 *(const void **)&jparams[0].iov_base = 168 "name"; 169 jparams[0].iov_len = sizeof("name"); 170 jparams[1].iov_base = *av; 171 jparams[1].iov_len = strlen(*av) + 1; 172 jid = jail_get(jparams, 2, 0); 173 if (jid < 0) 174 errx(1, "unknown jail: %s", 175 *av); 176 } 177 if (jail_attach(jid) == -1) 178 err(1, "jail_attach(%d)", jid); 179 break; 180 case 'u': 181 ++*av; 182 if (**av == '\0') { 183 ++av; 184 --ac; 185 } 186 if (*av == NULL) 187 errx(1, "must specify user"); 188 user = *av; 189 break; 190 case 't': 191 ++*av; 192 if (**av == '\0') { 193 ++av; 194 --ac; 195 } 196 if (*av == NULL) 197 errx(1, "must specify tty"); 198 tty = *av; 199 break; 200 case 'c': 201 ++*av; 202 if (**av == '\0') { 203 ++av; 204 --ac; 205 } 206 if (*av == NULL) 207 errx(1, "must specify procname"); 208 cmd = *av; 209 break; 210 case 'v': 211 vflag++; 212 break; 213 case 's': 214 sflag++; 215 break; 216 case 'd': 217 dflag++; 218 break; 219 case 'e': 220 eflag++; 221 break; 222 case 'm': 223 mflag++; 224 break; 225 case 'z': 226 zflag++; 227 break; 228 default: 229 if (isalpha((unsigned char)**av)) { 230 if (strncasecmp(*av, "sig", 3) == 0) 231 *av += 3; 232 for (sig = NSIG, p = sys_signame + 1; 233 --sig; ++p) 234 if (strcasecmp(*p, *av) == 0) { 235 sig = p - sys_signame; 236 break; 237 } 238 if (!sig) 239 nosig(*av); 240 } else if (isdigit((unsigned char)**av)) { 241 sig = strtol(*av, &ep, 10); 242 if (!*av || *ep) 243 errx(1, "illegal signal number: %s", *av); 244 if (sig < 0 || sig >= NSIG) 245 nosig(*av); 246 } else 247 nosig(*av); 248 } 249 ++av; 250 --ac; 251 } else { 252 break; 253 } 254 } 255 256 if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0) 257 usage(); 258 259 if (tty) { 260 if (strncmp(tty, "/dev/", 5) == 0) 261 snprintf(buf, sizeof(buf), "%s", tty); 262 else if (strncmp(tty, "tty", 3) == 0) 263 snprintf(buf, sizeof(buf), "/dev/%s", tty); 264 else 265 snprintf(buf, sizeof(buf), "/dev/tty%s", tty); 266 if (stat(buf, &sb) < 0) 267 err(1, "stat(%s)", buf); 268 if (!S_ISCHR(sb.st_mode)) 269 errx(1, "%s: not a character device", buf); 270 tdev = sb.st_rdev; 271 if (dflag) 272 printf("ttydev:0x%x\n", tdev); 273 } 274 if (user) { 275 uid = strtol(user, &ep, 10); 276 if (*user == '\0' || *ep != '\0') { /* was it a number? */ 277 pw = getpwnam(user); 278 if (pw == NULL) 279 errx(1, "user %s does not exist", user); 280 uid = pw->pw_uid; 281 if (dflag) 282 printf("uid:%d\n", uid); 283 } 284 } else { 285 uid = getuid(); 286 if (uid != 0) { 287 pw = getpwuid(uid); 288 if (pw) 289 user = pw->pw_name; 290 if (dflag) 291 printf("uid:%d\n", uid); 292 } 293 } 294 size = 0; 295 mib[0] = CTL_KERN; 296 mib[1] = KERN_PROC; 297 mib[2] = KERN_PROC_PROC; 298 mib[3] = 0; 299 miblen = 3; 300 301 if (user) { 302 mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID; 303 mib[3] = uid; 304 miblen = 4; 305 } else if (tty) { 306 mib[2] = KERN_PROC_TTY; 307 mib[3] = tdev; 308 miblen = 4; 309 } 310 311 st = sysctl(mib, miblen, NULL, &size, NULL, 0); 312 do { 313 size += size / 10; 314 newprocs = realloc(procs, size); 315 if (newprocs == 0) { 316 if (procs) 317 free(procs); 318 errx(1, "could not reallocate memory"); 319 } 320 procs = newprocs; 321 st = sysctl(mib, miblen, procs, &size, NULL, 0); 322 } while (st == -1 && errno == ENOMEM); 323 if (st == -1) 324 err(1, "could not sysctl(KERN_PROC)"); 325 if (size % sizeof(struct kinfo_proc) != 0) { 326 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n", 327 size, sizeof(struct kinfo_proc)); 328 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n"); 329 exit(1); 330 } 331 nprocs = size / sizeof(struct kinfo_proc); 332 if (dflag) 333 printf("nprocs %d\n", nprocs); 334 mypid = getpid(); 335 336 for (i = 0; i < nprocs; i++) { 337 if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag) 338 continue; 339 thispid = procs[i].ki_pid; 340 strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd)); 341 thistdev = procs[i].ki_tdev; 342 if (eflag) 343 thisuid = procs[i].ki_uid; /* effective uid */ 344 else 345 thisuid = procs[i].ki_ruid; /* real uid */ 346 347 if (thispid == mypid) 348 continue; 349 matched = 1; 350 if (user) { 351 if (thisuid != uid) 352 matched = 0; 353 } 354 if (tty) { 355 if (thistdev != tdev) 356 matched = 0; 357 } 358 if (cmd) { 359 if (mflag) { 360 if (regcomp(&rgx, cmd, 361 REG_EXTENDED|REG_NOSUB) != 0) { 362 mflag = 0; 363 warnx("%s: illegal regexp", cmd); 364 } 365 } 366 if (mflag) { 367 pmatch.rm_so = 0; 368 pmatch.rm_eo = strlen(thiscmd); 369 if (regexec(&rgx, thiscmd, 0, &pmatch, 370 REG_STARTEND) != 0) 371 matched = 0; 372 regfree(&rgx); 373 } else { 374 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0) 375 matched = 0; 376 } 377 } 378 if (jflag && thispid == getpid()) 379 matched = 0; 380 if (matched == 0) 381 continue; 382 if (ac > 0) 383 matched = 0; 384 for (j = 0; j < ac; j++) { 385 if (mflag) { 386 if (regcomp(&rgx, av[j], 387 REG_EXTENDED|REG_NOSUB) != 0) { 388 mflag = 0; 389 warnx("%s: illegal regexp", av[j]); 390 } 391 } 392 if (mflag) { 393 pmatch.rm_so = 0; 394 pmatch.rm_eo = strlen(thiscmd); 395 if (regexec(&rgx, thiscmd, 0, &pmatch, 396 REG_STARTEND) == 0) 397 matched = 1; 398 regfree(&rgx); 399 } else { 400 if (strcmp(thiscmd, av[j]) == 0) 401 matched = 1; 402 } 403 if (matched) 404 break; 405 } 406 if (matched == 0) 407 continue; 408 if (dflag) 409 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig, 410 thiscmd, thispid, thistdev, thisuid); 411 412 if (vflag || sflag) 413 printf("kill -%s %d\n", upper(sys_signame[sig]), 414 thispid); 415 416 killed++; 417 if (!dflag && !sflag) { 418 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) { 419 warn("warning: kill -%s %d", 420 upper(sys_signame[sig]), thispid); 421 errors = 1; 422 } 423 } 424 } 425 if (killed == 0) { 426 fprintf(stderr, "No matching processes %swere found\n", 427 getuid() != 0 ? "belonging to you " : ""); 428 errors = 1; 429 } 430 exit(errors); 431 } 432