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