Deleted Added
full compact
killall.c (84768) killall.c (93432)
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 84768 2001-10-10 17:48:44Z bde $
27 * $FreeBSD: head/usr.bin/killall/killall.c 93432 2002-03-30 16:24:03Z dwmalone $
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 uid_t uid = 0;
117 dev_t tdev = 0;
118 char thiscmd[MAXCOMLEN + 1];
119 pid_t thispid;
120 uid_t thisuid;
121 dev_t thistdev;
122 int sig = SIGTERM;
123 const char *const *p;
124 char *ep;
125 int errors = 0;
126 int mib[4];
127 size_t miblen;
128 int st, nprocs;
129 size_t size;
130 int matched;
131 int killed = 0;
132
133 prog = av[0];
134 av++;
135 ac--;
136
137 while (ac > 0) {
138 if (strcmp(*av, "-l") == 0) {
139 printsig(stdout);
140 exit(0);
141 }
142 if (strcmp(*av, "-help") == 0)
143 usage();
144 if (**av == '-') {
145 ++*av;
146 switch (**av) {
147 case 'u':
148 ++*av;
149 if (**av == '\0')
150 ++av;
151 --ac;
152 user = *av;
153 break;
154 case 't':
155 ++*av;
156 if (**av == '\0')
157 ++av;
158 --ac;
159 tty = *av;
160 break;
161 case 'c':
162 ++*av;
163 if (**av == '\0')
164 ++av;
165 --ac;
166 cmd = *av;
167 break;
168 case 'v':
169 vflag++;
170 break;
171 case 's':
172 sflag++;
173 break;
174 case 'd':
175 dflag++;
176 break;
177 case 'm':
178 mflag++;
179 break;
180 default:
181 if (isalpha(**av)) {
182 if (strncasecmp(*av, "sig", 3) == 0)
183 *av += 3;
184 for (sig = NSIG, p = sys_signame + 1;
185 --sig; ++p)
186 if (strcasecmp(*p, *av) == 0) {
187 sig = p - sys_signame;
188 break;
189 }
190 if (!sig)
191 nosig(*av);
192 } else if (isdigit(**av)) {
193 sig = strtol(*av, &ep, 10);
194 if (!*av || *ep)
195 errx(1, "illegal signal number: %s", *av);
196 if (sig < 0 || sig > NSIG)
197 nosig(*av);
198 } else
199 nosig(*av);
200 }
201 ++av;
202 --ac;
203 } else {
204 break;
205 }
206 }
207
208 if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
209 usage();
210
211 if (tty) {
212 if (strncmp(tty, "/dev/", 5) == 0)
213 snprintf(buf, sizeof(buf), "%s", tty);
214 else if (strncmp(tty, "tty", 3) == 0)
215 snprintf(buf, sizeof(buf), "/dev/%s", tty);
216 else
217 snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
218 if (stat(buf, &sb) < 0)
219 err(1, "stat(%s)", buf);
220 if (!S_ISCHR(sb.st_mode))
221 errx(1, "%s: not a character device", buf);
222 tdev = sb.st_rdev;
223 if (dflag)
224 printf("ttydev:0x%x\n", tdev);
225 }
226 if (user) {
227 uid = strtol(user, &ep, 10);
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 uid_t uid = 0;
117 dev_t tdev = 0;
118 char thiscmd[MAXCOMLEN + 1];
119 pid_t thispid;
120 uid_t thisuid;
121 dev_t thistdev;
122 int sig = SIGTERM;
123 const char *const *p;
124 char *ep;
125 int errors = 0;
126 int mib[4];
127 size_t miblen;
128 int st, nprocs;
129 size_t size;
130 int matched;
131 int killed = 0;
132
133 prog = av[0];
134 av++;
135 ac--;
136
137 while (ac > 0) {
138 if (strcmp(*av, "-l") == 0) {
139 printsig(stdout);
140 exit(0);
141 }
142 if (strcmp(*av, "-help") == 0)
143 usage();
144 if (**av == '-') {
145 ++*av;
146 switch (**av) {
147 case 'u':
148 ++*av;
149 if (**av == '\0')
150 ++av;
151 --ac;
152 user = *av;
153 break;
154 case 't':
155 ++*av;
156 if (**av == '\0')
157 ++av;
158 --ac;
159 tty = *av;
160 break;
161 case 'c':
162 ++*av;
163 if (**av == '\0')
164 ++av;
165 --ac;
166 cmd = *av;
167 break;
168 case 'v':
169 vflag++;
170 break;
171 case 's':
172 sflag++;
173 break;
174 case 'd':
175 dflag++;
176 break;
177 case 'm':
178 mflag++;
179 break;
180 default:
181 if (isalpha(**av)) {
182 if (strncasecmp(*av, "sig", 3) == 0)
183 *av += 3;
184 for (sig = NSIG, p = sys_signame + 1;
185 --sig; ++p)
186 if (strcasecmp(*p, *av) == 0) {
187 sig = p - sys_signame;
188 break;
189 }
190 if (!sig)
191 nosig(*av);
192 } else if (isdigit(**av)) {
193 sig = strtol(*av, &ep, 10);
194 if (!*av || *ep)
195 errx(1, "illegal signal number: %s", *av);
196 if (sig < 0 || sig > NSIG)
197 nosig(*av);
198 } else
199 nosig(*av);
200 }
201 ++av;
202 --ac;
203 } else {
204 break;
205 }
206 }
207
208 if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
209 usage();
210
211 if (tty) {
212 if (strncmp(tty, "/dev/", 5) == 0)
213 snprintf(buf, sizeof(buf), "%s", tty);
214 else if (strncmp(tty, "tty", 3) == 0)
215 snprintf(buf, sizeof(buf), "/dev/%s", tty);
216 else
217 snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
218 if (stat(buf, &sb) < 0)
219 err(1, "stat(%s)", buf);
220 if (!S_ISCHR(sb.st_mode))
221 errx(1, "%s: not a character device", buf);
222 tdev = sb.st_rdev;
223 if (dflag)
224 printf("ttydev:0x%x\n", tdev);
225 }
226 if (user) {
227 uid = strtol(user, &ep, 10);
228 if ((ep - user) < strlen(user)) {
228 if (*user == '\0' || *ep != '\0') { /* was it a number? */
229 pw = getpwnam(user);
230 if (pw == NULL)
231 errx(1, "user %s does not exist", user);
232 uid = pw->pw_uid;
233 if (dflag)
234 printf("uid:%d\n", uid);
235 }
236 } else {
237 uid = getuid();
238 if (uid != 0) {
239 pw = getpwuid(uid);
240 if (pw)
241 user = pw->pw_name;
242 if (dflag)
243 printf("uid:%d\n", uid);
244 }
245 }
246 size = 0;
247 mib[0] = CTL_KERN;
248 mib[1] = KERN_PROC;
249 mib[2] = KERN_PROC_ALL;
250 mib[3] = 0;
251 miblen = 3;
252
253 if (user && mib[2] == KERN_PROC_ALL) {
254 mib[2] = KERN_PROC_RUID;
255 mib[3] = uid;
256 miblen = 4;
257 }
258 if (tty && mib[2] == KERN_PROC_ALL) {
259 mib[2] = KERN_PROC_TTY;
260 mib[3] = tdev;
261 miblen = 4;
262 }
263
264 st = sysctl(mib, miblen, NULL, &size, NULL, 0);
265 do {
266 size += size / 10;
267 newprocs = realloc(procs, size);
268 if (newprocs == 0) {
269 if (procs)
270 free(procs);
271 errx(1, "could not reallocate memory");
272 }
273 procs = newprocs;
274 st = sysctl(mib, miblen, procs, &size, NULL, 0);
275 } while (st == -1 && errno == ENOMEM);
276 if (st == -1)
277 err(1, "could not sysctl(KERN_PROC)");
278 if (size % sizeof(struct kinfo_proc) != 0) {
279 fprintf(stderr, "proc size mismatch (%d total, %d chunks)\n",
280 size, sizeof(struct kinfo_proc));
281 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
282 exit(1);
283 }
284 nprocs = size / sizeof(struct kinfo_proc);
285 if (dflag)
286 printf("nprocs %d\n", nprocs);
287
288 for (i = 0; i < nprocs; i++) {
289 thispid = procs[i].ki_pid;
290 strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
291 thiscmd[MAXCOMLEN] = '\0';
292 thistdev = procs[i].ki_tdev;
293 thisuid = procs[i].ki_ruid; /* real uid */
294
295 matched = 1;
296 if (user) {
297 if (thisuid != uid)
298 matched = 0;
299 }
300 if (tty) {
301 if (thistdev != tdev)
302 matched = 0;
303 }
304 if (cmd) {
305 if (mflag) {
306 if (regcomp(&rgx, cmd,
307 REG_EXTENDED|REG_NOSUB) != 0) {
308 mflag = 0;
309 warnx("%s: illegal regexp", cmd);
310 }
311 }
312 if (mflag) {
313 pmatch.rm_so = 0;
314 pmatch.rm_eo = strlen(thiscmd);
315 if (regexec(&rgx, thiscmd, 0, &pmatch,
316 REG_STARTEND) != 0)
317 matched = 0;
318 regfree(&rgx);
319 } else {
320 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
321 matched = 0;
322 }
323 }
324 if (matched == 0)
325 continue;
326 if (ac > 0)
327 matched = 0;
328 for (j = 0; j < ac; j++) {
329 if (mflag) {
330 if (regcomp(&rgx, av[j],
331 REG_EXTENDED|REG_NOSUB) != 0) {
332 mflag = 0;
333 warnx("%s: illegal regexp", av[j]);
334 }
335 }
336 if (mflag) {
337 pmatch.rm_so = 0;
338 pmatch.rm_eo = strlen(thiscmd);
339 if (regexec(&rgx, thiscmd, 0, &pmatch,
340 REG_STARTEND) == 0)
341 matched = 1;
342 regfree(&rgx);
343 } else {
344 if (strcmp(thiscmd, av[j]) == 0)
345 matched = 1;
346 }
347 if (matched)
348 break;
349 }
350 if (matched == 0)
351 continue;
352 if (dflag)
353 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
354 thiscmd, thispid, thistdev, thisuid);
355
356 if (vflag || sflag)
357 printf("kill -%s %d\n", upper(sys_signame[sig]),
358 thispid);
359
360 killed++;
361 if (!dflag && !sflag) {
362 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
363 warn("kill -%s %d", upper(sys_signame[sig]),
364 thispid);
365 errors = 1;
366 }
367 }
368 }
369 if (killed == 0) {
370 fprintf(stderr, "No matching processes %swere found\n",
371 getuid() != 0 ? "belonging to you " : "");
372 errors = 1;
373 }
374 exit(errors);
375}
229 pw = getpwnam(user);
230 if (pw == NULL)
231 errx(1, "user %s does not exist", user);
232 uid = pw->pw_uid;
233 if (dflag)
234 printf("uid:%d\n", uid);
235 }
236 } else {
237 uid = getuid();
238 if (uid != 0) {
239 pw = getpwuid(uid);
240 if (pw)
241 user = pw->pw_name;
242 if (dflag)
243 printf("uid:%d\n", uid);
244 }
245 }
246 size = 0;
247 mib[0] = CTL_KERN;
248 mib[1] = KERN_PROC;
249 mib[2] = KERN_PROC_ALL;
250 mib[3] = 0;
251 miblen = 3;
252
253 if (user && mib[2] == KERN_PROC_ALL) {
254 mib[2] = KERN_PROC_RUID;
255 mib[3] = uid;
256 miblen = 4;
257 }
258 if (tty && mib[2] == KERN_PROC_ALL) {
259 mib[2] = KERN_PROC_TTY;
260 mib[3] = tdev;
261 miblen = 4;
262 }
263
264 st = sysctl(mib, miblen, NULL, &size, NULL, 0);
265 do {
266 size += size / 10;
267 newprocs = realloc(procs, size);
268 if (newprocs == 0) {
269 if (procs)
270 free(procs);
271 errx(1, "could not reallocate memory");
272 }
273 procs = newprocs;
274 st = sysctl(mib, miblen, procs, &size, NULL, 0);
275 } while (st == -1 && errno == ENOMEM);
276 if (st == -1)
277 err(1, "could not sysctl(KERN_PROC)");
278 if (size % sizeof(struct kinfo_proc) != 0) {
279 fprintf(stderr, "proc size mismatch (%d total, %d chunks)\n",
280 size, sizeof(struct kinfo_proc));
281 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
282 exit(1);
283 }
284 nprocs = size / sizeof(struct kinfo_proc);
285 if (dflag)
286 printf("nprocs %d\n", nprocs);
287
288 for (i = 0; i < nprocs; i++) {
289 thispid = procs[i].ki_pid;
290 strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
291 thiscmd[MAXCOMLEN] = '\0';
292 thistdev = procs[i].ki_tdev;
293 thisuid = procs[i].ki_ruid; /* real uid */
294
295 matched = 1;
296 if (user) {
297 if (thisuid != uid)
298 matched = 0;
299 }
300 if (tty) {
301 if (thistdev != tdev)
302 matched = 0;
303 }
304 if (cmd) {
305 if (mflag) {
306 if (regcomp(&rgx, cmd,
307 REG_EXTENDED|REG_NOSUB) != 0) {
308 mflag = 0;
309 warnx("%s: illegal regexp", cmd);
310 }
311 }
312 if (mflag) {
313 pmatch.rm_so = 0;
314 pmatch.rm_eo = strlen(thiscmd);
315 if (regexec(&rgx, thiscmd, 0, &pmatch,
316 REG_STARTEND) != 0)
317 matched = 0;
318 regfree(&rgx);
319 } else {
320 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
321 matched = 0;
322 }
323 }
324 if (matched == 0)
325 continue;
326 if (ac > 0)
327 matched = 0;
328 for (j = 0; j < ac; j++) {
329 if (mflag) {
330 if (regcomp(&rgx, av[j],
331 REG_EXTENDED|REG_NOSUB) != 0) {
332 mflag = 0;
333 warnx("%s: illegal regexp", av[j]);
334 }
335 }
336 if (mflag) {
337 pmatch.rm_so = 0;
338 pmatch.rm_eo = strlen(thiscmd);
339 if (regexec(&rgx, thiscmd, 0, &pmatch,
340 REG_STARTEND) == 0)
341 matched = 1;
342 regfree(&rgx);
343 } else {
344 if (strcmp(thiscmd, av[j]) == 0)
345 matched = 1;
346 }
347 if (matched)
348 break;
349 }
350 if (matched == 0)
351 continue;
352 if (dflag)
353 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
354 thiscmd, thispid, thistdev, thisuid);
355
356 if (vflag || sflag)
357 printf("kill -%s %d\n", upper(sys_signame[sig]),
358 thispid);
359
360 killed++;
361 if (!dflag && !sflag) {
362 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
363 warn("kill -%s %d", upper(sys_signame[sig]),
364 thispid);
365 errors = 1;
366 }
367 }
368 }
369 if (killed == 0) {
370 fprintf(stderr, "No matching processes %swere found\n",
371 getuid() != 0 ? "belonging to you " : "");
372 errors = 1;
373 }
374 exit(errors);
375}