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