xref: /illumos-gate/usr/src/cmd/ptools/ppriv/ppriv.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * Program to examine or set process privileges.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
35*7c478bd9Sstevel@tonic-gate #include <string.h>
36*7c478bd9Sstevel@tonic-gate #include <limits.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include <libproc.h>
39*7c478bd9Sstevel@tonic-gate #include <priv.h>
40*7c478bd9Sstevel@tonic-gate #include <errno.h>
41*7c478bd9Sstevel@tonic-gate #include <ctype.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <locale.h>
44*7c478bd9Sstevel@tonic-gate #include <langinfo.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate static int	look(char *);
47*7c478bd9Sstevel@tonic-gate static void	perr(char *);
48*7c478bd9Sstevel@tonic-gate static void	usage(void);
49*7c478bd9Sstevel@tonic-gate static void	loadprivinfo(void);
50*7c478bd9Sstevel@tonic-gate static int	parsespec(const char *);
51*7c478bd9Sstevel@tonic-gate static void	privupdate(prpriv_t *, const char *);
52*7c478bd9Sstevel@tonic-gate static void	privupdate_self(void);
53*7c478bd9Sstevel@tonic-gate static int	dumppriv(char **);
54*7c478bd9Sstevel@tonic-gate static void	flags2str(uint_t);
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate static char		*command;
57*7c478bd9Sstevel@tonic-gate static char		*procname;
58*7c478bd9Sstevel@tonic-gate static boolean_t	verb = B_FALSE;
59*7c478bd9Sstevel@tonic-gate static boolean_t	set = B_FALSE;
60*7c478bd9Sstevel@tonic-gate static boolean_t	exec = B_FALSE;
61*7c478bd9Sstevel@tonic-gate static boolean_t	Don = B_FALSE;
62*7c478bd9Sstevel@tonic-gate static boolean_t	Doff = B_FALSE;
63*7c478bd9Sstevel@tonic-gate static boolean_t	list = B_FALSE;
64*7c478bd9Sstevel@tonic-gate static int		mode = PRIV_STR_PORT;
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate int
67*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
68*7c478bd9Sstevel@tonic-gate {
69*7c478bd9Sstevel@tonic-gate 	int rc = 0;
70*7c478bd9Sstevel@tonic-gate 	int opt;
71*7c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
74*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
77*7c478bd9Sstevel@tonic-gate 		command++;
78*7c478bd9Sstevel@tonic-gate 	else
79*7c478bd9Sstevel@tonic-gate 		command = argv[0];
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "lDNevs:S")) != EOF) {
82*7c478bd9Sstevel@tonic-gate 		switch (opt) {
83*7c478bd9Sstevel@tonic-gate 		case 'l':
84*7c478bd9Sstevel@tonic-gate 			list = B_TRUE;
85*7c478bd9Sstevel@tonic-gate 			break;
86*7c478bd9Sstevel@tonic-gate 		case 'D':
87*7c478bd9Sstevel@tonic-gate 			set = B_TRUE;
88*7c478bd9Sstevel@tonic-gate 			Don = B_TRUE;
89*7c478bd9Sstevel@tonic-gate 			break;
90*7c478bd9Sstevel@tonic-gate 		case 'N':
91*7c478bd9Sstevel@tonic-gate 			set = B_TRUE;
92*7c478bd9Sstevel@tonic-gate 			Doff = B_TRUE;
93*7c478bd9Sstevel@tonic-gate 			break;
94*7c478bd9Sstevel@tonic-gate 		case 'e':
95*7c478bd9Sstevel@tonic-gate 			exec = B_TRUE;
96*7c478bd9Sstevel@tonic-gate 			break;
97*7c478bd9Sstevel@tonic-gate 		case 'S':
98*7c478bd9Sstevel@tonic-gate 			mode = PRIV_STR_SHORT;
99*7c478bd9Sstevel@tonic-gate 			break;
100*7c478bd9Sstevel@tonic-gate 		case 'v':
101*7c478bd9Sstevel@tonic-gate 			verb = B_TRUE;
102*7c478bd9Sstevel@tonic-gate 			mode = PRIV_STR_LIT;
103*7c478bd9Sstevel@tonic-gate 			break;
104*7c478bd9Sstevel@tonic-gate 		case 's':
105*7c478bd9Sstevel@tonic-gate 			set = B_TRUE;
106*7c478bd9Sstevel@tonic-gate 			if ((rc = parsespec(optarg)) != 0)
107*7c478bd9Sstevel@tonic-gate 				return (rc);
108*7c478bd9Sstevel@tonic-gate 			break;
109*7c478bd9Sstevel@tonic-gate 		default:
110*7c478bd9Sstevel@tonic-gate 			usage();
111*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
112*7c478bd9Sstevel@tonic-gate 		}
113*7c478bd9Sstevel@tonic-gate 	}
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	argc -= optind;
116*7c478bd9Sstevel@tonic-gate 	argv += optind;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	if ((argc < 1 && !list) || Doff && Don || list && (set || exec))
119*7c478bd9Sstevel@tonic-gate 		usage();
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	/*
122*7c478bd9Sstevel@tonic-gate 	 * Make sure we'll have enough file descriptors to handle a target
123*7c478bd9Sstevel@tonic-gate 	 * that has many many mappings.
124*7c478bd9Sstevel@tonic-gate 	 */
125*7c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
126*7c478bd9Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
127*7c478bd9Sstevel@tonic-gate 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
128*7c478bd9Sstevel@tonic-gate 	}
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	if (exec) {
131*7c478bd9Sstevel@tonic-gate 		privupdate_self();
132*7c478bd9Sstevel@tonic-gate 		rc = execvp(argv[0], &argv[0]);
133*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s: %s\n", command, argv[0],
134*7c478bd9Sstevel@tonic-gate 			strerror(errno));
135*7c478bd9Sstevel@tonic-gate 	} else if (list) {
136*7c478bd9Sstevel@tonic-gate 		rc = dumppriv(argv);
137*7c478bd9Sstevel@tonic-gate 	} else {
138*7c478bd9Sstevel@tonic-gate 		while (argc-- > 0)
139*7c478bd9Sstevel@tonic-gate 			rc += look(*argv++);
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	return (rc);
143*7c478bd9Sstevel@tonic-gate }
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate static int
146*7c478bd9Sstevel@tonic-gate look(char *arg)
147*7c478bd9Sstevel@tonic-gate {
148*7c478bd9Sstevel@tonic-gate 	static size_t pprivsz = sizeof (prpriv_t);
149*7c478bd9Sstevel@tonic-gate 	static prpriv_t *ppriv;
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *Pr;
152*7c478bd9Sstevel@tonic-gate 	int gcode;
153*7c478bd9Sstevel@tonic-gate 	size_t sz;
154*7c478bd9Sstevel@tonic-gate 	void *pdata;
155*7c478bd9Sstevel@tonic-gate 	char *x;
156*7c478bd9Sstevel@tonic-gate 	int i;
157*7c478bd9Sstevel@tonic-gate 	boolean_t nodata;
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	procname = arg;		/* for perr() */
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	if ((Pr = proc_arg_grab(arg, set ? PR_ARG_PIDS : PR_ARG_ANY,
162*7c478bd9Sstevel@tonic-gate 	    PGRAB_RETAIN | PGRAB_FORCE | (set ? 0 : PGRAB_RDONLY) |
163*7c478bd9Sstevel@tonic-gate 	    PGRAB_NOSTOP, &gcode)) == NULL) {
164*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
165*7c478bd9Sstevel@tonic-gate 		    command, arg, Pgrab_error(gcode));
166*7c478bd9Sstevel@tonic-gate 		return (1);
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	if (ppriv == NULL)
170*7c478bd9Sstevel@tonic-gate 		ppriv = malloc(pprivsz);
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	if (Ppriv(Pr, ppriv, pprivsz) == -1) {
173*7c478bd9Sstevel@tonic-gate 		perr(command);
174*7c478bd9Sstevel@tonic-gate 		Prelease(Pr, 0);
175*7c478bd9Sstevel@tonic-gate 		return (1);
176*7c478bd9Sstevel@tonic-gate 	}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	sz = PRIV_PRPRIV_SIZE(ppriv);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	/*
181*7c478bd9Sstevel@tonic-gate 	 * The ppriv fields are unsigned and may overflow, so check them
182*7c478bd9Sstevel@tonic-gate 	 * separately.  Size must be word aligned, so check that too.
183*7c478bd9Sstevel@tonic-gate 	 * Make sure size is "smallish" too.
184*7c478bd9Sstevel@tonic-gate 	 */
185*7c478bd9Sstevel@tonic-gate 	if ((sz & 3) || ppriv->pr_nsets == 0 ||
186*7c478bd9Sstevel@tonic-gate 	    sz / ppriv->pr_nsets < ppriv->pr_setsize ||
187*7c478bd9Sstevel@tonic-gate 	    ppriv->pr_infosize > sz || sz > 1024 * 1024) {
188*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
189*7c478bd9Sstevel@tonic-gate 			"%s: %s: bad PRNOTES section, size = %lx\n",
190*7c478bd9Sstevel@tonic-gate 			command, arg, (long)sz);
191*7c478bd9Sstevel@tonic-gate 		Prelease(Pr, 0);
192*7c478bd9Sstevel@tonic-gate 		return (1);
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	if (sz > pprivsz) {
196*7c478bd9Sstevel@tonic-gate 		ppriv = realloc(ppriv, sz);
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 		if (ppriv == NULL || Ppriv(Pr, ppriv, sz) != sz) {
199*7c478bd9Sstevel@tonic-gate 			perr(command);
200*7c478bd9Sstevel@tonic-gate 			Prelease(Pr, 0);
201*7c478bd9Sstevel@tonic-gate 			return (1);
202*7c478bd9Sstevel@tonic-gate 		}
203*7c478bd9Sstevel@tonic-gate 		pprivsz = sz;
204*7c478bd9Sstevel@tonic-gate 	}
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	if (set) {
207*7c478bd9Sstevel@tonic-gate 		privupdate(ppriv, arg);
208*7c478bd9Sstevel@tonic-gate 		if (Psetpriv(Pr, ppriv) != 0) {
209*7c478bd9Sstevel@tonic-gate 			perr(command);
210*7c478bd9Sstevel@tonic-gate 			Prelease(Pr, 0);
211*7c478bd9Sstevel@tonic-gate 			return (1);
212*7c478bd9Sstevel@tonic-gate 		}
213*7c478bd9Sstevel@tonic-gate 		Prelease(Pr, 0);
214*7c478bd9Sstevel@tonic-gate 		return (0);
215*7c478bd9Sstevel@tonic-gate 	}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	if (Pstate(Pr) == PS_DEAD) {
218*7c478bd9Sstevel@tonic-gate 		(void) printf("core '%s' of %d:\t%.70s\n",
219*7c478bd9Sstevel@tonic-gate 		    arg, (int)Ppsinfo(Pr)->pr_pid, Ppsinfo(Pr)->pr_psargs);
220*7c478bd9Sstevel@tonic-gate 		pdata = Pprivinfo(Pr);
221*7c478bd9Sstevel@tonic-gate 		nodata = Pstate(Pr) == PS_DEAD && pdata == NULL;
222*7c478bd9Sstevel@tonic-gate 	} else {
223*7c478bd9Sstevel@tonic-gate 		(void) printf("%d:\t%.70s\n",
224*7c478bd9Sstevel@tonic-gate 		    (int)Ppsinfo(Pr)->pr_pid, Ppsinfo(Pr)->pr_psargs);
225*7c478bd9Sstevel@tonic-gate 		pdata = NULL;
226*7c478bd9Sstevel@tonic-gate 		nodata = B_FALSE;
227*7c478bd9Sstevel@tonic-gate 	}
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	x = (char *)ppriv + sz - ppriv->pr_infosize;
230*7c478bd9Sstevel@tonic-gate 	while (x < (char *)ppriv + sz) {
231*7c478bd9Sstevel@tonic-gate 		/* LINTED: alignment */
232*7c478bd9Sstevel@tonic-gate 		priv_info_t *pi = (priv_info_t *)x;
233*7c478bd9Sstevel@tonic-gate 		priv_info_uint_t *pii;
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 		switch (pi->priv_info_type) {
236*7c478bd9Sstevel@tonic-gate 		case PRIV_INFO_FLAGS:
237*7c478bd9Sstevel@tonic-gate 			/* LINTED: alignment */
238*7c478bd9Sstevel@tonic-gate 			pii = (priv_info_uint_t *)x;
239*7c478bd9Sstevel@tonic-gate 			(void) printf("flags =");
240*7c478bd9Sstevel@tonic-gate 			flags2str(pii->val);
241*7c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
242*7c478bd9Sstevel@tonic-gate 			break;
243*7c478bd9Sstevel@tonic-gate 		default:
244*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: unknown priv_info: %d\n",
245*7c478bd9Sstevel@tonic-gate 				arg, pi->priv_info_type);
246*7c478bd9Sstevel@tonic-gate 			break;
247*7c478bd9Sstevel@tonic-gate 		}
248*7c478bd9Sstevel@tonic-gate 		if (pi->priv_info_size > ppriv->pr_infosize ||
249*7c478bd9Sstevel@tonic-gate 		    pi->priv_info_size <=  sizeof (priv_info_t) ||
250*7c478bd9Sstevel@tonic-gate 		    (pi->priv_info_size & 3) != 0) {
251*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: bad priv_info_size: %u\n",
252*7c478bd9Sstevel@tonic-gate 				arg, pi->priv_info_size);
253*7c478bd9Sstevel@tonic-gate 			break;
254*7c478bd9Sstevel@tonic-gate 		}
255*7c478bd9Sstevel@tonic-gate 		x += pi->priv_info_size;
256*7c478bd9Sstevel@tonic-gate 	}
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ppriv->pr_nsets; i++) {
259*7c478bd9Sstevel@tonic-gate 		extern const char *__priv_getsetbynum(const void *, int);
260*7c478bd9Sstevel@tonic-gate 		const char *setnm = pdata ? __priv_getsetbynum(pdata, i)
261*7c478bd9Sstevel@tonic-gate 					    : priv_getsetbynum(i);
262*7c478bd9Sstevel@tonic-gate 		priv_chunk_t *pc = (priv_chunk_t *)
263*7c478bd9Sstevel@tonic-gate 				    &ppriv->pr_sets[ppriv->pr_setsize * i];
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 		(void) printf("\t%c: ", setnm && !nodata ? *setnm : '?');
267*7c478bd9Sstevel@tonic-gate 		if (!nodata) {
268*7c478bd9Sstevel@tonic-gate 			extern char *__priv_set_to_str(void *,
269*7c478bd9Sstevel@tonic-gate 					const priv_set_t *, char, int);
270*7c478bd9Sstevel@tonic-gate 			priv_set_t *pset = (priv_set_t *)pc;
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 			char *s;
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 			if (pdata)
275*7c478bd9Sstevel@tonic-gate 				s = __priv_set_to_str(pdata, pset, ',', mode);
276*7c478bd9Sstevel@tonic-gate 			else
277*7c478bd9Sstevel@tonic-gate 				s = priv_set_to_str(pset, ',', mode);
278*7c478bd9Sstevel@tonic-gate 			(void) puts(s);
279*7c478bd9Sstevel@tonic-gate 			free(s);
280*7c478bd9Sstevel@tonic-gate 		} else {
281*7c478bd9Sstevel@tonic-gate 			int j;
282*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < ppriv->pr_setsize; j++)
283*7c478bd9Sstevel@tonic-gate 				(void) printf("%08x", pc[j]);
284*7c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
285*7c478bd9Sstevel@tonic-gate 		}
286*7c478bd9Sstevel@tonic-gate 	}
287*7c478bd9Sstevel@tonic-gate 	Prelease(Pr, 0);
288*7c478bd9Sstevel@tonic-gate 	return (0);
289*7c478bd9Sstevel@tonic-gate }
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate static void
292*7c478bd9Sstevel@tonic-gate fatal(const char *s)
293*7c478bd9Sstevel@tonic-gate {
294*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: %s: %s\n", command, s, strerror(errno));
295*7c478bd9Sstevel@tonic-gate 	exit(3);
296*7c478bd9Sstevel@tonic-gate }
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate static void
299*7c478bd9Sstevel@tonic-gate perr(char *s)
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	int err = errno;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if (s != NULL)
304*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", procname);
305*7c478bd9Sstevel@tonic-gate 	else
306*7c478bd9Sstevel@tonic-gate 		s = procname;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	errno = err;
309*7c478bd9Sstevel@tonic-gate 	perror(s);
310*7c478bd9Sstevel@tonic-gate }
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate static void
313*7c478bd9Sstevel@tonic-gate usage(void)
314*7c478bd9Sstevel@tonic-gate {
315*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
316*7c478bd9Sstevel@tonic-gate 	    "usage:\t%s [-v] [-S] [-D|-N] [-s spec] { pid | core } ...\n"
317*7c478bd9Sstevel@tonic-gate 	    "\t%s -e [-D|-N] [-s spec] cmd [args ...]\n"
318*7c478bd9Sstevel@tonic-gate 	    "\t%s -l [-v] [privilege ...]\n"
319*7c478bd9Sstevel@tonic-gate 	    "  (report, set or list process privileges)\n", command,
320*7c478bd9Sstevel@tonic-gate 	    command, command);
321*7c478bd9Sstevel@tonic-gate 	exit(2);
322*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
323*7c478bd9Sstevel@tonic-gate }
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate /*
326*7c478bd9Sstevel@tonic-gate  * Parse the privilege bits to add and/or remove from
327*7c478bd9Sstevel@tonic-gate  * a privilege set.
328*7c478bd9Sstevel@tonic-gate  *
329*7c478bd9Sstevel@tonic-gate  * [EPIL][+-=]priv,priv,priv
330*7c478bd9Sstevel@tonic-gate  */
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate static int
333*7c478bd9Sstevel@tonic-gate strindex(char c, const char *str)
334*7c478bd9Sstevel@tonic-gate {
335*7c478bd9Sstevel@tonic-gate 	const char *s;
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	if (islower(c))
338*7c478bd9Sstevel@tonic-gate 		c = toupper(c);
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	s = strchr(str, c);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	if (s == NULL)
343*7c478bd9Sstevel@tonic-gate 		return (-1);
344*7c478bd9Sstevel@tonic-gate 	else
345*7c478bd9Sstevel@tonic-gate 		return (s - str);
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate static void
349*7c478bd9Sstevel@tonic-gate badspec(const char *spec)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: bad privilege specification: \"%s\"\n",
352*7c478bd9Sstevel@tonic-gate 				command, spec);
353*7c478bd9Sstevel@tonic-gate 	exit(3);
354*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
355*7c478bd9Sstevel@tonic-gate }
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate /*
358*7c478bd9Sstevel@tonic-gate  * For each set, you can set either add and/or
359*7c478bd9Sstevel@tonic-gate  * remove or you can set assign.
360*7c478bd9Sstevel@tonic-gate  */
361*7c478bd9Sstevel@tonic-gate static priv_set_t **rem, **add, **assign;
362*7c478bd9Sstevel@tonic-gate static const priv_impl_info_t *pri = NULL;
363*7c478bd9Sstevel@tonic-gate static char *sets;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate static void
366*7c478bd9Sstevel@tonic-gate loadprivinfo(void)
367*7c478bd9Sstevel@tonic-gate {
368*7c478bd9Sstevel@tonic-gate 	int i;
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	if (pri != NULL)
371*7c478bd9Sstevel@tonic-gate 		return;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	pri = getprivimplinfo();
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	if (pri == NULL)
376*7c478bd9Sstevel@tonic-gate 		fatal("getprivimplinfo");
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	sets = malloc(pri->priv_nsets + 1);
379*7c478bd9Sstevel@tonic-gate 	if (sets == NULL)
380*7c478bd9Sstevel@tonic-gate 		fatal("malloc");
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < pri->priv_nsets; i++) {
383*7c478bd9Sstevel@tonic-gate 		sets[i] = *priv_getsetbynum(i);
384*7c478bd9Sstevel@tonic-gate 		if (islower(sets[i]))
385*7c478bd9Sstevel@tonic-gate 			sets[i] = toupper(sets[i]);
386*7c478bd9Sstevel@tonic-gate 	}
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	sets[pri->priv_nsets] = '\0';
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	rem = calloc(pri->priv_nsets, sizeof (priv_set_t *));
391*7c478bd9Sstevel@tonic-gate 	add = calloc(pri->priv_nsets, sizeof (priv_set_t *));
392*7c478bd9Sstevel@tonic-gate 	assign = calloc(pri->priv_nsets, sizeof (priv_set_t *));
393*7c478bd9Sstevel@tonic-gate 	if (rem == NULL || add == NULL || assign == NULL)
394*7c478bd9Sstevel@tonic-gate 		fatal("calloc");
395*7c478bd9Sstevel@tonic-gate }
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate static int
398*7c478bd9Sstevel@tonic-gate parsespec(const char *spec)
399*7c478bd9Sstevel@tonic-gate {
400*7c478bd9Sstevel@tonic-gate 	char *p;
401*7c478bd9Sstevel@tonic-gate 	const char *q;
402*7c478bd9Sstevel@tonic-gate 	int count;
403*7c478bd9Sstevel@tonic-gate 	priv_set_t ***toupd;
404*7c478bd9Sstevel@tonic-gate 	priv_set_t *upd;
405*7c478bd9Sstevel@tonic-gate 	int i;
406*7c478bd9Sstevel@tonic-gate 	boolean_t freeupd = B_TRUE;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	if (pri == NULL)
409*7c478bd9Sstevel@tonic-gate 		loadprivinfo();
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	p = strpbrk(spec, "+-=");
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	if (p == NULL || p - spec > pri->priv_nsets)
414*7c478bd9Sstevel@tonic-gate 		badspec(spec);
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	if (p[1] == '\0' || (upd = priv_str_to_set(p + 1, ",", NULL)) == NULL)
417*7c478bd9Sstevel@tonic-gate 		badspec(p + 1);
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	count = p - spec;
420*7c478bd9Sstevel@tonic-gate 	switch (*p) {
421*7c478bd9Sstevel@tonic-gate 	case '+':
422*7c478bd9Sstevel@tonic-gate 		toupd = &add;
423*7c478bd9Sstevel@tonic-gate 		break;
424*7c478bd9Sstevel@tonic-gate 	case '-':
425*7c478bd9Sstevel@tonic-gate 		toupd = &rem;
426*7c478bd9Sstevel@tonic-gate 		priv_inverse(upd);
427*7c478bd9Sstevel@tonic-gate 		break;
428*7c478bd9Sstevel@tonic-gate 	case '=':
429*7c478bd9Sstevel@tonic-gate 		toupd = &assign;
430*7c478bd9Sstevel@tonic-gate 		break;
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	/* Update all sets? */
434*7c478bd9Sstevel@tonic-gate 	if (count == 0 || *spec == 'a' || *spec == 'A') {
435*7c478bd9Sstevel@tonic-gate 		count = pri->priv_nsets;
436*7c478bd9Sstevel@tonic-gate 		q = sets;
437*7c478bd9Sstevel@tonic-gate 	} else
438*7c478bd9Sstevel@tonic-gate 		q = spec;
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
441*7c478bd9Sstevel@tonic-gate 		int ind = strindex(q[i], sets);
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 		if (ind == -1)
444*7c478bd9Sstevel@tonic-gate 			badspec(spec);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 		/* Assign is mutually exclusive with add/remove and itself */
447*7c478bd9Sstevel@tonic-gate 		if (((toupd == &rem || toupd == &add) && assign[ind] != NULL) ||
448*7c478bd9Sstevel@tonic-gate 		    (toupd == &assign && (assign[ind] != NULL ||
449*7c478bd9Sstevel@tonic-gate 			    rem[ind] != NULL || add[ind] != NULL))) {
450*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: conflicting spec: %s\n",
451*7c478bd9Sstevel@tonic-gate 					command, spec);
452*7c478bd9Sstevel@tonic-gate 			exit(1);
453*7c478bd9Sstevel@tonic-gate 		}
454*7c478bd9Sstevel@tonic-gate 		if ((*toupd)[ind] != NULL) {
455*7c478bd9Sstevel@tonic-gate 			if (*p == '-')
456*7c478bd9Sstevel@tonic-gate 				priv_intersect(upd, (*toupd)[ind]);
457*7c478bd9Sstevel@tonic-gate 			else
458*7c478bd9Sstevel@tonic-gate 				priv_union(upd, (*toupd)[ind]);
459*7c478bd9Sstevel@tonic-gate 		} else {
460*7c478bd9Sstevel@tonic-gate 			(*toupd)[ind] = upd;
461*7c478bd9Sstevel@tonic-gate 			freeupd = B_FALSE;
462*7c478bd9Sstevel@tonic-gate 		}
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 	if (freeupd)
465*7c478bd9Sstevel@tonic-gate 		priv_freeset(upd);
466*7c478bd9Sstevel@tonic-gate 	return (0);
467*7c478bd9Sstevel@tonic-gate }
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate static void
470*7c478bd9Sstevel@tonic-gate privupdate(prpriv_t *pr, const char *arg)
471*7c478bd9Sstevel@tonic-gate {
472*7c478bd9Sstevel@tonic-gate 	int i;
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	if (sets != NULL) {
475*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < pri->priv_nsets; i++) {
476*7c478bd9Sstevel@tonic-gate 			priv_set_t *target =
477*7c478bd9Sstevel@tonic-gate 				(priv_set_t *)&pr->pr_sets[pr->pr_setsize * i];
478*7c478bd9Sstevel@tonic-gate 			if (rem[i] != NULL)
479*7c478bd9Sstevel@tonic-gate 				priv_intersect(rem[i], target);
480*7c478bd9Sstevel@tonic-gate 			if (add[i] != NULL)
481*7c478bd9Sstevel@tonic-gate 				priv_union(add[i], target);
482*7c478bd9Sstevel@tonic-gate 			if (assign[i] != NULL)
483*7c478bd9Sstevel@tonic-gate 				priv_copyset(assign[i], target);
484*7c478bd9Sstevel@tonic-gate 		}
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	if (Doff || Don) {
488*7c478bd9Sstevel@tonic-gate 		priv_info_uint_t *pii;
489*7c478bd9Sstevel@tonic-gate 		int sz = PRIV_PRPRIV_SIZE(pr);
490*7c478bd9Sstevel@tonic-gate 		char *x = (char *)pr + PRIV_PRPRIV_INFO_OFFSET(pr);
491*7c478bd9Sstevel@tonic-gate 		uint32_t fl = 0;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 		while (x < (char *)pr + sz) {
494*7c478bd9Sstevel@tonic-gate 			/* LINTED: alignment */
495*7c478bd9Sstevel@tonic-gate 			priv_info_t *pi = (priv_info_t *)x;
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 			if (pi->priv_info_type == PRIV_INFO_FLAGS) {
498*7c478bd9Sstevel@tonic-gate 				/* LINTED: alignment */
499*7c478bd9Sstevel@tonic-gate 				pii = (priv_info_uint_t *)x;
500*7c478bd9Sstevel@tonic-gate 				fl = pii->val;
501*7c478bd9Sstevel@tonic-gate 				goto done;
502*7c478bd9Sstevel@tonic-gate 			}
503*7c478bd9Sstevel@tonic-gate 			if (pi->priv_info_size > pr->pr_infosize ||
504*7c478bd9Sstevel@tonic-gate 			    pi->priv_info_size <=  sizeof (priv_info_t) ||
505*7c478bd9Sstevel@tonic-gate 			    (pi->priv_info_size & 3) != 0)
506*7c478bd9Sstevel@tonic-gate 				break;
507*7c478bd9Sstevel@tonic-gate 			x += pi->priv_info_size;
508*7c478bd9Sstevel@tonic-gate 		}
509*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
510*7c478bd9Sstevel@tonic-gate 			"%s: cannot find privilege flags to set\n", arg);
511*7c478bd9Sstevel@tonic-gate 		pr->pr_infosize = 0;
512*7c478bd9Sstevel@tonic-gate 		return;
513*7c478bd9Sstevel@tonic-gate done:
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 		pr->pr_infosize = sizeof (priv_info_uint_t);
516*7c478bd9Sstevel@tonic-gate 		/* LINTED: alignment */
517*7c478bd9Sstevel@tonic-gate 		pii = (priv_info_uint_t *)
518*7c478bd9Sstevel@tonic-gate 			    ((char *)pr + PRIV_PRPRIV_INFO_OFFSET(pr));
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 		if (Don)
521*7c478bd9Sstevel@tonic-gate 			fl |= PRIV_DEBUG;
522*7c478bd9Sstevel@tonic-gate 		else
523*7c478bd9Sstevel@tonic-gate 			fl &= ~PRIV_DEBUG;
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 		pii->info.priv_info_size = sizeof (*pii);
526*7c478bd9Sstevel@tonic-gate 		pii->info.priv_info_type = PRIV_INFO_FLAGS;
527*7c478bd9Sstevel@tonic-gate 		pii->val = fl;
528*7c478bd9Sstevel@tonic-gate 	} else {
529*7c478bd9Sstevel@tonic-gate 		pr->pr_infosize = 0;
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate }
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate static void
534*7c478bd9Sstevel@tonic-gate privupdate_self(void)
535*7c478bd9Sstevel@tonic-gate {
536*7c478bd9Sstevel@tonic-gate 	int set;
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 	if (sets != NULL) {
539*7c478bd9Sstevel@tonic-gate 		priv_set_t *target = priv_allocset();
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 		if (target == NULL)
542*7c478bd9Sstevel@tonic-gate 			fatal("priv_allocet");
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 		set = priv_getsetbyname(PRIV_INHERITABLE);
545*7c478bd9Sstevel@tonic-gate 		if (rem[set] != NULL || add[set] != NULL ||
546*7c478bd9Sstevel@tonic-gate 		    assign[set] != NULL) {
547*7c478bd9Sstevel@tonic-gate 			(void) getppriv(PRIV_INHERITABLE, target);
548*7c478bd9Sstevel@tonic-gate 			if (rem[set] != NULL)
549*7c478bd9Sstevel@tonic-gate 				priv_intersect(rem[set], target);
550*7c478bd9Sstevel@tonic-gate 			if (add[set] != NULL)
551*7c478bd9Sstevel@tonic-gate 				priv_union(add[set], target);
552*7c478bd9Sstevel@tonic-gate 			if (assign[set] != NULL)
553*7c478bd9Sstevel@tonic-gate 				priv_copyset(assign[set], target);
554*7c478bd9Sstevel@tonic-gate 			if (setppriv(PRIV_SET, PRIV_INHERITABLE, target) != 0)
555*7c478bd9Sstevel@tonic-gate 				fatal("setppriv(Inheritable)");
556*7c478bd9Sstevel@tonic-gate 		}
557*7c478bd9Sstevel@tonic-gate 		set = priv_getsetbyname(PRIV_LIMIT);
558*7c478bd9Sstevel@tonic-gate 		if (rem[set] != NULL || add[set] != NULL ||
559*7c478bd9Sstevel@tonic-gate 		    assign[set] != NULL) {
560*7c478bd9Sstevel@tonic-gate 			(void) getppriv(PRIV_LIMIT, target);
561*7c478bd9Sstevel@tonic-gate 			if (rem[set] != NULL)
562*7c478bd9Sstevel@tonic-gate 				priv_intersect(rem[set], target);
563*7c478bd9Sstevel@tonic-gate 			if (add[set] != NULL)
564*7c478bd9Sstevel@tonic-gate 				priv_union(add[set], target);
565*7c478bd9Sstevel@tonic-gate 			if (assign[set] != NULL)
566*7c478bd9Sstevel@tonic-gate 				priv_copyset(assign[set], target);
567*7c478bd9Sstevel@tonic-gate 			if (setppriv(PRIV_SET, PRIV_LIMIT, target) != 0)
568*7c478bd9Sstevel@tonic-gate 				fatal("setppriv(Limit)");
569*7c478bd9Sstevel@tonic-gate 		}
570*7c478bd9Sstevel@tonic-gate 		priv_freeset(target);
571*7c478bd9Sstevel@tonic-gate 	}
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	if (Doff || Don)
574*7c478bd9Sstevel@tonic-gate 		(void) setpflags(PRIV_DEBUG, Don ? 1 : 0);
575*7c478bd9Sstevel@tonic-gate }
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate static int
578*7c478bd9Sstevel@tonic-gate dopriv(const char *p)
579*7c478bd9Sstevel@tonic-gate {
580*7c478bd9Sstevel@tonic-gate 	(void) puts(p);
581*7c478bd9Sstevel@tonic-gate 	if (verb) {
582*7c478bd9Sstevel@tonic-gate 		char *text = priv_gettext(p);
583*7c478bd9Sstevel@tonic-gate 		char *p, *q;
584*7c478bd9Sstevel@tonic-gate 		if (text == NULL)
585*7c478bd9Sstevel@tonic-gate 			return (1);
586*7c478bd9Sstevel@tonic-gate 		for (p = text; q = strchr(p, '\n'); p = q + 1)
587*7c478bd9Sstevel@tonic-gate 			(void) printf("\t%.*s", (int)(q - p + 1), p);
588*7c478bd9Sstevel@tonic-gate 		free(text);
589*7c478bd9Sstevel@tonic-gate 	}
590*7c478bd9Sstevel@tonic-gate 	return (0);
591*7c478bd9Sstevel@tonic-gate }
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate static int
594*7c478bd9Sstevel@tonic-gate dumppriv(char **argv)
595*7c478bd9Sstevel@tonic-gate {
596*7c478bd9Sstevel@tonic-gate 	int rc = 0;
597*7c478bd9Sstevel@tonic-gate 	const char *pname;
598*7c478bd9Sstevel@tonic-gate 	int i;
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	if (argv[0] == NULL) {
601*7c478bd9Sstevel@tonic-gate 		for (i = 0; ((pname = priv_getbynum(i++)) != NULL); )
602*7c478bd9Sstevel@tonic-gate 			rc += dopriv(pname);
603*7c478bd9Sstevel@tonic-gate 	} else {
604*7c478bd9Sstevel@tonic-gate 		for (; *argv; argv++) {
605*7c478bd9Sstevel@tonic-gate 			priv_set_t *pset = priv_str_to_set(*argv, ",", NULL);
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 			if (pset == NULL) {
608*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: %s: bad privilege"
609*7c478bd9Sstevel@tonic-gate 				    " list\n", command, *argv);
610*7c478bd9Sstevel@tonic-gate 				rc++;
611*7c478bd9Sstevel@tonic-gate 				continue;
612*7c478bd9Sstevel@tonic-gate 			}
613*7c478bd9Sstevel@tonic-gate 			for (i = 0; ((pname = priv_getbynum(i++)) != NULL); )
614*7c478bd9Sstevel@tonic-gate 				if (priv_ismember(pset, pname))
615*7c478bd9Sstevel@tonic-gate 					rc += dopriv(pname);
616*7c478bd9Sstevel@tonic-gate 		}
617*7c478bd9Sstevel@tonic-gate 	}
618*7c478bd9Sstevel@tonic-gate 	return (rc);
619*7c478bd9Sstevel@tonic-gate }
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate static struct {
622*7c478bd9Sstevel@tonic-gate 	int flag;
623*7c478bd9Sstevel@tonic-gate 	char *name;
624*7c478bd9Sstevel@tonic-gate } flags[] = {
625*7c478bd9Sstevel@tonic-gate 	{ PRIV_DEBUG, "PRIV_DEBUG" },
626*7c478bd9Sstevel@tonic-gate 	{ PRIV_AWARE, "PRIV_AWARE" },
627*7c478bd9Sstevel@tonic-gate 	{ PRIV_AWARE_INHERIT, "PRIV_AWARE_INHERIT" },
628*7c478bd9Sstevel@tonic-gate };
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate /*
631*7c478bd9Sstevel@tonic-gate  * Print flags preceeded by a space.
632*7c478bd9Sstevel@tonic-gate  */
633*7c478bd9Sstevel@tonic-gate static void
634*7c478bd9Sstevel@tonic-gate flags2str(uint_t pflags)
635*7c478bd9Sstevel@tonic-gate {
636*7c478bd9Sstevel@tonic-gate 	char c = ' ';
637*7c478bd9Sstevel@tonic-gate 	int i;
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	if (pflags == 0) {
640*7c478bd9Sstevel@tonic-gate 		(void) fputs(" <none>", stdout);
641*7c478bd9Sstevel@tonic-gate 		return;
642*7c478bd9Sstevel@tonic-gate 	}
643*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (flags)/sizeof (flags[0]) && pflags != 0; i++) {
644*7c478bd9Sstevel@tonic-gate 		if ((pflags & flags[i].flag) != 0) {
645*7c478bd9Sstevel@tonic-gate 			(void) printf("%c%s", c, flags[i].name);
646*7c478bd9Sstevel@tonic-gate 			pflags &= ~flags[i].flag;
647*7c478bd9Sstevel@tonic-gate 			c = '|';
648*7c478bd9Sstevel@tonic-gate 		}
649*7c478bd9Sstevel@tonic-gate 	}
650*7c478bd9Sstevel@tonic-gate 	if (pflags != 0)
651*7c478bd9Sstevel@tonic-gate 		(void) printf("%c<0x%x>", c, pflags);
652*7c478bd9Sstevel@tonic-gate }
653