1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/param.h>
31 #include <sys/task.h>
32 #include <sys/contract.h>
33
34 #include <signal.h>
35 #include <unistd.h>
36 #include <dirent.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include <libintl.h>
41 #include <locale.h>
42 #include <stdio.h>
43 #include <fcntl.h>
44 #include <ctype.h>
45 #include <wchar.h>
46 #include <limits.h>
47 #include <libuutil.h>
48 #include <libcontract_priv.h>
49
50 #include <procfs.h>
51 #include <project.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <zone.h>
55
56 #include "psexp.h"
57 #include "pgrep.h"
58
59 #ifndef TEXT_DOMAIN
60 #define TEXT_DOMAIN "SYS_TEST"
61 #endif
62
63 #define OPT_SETB 0x0001 /* Set the bits specified by o_bits */
64 #define OPT_CLRB 0x0002 /* Clear the bits specified by o_bits */
65 #define OPT_FUNC 0x0004 /* Call the function specified by o_func */
66 #define OPT_STR 0x0008 /* Set the string specified by o_ptr */
67 #define OPT_CRIT 0x0010 /* Option is part of selection criteria */
68
69 #define F_LONG_FMT 0x0001 /* Match against long format cmd */
70 #define F_NEWEST 0x0002 /* Match only newest pid */
71 #define F_REVERSE 0x0004 /* Reverse matching criteria */
72 #define F_EXACT_MATCH 0x0008 /* Require exact match */
73 #define F_HAVE_CRIT 0x0010 /* Criteria specified */
74 #define F_OUTPUT 0x0020 /* Some output has been printed */
75 #define F_KILL 0x0040 /* Pkill semantics active (vs pgrep) */
76 #define F_LONG_OUT 0x0080 /* Long output format (pgrep -l) */
77 #define F_OLDEST 0x0100 /* Match only oldest pid */
78
79 static int opt_euid(char, char *);
80 static int opt_uid(char, char *);
81 static int opt_gid(char, char *);
82 static int opt_ppid(char, char *);
83 static int opt_pgrp(char, char *);
84 static int opt_sid(char, char *);
85 static int opt_term(char, char *);
86 static int opt_projid(char, char *);
87 static int opt_taskid(char, char *);
88 static int opt_zoneid(char, char *);
89 static int opt_ctid(char, char *);
90
91 static const char *g_procdir = "/proc"; /* Default procfs mount point */
92 static const char *g_delim = "\n"; /* Default output delimiter */
93 static const char *g_pname; /* Program name for error messages */
94 static ushort_t g_flags; /* Miscellaneous flags */
95
96 static optdesc_t g_optdtab[] = {
97 { 0, 0, 0, 0 }, /* 'A' */
98 { 0, 0, 0, 0 }, /* 'B' */
99 { 0, 0, 0, 0 }, /* 'C' */
100 { OPT_STR, 0, 0, &g_procdir }, /* -D procfsdir */
101 { 0, 0, 0, 0 }, /* 'E' */
102 { 0, 0, 0, 0 }, /* 'F' */
103 { OPT_FUNC | OPT_CRIT, 0, opt_gid, 0 }, /* -G gid */
104 { 0, 0, 0, 0 }, /* 'H' */
105 { 0, 0, 0, 0 }, /* 'I' */
106 { OPT_FUNC | OPT_CRIT, 0, opt_projid, 0 }, /* -J projid */
107 { 0, 0, 0, 0 }, /* 'K' */
108 { 0, 0, 0, 0 }, /* 'L' */
109 { 0, 0, 0, 0 }, /* 'M' */
110 { 0, 0, 0, 0 }, /* 'N' */
111 { 0, 0, 0, 0 }, /* 'O' */
112 { OPT_FUNC | OPT_CRIT, 0, opt_ppid, 0 }, /* -P ppid */
113 { 0, 0, 0, 0 }, /* 'Q' */
114 { 0, 0, 0, 0 }, /* 'R' */
115 { 0, 0, 0, 0 }, /* 'S' */
116 { OPT_FUNC | OPT_CRIT, 0, opt_taskid, 0 }, /* -T taskid */
117 { OPT_FUNC | OPT_CRIT, 0, opt_uid, 0 }, /* -U uid */
118 { 0, 0, 0, 0 }, /* 'V' */
119 { 0, 0, 0, 0 }, /* 'W' */
120 { 0, 0, 0, 0 }, /* 'X' */
121 { 0, 0, 0, 0 }, /* 'Y' */
122 { 0, 0, 0, 0 }, /* 'Z' */
123 { 0, 0, 0, 0 }, /* '[' */
124 { 0, 0, 0, 0 }, /* '\\' */
125 { 0, 0, 0, 0 }, /* ']' */
126 { 0, 0, 0, 0 }, /* '^' */
127 { 0, 0, 0, 0 }, /* '_' */
128 { 0, 0, 0, 0 }, /* '`' */
129 { 0, 0, 0, 0 }, /* 'a' */
130 { 0, 0, 0, 0 }, /* 'b' */
131 { OPT_FUNC | OPT_CRIT, 0, opt_ctid, 0 }, /* -c ctid */
132 { OPT_STR, 0, 0, &g_delim }, /* -d delim */
133 { 0, 0, 0, 0 }, /* 'e' */
134 { OPT_SETB, F_LONG_FMT, 0, &g_flags }, /* -f */
135 { OPT_FUNC | OPT_CRIT, 0, opt_pgrp, 0 }, /* -g pgrp */
136 { 0, 0, 0, 0 }, /* 'h' */
137 { 0, 0, 0, 0 }, /* 'i' */
138 { 0, 0, 0, 0 }, /* 'j' */
139 { 0, 0, 0, 0 }, /* 'k' */
140 { OPT_SETB, F_LONG_OUT, 0, &g_flags }, /* 'l' */
141 { 0, 0, 0, 0 }, /* 'm' */
142 { OPT_SETB, F_NEWEST, 0, &g_flags }, /* -n */
143 { OPT_SETB, F_OLDEST, 0, &g_flags }, /* -o */
144 { 0, 0, 0, 0 }, /* 'p' */
145 { 0, 0, 0, 0 }, /* 'q' */
146 { 0, 0, 0, 0 }, /* 'r' */
147 { OPT_FUNC | OPT_CRIT, 0, opt_sid, 0 }, /* -s sid */
148 { OPT_FUNC | OPT_CRIT, 0, opt_term, 0 }, /* -t term */
149 { OPT_FUNC | OPT_CRIT, 0, opt_euid, 0 }, /* -u euid */
150 { OPT_SETB, F_REVERSE, 0, &g_flags }, /* -v */
151 { 0, 0, 0, 0 }, /* 'w' */
152 { OPT_SETB, F_EXACT_MATCH, 0, &g_flags }, /* -x */
153 { 0, 0, 0, 0 }, /* 'y' */
154 { OPT_FUNC | OPT_CRIT, 0, opt_zoneid, 0 } /* -z zoneid */
155 };
156
157 static const char PGREP_USAGE[] = "\
158 Usage: %s [-flnovx] [-d delim] [-P ppidlist] [-g pgrplist] [-s sidlist]\n\
159 [-u euidlist] [-U uidlist] [-G gidlist] [-J projidlist]\n\
160 [-T taskidlist] [-t termlist] [-z zonelist] [-c ctidlist] [pattern]\n";
161
162 static const char PKILL_USAGE[] = "\
163 Usage: %s [-signal] [-fnovx] [-P ppidlist] [-g pgrplist] [-s sidlist]\n\
164 [-u euidlist] [-U uidlist] [-G gidlist] [-J projidlist]\n\
165 [-T taskidlist] [-t termlist] [-z zonelist] [-c ctidlist] [pattern]\n";
166
167 static const char PGREP_OPTS[] = "flnovxc:d:D:u:U:G:P:g:s:t:z:J:T:";
168 static const char PKILL_OPTS[] = "fnovxc:D:u:U:G:P:g:s:t:z:J:T:";
169
170 static const char LSEP[] = ",\t "; /* Argument list delimiter chars */
171
172 static psexp_t g_psexp; /* Process matching expression */
173 static pid_t g_pid; /* Current pid */
174 static int g_signal = SIGTERM; /* Signal to send */
175
176 static void
print_proc(psinfo_t * psinfo)177 print_proc(psinfo_t *psinfo)
178 {
179 if (g_flags & F_OUTPUT)
180 (void) printf("%s%d", g_delim, (int)psinfo->pr_pid);
181 else {
182 (void) printf("%d", (int)psinfo->pr_pid);
183 g_flags |= F_OUTPUT;
184 }
185 }
186
187 static char *
mbstrip(char * buf,size_t nbytes)188 mbstrip(char *buf, size_t nbytes)
189 {
190 wchar_t wc;
191 char *p;
192 int n;
193
194 buf[nbytes - 1] = '\0';
195 p = buf;
196
197 while (*p != '\0') {
198 n = mbtowc(&wc, p, MB_LEN_MAX);
199
200 if (n < 0 || !iswprint(wc)) {
201 if (n < 0)
202 n = sizeof (char);
203
204 if (nbytes <= n) {
205 *p = '\0';
206 break;
207 }
208
209 (void) memmove(p, p + n, nbytes - n);
210
211 } else {
212 nbytes -= n;
213 p += n;
214 }
215 }
216
217 return (buf);
218 }
219
220 static void
print_proc_long(psinfo_t * psinfo)221 print_proc_long(psinfo_t *psinfo)
222 {
223 char *name;
224
225 if (g_flags & F_LONG_FMT)
226 name = mbstrip(psinfo->pr_psargs, PRARGSZ);
227 else
228 name = psinfo->pr_fname;
229
230 if (g_flags & F_OUTPUT)
231 (void) printf("%s%5d %s", g_delim, (int)psinfo->pr_pid, name);
232 else {
233 (void) printf("%5d %s", (int)psinfo->pr_pid, name);
234 g_flags |= F_OUTPUT;
235 }
236 }
237
238 static void
kill_proc(psinfo_t * psinfo)239 kill_proc(psinfo_t *psinfo)
240 {
241 if (psinfo->pr_pid > 0 && kill(psinfo->pr_pid, g_signal) == -1)
242 uu_warn(gettext("Failed to signal pid %d"),
243 (int)psinfo->pr_pid);
244 }
245
246 static DIR *
open_proc_dir(const char * dirpath)247 open_proc_dir(const char *dirpath)
248 {
249 struct stat buf;
250 DIR *dirp;
251
252 if ((dirp = opendir(dirpath)) == NULL) {
253 uu_warn(gettext("Failed to open %s"), dirpath);
254 return (NULL);
255 }
256
257 if (fstat(dirp->dd_fd, &buf) == -1) {
258 uu_warn(gettext("Failed to stat %s"), dirpath);
259 (void) closedir(dirp);
260 return (NULL);
261 }
262
263 if (strcmp(buf.st_fstype, "proc") != 0) {
264 uu_warn(gettext("%s is not a procfs mount point\n"), dirpath);
265 (void) closedir(dirp);
266 return (NULL);
267 }
268
269 return (dirp);
270 }
271
272 #define NEWER(ps1, ps2) \
273 ((ps1.pr_start.tv_sec > ps2.pr_start.tv_sec) || \
274 (ps1.pr_start.tv_sec == ps2.pr_start.tv_sec && \
275 ps1.pr_start.tv_nsec > ps2.pr_start.tv_nsec))
276
277 static int
scan_proc_dir(const char * dirpath,DIR * dirp,psexp_t * psexp,void (* funcp)(psinfo_t *))278 scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp,
279 void (*funcp)(psinfo_t *))
280 {
281 char procpath[MAXPATHLEN];
282 psinfo_t ps, ops;
283 dirent_t *dent;
284 int procfd;
285
286 int reverse = (g_flags & F_REVERSE) ? 1 : 0;
287 int ovalid = 0, nmatches = 0, flags = 0;
288
289 if (g_flags & F_LONG_FMT)
290 flags |= PSEXP_PSARGS;
291
292 if (g_flags & F_EXACT_MATCH)
293 flags |= PSEXP_EXACT;
294
295 while ((dent = readdir(dirp)) != NULL) {
296
297 if (dent->d_name[0] == '.')
298 continue;
299
300 (void) snprintf(procpath, sizeof (procpath), "%s/%s/psinfo",
301 dirpath, dent->d_name);
302
303 if ((procfd = open(procpath, O_RDONLY)) == -1)
304 continue;
305
306 if ((read(procfd, &ps, sizeof (ps)) == sizeof (psinfo_t)) &&
307 (ps.pr_nlwp != 0) && (ps.pr_pid != g_pid) &&
308 (psexp_match(psexp, &ps, flags) ^ reverse)) {
309
310 if (g_flags & F_NEWEST) {
311 /* LINTED - opsinfo use ok */
312 if (!ovalid || NEWER(ps, ops)) {
313 (void) memcpy(&ops, &ps,
314 sizeof (psinfo_t));
315 ovalid = 1;
316 }
317 } else if (g_flags & F_OLDEST) {
318 if (!ovalid || NEWER(ops, ps)) {
319 (void) memcpy(&ops, &ps,
320 sizeof (psinfo_t));
321 ovalid = 1;
322 }
323 } else {
324 (*funcp)(&ps);
325 nmatches++;
326 }
327 }
328
329 (void) close(procfd);
330 }
331
332 if ((g_flags & (F_NEWEST | F_OLDEST)) && ovalid) {
333 (*funcp)(&ops);
334 nmatches++;
335 }
336
337 return (nmatches);
338 }
339
340 static int
parse_ids(idtab_t * idt,char * arg,int base,int opt,idkey_t zero)341 parse_ids(idtab_t *idt, char *arg, int base, int opt, idkey_t zero)
342 {
343 char *ptr, *next;
344 idkey_t id;
345
346 for (ptr = strtok(arg, LSEP); ptr != NULL; ptr = strtok(NULL, LSEP)) {
347 if ((id = (idkey_t)strtoul(ptr, &next, base)) != 0)
348 idtab_append(idt, id);
349 else
350 idtab_append(idt, zero);
351
352 if (next == ptr || *next != 0) {
353 uu_warn("invalid argument for option '%c' -- %s\n",
354 opt, ptr);
355 return (-1);
356 }
357 }
358
359 return (0);
360 }
361
362 static int
parse_uids(idtab_t * idt,char * arg)363 parse_uids(idtab_t *idt, char *arg)
364 {
365 char *ptr, *next;
366 struct passwd *pwent;
367 idkey_t id;
368
369 for (ptr = strtok(arg, LSEP); ptr != NULL; ptr = strtok(NULL, LSEP)) {
370 if (isdigit(ptr[0])) {
371 id = strtol(ptr, &next, 10);
372
373 if (next != ptr && *next == '\0') {
374 idtab_append(idt, id);
375 continue;
376 }
377 }
378
379 if ((pwent = getpwnam(ptr)) != NULL)
380 idtab_append(idt, pwent->pw_uid);
381 else
382 goto err;
383 }
384
385 return (0);
386
387 err:
388 uu_warn(gettext("invalid user name -- %s\n"), ptr);
389 return (-1);
390 }
391
392 static int
parse_gids(idtab_t * idt,char * arg)393 parse_gids(idtab_t *idt, char *arg)
394 {
395 char *ptr, *next;
396 struct group *grent;
397 idkey_t id;
398
399 for (ptr = strtok(arg, LSEP); ptr != NULL; ptr = strtok(NULL, LSEP)) {
400 if (isdigit(ptr[0])) {
401 id = strtol(ptr, &next, 10);
402
403 if (next != ptr && *next == '\0') {
404 idtab_append(idt, id);
405 continue;
406 }
407 }
408
409 if ((grent = getgrnam(ptr)) != NULL)
410 idtab_append(idt, grent->gr_gid);
411 else
412 goto err;
413 }
414
415 return (0);
416
417 err:
418 uu_warn(gettext("invalid group name -- %s\n"), ptr);
419 return (-1);
420 }
421
422 static int
parse_ttys(idtab_t * idt,char * arg)423 parse_ttys(idtab_t *idt, char *arg)
424 {
425 char devpath[MAXPATHLEN];
426 struct stat buf;
427 char *ptr;
428
429 int seen_console = 0; /* Flag so we only stat syscon and systty once */
430
431 for (ptr = strtok(arg, LSEP); ptr != NULL; ptr = strtok(NULL, LSEP)) {
432 if (strcmp(ptr, "none") == 0) {
433 idtab_append(idt, (idkey_t)PRNODEV);
434 continue;
435 }
436
437 if (strcmp(ptr, "console") == 0) {
438 if (seen_console)
439 continue;
440
441 if (stat("/dev/syscon", &buf) == 0)
442 idtab_append(idt, (idkey_t)buf.st_rdev);
443
444 if (stat("/dev/systty", &buf) == 0)
445 idtab_append(idt, (idkey_t)buf.st_rdev);
446
447 seen_console++;
448 }
449
450 (void) snprintf(devpath, MAXPATHLEN - 1, "/dev/%s", ptr);
451
452 if (stat(devpath, &buf) == -1)
453 goto err;
454
455 idtab_append(idt, (idkey_t)buf.st_rdev);
456 }
457
458 return (0);
459
460 err:
461 uu_warn(gettext("unknown terminal name -- %s\n"), ptr);
462 return (-1);
463 }
464
465 static int
parse_projects(idtab_t * idt,char * arg)466 parse_projects(idtab_t *idt, char *arg)
467 {
468 char *ptr, *next;
469 projid_t projid;
470 idkey_t id;
471
472 for (ptr = strtok(arg, LSEP); ptr != NULL; ptr = strtok(NULL, LSEP)) {
473 if (isdigit(ptr[0])) {
474 id = strtol(ptr, &next, 10);
475
476 if (next != ptr && *next == '\0') {
477 idtab_append(idt, id);
478 continue;
479 }
480 }
481
482 if ((projid = getprojidbyname(ptr)) != -1)
483 idtab_append(idt, projid);
484 else
485 goto err;
486 }
487
488 return (0);
489
490 err:
491 uu_warn(gettext("invalid project name -- %s\n"), ptr);
492 return (-1);
493 }
494
495 static int
parse_zones(idtab_t * idt,char * arg)496 parse_zones(idtab_t *idt, char *arg)
497 {
498 char *ptr;
499 zoneid_t id;
500
501 for (ptr = strtok(arg, LSEP); ptr != NULL; ptr = strtok(NULL, LSEP)) {
502 if (zone_get_id(ptr, &id) != 0) {
503 uu_warn(gettext("invalid zone name -- %s\n"), ptr);
504 return (-1);
505 }
506 idtab_append(idt, id);
507 }
508
509 return (0);
510 }
511
512 /*ARGSUSED*/
513 static int
opt_euid(char c,char * arg)514 opt_euid(char c, char *arg)
515 {
516 return (parse_uids(&g_psexp.ps_euids, arg));
517 }
518
519 /*ARGSUSED*/
520 static int
opt_uid(char c,char * arg)521 opt_uid(char c, char *arg)
522 {
523 return (parse_uids(&g_psexp.ps_ruids, arg));
524 }
525
526 /*ARGSUSED*/
527 static int
opt_gid(char c,char * arg)528 opt_gid(char c, char *arg)
529 {
530 return (parse_gids(&g_psexp.ps_rgids, arg));
531 }
532
533 static int
opt_ppid(char c,char * arg)534 opt_ppid(char c, char *arg)
535 {
536 return (parse_ids(&g_psexp.ps_ppids, arg, 10, c, 0));
537 }
538
539 static int
opt_pgrp(char c,char * arg)540 opt_pgrp(char c, char *arg)
541 {
542 return (parse_ids(&g_psexp.ps_pgids, arg, 10, c, getpgrp()));
543 }
544
545 static int
opt_sid(char c,char * arg)546 opt_sid(char c, char *arg)
547 {
548 return (parse_ids(&g_psexp.ps_sids, arg, 10, c, getsid(0)));
549 }
550
551 /*ARGSUSED*/
552 static int
opt_term(char c,char * arg)553 opt_term(char c, char *arg)
554 {
555 return (parse_ttys(&g_psexp.ps_ttys, arg));
556 }
557
558 /*ARGSUSED*/
559 static int
opt_projid(char c,char * arg)560 opt_projid(char c, char *arg)
561 {
562 return (parse_projects(&g_psexp.ps_projids, arg));
563 }
564
565 static int
opt_taskid(char c,char * arg)566 opt_taskid(char c, char *arg)
567 {
568 return (parse_ids(&g_psexp.ps_taskids, arg, 10, c, gettaskid()));
569 }
570
571 /*ARGSUSED*/
572 static int
opt_zoneid(char c,char * arg)573 opt_zoneid(char c, char *arg)
574 {
575 return (parse_zones(&g_psexp.ps_zoneids, arg));
576 }
577
578 static int
opt_ctid(char c,char * arg)579 opt_ctid(char c, char *arg)
580 {
581 return (parse_ids(&g_psexp.ps_ctids, arg, 10, c, getctid()));
582 }
583
584 static void
print_usage(FILE * stream)585 print_usage(FILE *stream)
586 {
587 if (g_flags & F_KILL)
588 (void) fprintf(stream, gettext(PKILL_USAGE), g_pname);
589 else
590 (void) fprintf(stream, gettext(PGREP_USAGE), g_pname);
591 }
592
593 int
main(int argc,char * argv[])594 main(int argc, char *argv[])
595 {
596 void (*funcp)(psinfo_t *);
597
598 const char *optstr;
599 optdesc_t *optd;
600 int nmatches, c;
601
602 DIR *dirp;
603
604 (void) setlocale(LC_ALL, "");
605 (void) textdomain(TEXT_DOMAIN);
606
607 UU_EXIT_FATAL = E_ERROR;
608
609 g_pname = uu_setpname(argv[0]);
610 g_pid = getpid();
611
612 psexp_create(&g_psexp);
613
614 if (strcmp(g_pname, "pkill") == 0) {
615
616 if (argc > 1 && argv[1][0] == '-' &&
617 str2sig(&argv[1][1], &g_signal) == 0) {
618 argv[1] = argv[0];
619 argv++;
620 argc--;
621 }
622
623 optstr = PKILL_OPTS;
624 g_flags |= F_KILL;
625 } else
626 optstr = PGREP_OPTS;
627
628 opterr = 0;
629
630 while (optind < argc) {
631 while ((c = getopt(argc, argv, optstr)) != (int)EOF) {
632
633 if (c == '?' || g_optdtab[c - 'A'].o_opts == 0) {
634 if (optopt != '?') {
635 uu_warn(
636 gettext("illegal option -- %c\n"),
637 optopt);
638 }
639
640 print_usage(stderr);
641 return (E_USAGE);
642 }
643
644 optd = &g_optdtab[c - 'A'];
645
646 if (optd->o_opts & OPT_SETB)
647 *((ushort_t *)optd->o_ptr) |= optd->o_bits;
648
649 if (optd->o_opts & OPT_CLRB)
650 *((ushort_t *)optd->o_ptr) &= ~optd->o_bits;
651
652 if (optd->o_opts & OPT_STR)
653 *((char **)optd->o_ptr) = optarg;
654
655 if (optd->o_opts & OPT_CRIT)
656 g_flags |= F_HAVE_CRIT;
657
658 if (optd->o_opts & OPT_FUNC) {
659 if (optd->o_func(c, optarg) == -1)
660 return (E_USAGE);
661 }
662 }
663
664 if (optind < argc) {
665 if (g_psexp.ps_pat != NULL) {
666 uu_warn(gettext("illegal argument -- %s\n"),
667 argv[optind]);
668 print_usage(stderr);
669 return (E_USAGE);
670 }
671
672 g_psexp.ps_pat = argv[optind++];
673 g_flags |= F_HAVE_CRIT;
674 }
675 }
676
677 if ((g_flags & F_NEWEST) && (g_flags & F_OLDEST)) {
678 uu_warn(gettext("-n and -o are mutually exclusive\n"));
679 print_usage(stderr);
680 return (E_USAGE);
681 }
682
683 if ((g_flags & F_HAVE_CRIT) == 0) {
684 uu_warn(gettext("No matching criteria specified\n"));
685 print_usage(stderr);
686 return (E_USAGE);
687 }
688
689 if (psexp_compile(&g_psexp) == -1) {
690 psexp_destroy(&g_psexp);
691 return (E_USAGE);
692 }
693
694 if ((dirp = open_proc_dir(g_procdir)) == NULL)
695 return (E_ERROR);
696
697 if (g_flags & F_KILL)
698 funcp = kill_proc;
699 else if (g_flags & F_LONG_OUT)
700 funcp = print_proc_long;
701 else
702 funcp = print_proc;
703
704 nmatches = scan_proc_dir(g_procdir, dirp, &g_psexp, funcp);
705
706 if (g_flags & F_OUTPUT)
707 (void) fputc('\n', stdout);
708
709 psexp_destroy(&g_psexp);
710 return (nmatches ? E_MATCH : E_NOMATCH);
711 }
712