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