1 |
|
|
/* $OpenBSD: pkill.c,v 1.38 2015/10/11 03:08:20 deraadt Exp $ */ |
2 |
|
|
/* $NetBSD: pkill.c,v 1.5 2002/10/27 11:49:34 kleink Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (c) 2002 The NetBSD Foundation, Inc. |
6 |
|
|
* All rights reserved. |
7 |
|
|
* |
8 |
|
|
* This code is derived from software contributed to The NetBSD Foundation |
9 |
|
|
* by Andrew Doran. |
10 |
|
|
* |
11 |
|
|
* Redistribution and use in source and binary forms, with or without |
12 |
|
|
* modification, are permitted provided that the following conditions |
13 |
|
|
* are met: |
14 |
|
|
* 1. Redistributions of source code must retain the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer. |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer in the |
18 |
|
|
* documentation and/or other materials provided with the distribution. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 |
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 |
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 |
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <sys/param.h> /* MAXCOMLEN */ |
34 |
|
|
#include <sys/types.h> |
35 |
|
|
#include <sys/sysctl.h> |
36 |
|
|
#include <sys/proc.h> |
37 |
|
|
#include <sys/queue.h> |
38 |
|
|
#include <sys/stat.h> |
39 |
|
|
#include <sys/socket.h> |
40 |
|
|
|
41 |
|
|
#include <stdio.h> |
42 |
|
|
#include <stdlib.h> |
43 |
|
|
#include <stdint.h> |
44 |
|
|
#include <limits.h> |
45 |
|
|
#include <string.h> |
46 |
|
|
#include <unistd.h> |
47 |
|
|
#include <signal.h> |
48 |
|
|
#include <regex.h> |
49 |
|
|
#include <ctype.h> |
50 |
|
|
#include <kvm.h> |
51 |
|
|
#include <err.h> |
52 |
|
|
#include <pwd.h> |
53 |
|
|
#include <grp.h> |
54 |
|
|
#include <errno.h> |
55 |
|
|
|
56 |
|
|
#define STATUS_MATCH 0 |
57 |
|
|
#define STATUS_NOMATCH 1 |
58 |
|
|
#define STATUS_BADUSAGE 2 |
59 |
|
|
#define STATUS_ERROR 3 |
60 |
|
|
|
61 |
|
|
enum listtype { |
62 |
|
|
LT_GENERIC, |
63 |
|
|
LT_USER, |
64 |
|
|
LT_GROUP, |
65 |
|
|
LT_TTY, |
66 |
|
|
LT_PGRP, |
67 |
|
|
LT_SID, |
68 |
|
|
LT_RTABLE |
69 |
|
|
}; |
70 |
|
|
|
71 |
|
|
struct list { |
72 |
|
|
SLIST_ENTRY(list) li_chain; |
73 |
|
|
long li_number; |
74 |
|
|
}; |
75 |
|
|
|
76 |
|
|
SLIST_HEAD(listhead, list); |
77 |
|
|
|
78 |
|
|
struct kinfo_proc *plist; |
79 |
|
|
char *selected; |
80 |
|
|
char *delim = "\n"; |
81 |
|
|
int nproc; |
82 |
|
|
int pgrep; |
83 |
|
|
int signum = SIGTERM; |
84 |
|
|
int newest; |
85 |
|
|
int oldest; |
86 |
|
|
int quiet; |
87 |
|
|
int inverse; |
88 |
|
|
int longfmt; |
89 |
|
|
int matchargs; |
90 |
|
|
int fullmatch; |
91 |
|
|
int confirmkill; |
92 |
|
|
kvm_t *kd; |
93 |
|
|
pid_t mypid; |
94 |
|
|
|
95 |
|
|
struct listhead euidlist = SLIST_HEAD_INITIALIZER(list); |
96 |
|
|
struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list); |
97 |
|
|
struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list); |
98 |
|
|
struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list); |
99 |
|
|
struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list); |
100 |
|
|
struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list); |
101 |
|
|
struct listhead sidlist = SLIST_HEAD_INITIALIZER(list); |
102 |
|
|
struct listhead rtablist = SLIST_HEAD_INITIALIZER(list); |
103 |
|
|
|
104 |
|
|
int main(int, char **); |
105 |
|
|
void usage(void); |
106 |
|
|
int killact(struct kinfo_proc *, int); |
107 |
|
|
int grepact(struct kinfo_proc *, int); |
108 |
|
|
void makelist(struct listhead *, enum listtype, char *); |
109 |
|
|
char *getargv(struct kinfo_proc *); |
110 |
|
|
int askyn(struct kinfo_proc *); |
111 |
|
|
|
112 |
|
|
extern char *__progname; |
113 |
|
|
|
114 |
|
|
char * |
115 |
|
|
getargv(struct kinfo_proc *kp) |
116 |
|
|
{ |
117 |
|
|
static char buf[_POSIX2_LINE_MAX]; |
118 |
|
|
char **pargv; |
119 |
|
|
size_t j; |
120 |
|
|
|
121 |
|
|
if ((pargv = kvm_getargv(kd, kp, 0)) == NULL) { |
122 |
|
|
strlcpy(buf, kp->p_comm, sizeof(buf)); |
123 |
|
|
return buf; |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
j = 0; |
127 |
|
|
while (j < sizeof(buf) && *pargv != NULL) { |
128 |
|
|
int ret; |
129 |
|
|
|
130 |
|
|
ret = snprintf(buf + j, sizeof(buf) - j, |
131 |
|
|
pargv[1] != NULL ? "%s " : "%s", pargv[0]); |
132 |
|
|
if (ret >= sizeof(buf) - j) |
133 |
|
|
j += sizeof(buf) - j - 1; |
134 |
|
|
else if (ret > 0) |
135 |
|
|
j += ret; |
136 |
|
|
pargv++; |
137 |
|
|
} |
138 |
|
|
return buf; |
139 |
|
|
} |
140 |
|
|
|
141 |
|
|
int |
142 |
|
|
main(int argc, char **argv) |
143 |
|
|
{ |
144 |
|
|
extern char *optarg; |
145 |
|
|
extern int optind; |
146 |
|
|
char buf[_POSIX2_LINE_MAX], *mstr, *p, *q; |
147 |
|
|
int i, j, ch, bestidx, rv, criteria; |
148 |
|
|
int (*action)(struct kinfo_proc *, int); |
149 |
|
|
struct kinfo_proc *kp; |
150 |
|
|
struct list *li; |
151 |
|
|
u_int32_t bestsec, bestusec; |
152 |
|
|
regex_t reg; |
153 |
|
|
regmatch_t regmatch; |
154 |
|
|
|
155 |
|
|
if (strcmp(__progname, "pgrep") == 0) { |
156 |
|
|
action = grepact; |
157 |
|
|
pgrep = 1; |
158 |
|
|
} else { |
159 |
|
|
action = killact; |
160 |
|
|
p = argv[1]; |
161 |
|
|
|
162 |
|
|
if (argc > 1 && p[0] == '-') { |
163 |
|
|
p++; |
164 |
|
|
i = (int)strtol(p, &q, 10); |
165 |
|
|
if (*q == '\0') { |
166 |
|
|
signum = i; |
167 |
|
|
argv++; |
168 |
|
|
argc--; |
169 |
|
|
} else { |
170 |
|
|
if (strncasecmp(p, "sig", 3) == 0) |
171 |
|
|
p += 3; |
172 |
|
|
for (i = 1; i < NSIG; i++) |
173 |
|
|
if (strcasecmp(sys_signame[i], p) == 0) |
174 |
|
|
break; |
175 |
|
|
if (i != NSIG) { |
176 |
|
|
signum = i; |
177 |
|
|
argv++; |
178 |
|
|
argc--; |
179 |
|
|
} |
180 |
|
|
} |
181 |
|
|
} |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
criteria = 0; |
185 |
|
|
|
186 |
|
|
while ((ch = getopt(argc, argv, "G:P:T:U:d:fg:Ilnoqs:t:u:vx")) != -1) |
187 |
|
|
switch (ch) { |
188 |
|
|
case 'G': |
189 |
|
|
makelist(&rgidlist, LT_GROUP, optarg); |
190 |
|
|
criteria = 1; |
191 |
|
|
break; |
192 |
|
|
case 'P': |
193 |
|
|
makelist(&ppidlist, LT_GENERIC, optarg); |
194 |
|
|
criteria = 1; |
195 |
|
|
break; |
196 |
|
|
case 'T': |
197 |
|
|
makelist(&rtablist, LT_RTABLE, optarg); |
198 |
|
|
criteria = 1; |
199 |
|
|
break; |
200 |
|
|
case 'U': |
201 |
|
|
makelist(&ruidlist, LT_USER, optarg); |
202 |
|
|
criteria = 1; |
203 |
|
|
break; |
204 |
|
|
case 'd': |
205 |
|
|
if (!pgrep) |
206 |
|
|
usage(); |
207 |
|
|
delim = optarg; |
208 |
|
|
break; |
209 |
|
|
case 'f': |
210 |
|
|
matchargs = 1; |
211 |
|
|
break; |
212 |
|
|
case 'g': |
213 |
|
|
makelist(&pgrplist, LT_PGRP, optarg); |
214 |
|
|
criteria = 1; |
215 |
|
|
break; |
216 |
|
|
case 'I': |
217 |
|
|
confirmkill = 1; |
218 |
|
|
break; |
219 |
|
|
case 'l': |
220 |
|
|
longfmt = 1; |
221 |
|
|
break; |
222 |
|
|
case 'n': |
223 |
|
|
newest = 1; |
224 |
|
|
criteria = 1; |
225 |
|
|
break; |
226 |
|
|
case 'o': |
227 |
|
|
oldest = 1; |
228 |
|
|
criteria = 1; |
229 |
|
|
break; |
230 |
|
|
case 'q': |
231 |
|
|
quiet = 1; |
232 |
|
|
break; |
233 |
|
|
case 's': |
234 |
|
|
makelist(&sidlist, LT_SID, optarg); |
235 |
|
|
criteria = 1; |
236 |
|
|
break; |
237 |
|
|
case 't': |
238 |
|
|
makelist(&tdevlist, LT_TTY, optarg); |
239 |
|
|
criteria = 1; |
240 |
|
|
break; |
241 |
|
|
case 'u': |
242 |
|
|
makelist(&euidlist, LT_USER, optarg); |
243 |
|
|
criteria = 1; |
244 |
|
|
break; |
245 |
|
|
case 'v': |
246 |
|
|
inverse = 1; |
247 |
|
|
break; |
248 |
|
|
case 'x': |
249 |
|
|
fullmatch = 1; |
250 |
|
|
break; |
251 |
|
|
default: |
252 |
|
|
usage(); |
253 |
|
|
/* NOTREACHED */ |
254 |
|
|
} |
255 |
|
|
|
256 |
|
|
argc -= optind; |
257 |
|
|
argv += optind; |
258 |
|
|
if (argc != 0) |
259 |
|
|
criteria = 1; |
260 |
|
|
if (!criteria || (newest && oldest)) |
261 |
|
|
usage(); |
262 |
|
|
|
263 |
|
|
mypid = getpid(); |
264 |
|
|
|
265 |
|
|
/* |
266 |
|
|
* Retrieve the list of running processes from the kernel. |
267 |
|
|
*/ |
268 |
|
|
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf); |
269 |
|
|
if (kd == NULL) |
270 |
|
|
errx(STATUS_ERROR, "kvm_openfiles(): %s", buf); |
271 |
|
|
|
272 |
|
|
plist = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc); |
273 |
|
|
if (plist == NULL) |
274 |
|
|
errx(STATUS_ERROR, "kvm_getprocs() failed"); |
275 |
|
|
|
276 |
|
|
if (matchargs == 0 && confirmkill == 0) { |
277 |
|
|
if (action == killact) { |
278 |
|
|
if (pledge("stdio proc wpath cpath rpath", NULL) == -1) |
279 |
|
|
err(1, "pledge"); |
280 |
|
|
} else if (action == grepact) { |
281 |
|
|
if (pledge("stdio wpath cpath rpath", NULL) == -1) |
282 |
|
|
err(1, "pledge"); |
283 |
|
|
} |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
/* |
287 |
|
|
* Allocate memory which will be used to keep track of the |
288 |
|
|
* selection. |
289 |
|
|
*/ |
290 |
|
|
if ((selected = calloc(nproc, 1)) == NULL) |
291 |
|
|
errx(STATUS_ERROR, "memory allocation failure"); |
292 |
|
|
|
293 |
|
|
/* |
294 |
|
|
* Refine the selection. |
295 |
|
|
*/ |
296 |
|
|
for (; *argv != NULL; argv++) { |
297 |
|
|
if ((rv = regcomp(®, *argv, REG_EXTENDED)) != 0) { |
298 |
|
|
regerror(rv, ®, buf, sizeof(buf)); |
299 |
|
|
errx(STATUS_BADUSAGE, "bad expression: %s", buf); |
300 |
|
|
} |
301 |
|
|
|
302 |
|
|
for (i = 0, kp = plist; i < nproc; i++, kp++) { |
303 |
|
|
if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 || |
304 |
|
|
kp->p_pid == mypid) |
305 |
|
|
continue; |
306 |
|
|
|
307 |
|
|
if (matchargs) |
308 |
|
|
mstr = getargv(kp); |
309 |
|
|
else |
310 |
|
|
mstr = kp->p_comm; |
311 |
|
|
|
312 |
|
|
rv = regexec(®, mstr, 1, ®match, 0); |
313 |
|
|
if (rv == 0) { |
314 |
|
|
if (fullmatch) { |
315 |
|
|
if (regmatch.rm_so == 0 && |
316 |
|
|
regmatch.rm_eo == strlen(mstr)) |
317 |
|
|
selected[i] = 1; |
318 |
|
|
} else |
319 |
|
|
selected[i] = 1; |
320 |
|
|
} else if (rv != REG_NOMATCH) { |
321 |
|
|
regerror(rv, ®, buf, sizeof(buf)); |
322 |
|
|
errx(STATUS_ERROR, "regexec(): %s", buf); |
323 |
|
|
} |
324 |
|
|
} |
325 |
|
|
|
326 |
|
|
regfree(®); |
327 |
|
|
} |
328 |
|
|
|
329 |
|
|
for (i = 0, kp = plist; i < nproc; i++, kp++) { |
330 |
|
|
if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 || |
331 |
|
|
kp->p_pid == mypid) |
332 |
|
|
continue; |
333 |
|
|
|
334 |
|
|
SLIST_FOREACH(li, &ruidlist, li_chain) |
335 |
|
|
if (kp->p_ruid == (uid_t)li->li_number) |
336 |
|
|
break; |
337 |
|
|
if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { |
338 |
|
|
selected[i] = 0; |
339 |
|
|
continue; |
340 |
|
|
} |
341 |
|
|
|
342 |
|
|
SLIST_FOREACH(li, &rgidlist, li_chain) |
343 |
|
|
if (kp->p_rgid == (gid_t)li->li_number) |
344 |
|
|
break; |
345 |
|
|
if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { |
346 |
|
|
selected[i] = 0; |
347 |
|
|
continue; |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
SLIST_FOREACH(li, &euidlist, li_chain) |
351 |
|
|
if (kp->p_uid == (uid_t)li->li_number) |
352 |
|
|
break; |
353 |
|
|
if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { |
354 |
|
|
selected[i] = 0; |
355 |
|
|
continue; |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
SLIST_FOREACH(li, &ppidlist, li_chain) |
359 |
|
|
if (kp->p_ppid == (uid_t)li->li_number) |
360 |
|
|
break; |
361 |
|
|
if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { |
362 |
|
|
selected[i] = 0; |
363 |
|
|
continue; |
364 |
|
|
} |
365 |
|
|
|
366 |
|
|
SLIST_FOREACH(li, &pgrplist, li_chain) |
367 |
|
|
if (kp->p__pgid == (uid_t)li->li_number) |
368 |
|
|
break; |
369 |
|
|
if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { |
370 |
|
|
selected[i] = 0; |
371 |
|
|
continue; |
372 |
|
|
} |
373 |
|
|
|
374 |
|
|
SLIST_FOREACH(li, &tdevlist, li_chain) { |
375 |
|
|
if (li->li_number == -1 && |
376 |
|
|
(kp->p_psflags & PS_CONTROLT) == 0) |
377 |
|
|
break; |
378 |
|
|
if (kp->p_tdev == (uid_t)li->li_number) |
379 |
|
|
break; |
380 |
|
|
} |
381 |
|
|
if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { |
382 |
|
|
selected[i] = 0; |
383 |
|
|
continue; |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
SLIST_FOREACH(li, &sidlist, li_chain) |
387 |
|
|
if (kp->p_sid == (uid_t)li->li_number) |
388 |
|
|
break; |
389 |
|
|
if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { |
390 |
|
|
selected[i] = 0; |
391 |
|
|
continue; |
392 |
|
|
} |
393 |
|
|
|
394 |
|
|
SLIST_FOREACH(li, &rtablist, li_chain) |
395 |
|
|
if (kp->p_rtableid == (u_int32_t)li->li_number) |
396 |
|
|
break; |
397 |
|
|
if (SLIST_FIRST(&rtablist) != NULL && li == NULL) { |
398 |
|
|
selected[i] = 0; |
399 |
|
|
continue; |
400 |
|
|
} |
401 |
|
|
|
402 |
|
|
if (argc == 0) |
403 |
|
|
selected[i] = 1; |
404 |
|
|
} |
405 |
|
|
|
406 |
|
|
if (newest || oldest) { |
407 |
|
|
bestidx = -1; |
408 |
|
|
|
409 |
|
|
if (newest) |
410 |
|
|
bestsec = bestusec = 0; |
411 |
|
|
else |
412 |
|
|
bestsec = bestusec = UINT32_MAX; |
413 |
|
|
|
414 |
|
|
for (i = 0, kp = plist; i < nproc; i++, kp++) { |
415 |
|
|
if (!selected[i]) |
416 |
|
|
continue; |
417 |
|
|
|
418 |
|
|
if ((newest && (kp->p_ustart_sec > bestsec || |
419 |
|
|
(kp->p_ustart_sec == bestsec |
420 |
|
|
&& kp->p_ustart_usec > bestusec))) |
421 |
|
|
|| (oldest && (kp->p_ustart_sec < bestsec || |
422 |
|
|
(kp->p_ustart_sec == bestsec |
423 |
|
|
&& kp->p_ustart_usec < bestusec)))) { |
424 |
|
|
|
425 |
|
|
bestsec = kp->p_ustart_sec; |
426 |
|
|
bestusec = kp->p_ustart_usec; |
427 |
|
|
bestidx = i; |
428 |
|
|
} |
429 |
|
|
} |
430 |
|
|
|
431 |
|
|
memset(selected, 0, nproc); |
432 |
|
|
if (bestidx != -1) |
433 |
|
|
selected[bestidx] = 1; |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
/* |
437 |
|
|
* Take the appropriate action for each matched process, if any. |
438 |
|
|
*/ |
439 |
|
|
rv = STATUS_NOMATCH; |
440 |
|
|
for (i = 0, j = 0, kp = plist; i < nproc; i++, kp++) { |
441 |
|
|
if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 || |
442 |
|
|
kp->p_pid == mypid) |
443 |
|
|
continue; |
444 |
|
|
if (selected[i] == inverse) |
445 |
|
|
continue; |
446 |
|
|
|
447 |
|
|
switch ((*action)(kp, j++)) { |
448 |
|
|
case STATUS_MATCH: |
449 |
|
|
if (rv != STATUS_ERROR) |
450 |
|
|
rv = STATUS_MATCH; |
451 |
|
|
break; |
452 |
|
|
case STATUS_NOMATCH: |
453 |
|
|
j--; |
454 |
|
|
break; |
455 |
|
|
case STATUS_ERROR: |
456 |
|
|
rv = STATUS_ERROR; |
457 |
|
|
break; |
458 |
|
|
} |
459 |
|
|
} |
460 |
|
|
if (pgrep && j && !quiet) |
461 |
|
|
putchar('\n'); |
462 |
|
|
|
463 |
|
|
exit(rv); |
464 |
|
|
} |
465 |
|
|
|
466 |
|
|
void |
467 |
|
|
usage(void) |
468 |
|
|
{ |
469 |
|
|
const char *ustr; |
470 |
|
|
|
471 |
|
|
if (pgrep) |
472 |
|
|
ustr = "[-flnoqvx] [-d delim]"; |
473 |
|
|
else |
474 |
|
|
ustr = "[-signal] [-fIlnoqvx]"; |
475 |
|
|
|
476 |
|
|
fprintf(stderr, "usage: %s %s [-G gid] [-g pgrp] [-P ppid] [-s sid]" |
477 |
|
|
"\n\t[-T rtable] [-t tty] [-U uid] [-u euid] [pattern ...]\n", |
478 |
|
|
__progname, ustr); |
479 |
|
|
|
480 |
|
|
exit(STATUS_BADUSAGE); |
481 |
|
|
} |
482 |
|
|
|
483 |
|
|
int |
484 |
|
|
askyn(struct kinfo_proc *kp) |
485 |
|
|
{ |
486 |
|
|
int first, ch; |
487 |
|
|
|
488 |
|
|
printf("kill %d %.60s? ", (int)kp->p_pid, getargv(kp)); |
489 |
|
|
fflush(stdout); |
490 |
|
|
|
491 |
|
|
first = ch = getchar(); |
492 |
|
|
while (ch != '\n' && ch != EOF) |
493 |
|
|
ch = getchar(); |
494 |
|
|
return (first == 'y' || first == 'Y'); |
495 |
|
|
} |
496 |
|
|
|
497 |
|
|
int |
498 |
|
|
killact(struct kinfo_proc *kp, int dummy) |
499 |
|
|
{ |
500 |
|
|
int doit; |
501 |
|
|
|
502 |
|
|
if (confirmkill) { |
503 |
|
|
doit = askyn(kp); |
504 |
|
|
} else { |
505 |
|
|
if (longfmt && !quiet) |
506 |
|
|
printf("%d %s\n", (int)kp->p_pid, kp->p_comm); |
507 |
|
|
doit = 1; |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
if (doit && kill(kp->p_pid, signum) == -1) { |
511 |
|
|
if (errno == ESRCH) |
512 |
|
|
return (STATUS_NOMATCH); |
513 |
|
|
warn("signalling pid %d", (int)kp->p_pid); |
514 |
|
|
return (STATUS_ERROR); |
515 |
|
|
} |
516 |
|
|
return (STATUS_MATCH); |
517 |
|
|
} |
518 |
|
|
|
519 |
|
|
int |
520 |
|
|
grepact(struct kinfo_proc *kp, int printdelim) |
521 |
|
|
{ |
522 |
|
|
char **argv; |
523 |
|
|
|
524 |
|
|
if (quiet) |
525 |
|
|
return (STATUS_MATCH); |
526 |
|
|
if (longfmt && matchargs) |
527 |
|
|
if ((argv = kvm_getargv(kd, kp, 0)) == NULL) |
528 |
|
|
return (errno == ESRCH ? STATUS_NOMATCH : STATUS_ERROR); |
529 |
|
|
if (printdelim) |
530 |
|
|
fputs(delim, stdout); |
531 |
|
|
if (longfmt && matchargs) { |
532 |
|
|
printf("%d ", (int)kp->p_pid); |
533 |
|
|
for (; *argv != NULL; argv++) { |
534 |
|
|
printf("%s", *argv); |
535 |
|
|
if (argv[1] != NULL) |
536 |
|
|
putchar(' '); |
537 |
|
|
} |
538 |
|
|
} else if (longfmt) |
539 |
|
|
printf("%d %s", (int)kp->p_pid, kp->p_comm); |
540 |
|
|
else |
541 |
|
|
printf("%d", (int)kp->p_pid); |
542 |
|
|
|
543 |
|
|
return (STATUS_MATCH); |
544 |
|
|
} |
545 |
|
|
|
546 |
|
|
void |
547 |
|
|
makelist(struct listhead *head, enum listtype type, char *src) |
548 |
|
|
{ |
549 |
|
|
struct list *li; |
550 |
|
|
struct passwd *pw; |
551 |
|
|
struct group *gr; |
552 |
|
|
struct stat st; |
553 |
|
|
char *sp, *p, buf[PATH_MAX]; |
554 |
|
|
int empty; |
555 |
|
|
|
556 |
|
|
empty = 1; |
557 |
|
|
|
558 |
|
|
while ((sp = strsep(&src, ",")) != NULL) { |
559 |
|
|
if (*sp == '\0') |
560 |
|
|
usage(); |
561 |
|
|
|
562 |
|
|
if ((li = malloc(sizeof(*li))) == NULL) |
563 |
|
|
errx(STATUS_ERROR, "memory allocation failure"); |
564 |
|
|
SLIST_INSERT_HEAD(head, li, li_chain); |
565 |
|
|
empty = 0; |
566 |
|
|
|
567 |
|
|
li->li_number = strtol(sp, &p, 0); |
568 |
|
|
if (*p == '\0') { |
569 |
|
|
switch (type) { |
570 |
|
|
case LT_PGRP: |
571 |
|
|
if (li->li_number == 0) |
572 |
|
|
li->li_number = getpgrp(); |
573 |
|
|
break; |
574 |
|
|
case LT_SID: |
575 |
|
|
if (li->li_number == 0) |
576 |
|
|
li->li_number = getsid(mypid); |
577 |
|
|
break; |
578 |
|
|
case LT_RTABLE: |
579 |
|
|
if (li->li_number < 0 || |
580 |
|
|
li->li_number > RT_TABLEID_MAX) |
581 |
|
|
errx(STATUS_BADUSAGE, |
582 |
|
|
"rtable out of range"); |
583 |
|
|
break; |
584 |
|
|
case LT_TTY: |
585 |
|
|
usage(); |
586 |
|
|
default: |
587 |
|
|
break; |
588 |
|
|
} |
589 |
|
|
continue; |
590 |
|
|
} |
591 |
|
|
|
592 |
|
|
switch (type) { |
593 |
|
|
case LT_USER: |
594 |
|
|
if ((pw = getpwnam(sp)) == NULL) |
595 |
|
|
errx(STATUS_BADUSAGE, "unknown user `%s'", sp); |
596 |
|
|
li->li_number = pw->pw_uid; |
597 |
|
|
break; |
598 |
|
|
case LT_GROUP: |
599 |
|
|
if ((gr = getgrnam(sp)) == NULL) |
600 |
|
|
errx(STATUS_BADUSAGE, "unknown group `%s'", sp); |
601 |
|
|
li->li_number = gr->gr_gid; |
602 |
|
|
break; |
603 |
|
|
case LT_TTY: |
604 |
|
|
if (strcmp(sp, "-") == 0) { |
605 |
|
|
li->li_number = -1; |
606 |
|
|
break; |
607 |
|
|
} else if (strcmp(sp, "co") == 0) |
608 |
|
|
p = "console"; |
609 |
|
|
else if (strncmp(sp, "tty", 3) == 0) |
610 |
|
|
p = sp; |
611 |
|
|
else |
612 |
|
|
p = NULL; |
613 |
|
|
|
614 |
|
|
if (p == NULL) |
615 |
|
|
snprintf(buf, sizeof(buf), "/dev/tty%s", sp); |
616 |
|
|
else |
617 |
|
|
snprintf(buf, sizeof(buf), "/dev/%s", p); |
618 |
|
|
|
619 |
|
|
if (stat(buf, &st) < 0) { |
620 |
|
|
if (errno == ENOENT) |
621 |
|
|
errx(STATUS_BADUSAGE, |
622 |
|
|
"no such tty: `%s'", sp); |
623 |
|
|
err(STATUS_ERROR, "stat(%s)", sp); |
624 |
|
|
} |
625 |
|
|
|
626 |
|
|
if (!S_ISCHR(st.st_mode)) |
627 |
|
|
errx(STATUS_BADUSAGE, "not a tty: `%s'", sp); |
628 |
|
|
|
629 |
|
|
li->li_number = st.st_rdev; |
630 |
|
|
break; |
631 |
|
|
default: |
632 |
|
|
usage(); |
633 |
|
|
} |
634 |
|
|
} |
635 |
|
|
|
636 |
|
|
if (empty) |
637 |
|
|
usage(); |
638 |
|
|
} |