Deleted Added
full compact
killall.c (94689) killall.c (96976)
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 *
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 94689 2002-04-14 22:25:57Z des $
27 * $FreeBSD: head/usr.bin/killall/killall.c 96976 2002-05-20 07:17:22Z dd $
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 __dead2
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 int zflag = 0;
117 uid_t uid = 0;
118 dev_t tdev = 0;
119 char thiscmd[MAXCOMLEN + 1];
120 pid_t thispid;
121 uid_t thisuid;
122 dev_t thistdev;
123 int sig = SIGTERM;
124 const char *const *p;
125 char *ep;
126 int errors = 0;
127 int mib[4];
128 size_t miblen;
129 int st, nprocs;
130 size_t size;
131 int matched;
132 int killed = 0;
133
134 prog = av[0];
135 av++;
136 ac--;
137
138 while (ac > 0) {
139 if (strcmp(*av, "-l") == 0) {
140 printsig(stdout);
141 exit(0);
142 }
143 if (strcmp(*av, "-help") == 0)
144 usage();
145 if (**av == '-') {
146 ++*av;
147 switch (**av) {
148 case 'u':
149 ++*av;
150 if (**av == '\0')
151 ++av;
152 --ac;
153 user = *av;
154 break;
155 case 't':
156 ++*av;
157 if (**av == '\0')
158 ++av;
159 --ac;
160 tty = *av;
161 break;
162 case 'c':
163 ++*av;
164 if (**av == '\0')
165 ++av;
166 --ac;
167 cmd = *av;
168 break;
169 case 'v':
170 vflag++;
171 break;
172 case 's':
173 sflag++;
174 break;
175 case 'd':
176 dflag++;
177 break;
178 case 'm':
179 mflag++;
180 break;
181 case 'z':
182 zflag++;
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 (*user == '\0' || *ep != '\0') { /* was it a number? */
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++) {
293 if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
294 continue;
295 thispid = procs[i].ki_pid;
296 strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
297 thiscmd[MAXCOMLEN] = '\0';
298 thistdev = procs[i].ki_tdev;
299 thisuid = procs[i].ki_ruid; /* real uid */
300
301 matched = 1;
302 if (user) {
303 if (thisuid != uid)
304 matched = 0;
305 }
306 if (tty) {
307 if (thistdev != tdev)
308 matched = 0;
309 }
310 if (cmd) {
311 if (mflag) {
312 if (regcomp(&rgx, cmd,
313 REG_EXTENDED|REG_NOSUB) != 0) {
314 mflag = 0;
315 warnx("%s: illegal regexp", cmd);
316 }
317 }
318 if (mflag) {
319 pmatch.rm_so = 0;
320 pmatch.rm_eo = strlen(thiscmd);
321 if (regexec(&rgx, thiscmd, 0, &pmatch,
322 REG_STARTEND) != 0)
323 matched = 0;
324 regfree(&rgx);
325 } else {
326 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
327 matched = 0;
328 }
329 }
330 if (matched == 0)
331 continue;
332 if (ac > 0)
333 matched = 0;
334 for (j = 0; j < ac; j++) {
335 if (mflag) {
336 if (regcomp(&rgx, av[j],
337 REG_EXTENDED|REG_NOSUB) != 0) {
338 mflag = 0;
339 warnx("%s: illegal regexp", av[j]);
340 }
341 }
342 if (mflag) {
343 pmatch.rm_so = 0;
344 pmatch.rm_eo = strlen(thiscmd);
345 if (regexec(&rgx, thiscmd, 0, &pmatch,
346 REG_STARTEND) == 0)
347 matched = 1;
348 regfree(&rgx);
349 } else {
350 if (strcmp(thiscmd, av[j]) == 0)
351 matched = 1;
352 }
353 if (matched)
354 break;
355 }
356 if (matched == 0)
357 continue;
358 if (dflag)
359 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
360 thiscmd, thispid, thistdev, thisuid);
361
362 if (vflag || sflag)
363 printf("kill -%s %d\n", upper(sys_signame[sig]),
364 thispid);
365
366 killed++;
367 if (!dflag && !sflag) {
368 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
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 __dead2
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 int zflag = 0;
117 uid_t uid = 0;
118 dev_t tdev = 0;
119 char thiscmd[MAXCOMLEN + 1];
120 pid_t thispid;
121 uid_t thisuid;
122 dev_t thistdev;
123 int sig = SIGTERM;
124 const char *const *p;
125 char *ep;
126 int errors = 0;
127 int mib[4];
128 size_t miblen;
129 int st, nprocs;
130 size_t size;
131 int matched;
132 int killed = 0;
133
134 prog = av[0];
135 av++;
136 ac--;
137
138 while (ac > 0) {
139 if (strcmp(*av, "-l") == 0) {
140 printsig(stdout);
141 exit(0);
142 }
143 if (strcmp(*av, "-help") == 0)
144 usage();
145 if (**av == '-') {
146 ++*av;
147 switch (**av) {
148 case 'u':
149 ++*av;
150 if (**av == '\0')
151 ++av;
152 --ac;
153 user = *av;
154 break;
155 case 't':
156 ++*av;
157 if (**av == '\0')
158 ++av;
159 --ac;
160 tty = *av;
161 break;
162 case 'c':
163 ++*av;
164 if (**av == '\0')
165 ++av;
166 --ac;
167 cmd = *av;
168 break;
169 case 'v':
170 vflag++;
171 break;
172 case 's':
173 sflag++;
174 break;
175 case 'd':
176 dflag++;
177 break;
178 case 'm':
179 mflag++;
180 break;
181 case 'z':
182 zflag++;
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 (*user == '\0' || *ep != '\0') { /* was it a number? */
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++) {
293 if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
294 continue;
295 thispid = procs[i].ki_pid;
296 strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
297 thiscmd[MAXCOMLEN] = '\0';
298 thistdev = procs[i].ki_tdev;
299 thisuid = procs[i].ki_ruid; /* real uid */
300
301 matched = 1;
302 if (user) {
303 if (thisuid != uid)
304 matched = 0;
305 }
306 if (tty) {
307 if (thistdev != tdev)
308 matched = 0;
309 }
310 if (cmd) {
311 if (mflag) {
312 if (regcomp(&rgx, cmd,
313 REG_EXTENDED|REG_NOSUB) != 0) {
314 mflag = 0;
315 warnx("%s: illegal regexp", cmd);
316 }
317 }
318 if (mflag) {
319 pmatch.rm_so = 0;
320 pmatch.rm_eo = strlen(thiscmd);
321 if (regexec(&rgx, thiscmd, 0, &pmatch,
322 REG_STARTEND) != 0)
323 matched = 0;
324 regfree(&rgx);
325 } else {
326 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
327 matched = 0;
328 }
329 }
330 if (matched == 0)
331 continue;
332 if (ac > 0)
333 matched = 0;
334 for (j = 0; j < ac; j++) {
335 if (mflag) {
336 if (regcomp(&rgx, av[j],
337 REG_EXTENDED|REG_NOSUB) != 0) {
338 mflag = 0;
339 warnx("%s: illegal regexp", av[j]);
340 }
341 }
342 if (mflag) {
343 pmatch.rm_so = 0;
344 pmatch.rm_eo = strlen(thiscmd);
345 if (regexec(&rgx, thiscmd, 0, &pmatch,
346 REG_STARTEND) == 0)
347 matched = 1;
348 regfree(&rgx);
349 } else {
350 if (strcmp(thiscmd, av[j]) == 0)
351 matched = 1;
352 }
353 if (matched)
354 break;
355 }
356 if (matched == 0)
357 continue;
358 if (dflag)
359 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
360 thiscmd, thispid, thistdev, thisuid);
361
362 if (vflag || sflag)
363 printf("kill -%s %d\n", upper(sys_signame[sig]),
364 thispid);
365
366 killed++;
367 if (!dflag && !sflag) {
368 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
369 warn("kill -%s %d", upper(sys_signame[sig]),
370 thispid);
369 warn("warning: kill -%s %d",
370 upper(sys_signame[sig]), thispid);
371 errors = 1;
372 }
373 }
374 }
375 if (killed == 0) {
376 fprintf(stderr, "No matching processes %swere found\n",
377 getuid() != 0 ? "belonging to you " : "");
378 errors = 1;
379 }
380 exit(errors);
381}
371 errors = 1;
372 }
373 }
374 }
375 if (killed == 0) {
376 fprintf(stderr, "No matching processes %swere found\n",
377 getuid() != 0 ? "belonging to you " : "");
378 errors = 1;
379 }
380 exit(errors);
381}