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