1 |
/* $MidnightBSD$ */ |
2 |
/* $NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $ */ |
3 |
|
4 |
/*- |
5 |
* Copyright (c) 2002 The NetBSD Foundation, Inc. |
6 |
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> |
7 |
* All rights reserved. |
8 |
* |
9 |
* This code is derived from software contributed to The NetBSD Foundation |
10 |
* by Andrew Doran. |
11 |
* |
12 |
* Redistribution and use in source and binary forms, with or without |
13 |
* modification, are permitted provided that the following conditions |
14 |
* are met: |
15 |
* 1. Redistributions of source code must retain the above copyright |
16 |
* notice, this list of conditions and the following disclaimer. |
17 |
* 2. Redistributions in binary form must reproduce the above copyright |
18 |
* notice, this list of conditions and the following disclaimer in the |
19 |
* documentation and/or other materials provided with the distribution. |
20 |
* |
21 |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
22 |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
23 |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
25 |
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 |
* POSSIBILITY OF SUCH DAMAGE. |
32 |
*/ |
33 |
|
34 |
#include <sys/cdefs.h> |
35 |
__FBSDID("$FreeBSD: stable/10/bin/pkill/pkill.c 287269 2015-08-29 02:41:59Z jamie $"); |
36 |
|
37 |
#include <sys/types.h> |
38 |
#include <sys/param.h> |
39 |
#include <sys/sysctl.h> |
40 |
#include <sys/proc.h> |
41 |
#include <sys/queue.h> |
42 |
#include <sys/stat.h> |
43 |
#include <sys/time.h> |
44 |
#include <sys/user.h> |
45 |
|
46 |
#include <assert.h> |
47 |
#include <stdio.h> |
48 |
#include <stdlib.h> |
49 |
#include <limits.h> |
50 |
#include <paths.h> |
51 |
#include <string.h> |
52 |
#include <unistd.h> |
53 |
#include <signal.h> |
54 |
#include <regex.h> |
55 |
#include <ctype.h> |
56 |
#include <fcntl.h> |
57 |
#include <kvm.h> |
58 |
#include <err.h> |
59 |
#include <pwd.h> |
60 |
#include <grp.h> |
61 |
#include <errno.h> |
62 |
#include <locale.h> |
63 |
#include <jail.h> |
64 |
|
65 |
#define STATUS_MATCH 0 |
66 |
#define STATUS_NOMATCH 1 |
67 |
#define STATUS_BADUSAGE 2 |
68 |
#define STATUS_ERROR 3 |
69 |
|
70 |
#define MIN_PID 5 |
71 |
#define MAX_PID 99999 |
72 |
|
73 |
/* Ignore system-processes (if '-S' flag is not specified) and myself. */ |
74 |
#define PSKIP(kp) ((kp)->ki_pid == mypid || \ |
75 |
(!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0)) |
76 |
|
77 |
enum listtype { |
78 |
LT_GENERIC, |
79 |
LT_USER, |
80 |
LT_GROUP, |
81 |
LT_TTY, |
82 |
LT_PGRP, |
83 |
LT_JAIL, |
84 |
LT_SID, |
85 |
LT_CLASS |
86 |
}; |
87 |
|
88 |
struct list { |
89 |
SLIST_ENTRY(list) li_chain; |
90 |
long li_number; |
91 |
char *li_name; |
92 |
}; |
93 |
|
94 |
SLIST_HEAD(listhead, list); |
95 |
|
96 |
static struct kinfo_proc *plist; |
97 |
static char *selected; |
98 |
static const char *delim = "\n"; |
99 |
static int nproc; |
100 |
static int pgrep; |
101 |
static int signum = SIGTERM; |
102 |
static int newest; |
103 |
static int oldest; |
104 |
static int interactive; |
105 |
static int inverse; |
106 |
static int longfmt; |
107 |
static int matchargs; |
108 |
static int fullmatch; |
109 |
static int kthreads; |
110 |
static int cflags = REG_EXTENDED; |
111 |
static int quiet; |
112 |
static kvm_t *kd; |
113 |
static pid_t mypid; |
114 |
|
115 |
static struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist); |
116 |
static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist); |
117 |
static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist); |
118 |
static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist); |
119 |
static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); |
120 |
static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); |
121 |
static struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); |
122 |
static struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); |
123 |
static struct listhead classlist = SLIST_HEAD_INITIALIZER(classlist); |
124 |
|
125 |
static void usage(void) __attribute__((__noreturn__)); |
126 |
static int killact(const struct kinfo_proc *); |
127 |
static int grepact(const struct kinfo_proc *); |
128 |
static void makelist(struct listhead *, enum listtype, char *); |
129 |
static int takepid(const char *, int); |
130 |
|
131 |
int |
132 |
main(int argc, char **argv) |
133 |
{ |
134 |
char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; |
135 |
const char *execf, *coref; |
136 |
int ancestors, debug_opt, did_action; |
137 |
int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; |
138 |
size_t jsz; |
139 |
int (*action)(const struct kinfo_proc *); |
140 |
struct kinfo_proc *kp; |
141 |
struct list *li; |
142 |
struct timeval best_tval; |
143 |
regex_t reg; |
144 |
regmatch_t regmatch; |
145 |
pid_t pid; |
146 |
|
147 |
setlocale(LC_ALL, ""); |
148 |
|
149 |
if (strcmp(getprogname(), "pgrep") == 0) { |
150 |
action = grepact; |
151 |
pgrep = 1; |
152 |
} else { |
153 |
action = killact; |
154 |
p = argv[1]; |
155 |
|
156 |
if (argc > 1 && p[0] == '-') { |
157 |
p++; |
158 |
i = (int)strtol(p, &q, 10); |
159 |
if (*q == '\0') { |
160 |
signum = i; |
161 |
argv++; |
162 |
argc--; |
163 |
} else { |
164 |
if (strncasecmp(p, "SIG", 3) == 0) |
165 |
p += 3; |
166 |
for (i = 1; i < NSIG; i++) |
167 |
if (strcasecmp(sys_signame[i], p) == 0) |
168 |
break; |
169 |
if (i != NSIG) { |
170 |
signum = i; |
171 |
argv++; |
172 |
argc--; |
173 |
} |
174 |
} |
175 |
} |
176 |
} |
177 |
|
178 |
ancestors = 0; |
179 |
criteria = 0; |
180 |
debug_opt = 0; |
181 |
pidfile = NULL; |
182 |
pidfilelock = 0; |
183 |
quiet = 0; |
184 |
execf = NULL; |
185 |
coref = _PATH_DEVNULL; |
186 |
|
187 |
while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ac:d:fg:ij:lnoqs:t:u:vx")) != -1) |
188 |
switch (ch) { |
189 |
case 'D': |
190 |
debug_opt++; |
191 |
break; |
192 |
case 'F': |
193 |
pidfile = optarg; |
194 |
criteria = 1; |
195 |
break; |
196 |
case 'G': |
197 |
makelist(&rgidlist, LT_GROUP, optarg); |
198 |
criteria = 1; |
199 |
break; |
200 |
case 'I': |
201 |
if (pgrep) |
202 |
usage(); |
203 |
interactive = 1; |
204 |
break; |
205 |
case 'L': |
206 |
pidfilelock = 1; |
207 |
break; |
208 |
case 'M': |
209 |
coref = optarg; |
210 |
break; |
211 |
case 'N': |
212 |
execf = optarg; |
213 |
break; |
214 |
case 'P': |
215 |
makelist(&ppidlist, LT_GENERIC, optarg); |
216 |
criteria = 1; |
217 |
break; |
218 |
case 'S': |
219 |
if (!pgrep) |
220 |
usage(); |
221 |
kthreads = 1; |
222 |
break; |
223 |
case 'U': |
224 |
makelist(&ruidlist, LT_USER, optarg); |
225 |
criteria = 1; |
226 |
break; |
227 |
case 'a': |
228 |
ancestors++; |
229 |
break; |
230 |
case 'c': |
231 |
makelist(&classlist, LT_CLASS, optarg); |
232 |
criteria = 1; |
233 |
break; |
234 |
case 'd': |
235 |
if (!pgrep) |
236 |
usage(); |
237 |
delim = optarg; |
238 |
break; |
239 |
case 'f': |
240 |
matchargs = 1; |
241 |
break; |
242 |
case 'g': |
243 |
makelist(&pgrplist, LT_PGRP, optarg); |
244 |
criteria = 1; |
245 |
break; |
246 |
case 'i': |
247 |
cflags |= REG_ICASE; |
248 |
break; |
249 |
case 'j': |
250 |
makelist(&jidlist, LT_JAIL, optarg); |
251 |
criteria = 1; |
252 |
break; |
253 |
case 'l': |
254 |
longfmt = 1; |
255 |
break; |
256 |
case 'n': |
257 |
newest = 1; |
258 |
criteria = 1; |
259 |
break; |
260 |
case 'o': |
261 |
oldest = 1; |
262 |
criteria = 1; |
263 |
break; |
264 |
case 'q': |
265 |
if (!pgrep) |
266 |
usage(); |
267 |
quiet = 1; |
268 |
break; |
269 |
case 's': |
270 |
makelist(&sidlist, LT_SID, optarg); |
271 |
criteria = 1; |
272 |
break; |
273 |
case 't': |
274 |
makelist(&tdevlist, LT_TTY, optarg); |
275 |
criteria = 1; |
276 |
break; |
277 |
case 'u': |
278 |
makelist(&euidlist, LT_USER, optarg); |
279 |
criteria = 1; |
280 |
break; |
281 |
case 'v': |
282 |
inverse = 1; |
283 |
break; |
284 |
case 'x': |
285 |
fullmatch = 1; |
286 |
break; |
287 |
default: |
288 |
usage(); |
289 |
/* NOTREACHED */ |
290 |
} |
291 |
|
292 |
argc -= optind; |
293 |
argv += optind; |
294 |
if (argc != 0) |
295 |
criteria = 1; |
296 |
if (!criteria) |
297 |
usage(); |
298 |
if (newest && oldest) |
299 |
errx(STATUS_ERROR, "Options -n and -o are mutually exclusive"); |
300 |
if (pidfile != NULL) |
301 |
pidfromfile = takepid(pidfile, pidfilelock); |
302 |
else { |
303 |
if (pidfilelock) { |
304 |
errx(STATUS_ERROR, |
305 |
"Option -L doesn't make sense without -F"); |
306 |
} |
307 |
pidfromfile = -1; |
308 |
} |
309 |
|
310 |
mypid = getpid(); |
311 |
|
312 |
/* |
313 |
* Retrieve the list of running processes from the kernel. |
314 |
*/ |
315 |
kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); |
316 |
if (kd == NULL) |
317 |
errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); |
318 |
|
319 |
/* |
320 |
* Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we |
321 |
* just want processes and not individual kernel threads. |
322 |
*/ |
323 |
plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); |
324 |
if (plist == NULL) { |
325 |
errx(STATUS_ERROR, "Cannot get process list (%s)", |
326 |
kvm_geterr(kd)); |
327 |
} |
328 |
|
329 |
/* |
330 |
* Allocate memory which will be used to keep track of the |
331 |
* selection. |
332 |
*/ |
333 |
if ((selected = malloc(nproc)) == NULL) { |
334 |
err(STATUS_ERROR, "Cannot allocate memory for %d processes", |
335 |
nproc); |
336 |
} |
337 |
memset(selected, 0, nproc); |
338 |
|
339 |
/* |
340 |
* Refine the selection. |
341 |
*/ |
342 |
for (; *argv != NULL; argv++) { |
343 |
if ((rv = regcomp(®, *argv, cflags)) != 0) { |
344 |
regerror(rv, ®, buf, sizeof(buf)); |
345 |
errx(STATUS_BADUSAGE, |
346 |
"Cannot compile regular expression `%s' (%s)", |
347 |
*argv, buf); |
348 |
} |
349 |
|
350 |
for (i = 0, kp = plist; i < nproc; i++, kp++) { |
351 |
if (PSKIP(kp)) { |
352 |
if (debug_opt > 0) |
353 |
fprintf(stderr, "* Skipped %5d %3d %s\n", |
354 |
kp->ki_pid, kp->ki_uid, kp->ki_comm); |
355 |
continue; |
356 |
} |
357 |
|
358 |
if (matchargs && |
359 |
(pargv = kvm_getargv(kd, kp, 0)) != NULL) { |
360 |
jsz = 0; |
361 |
while (jsz < sizeof(buf) && *pargv != NULL) { |
362 |
jsz += snprintf(buf + jsz, |
363 |
sizeof(buf) - jsz, |
364 |
pargv[1] != NULL ? "%s " : "%s", |
365 |
pargv[0]); |
366 |
pargv++; |
367 |
} |
368 |
mstr = buf; |
369 |
} else |
370 |
mstr = kp->ki_comm; |
371 |
|
372 |
rv = regexec(®, mstr, 1, ®match, 0); |
373 |
if (rv == 0) { |
374 |
if (fullmatch) { |
375 |
if (regmatch.rm_so == 0 && |
376 |
regmatch.rm_eo == |
377 |
(off_t)strlen(mstr)) |
378 |
selected[i] = 1; |
379 |
} else |
380 |
selected[i] = 1; |
381 |
} else if (rv != REG_NOMATCH) { |
382 |
regerror(rv, ®, buf, sizeof(buf)); |
383 |
errx(STATUS_ERROR, |
384 |
"Regular expression evaluation error (%s)", |
385 |
buf); |
386 |
} |
387 |
if (debug_opt > 1) { |
388 |
const char *rv_res = "NoMatch"; |
389 |
if (selected[i]) |
390 |
rv_res = "Matched"; |
391 |
fprintf(stderr, "* %s %5d %3d %s\n", rv_res, |
392 |
kp->ki_pid, kp->ki_uid, mstr); |
393 |
} |
394 |
} |
395 |
|
396 |
regfree(®); |
397 |
} |
398 |
|
399 |
for (i = 0, kp = plist; i < nproc; i++, kp++) { |
400 |
if (PSKIP(kp)) |
401 |
continue; |
402 |
|
403 |
if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { |
404 |
selected[i] = 0; |
405 |
continue; |
406 |
} |
407 |
|
408 |
SLIST_FOREACH(li, &ruidlist, li_chain) |
409 |
if (kp->ki_ruid == (uid_t)li->li_number) |
410 |
break; |
411 |
if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { |
412 |
selected[i] = 0; |
413 |
continue; |
414 |
} |
415 |
|
416 |
SLIST_FOREACH(li, &rgidlist, li_chain) |
417 |
if (kp->ki_rgid == (gid_t)li->li_number) |
418 |
break; |
419 |
if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { |
420 |
selected[i] = 0; |
421 |
continue; |
422 |
} |
423 |
|
424 |
SLIST_FOREACH(li, &euidlist, li_chain) |
425 |
if (kp->ki_uid == (uid_t)li->li_number) |
426 |
break; |
427 |
if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { |
428 |
selected[i] = 0; |
429 |
continue; |
430 |
} |
431 |
|
432 |
SLIST_FOREACH(li, &ppidlist, li_chain) |
433 |
if (kp->ki_ppid == (pid_t)li->li_number) |
434 |
break; |
435 |
if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { |
436 |
selected[i] = 0; |
437 |
continue; |
438 |
} |
439 |
|
440 |
SLIST_FOREACH(li, &pgrplist, li_chain) |
441 |
if (kp->ki_pgid == (pid_t)li->li_number) |
442 |
break; |
443 |
if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { |
444 |
selected[i] = 0; |
445 |
continue; |
446 |
} |
447 |
|
448 |
SLIST_FOREACH(li, &tdevlist, li_chain) { |
449 |
if (li->li_number == -1 && |
450 |
(kp->ki_flag & P_CONTROLT) == 0) |
451 |
break; |
452 |
if (kp->ki_tdev == (dev_t)li->li_number) |
453 |
break; |
454 |
} |
455 |
if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { |
456 |
selected[i] = 0; |
457 |
continue; |
458 |
} |
459 |
|
460 |
SLIST_FOREACH(li, &sidlist, li_chain) |
461 |
if (kp->ki_sid == (pid_t)li->li_number) |
462 |
break; |
463 |
if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { |
464 |
selected[i] = 0; |
465 |
continue; |
466 |
} |
467 |
|
468 |
SLIST_FOREACH(li, &jidlist, li_chain) { |
469 |
/* A particular jail ID, including 0 (not in jail) */ |
470 |
if (kp->ki_jid == (int)li->li_number) |
471 |
break; |
472 |
/* Any jail */ |
473 |
if (kp->ki_jid > 0 && li->li_number == -1) |
474 |
break; |
475 |
} |
476 |
if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { |
477 |
selected[i] = 0; |
478 |
continue; |
479 |
} |
480 |
|
481 |
SLIST_FOREACH(li, &classlist, li_chain) { |
482 |
/* |
483 |
* We skip P_SYSTEM processes to match ps(1) output. |
484 |
*/ |
485 |
if ((kp->ki_flag & P_SYSTEM) == 0 && |
486 |
strcmp(kp->ki_loginclass, li->li_name) == 0) |
487 |
break; |
488 |
} |
489 |
if (SLIST_FIRST(&classlist) != NULL && li == NULL) { |
490 |
selected[i] = 0; |
491 |
continue; |
492 |
} |
493 |
|
494 |
if (argc == 0) |
495 |
selected[i] = 1; |
496 |
} |
497 |
|
498 |
if (!ancestors) { |
499 |
pid = mypid; |
500 |
while (pid) { |
501 |
for (i = 0, kp = plist; i < nproc; i++, kp++) { |
502 |
if (PSKIP(kp)) |
503 |
continue; |
504 |
if (kp->ki_pid == pid) { |
505 |
selected[i] = 0; |
506 |
pid = kp->ki_ppid; |
507 |
break; |
508 |
} |
509 |
} |
510 |
if (i == nproc) { |
511 |
if (pid == mypid) |
512 |
pid = getppid(); |
513 |
else |
514 |
break; /* Maybe we're in a jail ? */ |
515 |
} |
516 |
} |
517 |
} |
518 |
|
519 |
if (newest || oldest) { |
520 |
best_tval.tv_sec = 0; |
521 |
best_tval.tv_usec = 0; |
522 |
bestidx = -1; |
523 |
|
524 |
for (i = 0, kp = plist; i < nproc; i++, kp++) { |
525 |
if (!selected[i]) |
526 |
continue; |
527 |
if (bestidx == -1) { |
528 |
/* The first entry of the list which matched. */ |
529 |
; |
530 |
} else if (timercmp(&kp->ki_start, &best_tval, >)) { |
531 |
/* This entry is newer than previous "best". */ |
532 |
if (oldest) /* but we want the oldest */ |
533 |
continue; |
534 |
} else { |
535 |
/* This entry is older than previous "best". */ |
536 |
if (newest) /* but we want the newest */ |
537 |
continue; |
538 |
} |
539 |
/* This entry is better than previous "best" entry. */ |
540 |
best_tval.tv_sec = kp->ki_start.tv_sec; |
541 |
best_tval.tv_usec = kp->ki_start.tv_usec; |
542 |
bestidx = i; |
543 |
} |
544 |
|
545 |
memset(selected, 0, nproc); |
546 |
if (bestidx != -1) |
547 |
selected[bestidx] = 1; |
548 |
} |
549 |
|
550 |
/* |
551 |
* Take the appropriate action for each matched process, if any. |
552 |
*/ |
553 |
did_action = 0; |
554 |
for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { |
555 |
if (PSKIP(kp)) |
556 |
continue; |
557 |
if (selected[i]) { |
558 |
if (longfmt && !pgrep) { |
559 |
did_action = 1; |
560 |
printf("kill -%d %d\n", signum, kp->ki_pid); |
561 |
} |
562 |
if (inverse) |
563 |
continue; |
564 |
} else if (!inverse) |
565 |
continue; |
566 |
rv |= (*action)(kp); |
567 |
} |
568 |
if (!did_action && !pgrep && longfmt) |
569 |
fprintf(stderr, |
570 |
"No matching processes belonging to you were found\n"); |
571 |
|
572 |
exit(rv ? STATUS_MATCH : STATUS_NOMATCH); |
573 |
} |
574 |
|
575 |
static void |
576 |
usage(void) |
577 |
{ |
578 |
const char *ustr; |
579 |
|
580 |
if (pgrep) |
581 |
ustr = "[-LSfilnoqvx] [-d delim]"; |
582 |
else |
583 |
ustr = "[-signal] [-ILfilnovx]"; |
584 |
|
585 |
fprintf(stderr, |
586 |
"usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" |
587 |
" [-P ppid] [-U uid] [-c class] [-g pgrp] [-j jail]\n" |
588 |
" [-s sid] [-t tty] [-u euid] pattern ...\n", |
589 |
getprogname(), ustr); |
590 |
|
591 |
exit(STATUS_BADUSAGE); |
592 |
} |
593 |
|
594 |
static void |
595 |
show_process(const struct kinfo_proc *kp) |
596 |
{ |
597 |
char **argv; |
598 |
|
599 |
if (quiet) { |
600 |
assert(pgrep); |
601 |
return; |
602 |
} |
603 |
if ((longfmt || !pgrep) && matchargs && |
604 |
(argv = kvm_getargv(kd, kp, 0)) != NULL) { |
605 |
printf("%d ", (int)kp->ki_pid); |
606 |
for (; *argv != NULL; argv++) { |
607 |
printf("%s", *argv); |
608 |
if (argv[1] != NULL) |
609 |
putchar(' '); |
610 |
} |
611 |
} else if (longfmt || !pgrep) |
612 |
printf("%d %s", (int)kp->ki_pid, kp->ki_comm); |
613 |
else |
614 |
printf("%d", (int)kp->ki_pid); |
615 |
} |
616 |
|
617 |
static int |
618 |
killact(const struct kinfo_proc *kp) |
619 |
{ |
620 |
int ch, first; |
621 |
|
622 |
if (interactive) { |
623 |
/* |
624 |
* Be careful, ask before killing. |
625 |
*/ |
626 |
printf("kill "); |
627 |
show_process(kp); |
628 |
printf("? "); |
629 |
fflush(stdout); |
630 |
first = ch = getchar(); |
631 |
while (ch != '\n' && ch != EOF) |
632 |
ch = getchar(); |
633 |
if (first != 'y' && first != 'Y') |
634 |
return (1); |
635 |
} |
636 |
if (kill(kp->ki_pid, signum) == -1) { |
637 |
/* |
638 |
* Check for ESRCH, which indicates that the process |
639 |
* disappeared between us matching it and us |
640 |
* signalling it; don't issue a warning about it. |
641 |
*/ |
642 |
if (errno != ESRCH) |
643 |
warn("signalling pid %d", (int)kp->ki_pid); |
644 |
/* |
645 |
* Return 0 to indicate that the process should not be |
646 |
* considered a match, since we didn't actually get to |
647 |
* signal it. |
648 |
*/ |
649 |
return (0); |
650 |
} |
651 |
return (1); |
652 |
} |
653 |
|
654 |
static int |
655 |
grepact(const struct kinfo_proc *kp) |
656 |
{ |
657 |
|
658 |
show_process(kp); |
659 |
if (!quiet) |
660 |
printf("%s", delim); |
661 |
return (1); |
662 |
} |
663 |
|
664 |
static void |
665 |
makelist(struct listhead *head, enum listtype type, char *src) |
666 |
{ |
667 |
struct list *li; |
668 |
struct passwd *pw; |
669 |
struct group *gr; |
670 |
struct stat st; |
671 |
const char *cp; |
672 |
char *sp, *ep, buf[MAXPATHLEN]; |
673 |
int empty; |
674 |
|
675 |
empty = 1; |
676 |
|
677 |
while ((sp = strsep(&src, ",")) != NULL) { |
678 |
if (*sp == '\0') |
679 |
usage(); |
680 |
|
681 |
if ((li = malloc(sizeof(*li))) == NULL) { |
682 |
err(STATUS_ERROR, "Cannot allocate %zu bytes", |
683 |
sizeof(*li)); |
684 |
} |
685 |
|
686 |
SLIST_INSERT_HEAD(head, li, li_chain); |
687 |
empty = 0; |
688 |
|
689 |
if (type != LT_CLASS) |
690 |
li->li_number = (uid_t)strtol(sp, &ep, 0); |
691 |
|
692 |
if (type != LT_CLASS && *ep == '\0') { |
693 |
switch (type) { |
694 |
case LT_PGRP: |
695 |
if (li->li_number == 0) |
696 |
li->li_number = getpgrp(); |
697 |
break; |
698 |
case LT_SID: |
699 |
if (li->li_number == 0) |
700 |
li->li_number = getsid(mypid); |
701 |
break; |
702 |
case LT_JAIL: |
703 |
if (li->li_number < 0) |
704 |
errx(STATUS_BADUSAGE, |
705 |
"Negative jail ID `%s'", sp); |
706 |
/* For compatibility with old -j */ |
707 |
if (li->li_number == 0) |
708 |
li->li_number = -1; /* any jail */ |
709 |
break; |
710 |
case LT_TTY: |
711 |
if (li->li_number < 0) |
712 |
errx(STATUS_BADUSAGE, |
713 |
"Negative /dev/pts tty `%s'", sp); |
714 |
snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s", |
715 |
sp); |
716 |
if (stat(buf, &st) != -1) |
717 |
goto foundtty; |
718 |
if (errno == ENOENT) |
719 |
errx(STATUS_BADUSAGE, "No such tty: `" |
720 |
_PATH_DEV "pts/%s'", sp); |
721 |
err(STATUS_ERROR, "Cannot access `" |
722 |
_PATH_DEV "pts/%s'", sp); |
723 |
break; |
724 |
default: |
725 |
break; |
726 |
} |
727 |
continue; |
728 |
} |
729 |
|
730 |
switch (type) { |
731 |
case LT_USER: |
732 |
if ((pw = getpwnam(sp)) == NULL) |
733 |
errx(STATUS_BADUSAGE, "Unknown user `%s'", sp); |
734 |
li->li_number = pw->pw_uid; |
735 |
break; |
736 |
case LT_GROUP: |
737 |
if ((gr = getgrnam(sp)) == NULL) |
738 |
errx(STATUS_BADUSAGE, "Unknown group `%s'", sp); |
739 |
li->li_number = gr->gr_gid; |
740 |
break; |
741 |
case LT_TTY: |
742 |
if (strcmp(sp, "-") == 0) { |
743 |
li->li_number = -1; |
744 |
break; |
745 |
} else if (strcmp(sp, "co") == 0) { |
746 |
cp = "console"; |
747 |
} else { |
748 |
cp = sp; |
749 |
} |
750 |
|
751 |
snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp); |
752 |
if (stat(buf, &st) != -1) |
753 |
goto foundtty; |
754 |
|
755 |
snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp); |
756 |
if (stat(buf, &st) != -1) |
757 |
goto foundtty; |
758 |
|
759 |
if (errno == ENOENT) |
760 |
errx(STATUS_BADUSAGE, "No such tty: `%s'", sp); |
761 |
err(STATUS_ERROR, "Cannot access `%s'", sp); |
762 |
|
763 |
foundtty: if ((st.st_mode & S_IFCHR) == 0) |
764 |
errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp); |
765 |
|
766 |
li->li_number = st.st_rdev; |
767 |
break; |
768 |
case LT_JAIL: { |
769 |
int jid; |
770 |
|
771 |
if (strcmp(sp, "none") == 0) |
772 |
li->li_number = 0; |
773 |
else if (strcmp(sp, "any") == 0) |
774 |
li->li_number = -1; |
775 |
else if ((jid = jail_getid(sp)) != -1) |
776 |
li->li_number = jid; |
777 |
else if (*ep != '\0') |
778 |
errx(STATUS_BADUSAGE, |
779 |
"Invalid jail ID or name `%s'", sp); |
780 |
break; |
781 |
} |
782 |
case LT_CLASS: |
783 |
li->li_number = -1; |
784 |
li->li_name = strdup(sp); |
785 |
if (li->li_name == NULL) |
786 |
err(STATUS_ERROR, "Cannot allocate memory"); |
787 |
break; |
788 |
default: |
789 |
usage(); |
790 |
} |
791 |
} |
792 |
|
793 |
if (empty) |
794 |
usage(); |
795 |
} |
796 |
|
797 |
static int |
798 |
takepid(const char *pidfile, int pidfilelock) |
799 |
{ |
800 |
char *endp, line[BUFSIZ]; |
801 |
FILE *fh; |
802 |
long rval; |
803 |
|
804 |
fh = fopen(pidfile, "r"); |
805 |
if (fh == NULL) |
806 |
err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); |
807 |
|
808 |
if (pidfilelock) { |
809 |
/* |
810 |
* If we can lock pidfile, this means that daemon is not |
811 |
* running, so would be better not to kill some random process. |
812 |
*/ |
813 |
if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { |
814 |
(void)fclose(fh); |
815 |
errx(STATUS_ERROR, "File '%s' can be locked", pidfile); |
816 |
} else { |
817 |
if (errno != EWOULDBLOCK) { |
818 |
errx(STATUS_ERROR, |
819 |
"Error while locking file '%s'", pidfile); |
820 |
} |
821 |
} |
822 |
} |
823 |
|
824 |
if (fgets(line, sizeof(line), fh) == NULL) { |
825 |
if (feof(fh)) { |
826 |
(void)fclose(fh); |
827 |
errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); |
828 |
} |
829 |
(void)fclose(fh); |
830 |
err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); |
831 |
} |
832 |
(void)fclose(fh); |
833 |
|
834 |
rval = strtol(line, &endp, 10); |
835 |
if (*endp != '\0' && !isspace((unsigned char)*endp)) |
836 |
errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); |
837 |
else if (rval < MIN_PID || rval > MAX_PID) |
838 |
errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); |
839 |
return (rval); |
840 |
} |