dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / priocntl / priocntl.c
blobd15f571a13551be0a84f7398a3f35f70d9fc4cfb
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <wait.h>
35 #include <search.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <dirent.h>
39 #include <fcntl.h>
40 #include <sys/param.h>
41 #include <sys/procset.h>
42 #include <sys/priocntl.h>
43 #include <procfs.h>
44 #include <macros.h>
45 #include <libgen.h>
46 #include <limits.h>
47 #include <errno.h>
49 #include "priocntl.h"
52 * This file contains the code implementing the class independent part
53 * of the priocntl command. Most of the useful work for the priocntl
54 * command is done by the class specific sub-commands, the code for
55 * which is elsewhere. The class independent part of the command is
56 * responsible for executing the appropriate class specific sub-commands
57 * and providing any necessary input to the sub-commands.
58 * Code in this file should never assume any knowledge of any specific
59 * scheduler class (other than the SYS class).
62 #define CLASSPATH "/usr/lib/class"
64 typedef struct classpids {
65 char clp_clname[PC_CLNMSZ];
66 pid_t *clp_pidlist;
67 int clp_pidlistsz;
68 int clp_npids;
69 } classpids_t;
71 static char usage[] =
72 "usage: priocntl -l\n\
73 priocntl -d [-i idtype] [idlist]\n\
74 priocntl -s [-c class] [c.s.o.] [-i idtype] [idlist]\n\
75 priocntl -e [-c class] [c.s.o.] command [argument(s)]\n";
77 static char basenm[BASENMSZ];
78 static char cmdpath[MAXPATHLEN];
80 static char *procdir = "/proc";
82 static int print_classlist(void);
83 static void set_procs(char *, idtype_t, int, char **, char **);
84 static void exec_cmd(char *, char **);
85 static int print_procs(idtype_t, int, char *[]);
86 static void ids2pids(idtype_t, id_t *, int, classpids_t *, int);
87 static void add_pid_tolist(classpids_t *, int, char *, pid_t);
88 static void increase_pidlist(classpids_t *);
89 static boolean_t idmatch(char *, char *, int, char **);
92 * These variables are defined to be used in prio_getopt() below.
94 static int prio_getopt();
95 /* LINTED static unused */
96 static int prio_optopt = 0;
97 static char *prio_optarg = 0;
98 static int prio_optind = 1;
99 static int prio_sp = 1;
102 main(int argc, char *argv[])
104 int c;
105 int lflag, dflag, sflag, eflag, cflag, iflag, csoptsflag;
106 char *clname;
107 char *idtypnm;
108 idtype_t idtype;
109 int idargc;
110 char **idargv;
112 (void) strlcpy(cmdpath, argv[0], MAXPATHLEN);
113 (void) strlcpy(basenm, basename(argv[0]), BASENMSZ);
114 lflag = dflag = sflag = eflag = cflag = iflag = csoptsflag = 0;
115 while ((c = prio_getopt(argc, argv, "ldsec:i:")) != -1) {
117 switch (c) {
119 case 'l':
120 lflag++;
121 break;
123 case 'd':
124 dflag++;
125 break;
127 case 's':
128 sflag++;
129 break;
131 case 'e':
132 eflag++;
133 break;
135 case 'c':
136 cflag++;
137 clname = prio_optarg;
138 break;
140 case 'i':
141 iflag++;
142 idtypnm = prio_optarg;
143 break;
145 case '?':
146 if (strcmp(argv[prio_optind - 1], "-c") == 0 ||
147 strcmp(argv[prio_optind - 1], "-i") == 0) {
150 * getopt() will return ? if either
151 * of these appear without an argument.
153 fatalerr(usage);
157 * We assume for now that any option that
158 * getopt() doesn't recognize (with the
159 * exception of c and i) is intended for a
160 * class specific subcommand. For now we also
161 * require that all class specific options
162 * take an argument (until we can get smarter
163 * about parsing our options).
165 csoptsflag++;
166 prio_optind++;
167 prio_sp = 1;
168 break;
170 default:
171 break;
175 if (lflag) {
176 if (dflag || sflag || eflag || cflag || iflag || csoptsflag)
177 fatalerr(usage);
179 return (print_classlist());
181 } else if (dflag) {
182 if (lflag || sflag || eflag || cflag || csoptsflag)
183 fatalerr(usage);
184 if (iflag) {
185 if (str2idtyp(idtypnm, &idtype) == -1)
186 fatalerr("%s: bad idtype %s\n", cmdpath,
187 idtypnm);
188 } else {
189 idtype = P_PID;
192 if (prio_optind < argc) {
193 idargc = argc - prio_optind;
194 idargv = &argv[prio_optind];
195 } else {
196 idargc = 0;
199 return (print_procs(idtype, idargc, idargv));
201 } else if (sflag) {
202 if (lflag || dflag || eflag)
203 fatalerr(usage);
204 if (iflag) {
205 if (str2idtyp(idtypnm, &idtype) == -1)
206 fatalerr("%s: bad idtype %s\n", cmdpath,
207 idtypnm);
208 } else {
209 idtype = P_PID;
212 if (cflag == 0)
213 clname = NULL;
215 if (prio_optind < argc) {
216 idargc = argc - prio_optind;
217 idargv = &argv[prio_optind];
218 } else {
219 idargc = 0;
222 set_procs(clname, idtype, idargc, idargv, argv);
224 } else if (eflag) {
225 if (lflag || dflag || sflag || iflag)
226 fatalerr(usage);
228 if (cflag == 0)
229 clname = NULL;
231 if (prio_optind >= argc)
232 fatalerr(usage);
234 exec_cmd(clname, argv);
236 } else {
237 fatalerr(usage);
240 return (0);
245 * Print the heading for the class list and execute the class
246 * specific sub-command with the -l option for each configured class.
248 static int
249 print_classlist(void)
251 id_t cid;
252 int nclass;
253 pcinfo_t pcinfo;
254 static char subcmdpath[128];
255 int status;
256 pid_t pid;
257 int error = 0;
260 * No special privileges required for this operation.
261 * Set the effective UID back to the real UID.
263 if (setuid(getuid()) == -1)
264 fatalerr("%s: Can't set effective UID back to real UID\n",
265 cmdpath);
267 if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1)
268 fatalerr("%s: Can't get number of configured classes, priocntl"
269 " system call failed with errno %d\n", cmdpath, errno);
271 (void) printf("CONFIGURED CLASSES\n==================\n\n");
272 (void) printf("SYS (System Class)\n");
273 for (cid = 1; cid < nclass; cid++) {
274 (void) printf("\n");
275 (void) fflush(stdout);
276 pcinfo.pc_cid = cid;
277 if (priocntl(0, 0, PC_GETCLINFO, (caddr_t)&pcinfo) == -1)
278 fatalerr("%s: can't get class name (class ID = %ld)\n",
279 cmdpath, cid);
280 if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s",
281 CLASSPATH, pcinfo.pc_clname, pcinfo.pc_clname, basenm) >=
282 sizeof (subcmdpath))
283 fatalerr("%s: can't generate %s specific subcommand\n",
284 cmdpath, pcinfo.pc_clname);
285 if ((pid = fork()) == 0) {
286 (void) execl(subcmdpath, subcmdpath, "-l", (char *)0);
287 (void) printf("%s\n", pcinfo.pc_clname);
288 fatalerr("\tCan't execute %s specific subcommand\n",
289 pcinfo.pc_clname);
290 } else if (pid == (pid_t)-1) {
291 (void) printf("%s\n", pcinfo.pc_clname);
292 (void) fprintf(stderr,
293 "Can't execute %s specific subcommand)\n",
294 pcinfo.pc_clname);
295 error = 1;
296 } else {
297 (void) wait(&status);
298 if (status)
299 error = 1;
303 return (error);
308 * For each class represented within the set of processes specified by
309 * idtype/idargv, print_procs() executes the class specific sub-command
310 * with the -d option. We pipe to each sub-command a list of pids in
311 * the set belonging to that class.
313 static int
314 print_procs(idtype_t idtype, int idargc, char *idargv[])
316 int i;
317 id_t id;
318 id_t idlist[NIDS];
319 int nids;
320 classpids_t *clpids;
321 int nclass;
322 id_t cid;
323 pcinfo_t pcinfo;
324 int pidexists;
325 FILE *pipe_to_subcmd;
326 char subcmd[128];
327 int error = 0;
331 * Build a list of ids eliminating any duplicates in idargv.
333 if (idtype == P_ALL) {
335 * No idlist should be specified. If one is specified,
336 * it is ignored.
338 nids = 0;
339 } else if (idargc == 0) {
342 * No ids supplied by user; use current id.
344 if (getmyid(idtype, &idlist[0]) == -1)
345 fatalerr("%s: Can't get ID for current process,"
346 " idtype = %d\n", cmdpath, idtype);
347 nids = 1;
348 } else {
349 nids = 0;
350 for (i = 0; i < idargc && nids < NIDS; i++) {
351 if (idtype == P_CID) {
352 if ((id = clname2cid(idargv[i])) == -1) {
353 (void) fprintf(stderr, "%s: Invalid or"
354 " unconfigured class %s in idlist"
355 " - ignored\n", cmdpath, idargv[i]);
356 error = 1;
358 } else {
359 id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX);
360 if (errno) {
361 (void) fprintf(stderr,
362 "%s: Invalid id \"%s\"\n",
363 cmdpath, idargv[i]);
364 error = 1;
365 id = BADPID;
370 * lsearch(3C) adds ids to the idlist,
371 * eliminating duplicates.
373 (void) lsearch((void *)&id, (void *)idlist,
374 (size_t *)&nids, sizeof (id), (int (*)())idcompar);
378 if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1)
379 fatalerr("%s: Can't get number of configured classes, priocntl"
380 " system call failed with errno %d\n", cmdpath, errno);
382 if ((clpids = (classpids_t *)malloc(sizeof (classpids_t) * nclass)) ==
383 NULL)
384 fatalerr("%s: Can't allocate memory for clpids.\n", cmdpath);
386 for (cid = 1; cid < nclass; cid++) {
387 pcinfo.pc_cid = cid;
388 if (priocntl(0, 0, PC_GETCLINFO, (caddr_t)&pcinfo) == -1)
389 fatalerr("%s: Can't get class name, cid = %ld\n",
390 cmdpath, cid);
392 (void) strncpy(clpids[cid].clp_clname, pcinfo.pc_clname,
393 PC_CLNMSZ);
396 * The memory allocation for the pidlist uses realloc().
397 * A realloc() call is required, when "clp_npids" is
398 * equal to "clp_pidlistsz".
400 clpids[cid].clp_pidlist = (pid_t *)NULL;
401 clpids[cid].clp_pidlistsz = 0;
402 clpids[cid].clp_npids = 0;
406 * Build the pidlist.
408 ids2pids(idtype, idlist, nids, clpids, nclass);
411 * No need for special privileges any more.
412 * Set the effective UID back to the real UID.
414 if (setuid(getuid()) == -1)
415 fatalerr("%s: Can't set effective UID back to real UID\n",
416 cmdpath);
418 pidexists = 0;
419 for (cid = 1; cid < nclass; cid++) {
420 if (clpids[cid].clp_npids == 0)
421 continue;
423 pidexists = 1;
424 if (snprintf(subcmd, sizeof (subcmd), "%s/%s/%s%s -d",
425 CLASSPATH, clpids[cid].clp_clname, clpids[cid].clp_clname,
426 basenm) >= sizeof (subcmd)) {
427 (void) fprintf(stderr,
428 "Can't generate %s specific subcommand\n",
429 clpids[cid].clp_clname);
430 error = 1;
431 free(clpids[cid].clp_pidlist);
432 continue;
434 if ((pipe_to_subcmd = popen(subcmd, "w")) == NULL) {
435 (void) printf("%s\n", clpids[cid].clp_clname);
436 (void) fprintf(stderr,
437 "Can't execute %s specific subcommand\n",
438 clpids[cid].clp_clname);
439 error = 1;
440 free(clpids[cid].clp_pidlist);
441 continue;
443 (void) fwrite(clpids[cid].clp_pidlist, sizeof (pid_t),
444 clpids[cid].clp_npids, pipe_to_subcmd);
445 if (pclose(pipe_to_subcmd))
446 error = 1;
448 free(clpids[cid].clp_pidlist);
451 free(clpids);
453 if (pidexists == 0)
454 fatalerr("%s: Process(es) not found.\n", cmdpath);
456 return (error);
461 * Execute the appropriate class specific sub-command with the arguments
462 * pointed to by subcmdargv. If the user specified a class we simply
463 * exec the sub-command for that class. If no class was specified we
464 * verify that the processes in the set specified by idtype/idargv are
465 * all in the same class and then execute the sub-command for that class.
467 static void
468 set_procs(clname, idtype, idargc, idargv, subcmdargv)
469 char *clname;
470 idtype_t idtype;
471 int idargc;
472 char **idargv;
473 char **subcmdargv;
475 char idstr[PC_IDTYPNMSZ];
476 char myidstr[PC_IDTYPNMSZ];
477 char clnmbuf[PC_CLNMSZ];
478 pcinfo_t pcinfo;
479 static psinfo_t prinfo;
480 static prcred_t prcred;
481 DIR *dirp;
482 struct dirent *dentp;
483 static char pname[100];
484 char *fname;
485 int procfd;
486 int saverr;
487 static char subcmdpath[128];
488 boolean_t procinset;
489 id_t id;
490 size_t len;
492 if (clname == NULL && idtype == P_PID && idargc <= 1) {
495 * No class specified by user but only one process
496 * in specified set. Get the class the easy way.
498 if (idargc == 0) {
499 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL,
500 PC_KY_CLNAME, clnmbuf, 0) == -1)
501 if (errno == ESRCH)
502 fatalerr("%s: Process not found.\n",
503 cmdpath);
504 else
505 fatalerr("%s: Can't get class of"
506 " current process\npriocntl"
507 " system call failed with"
508 " errno %d\n", cmdpath, errno);
509 } else {
510 /* idargc == 1 */
511 id = (id_t)str2num(idargv[0], INT_MIN, INT_MAX);
512 if (errno)
513 fatalerr("%s: Invalid id \"%s\"\n", cmdpath,
514 idargv[0]);
516 if (priocntl(P_PID, id, PC_GETXPARMS,
517 NULL, PC_KY_CLNAME, clnmbuf, 0) == -1)
518 if (errno == ESRCH)
519 fatalerr("%s: Process not found.\n",
520 cmdpath);
521 else
522 fatalerr("%s: Can't get class of "
523 " specified process\npriocntl"
524 " system call failed with"
525 " errno %d\n", cmdpath, errno);
528 clname = clnmbuf;
529 } else if (clname == NULL) {
532 * No class specified by user and potentially more
533 * than one process in specified set. Verify that
534 * all procs in set are in the same class.
536 if (idargc == 0 && idtype != P_ALL) {
539 * No ids supplied by user; use current id.
541 if (getmyidstr(idtype, myidstr) == -1)
542 fatalerr("%s: Can't get ID string for current"
543 " process, idtype = %d\n", cmdpath, idtype);
545 if ((dirp = opendir(procdir)) == NULL)
546 fatalerr("%s: Can't open PROC directory %s\n",
547 cmdpath, procdir);
549 while ((dentp = readdir(dirp)) != NULL) {
550 if (dentp->d_name[0] == '.') /* skip . and .. */
551 continue;
553 len = snprintf(pname, sizeof (pname), "%s/%s/",
554 procdir, dentp->d_name);
555 /* Really max(sizeof ("psinfo"), sizeof ("cred")) */
556 if (len + sizeof ("psinfo") > sizeof (pname)) {
557 (void) fprintf(stderr,
558 "%s: skipping %s, name too long.\n",
559 cmdpath, dentp->d_name);
560 continue;
562 fname = pname + len;
563 retry:
564 (void) strcpy(fname, "psinfo");
565 if ((procfd = open(pname, O_RDONLY)) < 0)
566 continue;
568 if (read(procfd, &prinfo, sizeof (prinfo)) !=
569 sizeof (prinfo)) {
570 saverr = errno;
571 (void) close(procfd);
572 if (saverr == EAGAIN)
573 goto retry;
574 if (saverr != ENOENT) {
575 (void) fprintf(stderr,
576 "%s: Can't get process info for"
577 " %s\n", cmdpath, pname);
579 continue;
581 (void) close(procfd);
583 if (idtype == P_UID || idtype == P_GID) {
584 (void) strcpy(fname, "cred");
585 if ((procfd = open(pname, O_RDONLY)) < 0 ||
586 read(procfd, &prcred, sizeof (prcred)) !=
587 sizeof (prcred)) {
588 saverr = errno;
589 if (procfd >= 0)
590 (void) close(procfd);
591 if (saverr == EAGAIN)
592 goto retry;
593 if (saverr != ENOENT) {
594 (void) fprintf(stderr,
595 "%s: Can't get process"
596 " credentials for %s\n",
597 cmdpath, pname);
599 continue;
601 (void) close(procfd);
604 if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0)
605 continue;
608 switch (idtype) {
610 case P_PID:
611 itoa((long)prinfo.pr_pid, idstr);
612 procinset = idmatch(idstr, myidstr,
613 idargc, idargv);
614 break;
616 case P_PPID:
617 itoa((long)prinfo.pr_ppid, idstr);
618 procinset = idmatch(idstr, myidstr,
619 idargc, idargv);
620 break;
622 case P_PGID:
623 itoa((long)prinfo.pr_pgid, idstr);
624 procinset = idmatch(idstr, myidstr,
625 idargc, idargv);
626 break;
628 case P_SID:
629 itoa((long)prinfo.pr_sid, idstr);
630 procinset = idmatch(idstr, myidstr,
631 idargc, idargv);
632 break;
634 case P_CID:
635 procinset = idmatch(prinfo.pr_lwp.pr_clname,
636 myidstr, idargc, idargv);
637 break;
639 case P_UID:
640 itoa((long)prcred.pr_euid, idstr);
641 procinset = idmatch(idstr, myidstr,
642 idargc, idargv);
643 break;
645 case P_GID:
646 itoa((long)prcred.pr_egid, idstr);
647 procinset = idmatch(idstr, myidstr,
648 idargc, idargv);
649 break;
651 case P_PROJID:
652 itoa((long)prinfo.pr_projid, idstr);
653 procinset = idmatch(idstr, myidstr,
654 idargc, idargv);
655 break;
657 case P_TASKID:
658 itoa((long)prinfo.pr_taskid, idstr);
659 procinset = idmatch(idstr, myidstr,
660 idargc, idargv);
661 break;
663 case P_ZONEID:
664 itoa((long)prinfo.pr_zoneid, idstr);
665 procinset = idmatch(idstr, myidstr,
666 idargc, idargv);
667 break;
669 case P_CTID:
670 itoa((long)prinfo.pr_contract, idstr);
671 procinset = idmatch(idstr, myidstr,
672 idargc, idargv);
673 break;
675 case P_ALL:
676 procinset = B_TRUE;
677 break;
679 default:
680 fatalerr("%s: Bad idtype %d in set_procs()\n",
681 cmdpath, idtype);
683 if (procinset == B_TRUE) {
684 if (clname == NULL) {
687 * First proc found in set.
689 (void) strcpy(clnmbuf,
690 prinfo.pr_lwp.pr_clname);
691 clname = clnmbuf;
692 } else if (strcmp(clname,
693 prinfo.pr_lwp.pr_clname) != 0) {
694 fatalerr("%s: Specified processes"
695 " from different classes.\n",
696 cmdpath);
700 (void) closedir(dirp);
701 if (clname == NULL)
702 fatalerr("%s: Process(es) not found.\n", cmdpath);
703 } else {
706 * User specified class. Check it for validity.
708 (void) strcpy(pcinfo.pc_clname, clname);
709 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
710 fatalerr("%s: Invalid or unconfigured class %s\n",
711 cmdpath, clname);
715 * No need for special privileges any more.
716 * Set the effective UID back to the real UID.
718 if (setuid(getuid()) == -1)
719 fatalerr("%s: Can't set effective UID back to real UID\n",
720 cmdpath);
722 if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s",
723 CLASSPATH, clname, clname, basenm) >= sizeof (subcmdpath))
724 fatalerr("%s: can't generate %s specific subcommand\n",
725 cmdpath, clname);
727 subcmdargv[0] = subcmdpath;
728 (void) execv(subcmdpath, subcmdargv);
729 fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname);
734 * Execute the appropriate class specific sub-command with the arguments
735 * pointed to by subcmdargv. If the user specified a class we simply
736 * exec the sub-command for that class. If no class was specified we
737 * execute the sub-command for our own current class.
739 static void
740 exec_cmd(clname, subcmdargv)
741 char *clname;
742 char **subcmdargv;
744 pcinfo_t pcinfo;
745 char clnmbuf[PC_CLNMSZ];
746 char subcmdpath[128];
749 * No special privileges required for this operation.
750 * Set the effective UID back to the real UID.
752 if (setuid(getuid()) == -1)
753 fatalerr("%s: Can't set effective UID back to real UID\n",
754 cmdpath);
756 if (clname == NULL) {
757 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL,
758 PC_KY_CLNAME, clnmbuf, 0) == -1)
759 fatalerr("%s: Can't get class name of current process\n"
760 "priocntl system call failed with errno %d\n",
761 cmdpath, errno);
763 clname = clnmbuf;
764 } else {
767 * User specified class. Check it for validity.
769 (void) strcpy(pcinfo.pc_clname, clname);
770 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
771 fatalerr("%s: Invalid or unconfigured class %s\n",
772 cmdpath, clname);
775 if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s",
776 CLASSPATH, clname, clname, basenm) >= sizeof (subcmdpath))
777 fatalerr("%s: can't generate %s specific subcommand\n",
778 cmdpath, clname);
779 subcmdargv[0] = subcmdpath;
780 (void) execv(subcmdpath, subcmdargv);
781 fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname);
786 * Fill in the classpids structures in the array pointed to by clpids
787 * with pids for the processes in the set specified by idtype/idlist.
788 * We read the /proc/<pid>/psinfo file to get the necessary process
789 * information.
791 static void
792 ids2pids(idtype, idlist, nids, clpids, nclass)
793 idtype_t idtype;
794 id_t *idlist;
795 int nids;
796 classpids_t *clpids;
797 int nclass;
799 static psinfo_t prinfo;
800 static prcred_t prcred;
801 DIR *dirp;
802 struct dirent *dentp;
803 char pname[100];
804 char *fname;
805 int procfd;
806 int saverr;
807 int i;
808 char *clname;
809 size_t len;
811 if ((dirp = opendir(procdir)) == NULL)
812 fatalerr("%s: Can't open PROC directory %s\n",
813 cmdpath, procdir);
815 while ((dentp = readdir(dirp)) != NULL) {
816 if (dentp->d_name[0] == '.') /* skip . and .. */
817 continue;
819 len = snprintf(pname, sizeof (pname), "%s/%s/",
820 procdir, dentp->d_name);
821 /* Really max(sizeof ("psinfo"), sizeof ("cred")) */
822 if (len + sizeof ("psinfo") > sizeof (pname)) {
823 (void) fprintf(stderr,
824 "%s: skipping %s, name too long.\n",
825 cmdpath, dentp->d_name);
826 continue;
828 fname = pname + len;
829 retry:
830 (void) strcpy(fname, "psinfo");
831 if ((procfd = open(pname, O_RDONLY)) < 0)
832 continue;
833 if (read(procfd, &prinfo, sizeof (prinfo)) != sizeof (prinfo)) {
834 saverr = errno;
835 (void) close(procfd);
836 if (saverr == EAGAIN)
837 goto retry;
838 if (saverr != ENOENT) {
839 (void) fprintf(stderr,
840 "%s: Can't get process info for %s\n",
841 cmdpath, pname);
843 continue;
845 (void) close(procfd);
847 if (idtype == P_UID || idtype == P_GID) {
848 (void) strcpy(fname, "cred");
849 if ((procfd = open(pname, O_RDONLY)) < 0 ||
850 read(procfd, &prcred, sizeof (prcred)) !=
851 sizeof (prcred)) {
852 saverr = errno;
853 (void) close(procfd);
854 if (saverr == EAGAIN)
855 goto retry;
856 if (saverr != ENOENT) {
857 (void) fprintf(stderr,
858 "%s: Can't get process credentials"
859 " for %s\n",
860 cmdpath, pname);
862 continue;
864 (void) close(procfd);
867 if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0)
868 continue;
870 switch (idtype) {
872 case P_PID:
873 for (i = 0; i < nids; i++) {
874 if (idlist[i] == (id_t)prinfo.pr_pid)
875 add_pid_tolist(clpids, nclass,
876 prinfo.pr_lwp.pr_clname,
877 prinfo.pr_pid);
879 break;
881 case P_PPID:
882 for (i = 0; i < nids; i++) {
883 if (idlist[i] == (id_t)prinfo.pr_ppid)
884 add_pid_tolist(clpids, nclass,
885 prinfo.pr_lwp.pr_clname,
886 prinfo.pr_pid);
888 break;
890 case P_PGID:
891 for (i = 0; i < nids; i++) {
892 if (idlist[i] == (id_t)prinfo.pr_pgid)
893 add_pid_tolist(clpids, nclass,
894 prinfo.pr_lwp.pr_clname,
895 prinfo.pr_pid);
897 break;
899 case P_SID:
900 for (i = 0; i < nids; i++) {
901 if (idlist[i] == (id_t)prinfo.pr_sid)
902 add_pid_tolist(clpids, nclass,
903 prinfo.pr_lwp.pr_clname,
904 prinfo.pr_pid);
906 break;
908 case P_CID:
909 for (i = 0; i < nids; i++) {
910 clname = clpids[idlist[i]].clp_clname;
911 if (strcmp(clname,
912 prinfo.pr_lwp.pr_clname) == 0)
913 add_pid_tolist(clpids, nclass,
914 prinfo.pr_lwp.pr_clname,
915 prinfo.pr_pid);
917 break;
919 case P_UID:
920 for (i = 0; i < nids; i++) {
921 if (idlist[i] == (id_t)prcred.pr_euid)
922 add_pid_tolist(clpids, nclass,
923 prinfo.pr_lwp.pr_clname,
924 prinfo.pr_pid);
926 break;
928 case P_GID:
929 for (i = 0; i < nids; i++) {
930 if (idlist[i] == (id_t)prcred.pr_egid)
931 add_pid_tolist(clpids, nclass,
932 prinfo.pr_lwp.pr_clname,
933 prinfo.pr_pid);
935 break;
937 case P_PROJID:
938 for (i = 0; i < nids; i++) {
939 if (idlist[i] == (id_t)prinfo.pr_projid)
940 add_pid_tolist(clpids, nclass,
941 prinfo.pr_lwp.pr_clname,
942 prinfo.pr_pid);
944 break;
946 case P_TASKID:
947 for (i = 0; i < nids; i++) {
948 if (idlist[i] == (id_t)prinfo.pr_taskid)
949 add_pid_tolist(clpids, nclass,
950 prinfo.pr_lwp.pr_clname,
951 prinfo.pr_pid);
953 break;
955 case P_ZONEID:
956 for (i = 0; i < nids; i++) {
957 if (idlist[i] == (id_t)prinfo.pr_zoneid)
958 add_pid_tolist(clpids, nclass,
959 prinfo.pr_lwp.pr_clname,
960 prinfo.pr_pid);
962 break;
964 case P_CTID:
965 for (i = 0; i < nids; i++) {
966 if (idlist[i] == (id_t)prinfo.pr_contract)
967 add_pid_tolist(clpids, nclass,
968 prinfo.pr_lwp.pr_clname,
969 prinfo.pr_pid);
971 break;
973 case P_ALL:
974 add_pid_tolist(clpids, nclass, prinfo.pr_lwp.pr_clname,
975 prinfo.pr_pid);
976 break;
978 default:
979 fatalerr("%s: Bad idtype %d in ids2pids()\n",
980 cmdpath, idtype);
983 (void) closedir(dirp);
988 * Search the array pointed to by clpids for the classpids
989 * structure corresponding to clname and add pid to its
990 * pidlist.
992 static void
993 add_pid_tolist(clpids, nclass, clname, pid)
994 classpids_t *clpids;
995 int nclass;
996 char *clname;
997 pid_t pid;
999 classpids_t *clp;
1001 for (clp = clpids; clp != &clpids[nclass]; clp++) {
1002 if (strcmp(clp->clp_clname, clname) == 0) {
1003 if (clp->clp_npids == clp->clp_pidlistsz)
1004 increase_pidlist(clp);
1006 (clp->clp_pidlist)[clp->clp_npids] = pid;
1007 clp->clp_npids++;
1008 return;
1014 static void
1015 increase_pidlist(classpids_t *clp)
1017 if ((clp->clp_pidlist = reallocarray(clp->clp_pidlist,
1018 clp->clp_pidlistsz + NPIDS, sizeof (pid_t))) == NULL)
1020 * The pidlist is filled up and we cannot increase the size.
1022 fatalerr("%s: Can't allocate memory for pidlist.\n", cmdpath);
1024 clp->clp_pidlistsz += NPIDS;
1029 * Compare id strings for equality. If idargv contains ids
1030 * (idargc > 0) compare idstr to each id in idargv, otherwise
1031 * just compare to curidstr.
1033 static boolean_t
1034 idmatch(idstr, curidstr, idargc, idargv)
1035 char *idstr;
1036 char *curidstr;
1037 int idargc;
1038 char **idargv;
1040 int i;
1042 if (idargc == 0) {
1043 if (strcmp(curidstr, idstr) == 0)
1044 return (B_TRUE);
1045 } else {
1046 for (i = 0; i < idargc; i++) {
1047 if (strcmp(idargv[i], idstr) == 0)
1048 return (B_TRUE);
1051 return (B_FALSE);
1055 * This is a copy of the getopt() function found in libc:getopt.c. A separate
1056 * copy is required to fix the bug id #1114636. To fix the problem we need to
1057 * reset the _sp to 1. Since _sp in libc:getopt() is not exposed, a copy of
1058 * the getopt() is kept so that prio_sp can be reset to 1.
1061 static int
1062 prio_getopt(argc, argv, opts)
1063 int argc;
1064 #ifdef __STDC__
1065 char *const *argv, *opts;
1066 #else
1067 char **argv, *opts;
1068 #endif
1070 register char c;
1071 register char *cp;
1073 if (prio_sp == 1)
1074 if (prio_optind >= argc ||
1075 argv[prio_optind][0] != '-' || argv[prio_optind][1] == '\0')
1076 return (EOF);
1077 else if (strcmp(argv[prio_optind], "--") == 0) {
1078 prio_optind++;
1079 return (EOF);
1081 prio_optopt = c = (unsigned char)argv[prio_optind][prio_sp];
1082 if (c == ':' || (cp = strchr(opts, c)) == NULL) {
1083 if (argv[prio_optind][++prio_sp] == '\0') {
1084 prio_optind++;
1085 prio_sp = 1;
1087 return ('?');
1089 if (*++cp == ':') {
1090 if (argv[prio_optind][prio_sp+1] != '\0')
1091 prio_optarg = &argv[prio_optind++][prio_sp+1];
1092 else if (++prio_optind >= argc) {
1093 prio_sp = 1;
1094 return ('?');
1095 } else
1096 prio_optarg = argv[prio_optind++];
1097 prio_sp = 1;
1098 } else {
1099 if (argv[prio_optind][++prio_sp] == '\0') {
1100 prio_sp = 1;
1101 prio_optind++;
1103 prio_optarg = NULL;
1105 return (c);