]> git.saurik.com Git - apple/shell_cmds.git/blob - killall/killall.c
795df0424a3b1e9f281340a2aafcfa3d030a68a1
[apple/shell_cmds.git] / killall / killall.c
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 static void __dead2
53 usage(void)
54 {
55
56 #ifdef __APPLE__
57 fprintf(stderr, "usage: killall [-delmsvz] [-help]\n");
58 #else /* !__APPLE__ */
59 fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jid]\n");
60 #endif /* __APPLE__ */
61 fprintf(stderr,
62 " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
63 fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
64 exit(1);
65 }
66
67 static char *
68 upper(const char *str)
69 {
70 static char buf[80];
71 char *s;
72
73 strncpy(buf, str, sizeof(buf));
74 buf[sizeof(buf) - 1] = '\0';
75 for (s = buf; *s; s++)
76 *s = toupper((unsigned char)*s);
77 return buf;
78 }
79
80
81 static void
82 printsig(FILE *fp)
83 {
84 const char *const * p;
85 int cnt;
86 int offset = 0;
87
88 for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
89 offset += fprintf(fp, "%s ", upper(*p));
90 if (offset >= 75 && cnt > 1) {
91 offset = 0;
92 fprintf(fp, "\n");
93 }
94 }
95 fprintf(fp, "\n");
96 }
97
98 static void
99 nosig(char *name)
100 {
101
102 warnx("unknown signal %s; valid signals:", name);
103 printsig(stderr);
104 exit(1);
105 }
106
107 int
108 main(int ac, char **av)
109 {
110 struct kinfo_proc *procs = NULL, *newprocs;
111 struct stat sb;
112 struct passwd *pw;
113 regex_t rgx;
114 regmatch_t pmatch;
115 int i, j;
116 char buf[256];
117 char *user = NULL;
118 char *tty = NULL;
119 char *cmd = NULL;
120 int vflag = 0;
121 int sflag = 0;
122 int dflag = 0;
123 int eflag = 0;
124 #ifndef __APPLE__
125 int jflag = 0;
126 #endif /* !__APPLE__*/
127 int mflag = 0;
128 int zflag = 0;
129 uid_t uid = 0;
130 dev_t tdev = 0;
131 pid_t mypid;
132 #ifdef __APPLE__
133 char *thiscmd;
134 #else /* !__APPLE__ */
135 char thiscmd[MAXCOMLEN + 1];
136 #endif /* __APPLE__ */
137 pid_t thispid;
138 #ifndef __APPLE__
139 uid_t thisuid;
140 #endif /* !__APPLE__ */
141 dev_t thistdev;
142 int sig = SIGTERM;
143 const char *const *p;
144 char *ep;
145 int errors = 0;
146 #ifndef __APPLE__
147 int jid;
148 #endif /* !__APPLE__ */
149 int mib[4];
150 size_t miblen;
151 int st, nprocs;
152 size_t size;
153 int matched;
154 int killed = 0;
155
156 setlocale(LC_ALL, "");
157
158 av++;
159 ac--;
160
161 while (ac > 0) {
162 if (strcmp(*av, "-l") == 0) {
163 printsig(stdout);
164 exit(0);
165 }
166 if (strcmp(*av, "-help") == 0)
167 usage();
168 if (**av == '-') {
169 ++*av;
170 switch (**av) {
171 #ifndef __APPLE__
172 case 'j':
173 ++*av;
174 if (**av == '\0')
175 ++av;
176 --ac;
177 jflag++;
178 if (!*av)
179 errx(1, "must specify jid");
180 jid = strtol(*av, &ep, 10);
181 if (!*av || *ep)
182 errx(1, "illegal jid: %s", *av);
183 if (jail_attach(jid) == -1)
184 err(1, "jail_attach(): %d", jid);
185 break;
186 #endif /* !__APPLE__ */
187 case 'u':
188 ++*av;
189 if (**av == '\0')
190 ++av;
191 --ac;
192 user = *av;
193 break;
194 case 't':
195 ++*av;
196 if (**av == '\0')
197 ++av;
198 --ac;
199 tty = *av;
200 break;
201 case 'c':
202 ++*av;
203 if (**av == '\0')
204 ++av;
205 --ac;
206 cmd = *av;
207 break;
208 case 'v':
209 vflag++;
210 break;
211 case 's':
212 sflag++;
213 break;
214 case 'd':
215 dflag++;
216 break;
217 case 'e':
218 eflag++;
219 break;
220 case 'm':
221 mflag++;
222 break;
223 case 'z':
224 zflag++;
225 break;
226 default:
227 if (isalpha((unsigned char)**av)) {
228 if (strncasecmp(*av, "sig", 3) == 0)
229 *av += 3;
230 for (sig = NSIG, p = sys_signame + 1;
231 --sig; ++p)
232 if (strcasecmp(*p, *av) == 0) {
233 sig = p - sys_signame;
234 break;
235 }
236 if (!sig)
237 nosig(*av);
238 } else if (isdigit((unsigned char)**av)) {
239 sig = strtol(*av, &ep, 10);
240 if (!*av || *ep)
241 errx(1, "illegal signal number: %s", *av);
242 if (sig < 0 || sig >= NSIG)
243 nosig(*av);
244 } else
245 nosig(*av);
246 }
247 ++av;
248 --ac;
249 } else {
250 break;
251 }
252 }
253
254 #ifdef __APPLE__
255 if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
256 #else /* !__APPLE__*/
257 if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
258 #endif /* __APPLE__ */
259 usage();
260
261 if (tty) {
262 if (strncmp(tty, "/dev/", 5) == 0)
263 snprintf(buf, sizeof(buf), "%s", tty);
264 else if (strncmp(tty, "tty", 3) == 0)
265 snprintf(buf, sizeof(buf), "/dev/%s", tty);
266 else
267 snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
268 if (stat(buf, &sb) < 0)
269 err(1, "stat(%s)", buf);
270 if (!S_ISCHR(sb.st_mode))
271 errx(1, "%s: not a character device", buf);
272 tdev = sb.st_rdev;
273 if (dflag)
274 printf("ttydev:0x%x\n", tdev);
275 }
276 if (user) {
277 uid = strtol(user, &ep, 10);
278 if (*user == '\0' || *ep != '\0') { /* was it a number? */
279 pw = getpwnam(user);
280 if (pw == NULL)
281 errx(1, "user %s does not exist", user);
282 uid = pw->pw_uid;
283 if (dflag)
284 printf("uid:%d\n", uid);
285 }
286 } else {
287 uid = getuid();
288 if (uid != 0) {
289 pw = getpwuid(uid);
290 if (pw)
291 user = pw->pw_name;
292 if (dflag)
293 printf("uid:%d\n", uid);
294 }
295 }
296 size = 0;
297 mib[0] = CTL_KERN;
298 mib[1] = KERN_PROC;
299 #ifdef __APPLE__
300 mib[2] = KERN_PROC_ALL;
301 #else /* !__APPLE__ */
302 mib[2] = KERN_PROC_PROC;
303 #endif /* __APPLE__ */
304 mib[3] = 0;
305 miblen = 3;
306
307 if (user) {
308 mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
309 mib[3] = uid;
310 miblen = 4;
311 } else if (tty) {
312 mib[2] = KERN_PROC_TTY;
313 mib[3] = tdev;
314 miblen = 4;
315 }
316
317 st = sysctl(mib, miblen, NULL, &size, NULL, 0);
318 do {
319 size += size / 10;
320 newprocs = realloc(procs, size);
321 if (newprocs == 0) {
322 if (procs)
323 free(procs);
324 errx(1, "could not reallocate memory");
325 }
326 procs = newprocs;
327 st = sysctl(mib, miblen, procs, &size, NULL, 0);
328 } while (st == -1 && errno == ENOMEM);
329 if (st == -1)
330 err(1, "could not sysctl(KERN_PROC)");
331 if (size % sizeof(struct kinfo_proc) != 0) {
332 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
333 size, sizeof(struct kinfo_proc));
334 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
335 exit(1);
336 }
337 nprocs = size / sizeof(struct kinfo_proc);
338 if (dflag)
339 printf("nprocs %d\n", nprocs);
340 mypid = getpid();
341
342 for (i = 0; i < nprocs; i++) {
343 #ifdef __APPLE__
344 if ((procs[i].kp_proc.p_stat & SZOMB) == SZOMB && !zflag)
345 continue;
346 thispid = procs[i].kp_proc.p_pid;
347
348 int mib[3], argmax;
349 size_t syssize;
350 char *procargs, *cp;
351
352 mib[0] = CTL_KERN;
353 mib[1] = KERN_ARGMAX;
354
355 syssize = sizeof(argmax);
356 if (sysctl(mib, 2, &argmax, &syssize, NULL, 0) == -1)
357 continue;
358
359 procargs = malloc(argmax);
360 if (procargs == NULL)
361 continue;
362
363 mib[0] = CTL_KERN;
364 mib[1] = KERN_PROCARGS;
365 mib[2] = thispid;
366
367 syssize = (size_t)argmax;
368 if (sysctl(mib, 3, procargs, &syssize, NULL, 0) == -1) {
369 free(procargs);
370 continue;
371 }
372
373 for (cp = procargs; cp < &procargs[syssize]; cp++) {
374 if (*cp == '\0') {
375 break;
376 }
377 }
378
379 if (cp == &procargs[syssize]) {
380 free(procargs);
381 continue;
382 }
383
384 for (; cp < &procargs[syssize]; cp++) {
385 if (*cp != '\0') {
386 break;
387 }
388 }
389
390 if (cp == &procargs[syssize]) {
391 free(procargs);
392 continue;
393 }
394
395 /* Strip off any path that was specified */
396 for (thiscmd = cp; (cp < &procargs[syssize]) && (*cp != '\0'); cp++) {
397 if (*cp == '/') {
398 thiscmd = cp + 1;
399 }
400 }
401
402 thistdev = procs[i].kp_eproc.e_tdev;
403 #else /* !__APPLE__ */
404 if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
405 continue;
406 thispid = procs[i].ki_pid;
407 strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
408 thiscmd[MAXCOMLEN] = '\0';
409 thistdev = procs[i].ki_tdev;
410 #endif /* __APPLE__ */
411 #ifndef __APPLE__
412 if (eflag)
413 thisuid = procs[i].ki_uid; /* effective uid */
414 else
415 thisuid = procs[i].ki_ruid; /* real uid */
416 #endif /* !__APPLE__ */
417
418 if (thispid == mypid) {
419 #ifdef __APPLE__
420 free(procargs);
421 #endif /* __APPLE__ */
422 continue;
423 }
424 matched = 1;
425 #ifndef __APPLE__
426 if (user) {
427 if (thisuid != uid)
428 matched = 0;
429 }
430 #endif /* !__APPLE__ */
431 if (tty) {
432 if (thistdev != tdev)
433 matched = 0;
434 }
435 if (cmd) {
436 if (mflag) {
437 if (regcomp(&rgx, cmd,
438 REG_EXTENDED|REG_NOSUB) != 0) {
439 mflag = 0;
440 warnx("%s: illegal regexp", cmd);
441 }
442 }
443 if (mflag) {
444 pmatch.rm_so = 0;
445 pmatch.rm_eo = strlen(thiscmd);
446 if (regexec(&rgx, thiscmd, 0, &pmatch,
447 REG_STARTEND) != 0)
448 matched = 0;
449 regfree(&rgx);
450 } else {
451 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
452 matched = 0;
453 }
454 }
455 #ifndef __APPLE__
456 if (jflag && thispid == getpid())
457 matched = 0;
458 #endif /* !__APPLE__ */
459 if (matched == 0) {
460 #ifdef __APPLE__
461 free(procargs);
462 #endif /* !__APPLE__ */
463 continue;
464 }
465 if (ac > 0)
466 matched = 0;
467 for (j = 0; j < ac; j++) {
468 if (mflag) {
469 if (regcomp(&rgx, av[j],
470 REG_EXTENDED|REG_NOSUB) != 0) {
471 mflag = 0;
472 warnx("%s: illegal regexp", av[j]);
473 }
474 }
475 if (mflag) {
476 pmatch.rm_so = 0;
477 pmatch.rm_eo = strlen(thiscmd);
478 if (regexec(&rgx, thiscmd, 0, &pmatch,
479 REG_STARTEND) == 0)
480 matched = 1;
481 regfree(&rgx);
482 } else {
483 if (strcmp(thiscmd, av[j]) == 0)
484 matched = 1;
485 }
486 if (matched)
487 break;
488 }
489 if (matched == 0) {
490 #ifdef __APPLE__
491 free(procargs);
492 #endif /* __APPLE__ */
493 continue;
494 }
495 if (dflag)
496 #ifdef __APPLE__
497 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x\n", sig,
498 thiscmd, thispid, thistdev);
499 #else /* !__APPLE__ */
500 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
501 thiscmd, thispid, thistdev, thisuid);
502 #endif /* __APPLE__ */
503
504 if (vflag || sflag)
505 printf("kill -%s %d\n", upper(sys_signame[sig]),
506 thispid);
507
508 killed++;
509 if (!dflag && !sflag) {
510 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
511 warn("warning: kill -%s %d",
512 upper(sys_signame[sig]), thispid);
513 errors = 1;
514 }
515 }
516 #ifdef __APPLE__
517 free(procargs);
518 #endif /* __APPLE__ */
519 }
520 if (killed == 0) {
521 fprintf(stderr, "No matching processes %swere found\n",
522 getuid() != 0 ? "belonging to you " : "");
523 errors = 1;
524 }
525 exit(errors);
526 }