1 /*
2 * pgrep, pkill - find or signal processes by name and other attributes
3 *
4 * Gunnar Ritter, Freiburg i. Br., Germany, March 2003.
5 */
6 /*
7 * Copyright (c) 2003 Gunnar Ritter
8 *
9 * This software is provided 'as-is', without any express or implied
10 * warranty. In no event will the authors be held liable for any damages
11 * arising from the use of this software.
12 *
13 * Permission is granted to anyone to use this software for any purpose,
14 * including commercial applications, and to alter it and redistribute
15 * it freely, subject to the following restrictions:
16 *
17 * 1. The origin of this software must not be misrepresented; you must not
18 * claim that you wrote the original software. If you use this software
19 * in a product, an acknowledgment in the product documentation would be
20 * appreciated but is not required.
21 *
22 * 2. Altered source versions must be plainly marked as such, and must not be
23 * misrepresented as being the original software.
24 *
25 * 3. This notice may not be removed or altered from any source distribution.
26 */
27
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define USED __attribute__ ((used))
30 #elif defined __GNUC__
31 #define USED __attribute__ ((unused))
32 #else
33 #define USED
34 #endif
35 static const char sccsid[] USED = "@(#)pgrep.sl 1.24 (gritter) 1/12/07";
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <errno.h>
45 #include <libgen.h>
46 #include <dirent.h>
47 #include <limits.h>
48 #include <pwd.h>
49 #include <signal.h>
50 #include <grp.h>
51 #include <locale.h>
52 #include <ctype.h>
53 #include <regex.h>
54
55 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
56 && !defined (__APPLE__)
57 #if defined (__hpux)
58 #include <sys/param.h>
59 #include <sys/pstat.h>
60 #elif defined (_AIX)
61 #include <procinfo.h>
62 #define proc process
63 #else /* !__hpux, !_AIX */
64 #ifdef sun
65 #define _STRUCTURED_PROC 1
66 #endif /* sun */
67 #include <sys/procfs.h>
68 #endif /* !__hpux, !_AIX */
69 #endif /* !__linux__, !__NetBSD__, !__OpenBSD__ */
70
71 #if defined (__NetBSD__) || defined (__OpenBSD__) || defined (__APPLE__)
72 #include <kvm.h>
73 #include <sys/param.h>
74 #include <sys/sysctl.h>
75 #if defined (__APPLE__)
76 #include <mach/mach_types.h>
77 #include <mach/task_info.h>
78 #endif /* __APPLE__ */
79 #define proc process
80 #undef p_pgid
81 #define p_pgid p__pgid
82 #endif /* __NetBSD__, __OpenBSD__, __APPLE__ */
83
84 #ifndef PRNODEV
85 #define PRNODEV 0
86 #endif
87
88 #include <blank.h>
89
90 #define PROCDIR "/proc"
91 #define eq(a, b) (strcmp(a, b) == 0)
92
93 enum okay {
94 OKAY,
95 STOP
96 };
97
98 enum valtype {
99 VT_CHAR,
100 VT_INT,
101 VT_UINT,
102 VT_LONG,
103 VT_ULONG
104 };
105
106 union value {
107 char v_char;
108 int v_int;
109 unsigned int v_uint;
110 long v_long;
111 unsigned long v_ulong;
112 };
113
114 struct proc {
115 struct proc *p_nxt; /* next proc structure */
116 pid_t p_pid; /* process id */
117 char p_fname[19]; /* executable name */
118 pid_t p_ppid; /* parent process id */
119 pid_t p_pgid; /* process group id */
120 pid_t p_sid; /* session id */
121 int p_ttydev; /* controlling terminal */
122 char p_psargs[80]; /* process arguments */
123 uid_t p_uid; /* real user id */
124 uid_t p_euid; /* effective user id */
125 gid_t p_gid; /* real group id */
126 gid_t p_egid; /* effective group id */
127 unsigned long p_start; /* start time (in jiffies except BSD) */
128 unsigned long p_size; /* size in kilobytes */
129 int p_match; /* matched this process */
130 };
131
132 enum attype {
133 ATT_PPID, /* parent process id */
134 ATT_PGRP, /* process group id */
135 ATT_SID, /* sessiond id */
136 ATT_EUID, /* effective user id */
137 ATT_UID, /* real user id */
138 ATT_GID, /* real group id */
139 ATT_TTY, /* controlling terminal */
140 ATT_ALL
141 };
142
143 struct attrib {
144 struct attrib *a_nxt; /* next element of list */
145 enum attype a_type; /* type of attribute */
146 long a_val; /* value of attribute */
147 };
148
149 struct attlist {
150 struct attlist *al_nxt; /* next element of list */
151 struct attrib *al_att; /* this attribute */
152 };
153
154 static const char *progname;
155 static pid_t mypid; /* this instance's pid */
156 static unsigned errcnt; /* error count */
157 static int matched; /* a process matched */
158 static int pkill; /* this is the pkill command */
159 static int fflag; /* match against full command line */
160 static int lflag; /* long output format */
161 static int nflag; /* match newest process only */
162 static int oflag; /* match oldest process only */
163 static int vflag; /* reverse matching */
164 static int xflag; /* match exact string */
165 static int signo = SIGTERM; /* signal to send */
166 static int need_euid_egid; /* need euid or egid */
167 static struct attlist *attributes; /* required attributes */
168 static struct proc *processes; /* collected processes */
169 static regex_t *expression; /* regular expression to match */
170 static const char *delimiter; /* delimiter string */
171 static int prdelim; /* print a delimiter (not first proc) */
172
173 static int str_2_sig(const char *, int *);
174
175 static void *
srealloc(void * vp,size_t nbytes)176 srealloc(void *vp, size_t nbytes)
177 {
178 void *p;
179
180 if ((p = realloc(vp, nbytes)) == NULL) {
181 write(2, "no memory\n", 10);
182 exit(3);
183 }
184 return p;
185 }
186
187 static void *
smalloc(size_t nbytes)188 smalloc(size_t nbytes)
189 {
190 return srealloc(NULL, nbytes);
191 }
192
193 static void *
scalloc(size_t nmemb,size_t size)194 scalloc(size_t nmemb, size_t size)
195 {
196 void *p;
197
198 if ((p = (void *)calloc(nmemb, size)) == NULL) {
199 write(2, "no memory\n", 10);
200 exit(3);
201 }
202 return p;
203 }
204
205 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) \
206 && !defined (__OpenBSD__) && !defined (__APPLE__)
207 static void
chdir_to_proc(void)208 chdir_to_proc(void)
209 {
210 static int fd = -1;
211
212 if (fd == -1 && (fd = open(PROCDIR, O_RDONLY)) < 0) {
213 fprintf(stderr, "%s: cannot open %s\n", progname, PROCDIR);
214 exit(3);
215 }
216 if (fchdir(fd) < 0) {
217 fprintf(stderr, "%s: cannot chdir to %s\n", progname, PROCDIR);
218 exit(3);
219 }
220 }
221
222 static union value *
getval(char ** listp,enum valtype type,int separator,int sep2)223 getval(char **listp, enum valtype type, int separator, int sep2)
224 {
225 char *buf;
226 static union value v;
227 const char *cp, *op;
228 char *cq, *x;
229
230 if (**listp == '\0')
231 return NULL;
232 op = *listp;
233 while (**listp != '\0') {
234 if ((separator==' ' ? isspace(**listp) : **listp == separator)
235 || **listp == sep2)
236 break;
237 (*listp)++;
238 }
239 buf = alloca(*listp - op + 1);
240 for (cp = op, cq = buf; cp < *listp; cp++, cq++)
241 *cq = *cp;
242 *cq = '\0';
243 if (**listp) {
244 while ((separator == ' ' ?
245 isspace(**listp) : **listp == separator) ||
246 **listp == sep2)
247 (*listp)++;
248 }
249 switch (type) {
250 case VT_CHAR:
251 if (buf[1] != '\0')
252 return NULL;
253 v.v_char = buf[0];
254 break;
255 case VT_INT:
256 v.v_int = strtol(buf, &x, 10);
257 if (*x != '\0')
258 return NULL;
259 break;
260 case VT_UINT:
261 v.v_uint = strtoul(buf, &x, 10);
262 if (*x != '\0')
263 return NULL;
264 break;
265 case VT_LONG:
266 v.v_long = strtol(buf, &x, 10);
267 if (*x != '\0')
268 return NULL;
269 break;
270 case VT_ULONG:
271 v.v_ulong = strtoul(buf, &x, 10);
272 if (*x != '\0')
273 return NULL;
274 break;
275 }
276 return &v;
277 }
278 #endif /* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */
279
280 static const char *
element(const char ** listp,int override)281 element(const char **listp, int override)
282 {
283 static char *buf;
284 static size_t buflen;
285 const char *cp, *op;
286 char *cq;
287 size_t sz;
288 int stop = ',';
289
290 if (**listp == '\0')
291 return NULL;
292 op = *listp;
293 while (**listp != '\0') {
294 if (**listp == override)
295 stop = '\0';
296 if (stop != '\0' && (**listp == stop || isblank(**listp)))
297 break;
298 (*listp)++;
299 }
300 if (**listp == '\0')
301 return op;
302 if ((sz = *listp - op + 1) > buflen) {
303 buflen = sz;
304 buf = srealloc(buf, buflen);
305 }
306 for (cp = op, cq = buf; cp < *listp; cp++, cq++)
307 *cq = *cp;
308 *cq = '\0';
309 if (**listp) {
310 while (**listp == stop || isblank(**listp))
311 (*listp)++;
312 }
313 return buf;
314 }
315
316 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \
317 !defined (__OpenBSD__) && !defined (__APPLE__)
318
319 #if defined (__linux__) || defined (__FreeBSD__) || defined (__DragonFly__)
320
321 #define GETVAL_REQ(a) if ((v = getval(&cp, (a), ' ', 0)) == NULL) \
322 return STOP
323
324 #define GETVAL_OPT(a) if ((v = getval(&cp, (a), ' ', 0)) == NULL) \
325 goto complete
326
327 #define GETVAL_COMMA(a) if ((v = getval(&cp, (a), ' ', ',')) == NULL) \
328 return STOP
329
330 #endif /* __linux__ || __FreeBSD__ || __DragonFly__ */
331
332
333 #if defined (__linux__)
334 static enum okay
getproc_stat(struct proc * p,pid_t expected_pid)335 getproc_stat(struct proc *p, pid_t expected_pid)
336 {
337 static char *buf;
338 static size_t buflen;
339 union value *v;
340 FILE *fp;
341 char *cp, *cq, *ce;
342 size_t sz, sc;
343
344 if ((fp = fopen("stat", "r")) == NULL)
345 return STOP;
346 for (cp = buf; ;) {
347 const unsigned chunk = 32;
348
349 if (buflen < (sz = cp - buf + chunk)) {
350 sc = cp - buf;
351 buf = srealloc(buf, buflen = sz);
352 cp = &buf[sc];
353 }
354 if ((sz = fread(cp, 1, chunk, fp)) < chunk) {
355 ce = &cp[sz - 1];
356 break;
357 }
358 cp += chunk;
359 }
360 fclose(fp);
361 if (*ce != '\n')
362 return STOP;
363 *ce-- = '\0';
364 cp = buf;
365 GETVAL_REQ(VT_INT);
366 if ((p->p_pid = v->v_int) != expected_pid)
367 return STOP;
368 if (*cp++ != '(')
369 return STOP;
370 for (cq = ce; cq >= cp && *cq != ')'; cq--);
371 if (cq < cp)
372 return STOP;
373 *cq = '\0';
374 strncpy(p->p_fname, cp, sizeof p->p_fname);
375 p->p_fname[sizeof p->p_fname - 1] = '\0';
376 cp = &cq[1];
377 while (isspace(*cp))
378 cp++;
379 GETVAL_REQ(VT_CHAR);
380 if (v->v_char == 'Z')
381 return STOP;
382 GETVAL_REQ(VT_INT);
383 p->p_ppid = v->v_int;
384 GETVAL_REQ(VT_INT);
385 p->p_pgid = v->v_int;
386 GETVAL_REQ(VT_INT);
387 p->p_sid = v->v_int;
388 GETVAL_REQ(VT_INT);
389 p->p_ttydev = v->v_int;
390 GETVAL_REQ(VT_INT);
391 /* tty_pgrp not used */
392 GETVAL_REQ(VT_ULONG);
393 /* flag not used */
394 GETVAL_REQ(VT_ULONG);
395 /* min_flt */
396 GETVAL_REQ(VT_ULONG);
397 /* cmin_flt */
398 GETVAL_REQ(VT_ULONG);
399 /* maj_flt */
400 GETVAL_REQ(VT_ULONG);
401 /* cmaj_flt */
402 GETVAL_REQ(VT_ULONG);
403 /* time */
404 GETVAL_REQ(VT_ULONG);
405 /* stime */
406 GETVAL_REQ(VT_LONG);
407 /* ctime */
408 GETVAL_REQ(VT_LONG);
409 /* cstime */
410 GETVAL_REQ(VT_LONG);
411 /* priority */
412 GETVAL_REQ(VT_LONG);
413 /* nice */
414 GETVAL_REQ(VT_LONG);
415 /* timeout not used */
416 GETVAL_REQ(VT_LONG);
417 /* it_real_value not used */
418 GETVAL_REQ(VT_ULONG);
419 p->p_start = v->v_ulong;
420 GETVAL_REQ(VT_ULONG);
421 p->p_size = (v->v_ulong >> 10);
422 return OKAY;
423 }
424
425 static enum okay
getproc_cmdline(struct proc * p)426 getproc_cmdline(struct proc *p)
427 {
428 FILE *fp;
429 char *cp, *ce;
430 int hadzero = 0, c;
431
432 if ((fp = fopen("cmdline", "r")) != NULL) {
433 cp = p->p_psargs;
434 ce = cp + sizeof p->p_psargs - 1;
435 while (cp < ce && (c = getc(fp)) != EOF) {
436 if (c != '\0') {
437 if (hadzero) {
438 *cp++ = ' ';
439 if (cp == ce)
440 break;
441 hadzero = 0;
442 }
443 *cp++ = c;
444 } else {
445 hadzero = 1;
446 }
447 }
448 *cp = '\0';
449 fclose(fp);
450 }
451 if (*p->p_psargs == '\0' && p->p_size == 0)
452 strcpy(p->p_psargs, p->p_fname);
453 return OKAY;
454 }
455
456 static enum okay
getproc_status(struct proc * p)457 getproc_status(struct proc *p)
458 {
459 char line[LINE_MAX];
460 union value *v;
461 FILE *fp;
462 char *cp;
463 int scanr;
464
465 if ((fp = fopen("status", "r")) == NULL)
466 return STOP;
467 scanr = 0;
468 while (fgets(line, sizeof line, fp) != NULL) {
469 if (strncmp(line, "Uid:", 4) == 0) {
470 cp = &line[4];
471 while (isspace(*cp))
472 cp++;
473 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
474 fclose(fp);
475 return STOP;
476 }
477 p->p_uid = v->v_int;
478 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
479 fclose(fp);
480 return STOP;
481 }
482 p->p_euid = v->v_int;
483 scanr++;
484 } else if (strncmp(line, "Gid:", 4) == 0) {
485 cp = &line[4];
486 while (isspace(*cp))
487 cp++;
488 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
489 fclose(fp);
490 return STOP;
491 }
492 p->p_gid = v->v_int;
493 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
494 fclose(fp);
495 return STOP;
496 }
497 p->p_egid = v->v_int;
498 scanr++;
499 }
500 }
501 fclose(fp);
502 if (scanr != 2)
503 return STOP;
504 return OKAY;
505 }
506
507 static struct proc *
getproc(const char * dir,pid_t expected_pid)508 getproc(const char *dir, pid_t expected_pid)
509 {
510 struct proc *p;
511 enum okay result;
512
513 p = scalloc(1, sizeof *p);
514 if (chdir(dir) == 0) {
515 if ((result = getproc_stat(p, expected_pid)) == OKAY)
516 if ((result = getproc_cmdline(p)) == OKAY)
517 result = getproc_status(p);
518 chdir_to_proc();
519 } else
520 result = STOP;
521 if (result == STOP) {
522 free(p);
523 return NULL;
524 }
525 return p;
526 }
527
528 #elif defined (__FreeBSD__) || defined (__DragonFly__)
529
530 static enum okay
getproc_status(struct proc * p,pid_t expected_pid)531 getproc_status(struct proc *p, pid_t expected_pid)
532 {
533 static char *buf;
534 static size_t buflen;
535 union value *v;
536 FILE *fp;
537 char *cp, *ce, *cq;
538 size_t sz, sc;
539 int mj, mi;
540
541 if ((fp = fopen("status", "r")) == NULL)
542 return STOP;
543 for (cp = buf; ;) {
544 const unsigned chunk = 32;
545
546 if (buflen < (sz = cp - buf + chunk)) {
547 sc = cp - buf;
548 buf = srealloc(buf, buflen = sz);
549 cp = &buf[sc];
550 }
551 if ((sz = fread(cp, 1, chunk, fp)) < chunk) {
552 ce = &cp[sz - 1];
553 break;
554 }
555 cp += chunk;
556 }
557 fclose(fp);
558 if (*ce != '\n')
559 return STOP;
560 *ce-- = '\0';
561 cp = buf;
562 while (*cp != ' ') {
563 if (cp - buf < sizeof p->p_fname - 2)
564 p->p_fname[cp-buf] = *cp;
565 cp++;
566 }
567 if (cp - buf < sizeof p->p_fname - 1)
568 p->p_fname[cp-buf] = '\0';
569 else
570 p->p_fname[sizeof p->p_fname - 1] = '\0';
571 while (*cp == ' ')
572 cp++;
573 GETVAL_REQ(VT_INT);
574 p->p_pid = v->v_int;
575 GETVAL_REQ(VT_INT);
576 p->p_ppid = v->v_int;
577 GETVAL_REQ(VT_INT);
578 p->p_pgid = v->v_int;
579 GETVAL_REQ(VT_INT);
580 p->p_sid = v->v_int;
581 if (isdigit(*cp)) {
582 GETVAL_COMMA(VT_INT);
583 mj = v->v_int;
584 GETVAL_REQ(VT_INT);
585 mi = v->v_int;
586 if (mj != -1 || mi != -1)
587 p->p_ttydev = makedev(mj, mi);
588 } else {
589 struct stat st;
590 char *dev;
591 cq = cp;
592 while (*cp != ' ') cp++;
593 *cp = '\0';
594 dev = smalloc(cp - cq + 8);
595 strcpy(dev, "/dev/");
596 strcpy(&dev[5], cq);
597 if (stat(dev, &st) < 0)
598 p->p_ttydev = PRNODEV;
599 else
600 p->p_ttydev = st.st_rdev;
601 free(dev);
602 *cp = ' ';
603 while (*cp == ' ') cp++;
604 }
605 while (*cp != ' ') cp++; while (*cp == ' ') cp++;
606 /* skip flags */
607 GETVAL_COMMA(VT_LONG);
608 p->p_start = v->v_long;
609 GETVAL_REQ(VT_LONG);
610 /* skip microseconds */
611 while (*cp != ' ') cp++; while (*cp == ' ') cp++;
612 /* skip user time */
613 while (*cp != ' ') cp++; while (*cp == ' ') cp++;
614 /* skip system time */
615 while (*cp != ' ') cp++; while (*cp == ' ') cp++;
616 /* skip wchan message */
617 GETVAL_REQ(VT_INT);
618 p->p_euid = v->v_int;
619 GETVAL_REQ(VT_INT);
620 p->p_uid = v->v_int;
621 GETVAL_COMMA(VT_INT);
622 p->p_gid = v->v_int;
623 GETVAL_COMMA(VT_INT);
624 p->p_egid = v->v_int;
625 return OKAY;
626 }
627
628 static enum okay
getproc_cmdline(struct proc * p)629 getproc_cmdline(struct proc *p)
630 {
631 FILE *fp;
632 char *cp, *ce;
633 int hadzero = 0, c;
634
635 if ((fp = fopen("cmdline", "r")) != NULL) {
636 cp = p->p_psargs;
637 ce = cp + sizeof p->p_psargs - 1;
638 while (cp < ce && (c = getc(fp)) != EOF) {
639 if (c != '\0') {
640 if (hadzero) {
641 *cp++ = ' ';
642 if (cp == ce)
643 break;
644 hadzero = 0;
645 }
646 *cp++ = c;
647 } else {
648 hadzero = 1;
649 }
650 }
651 *cp = '\0';
652 fclose(fp);
653 }
654 if (*p->p_psargs == '\0' && p->p_size == 0)
655 strcpy(p->p_psargs, p->p_fname);
656 return OKAY;
657 }
658
659 static struct proc *
getproc(const char * dir,pid_t expected_pid)660 getproc(const char *dir, pid_t expected_pid)
661 {
662 struct proc *p;
663 enum okay result;
664
665 p = scalloc(1, sizeof *p);
666 if (chdir(dir) == 0) {
667 if ((result = getproc_status(p, expected_pid)) == OKAY)
668 result = getproc_cmdline(p);
669 chdir_to_proc();
670 } else
671 result = STOP;
672 if (result == STOP) {
673 free(p);
674 return NULL;
675 }
676 return p;
677 }
678
679 #else /* !__linux__, !__FreeBSD__, !__DragonFly__ */
680
681 static const char *
concat(const char * dir,const char * base)682 concat(const char *dir, const char *base)
683 {
684 static char *name;
685 static long size;
686 long length;
687 char *np;
688 const char *cp;
689
690 if ((length = strlen(dir) + strlen(base) + 2) > size)
691 name = srealloc(name, size = length);
692 np = name;
693 for (cp = dir; *cp; cp++)
694 *np++ = *cp;
695 *np++ = '/';
696 for (cp = base; *cp; cp++)
697 *np++ = *cp;
698 *np = '\0';
699 return name;
700 }
701
702 static enum okay
getproc_psinfo(const char * dir,struct proc * p,pid_t expected_pid)703 getproc_psinfo(const char *dir, struct proc *p, pid_t expected_pid)
704 {
705 FILE *fp;
706 struct psinfo pi;
707
708 if ((fp = fopen(concat(dir, "psinfo"), "r")) == NULL)
709 return STOP;
710 if (fread(&pi, 1, sizeof pi, fp) != sizeof pi ||
711 pi.pr_pid != expected_pid) {
712 fclose(fp);
713 return STOP;
714 }
715 fclose(fp);
716 p->p_pid = pi.pr_pid;
717 strncpy(p->p_fname, pi.pr_fname, sizeof p->p_fname);
718 p->p_fname[sizeof p->p_fname - 1] = '\0';
719 p->p_ppid = pi.pr_ppid;
720 p->p_pgid = pi.pr_pgid;
721 p->p_sid = pi.pr_sid;
722 p->p_ttydev = pi.pr_ttydev;
723 strncpy(p->p_psargs, pi.pr_psargs, sizeof p->p_psargs);
724 p->p_psargs[sizeof p->p_psargs - 1] = '\0';
725 p->p_uid = pi.pr_uid;
726 p->p_gid = pi.pr_gid;
727 #ifdef __sun
728 p->p_euid = pi.pr_euid;
729 p->p_egid = pi.pr_egid;
730 #endif /* __sun */
731 p->p_start = pi.pr_start.tv_sec;
732 p->p_size = pi.pr_size;
733 return OKAY;
734 }
735
736 #ifndef __sun
737 static enum okay
getproc_cred(const char * dir,struct proc * p)738 getproc_cred(const char *dir, struct proc *p)
739 {
740 FILE *fp;
741 struct prcred pc;
742
743 if ((fp = fopen(concat(dir, "cred"), "r")) == NULL)
744 return need_euid_egid ? STOP : OKAY;
745 if (fread(&pc, 1, sizeof pc, fp) != sizeof pc) {
746 fclose(fp);
747 return STOP;
748 }
749 fclose(fp);
750 p->p_euid = pc.pr_euid;
751 p->p_egid = pc.pr_egid;
752 return OKAY;
753 }
754 #endif /* !__sun */
755
756 static struct proc *
getproc(const char * dir,pid_t expected_pid)757 getproc(const char *dir, pid_t expected_pid)
758 {
759 struct proc *p;
760 enum okay result;
761
762 p = scalloc(1, sizeof *p);
763 result = getproc_psinfo(dir, p, expected_pid);
764 #ifndef __sun
765 if (result == OKAY)
766 result = getproc_cred(dir, p);
767 #endif /* !__sun */
768 if (result == STOP) {
769 free(p);
770 return NULL;
771 }
772 return p;
773 }
774 #endif /* !__linux__ */
775
776 static void
collectprocs(void)777 collectprocs(void)
778 {
779 struct proc *p, *pq = NULL;
780 DIR *Dp;
781 struct dirent *dp;
782 unsigned long val;
783 char *x;
784
785 if ((Dp = opendir(".")) != NULL) {
786 while ((dp = readdir(Dp)) != NULL) {
787 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
788 (dp->d_name[1] == '.' &&
789 dp->d_name[2] == '\0')))
790 continue;
791 val = strtoul(dp->d_name, &x, 10);
792 if (*x != 0)
793 continue;
794 if ((p = getproc(dp->d_name, val)) != NULL) {
795 if (pq)
796 pq->p_nxt = p;
797 else
798 processes = p;
799 pq = p;
800 }
801 }
802 closedir(Dp);
803 }
804 }
805
806 #elif defined (__hpux)
807 static void
collectprocs(void)808 collectprocs(void)
809 {
810 #define burst ((size_t)10)
811 struct proc *p, *pq = NULL;
812 struct pst_status pst[burst];
813 int i, count;
814 int idx = 0;
815
816 while ((count = pstat_getproc(pst, sizeof *pst, burst, idx)) > 0) {
817 for (i = 0; i < count; i++) {
818 p = scalloc(sizeof *p, 1);
819 if (pq)
820 pq->p_nxt = p;
821 else
822 processes = p;
823 pq = p;
824 p->p_pid = pst[i].pst_pid;
825 strncpy(p->p_fname, pst[i].pst_ucomm,
826 sizeof p->p_fname);
827 p->p_fname[sizeof p->p_fname - 1] = '\0';
828 p->p_ppid = pst[i].pst_ppid;
829 p->p_pgid = pst[i].pst_pgrp;
830 p->p_sid = pst[i].pst_sid;
831 if (pst[i].pst_term.psd_major != -1 ||
832 pst[i].pst_term.psd_minor != -1)
833 p->p_ttydev = makedev(pst[i].pst_term.psd_major,
834 pst[i].pst_term.psd_minor);
835 strncpy(p->p_psargs, pst[i].pst_cmd,
836 sizeof p->p_psargs);
837 p->p_psargs[sizeof p->p_psargs - 1] = '\0';
838 p->p_uid = pst[i].pst_uid;
839 p->p_euid = pst[i].pst_euid;
840 p->p_gid = pst[i].pst_gid;
841 p->p_egid = pst[i].pst_egid;
842 p->p_start = pst[i].pst_start;
843 p->p_size = pst[i].pst_dsize + pst[i].pst_tsize +
844 pst[i].pst_ssize;
845 }
846 idx = pst[count-1].pst_idx + 1;
847 }
848 }
849 #elif defined (_AIX)
850 static void
oneproc(struct proc * p,struct procentry64 * pi)851 oneproc(struct proc *p, struct procentry64 *pi)
852 {
853 char args[100], *ap, *cp;
854
855 p->p_pid = pi->pi_pid;
856 strncpy(p->p_fname, pi->pi_comm, sizeof p->p_fname);
857 p->p_fname[sizeof p->p_fname - 1] = '\0';
858 p->p_ppid = pi->pi_ppid;
859 p->p_pgid = pi->pi_pgrp;
860 p->p_sid = pi->pi_sid;
861 p->p_ttydev = pi->pi_ttyp ? pi->pi_ttyd : PRNODEV;
862 p->p_uid = pi->pi_uid;
863 p->p_euid = pi->pi_cred.crx_uid;
864 p->p_gid = pi->pi_cred.crx_rgid;
865 p->p_egid = pi->pi_cred.crx_gid;
866 p->p_start = pi->pi_start;
867 p->p_size = pi->pi_size;
868 if (getargs(pi, sizeof *pi, args, sizeof args) == 0) {
869 ap = args;
870 cp = p->p_psargs;
871 while (cp < &p->p_psargs[sizeof p->p_psargs - 1]) {
872 if (ap[0] == '\0') {
873 if (ap[1] == '\0')
874 break;
875 *cp++ = ' ';
876 } else
877 *cp++ = *ap;
878 ap++;
879 }
880 *cp = '\0';
881 }
882 }
883
884 static void
collectprocs(void)885 collectprocs(void)
886 {
887 #define burst ((size_t)10)
888 struct proc *p, *pq = NULL;
889 struct procentry64 pi[burst];
890 pid_t idx = 0;
891 int i, count;
892
893 while ((count = getprocs64(pi, sizeof *pi, NULL, 0, &idx, burst)) > 0) {
894 for (i = 0; i < count; i++) {
895 p = scalloc(sizeof *p, 1);
896 if (pq)
897 pq->p_nxt = p;
898 else
899 processes = p;
900 pq = p;
901 oneproc(p, &pi[i]);
902 }
903 if (count < burst)
904 break;
905 }
906 }
907 #elif defined (__OpenBSD__)
908 #include <uvm/uvm_extern.h>
909 static void
oneproc(struct proc * p,struct kinfo_proc * kp)910 oneproc(struct proc *p, struct kinfo_proc *kp)
911 {
912 p->p_pid = kp->kp_proc.p_pid;
913 strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname);
914 p->p_fname[sizeof p->p_fname - 1] = '\0';
915 p->p_ppid = kp->kp_eproc.e_ppid;
916 p->p_pgid = kp->kp_eproc.e_pgid;
917 p->p_sid = kp->kp_eproc.e_tpgid; /* ? */
918 p->p_ttydev = kp->kp_eproc.e_tdev;
919 p->p_uid = kp->kp_eproc.e_pcred.p_ruid;
920 p->p_euid = kp->kp_eproc.e_ucred.cr_uid;
921 p->p_gid = kp->kp_eproc.e_pcred.p_rgid;
922 p->p_egid = kp->kp_eproc.e_ucred.cr_gid;
923 p->p_start = kp->kp_eproc.e_pstats.p_start.tv_sec;
924 p->p_size = kp->kp_eproc.e_vm.vm_tsize +
925 kp->kp_eproc.e_vm.vm_dsize +
926 kp->kp_eproc.e_vm.vm_ssize;
927 }
928 static void
argproc(struct proc * p,struct kinfo_proc * kp,kvm_t * kt)929 argproc(struct proc *p, struct kinfo_proc *kp, kvm_t *kt)
930 {
931 char **args;
932 char *ap, *pp;
933
934 if ((args = kvm_getargv(kt, kp, sizeof p->p_psargs)) == NULL)
935 return;
936 ap = args[0];
937 for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
938 if (*ap == '\0') {
939 *pp = ' ';
940 ap = *++args;
941 if (ap == NULL)
942 break;
943 } else
944 *pp = *ap++;
945 }
946 }
947
948 static void
collectprocs(void)949 collectprocs(void)
950 {
951 struct proc *p, *pq = NULL;
952 kvm_t *kt;
953 struct kinfo_proc *kp;
954 int i, cnt;
955
956 if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
957 exit(1);
958 kp = kvm_getprocs(kt, KERN_PROC_ALL, 0, &cnt);
959 for (i = 0; i < cnt; i++) {
960 p = scalloc(sizeof *p, 1);
961 if (pq)
962 pq->p_nxt = p;
963 else
964 processes = p;
965 pq = p;
966 oneproc(p, &kp[i]);
967 argproc(p, &kp[i], kt);
968 }
969 kvm_close(kt);
970 }
971 #elif defined (__NetBSD__)
972 static void
oneproc(struct proc * p,struct kinfo_proc2 * kp)973 oneproc(struct proc *p, struct kinfo_proc2 *kp)
974 {
975 p->p_pid = kp->p_pid;
976 strncpy(p->p_fname, kp->p_comm, sizeof p->p_fname);
977 p->p_fname[sizeof p->p_fname - 1] = '\0';
978 p->p_ppid = kp->p_ppid;
979 p->p_pgid = kp->p__pgid;
980 p->p_sid = kp->p_sid;
981 p->p_ttydev = kp->p_tdev;
982 p->p_uid = kp->p_ruid;
983 p->p_euid = kp->p_uid;
984 p->p_gid = kp->p_rgid;
985 p->p_egid = kp->p_gid;
986 p->p_start = kp->p_ustart_sec;
987 p->p_size = kp->p_vm_tsize + kp->p_vm_dsize + kp->p_vm_ssize;
988 }
989
990 static void
argproc(struct proc * p,struct kinfo_proc2 * kp,kvm_t * kt)991 argproc(struct proc *p, struct kinfo_proc2 *kp, kvm_t *kt)
992 {
993 char **args;
994 char *ap, *pp;
995
996 if ((args = kvm_getargv2(kt, kp, sizeof p->p_psargs)) == NULL)
997 return;
998 ap = args[0];
999 for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
1000 if (*ap == '\0') {
1001 *pp = ' ';
1002 ap = *++args;
1003 if (ap == NULL)
1004 break;
1005 } else
1006 *pp = *ap++;
1007 }
1008 }
1009
1010 static void
collectprocs(void)1011 collectprocs(void)
1012 {
1013 struct proc *p, *pq = NULL;
1014 kvm_t *kt;
1015 struct kinfo_proc2 *kp;
1016 int i, cnt;
1017
1018 if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
1019 exit(1);
1020 kp = kvm_getproc2(kt, KERN_PROC_ALL, 0, sizeof *kp, &cnt);
1021 for (i = 0; i < cnt; i++) {
1022 p = scalloc(sizeof *p, 1);
1023 if (pq)
1024 pq->p_nxt = p;
1025 else
1026 processes = p;
1027 pq = p;
1028 oneproc(p, &kp[i]);
1029 argproc(p, &kp[i], kt);
1030 }
1031 kvm_close(kt);
1032 }
1033 #elif defined (__APPLE__)
1034
1035 static int
GetBSDProcessList(pid_t thepid,struct kinfo_proc ** procList,size_t * procCount)1036 GetBSDProcessList(pid_t thepid, struct kinfo_proc **procList, size_t *procCount)
1037 /* derived from http://developer.apple.com/qa/qa2001/qa1123.html */
1038 /* Returns a list of all BSD processes on the system. This routine
1039 allocates the list and puts it in *procList and a count of the
1040 number of entries in *procCount. You are responsible for freeing
1041 this list (use "free" from System framework).
1042 all classic apps run in one process
1043 On success, the function returns 0.
1044 On error, the function returns a BSD errno value.
1045 Preconditions:
1046 assert( procList != NULL);
1047 assert(*procList == NULL);
1048 assert(procCount != NULL);
1049 Postconditions:
1050 assert( (err == 0) == (*procList != NULL) );
1051 */
1052 {
1053 int err;
1054 struct kinfo_proc *result;
1055 int mib[4];
1056 size_t length;
1057
1058 mib[0] = CTL_KERN;
1059 mib[1] = KERN_PROC;
1060 if (thepid == 0) {
1061 mib[2] = KERN_PROC_ALL;
1062 mib[3] = 0;
1063 } else {
1064 mib[2] = KERN_PROC_PID;
1065 mib[3] = thepid;
1066 }
1067 /* We start by calling sysctl with result == NULL and length == 0.
1068 That will succeed, and set length to the appropriate length.
1069 We then allocate a buffer of that size and call sysctl again
1070 with that buffer.
1071 */
1072 length = 0;
1073 err = sysctl(mib, 4, NULL, &length, NULL, 0);
1074 if (err == -1)
1075 err = errno;
1076 if (err == 0) {
1077 result = smalloc(length);
1078 err = sysctl(mib, 4, result, &length, NULL, 0);
1079 if (err == -1)
1080 err = errno;
1081 if (err == ENOMEM) {
1082 free(result); /* clean up */
1083 result = NULL;
1084 }
1085 }
1086 *procList = result;
1087 *procCount = err == 0 ? length / sizeof **procList : 0;
1088 return err;
1089 }
1090
1091 extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target);
1092
1093 static void
oneproc(struct proc * p,struct kinfo_proc * kp)1094 oneproc(struct proc *p, struct kinfo_proc *kp)
1095 {
1096 task_port_t task;
1097 kern_return_t error;
1098 struct task_basic_info task_binfo;
1099 unsigned int info_count = TASK_BASIC_INFO_COUNT;
1100
1101 p->p_pid = kp->kp_proc.p_pid;
1102 strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname);
1103 p->p_fname[sizeof p->p_fname - 1] = '\0';
1104 p->p_ppid = kp->kp_eproc.e_ppid;
1105 p->p_pgid = kp->kp_eproc.e_pgid;
1106 p->p_sid = kp->kp_eproc.e_tpgid;
1107 p->p_ttydev = kp->kp_eproc.e_tdev == -1 ? PRNODEV : kp->kp_eproc.e_tdev;;
1108 p->p_uid = kp->kp_eproc.e_pcred.p_ruid;
1109 p->p_euid = kp->kp_eproc.e_ucred.cr_uid;
1110 p->p_gid = kp->kp_eproc.e_pcred.p_rgid;
1111 p->p_egid = kp->kp_eproc.e_ucred.cr_gid;
1112 p->p_start = kp->kp_proc.p_starttime.tv_sec +
1113 (kp->kp_proc.p_starttime.tv_usec >= 500000);
1114
1115 error = task_for_pid(mach_task_self(), p->p_pid, &task);
1116 if (error != KERN_SUCCESS) {
1117 return; /* no process, nothing to show/kill */
1118 }
1119
1120 info_count = TASK_BASIC_INFO_COUNT;
1121 error = task_info(task, TASK_BASIC_INFO, &task_binfo, &info_count);
1122 if (error != KERN_SUCCESS) {
1123 fprintf(stderr, "Error calling task_info():%d\n", error);
1124 exit(3);
1125 }
1126
1127 p->p_size = task_binfo.virtual_size / 1024; /* in kilobytes */
1128 }
1129
1130 static void
argproc(struct proc * p,struct kinfo_proc * kp)1131 argproc(struct proc *p, struct kinfo_proc *kp)
1132 {
1133 size_t size, argsz;
1134 char *argbuf;
1135 int mib[3];
1136 long nargs;
1137 char *ap, *pp;
1138
1139 /* allocate a procargs space per process */
1140 mib[0] = CTL_KERN;
1141 mib[1] = KERN_ARGMAX;
1142 size = sizeof argsz;
1143 if (sysctl(mib, 2, &argsz, &size, NULL, 0) == -1) {
1144 fprintf(stderr, "error in sysctl(): %s\n", strerror(errno));
1145 exit(3);
1146 }
1147 argbuf = (char *)smalloc(argsz);
1148
1149 /* fetch the process arguments */
1150 mib[0] = CTL_KERN;
1151 mib[1] = KERN_PROCARGS2;
1152 mib[2] = kp->kp_proc.p_pid;
1153 if (sysctl(mib, 3, argbuf, &argsz, NULL, 0) == -1)
1154 goto DONE; /* process has no args or already left the system */
1155
1156 /* the number of args is at offset 0, this works for 32 and 64bit */
1157 memcpy(&nargs, argbuf, sizeof nargs);
1158 ap = argbuf + sizeof nargs;
1159
1160 /* skip the exec_path */
1161 while (ap < &argbuf[argsz] && *ap != '\0')
1162 ap++;
1163 if (ap == &argbuf[argsz])
1164 goto DONE; /* no args to show */
1165 /* skip trailing '\0' chars */
1166 while (ap < &argbuf[argsz] && *ap == '\0')
1167 ap++;
1168 if (ap == &argbuf[argsz])
1169 goto DONE; /* no args to show */
1170
1171 /* now concat copy the arguments */
1172 for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
1173 if (*ap == '\0') {
1174 if (--nargs == 0)
1175 break;
1176 *pp = ' ';
1177 ++ap;
1178 } else
1179 *pp = *ap++;
1180 }
1181 *pp = '\0';
1182
1183 DONE: free(argbuf);
1184 return;
1185 }
1186
1187 static void
collectprocs(void)1188 collectprocs(void)
1189 {
1190 int mib[2];
1191 struct proc *p, *pq = NULL;
1192 struct kinfo_proc *kp = NULL;
1193 size_t i, cnt;
1194 int err;
1195
1196 if ((err = GetBSDProcessList(0, &kp, &cnt)) != 0) {
1197 fprintf(stderr, "error getting proc list: %s\n", strerror(err));
1198 exit(3);
1199 }
1200 for (i = 0; i < cnt; i++) {
1201 p = smalloc(sizeof *p);
1202 if (pq)
1203 pq->p_nxt = p;
1204 else
1205 processes = p;
1206 pq = p;
1207 oneproc(p, &kp[i]);
1208 argproc(p, &kp[i]);
1209 }
1210 /* free the memory allocated by GetBSDProcessList */
1211 free(kp);
1212 }
1213 #endif /* all */
1214
1215 static enum okay
hasattr(struct proc * p,struct attrib * a)1216 hasattr(struct proc *p, struct attrib *a)
1217 {
1218 long val = 0;
1219
1220 switch (a->a_type) {
1221 case ATT_ALL:
1222 return OKAY;
1223 case ATT_PPID:
1224 val = p->p_ppid;
1225 break;
1226 case ATT_PGRP:
1227 val = p->p_pgid;
1228 break;
1229 case ATT_SID:
1230 val = p->p_sid;
1231 break;
1232 case ATT_EUID:
1233 val = p->p_euid;
1234 break;
1235 case ATT_UID:
1236 val = p->p_uid;
1237 break;
1238 case ATT_GID:
1239 val = p->p_gid;
1240 break;
1241 case ATT_TTY:
1242 /*
1243 * Never matches processes without controlling tty.
1244 */
1245 if (p->p_ttydev == PRNODEV)
1246 return STOP;
1247 val = p->p_ttydev;
1248 break;
1249 }
1250 return val == a->a_val ? OKAY : STOP;
1251 }
1252
1253 static void
tryproc(struct proc * p)1254 tryproc(struct proc *p)
1255 {
1256 struct attlist *alp;
1257 struct attrib *ap;
1258 const char *line;
1259 regmatch_t where;
1260
1261 for (alp = attributes; alp; alp = alp->al_nxt) {
1262 for (ap = alp->al_att; ap; ap = ap->a_nxt)
1263 if (hasattr(p, ap) == OKAY)
1264 break;
1265 if (ap == NULL)
1266 return;
1267 }
1268 if (expression) {
1269 line = fflag ? p->p_psargs : p->p_fname;
1270 if (regexec(expression, line, 1, &where, 0) != 0)
1271 return;
1272 if (xflag && (where.rm_so != 0 || where.rm_eo == -1 ||
1273 line[where.rm_eo] != '\0'))
1274 return;
1275 }
1276 p->p_match = 1;
1277 }
1278
1279 static void
selectprocs(void)1280 selectprocs(void)
1281 {
1282 struct proc *p;
1283
1284 for (p = processes; p; p = p->p_nxt)
1285 tryproc(p);
1286 }
1287
1288 static void
outproc(struct proc * p)1289 outproc(struct proc *p)
1290 {
1291 if (pkill) {
1292 if (kill(p->p_pid, signo) < 0)
1293 fprintf(stderr,
1294 "%s: Failed to signal pid %ld: %s\n",
1295 progname, (long)p->p_pid, strerror(errno));
1296 } else {
1297 if (delimiter && prdelim++)
1298 printf("%s", delimiter);
1299 if (lflag)
1300 printf("%5ld %s", (long)p->p_pid,
1301 fflag ? p->p_psargs : p->p_fname);
1302 else
1303 printf("%ld", (long)p->p_pid);
1304 if (delimiter == NULL)
1305 printf("\n");
1306 }
1307 }
1308
1309 static void
handleprocs(void)1310 handleprocs(void)
1311 {
1312 struct proc *p, *selected = NULL;
1313
1314 for (p = processes; p; p = p->p_nxt) {
1315 if (p->p_pid != mypid && p->p_match ^ vflag) {
1316 matched = 1;
1317 if (nflag) {
1318 if (selected == NULL ||
1319 p->p_start >= selected->p_start)
1320 selected = p;
1321 } else if (oflag) {
1322 if (selected == NULL ||
1323 p->p_start < selected->p_start)
1324 selected = p;
1325 } else
1326 outproc(p);
1327 }
1328 }
1329 if ((nflag || oflag) && selected)
1330 outproc(selected);
1331 if (prdelim && delimiter)
1332 printf("\n");
1333 }
1334
1335 static long
getrdev(const char * device)1336 getrdev(const char *device)
1337 {
1338 struct stat st;
1339 long id = 0;
1340 char *file;
1341
1342 file = alloca(strlen(device) + 9);
1343 strcpy(file, "/dev/");
1344 strcpy(&file[5], device);
1345 if (stat(file, &st) < 0) {
1346 strcpy(file, "/dev/tty/");
1347 strcpy(&file[8], device);
1348 if (stat(file, &st) == 0)
1349 id = st.st_rdev;
1350 else {
1351 fprintf(stderr, "%s: unknown terminal name -- %s\n",
1352 progname, device);
1353 exit(2);
1354 }
1355 } else
1356 id = st.st_rdev;
1357 return id;
1358 }
1359
1360 static struct attrib *
makatt(enum attype at,const char * string,int optc,struct attrib * aq)1361 makatt(enum attype at, const char *string, int optc, struct attrib *aq)
1362 {
1363 struct attrib *ap;
1364 struct passwd *pwd;
1365 struct group *grp;
1366 char *x;
1367 long val = 0;
1368
1369 if (*string == '\0')
1370 at = ATT_ALL;
1371 else switch (at) {
1372 case ATT_PPID:
1373 case ATT_PGRP:
1374 case ATT_SID:
1375 val = strtol(string, &x, 10);
1376 if (*x != '\0' || *string == '+' || *string == '-') {
1377 fprintf(stderr,
1378 "%s: invalid argument for option '%c' -- %s\n",
1379 progname, optc, string);
1380 exit(2);
1381 }
1382 if (val == 0) switch (at) {
1383 case ATT_PGRP:
1384 val = getpgid(0);
1385 break;
1386 case ATT_SID:
1387 val = getsid(0);
1388 break;
1389 }
1390 break;
1391 case ATT_EUID:
1392 need_euid_egid = 1;
1393 /*FALLTHRU*/
1394 case ATT_UID:
1395 if ((pwd = getpwnam(string)) != NULL)
1396 val = pwd->pw_uid;
1397 else {
1398 val = strtol(string, &x, 10);
1399 if (*x != '\0' || *string == '+' || *string == '-') {
1400 fprintf(stderr,
1401 "%s: invalid user name -- %s\n",
1402 progname, string);
1403 exit(2);
1404 }
1405 }
1406 break;
1407 case ATT_GID:
1408 if ((grp = getgrnam(string)) != NULL)
1409 val = grp->gr_gid;
1410 else {
1411 val = strtol(string, &x, 10);
1412 if (*x != '\0' || *string == '+' || *string == '-') {
1413 fprintf(stderr,
1414 "%s: invalid group name -- %s\n",
1415 progname, string);
1416 exit(2);
1417 }
1418 }
1419 break;
1420 case ATT_TTY:
1421 val = getrdev(string);
1422 break;
1423 }
1424 ap = scalloc(1, sizeof *ap);
1425 ap->a_type = at;
1426 ap->a_val = val;
1427 ap->a_nxt = aq;
1428 return ap;
1429 }
1430
1431 static void
addattribs(enum attype at,const char * list,int optc)1432 addattribs(enum attype at, const char *list, int optc)
1433 {
1434 struct attlist *al = NULL;
1435 const char *cp;
1436
1437 for (al = attributes; al; al = al->al_nxt)
1438 if (al->al_att && al->al_att->a_type == at)
1439 break;
1440 if (al == NULL) {
1441 al = scalloc(1, sizeof *al);
1442 al->al_nxt = attributes;
1443 attributes = al;
1444 }
1445 while (*list == ',' || isblank(*list&0377))
1446 list++;
1447 if (*list)
1448 while ((cp = element(&list, '\0')) != NULL)
1449 al->al_att = makatt(at, cp, optc, al->al_att);
1450 else
1451 al->al_att = makatt(at, "", optc, al->al_att);
1452 }
1453
1454 static enum okay
getsig(const char * str)1455 getsig(const char *str)
1456 {
1457 char *x;
1458 int val;
1459
1460 if ((val = strtol(str, &x, 10)) >= 0 && *x == '\0' &&
1461 *str != '-' && *str != '+') {
1462 signo = val;
1463 return OKAY;
1464 }
1465 if (str_2_sig(str, &val) == OKAY) {
1466 signo = val;
1467 return OKAY;
1468 }
1469 return STOP;
1470 }
1471
1472 static void
usage(void)1473 usage(void)
1474 {
1475 if (pkill)
1476 fprintf(stderr, "\
1477 Usage: %s [-signal] [-fnovx] [-P ppidlist] [-g pgrplist] [-s sidlist]\n\
1478 \t[-u euidlist] [-U uidlist] [-G gidlist] [-t termlist] [pattern]\n",
1479 progname);
1480 else
1481 fprintf(stderr, "\
1482 Usage: %s [-flnovx] [-d delim] [-P ppidlist] [-g pgrplist] [-s sidlist]\n\
1483 \t[-u euidlist] [-U uidlist] [-G gidlist] [-t termlist] [pattern]\n",
1484 progname);
1485 exit(2);
1486 }
1487
1488 int
main(int argc,char ** argv)1489 main(int argc, char **argv)
1490 {
1491 int i, flags;
1492
1493 progname = basename(argv[0]);
1494 if (strncmp(progname, "pkill", 5) == 0)
1495 pkill = 1;
1496 setlocale(LC_COLLATE, "");
1497 setlocale(LC_CTYPE, "");
1498 if (pkill && argc > 1 && argv[1][0] == '-' &&
1499 getsig(&argv[1][1]) == OKAY)
1500 optind = 2;
1501 while ((i = getopt(argc, argv, pkill ? "fnovxP:g:s:u:U:G:t:" :
1502 "flnovxd:P:g:s:u:U:G:t:")) != EOF) {
1503 switch (i) {
1504 case 'f':
1505 fflag = 1;
1506 break;
1507 case 'l':
1508 lflag = 1;
1509 break;
1510 case 'n':
1511 nflag = 1;
1512 break;
1513 case 'o':
1514 oflag = 1;
1515 break;
1516 case 'v':
1517 vflag = 1;
1518 break;
1519 case 'x':
1520 xflag = 1;
1521 break;
1522 case 'd':
1523 delimiter = optarg;
1524 break;
1525 case 'P':
1526 addattribs(ATT_PPID, optarg, i);
1527 break;
1528 case 'g':
1529 addattribs(ATT_PGRP, optarg, i);
1530 break;
1531 case 's':
1532 addattribs(ATT_SID, optarg, i);
1533 break;
1534 case 'u':
1535 addattribs(ATT_EUID, optarg, i);
1536 break;
1537 case 'U':
1538 addattribs(ATT_UID, optarg, i);
1539 break;
1540 case 'G':
1541 addattribs(ATT_GID, optarg, i);
1542 break;
1543 case 't':
1544 addattribs(ATT_TTY, optarg, i);
1545 break;
1546 default:
1547 usage();
1548 }
1549 }
1550 if (nflag && oflag) {
1551 fprintf(stderr, "%s: -n and -o are mutually exclusive\n",
1552 progname);
1553 usage();
1554 }
1555 if (argv[optind]) {
1556 if (argv[optind+1]) {
1557 fprintf(stderr, "%s: illegal argument -- %s\n",
1558 progname, argv[optind + 1]);
1559 usage();
1560 }
1561 flags = REG_EXTENDED;
1562 #ifdef REG_MTPARENBAD
1563 flags |= REG_MTPARENBAD;
1564 #endif
1565 if (!xflag)
1566 flags |= REG_NOSUB;
1567 #ifdef REG_ONESUB
1568 else
1569 flags |= REG_ONESUB;
1570 #endif
1571 expression = scalloc(1, sizeof *expression);
1572 if ((i = regcomp(expression, argv[optind], flags)) != 0) {
1573 char *errst;
1574 size_t errsz;
1575
1576 errsz = regerror(i, expression, NULL, 0) + 1;
1577 errst = smalloc(errsz);
1578 regerror(i, expression, errst, errsz);
1579 fprintf(stderr, "%s: %s\n", progname, errst);
1580 exit(2);
1581 }
1582 } else if (attributes == NULL) {
1583 fprintf(stderr, "%s: No matching criteria specified\n",
1584 progname);
1585 usage();
1586 }
1587 mypid = getpid();
1588 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \
1589 !defined (__OpenBSD__) && !defined (__APPLE__)
1590 chdir_to_proc();
1591 #endif /* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */
1592 collectprocs();
1593 selectprocs();
1594 handleprocs();
1595 return errcnt ? errcnt : matched == 0;
1596 }
1597
1598 struct sig_strlist
1599 {
1600 const int sig_num;
1601 const char *sig_str;
1602 };
1603
1604 static const struct sig_strlist sig_strs[] = {
1605 { 0, "EXIT" },
1606 { SIGHUP, "HUP" },
1607 { SIGINT, "INT" },
1608 { SIGQUIT, "QUIT" },
1609 { SIGILL, "ILL" },
1610 { SIGTRAP, "TRAP" },
1611 { SIGABRT, "ABRT" },
1612 #ifdef SIGIOT
1613 { SIGIOT, "IOT" },
1614 #endif
1615 #ifdef SIGEMT
1616 { SIGEMT, "EMT" },
1617 #endif
1618 #ifdef SIGFPE
1619 { SIGFPE, "FPE" },
1620 #endif
1621 #ifdef SIGKILL
1622 { SIGKILL, "KILL" },
1623 #endif
1624 #ifdef SIGBUS
1625 { SIGBUS, "BUS" },
1626 #endif
1627 #ifdef SIGSEGV
1628 { SIGSEGV, "SEGV" },
1629 #endif
1630 #ifdef SIGSYS
1631 { SIGSYS, "SYS" },
1632 #endif
1633 #ifdef SIGPIPE
1634 { SIGPIPE, "PIPE" },
1635 #endif
1636 #ifdef SIGALRM
1637 { SIGALRM, "ALRM" },
1638 #endif
1639 #ifdef SIGTERM
1640 { SIGTERM, "TERM" },
1641 #endif
1642 #ifdef SIGUSR1
1643 { SIGUSR1, "USR1" },
1644 #endif
1645 #ifdef SIGUSR2
1646 { SIGUSR2, "USR2" },
1647 #endif
1648 #ifdef SIGCLD
1649 { SIGCLD, "CLD" },
1650 #endif
1651 #ifdef SIGCHLD
1652 { SIGCHLD, "CHLD" },
1653 #endif
1654 #ifdef SIGPWR
1655 { SIGPWR, "PWR" },
1656 #endif
1657 #ifdef SIGWINCH
1658 { SIGWINCH, "WINCH" },
1659 #endif
1660 #ifdef SIGURG
1661 { SIGURG, "URG" },
1662 #endif
1663 #ifdef SIGPOLL
1664 { SIGPOLL, "POLL" },
1665 #endif
1666 #ifdef SIGIO
1667 { SIGIO, "IO" },
1668 #endif
1669 #ifdef SIGSTOP
1670 { SIGSTOP, "STOP" },
1671 #endif
1672 #ifdef SIGTSTP
1673 { SIGTSTP, "TSTP" },
1674 #endif
1675 #ifdef SIGCONT
1676 { SIGCONT, "CONT" },
1677 #endif
1678 #ifdef SIGTTIN
1679 { SIGTTIN, "TTIN" },
1680 #endif
1681 #ifdef SIGTTOU
1682 { SIGTTOU, "TTOU" },
1683 #endif
1684 #ifdef SIGVTALRM
1685 { SIGVTALRM, "VTALRM" },
1686 #endif
1687 #ifdef SIGPROF
1688 { SIGPROF, "PROF" },
1689 #endif
1690 #ifdef SIGXCPU
1691 { SIGXCPU, "XCPU" },
1692 #endif
1693 #ifdef SIGXFSZ
1694 { SIGXFSZ, "XFSZ" },
1695 #endif
1696 #ifdef SIGWAITING
1697 { SIGWAITING, "WAITING" },
1698 #endif
1699 #ifdef SIGLWP
1700 { SIGLWP, "LWP" },
1701 #endif
1702 #ifdef SIGFREEZE
1703 { SIGFREEZE, "FREEZE" },
1704 #endif
1705 #ifdef SIGTHAW
1706 { SIGTHAW, "THAW" },
1707 #endif
1708 #ifdef SIGCANCEL
1709 { SIGCANCEL, "CANCEL" },
1710 #endif
1711 #ifdef SIGLOST
1712 { SIGLOST, "LOST" },
1713 #endif
1714 #ifdef SIGSTKFLT
1715 { SIGSTKFLT, "STKFLT" },
1716 #endif
1717 #ifdef SIGINFO
1718 { SIGINFO, "INFO" },
1719 #endif
1720 #ifdef SIG_2_STR_WITH_RT_SIGNALS
1721 { SIGRTMIN, "RTMIN" },
1722 { SIGRTMIN+1, "RTMIN+1" },
1723 { SIGRTMIN+2, "RTMIN+2" },
1724 { SIGRTMIN+3, "RTMIN+3" },
1725 { SIGRTMAX-3, "RTMAX-3" },
1726 { SIGRTMAX-2, "RTMAX-2" },
1727 { SIGRTMAX-1, "RTMAX-1" },
1728 { SIGRTMAX, "RTMAX" },
1729 #endif /* SIG_2_STR_WITH_RT_SIGNALS */
1730 { -1, NULL }
1731 };
1732
1733 static int
str_2_sig(const char * str,int * signum)1734 str_2_sig(const char *str, int *signum)
1735 {
1736 int i;
1737
1738 for (i = 0; sig_strs[i].sig_str; i++)
1739 if (eq(str, sig_strs[i].sig_str))
1740 break;
1741 if (sig_strs[i].sig_str == NULL)
1742 return STOP;
1743 *signum = sig_strs[i].sig_num;
1744 return OKAY;
1745 }
1746