xref: /titanic_50/usr/src/cmd/prctl/prctl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <unistd.h>
30*7c478bd9Sstevel@tonic-gate #include <rctl.h>
31*7c478bd9Sstevel@tonic-gate #include <libproc.h>
32*7c478bd9Sstevel@tonic-gate #include <stdio.h>
33*7c478bd9Sstevel@tonic-gate #include <libintl.h>
34*7c478bd9Sstevel@tonic-gate #include <locale.h>
35*7c478bd9Sstevel@tonic-gate #include <string.h>
36*7c478bd9Sstevel@tonic-gate #include <signal.h>
37*7c478bd9Sstevel@tonic-gate #include <strings.h>
38*7c478bd9Sstevel@tonic-gate #include <ctype.h>
39*7c478bd9Sstevel@tonic-gate #include <project.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
41*7c478bd9Sstevel@tonic-gate #include <dirent.h>
42*7c478bd9Sstevel@tonic-gate #include <errno.h>
43*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
45*7c478bd9Sstevel@tonic-gate #include <priv.h>
46*7c478bd9Sstevel@tonic-gate #include <zone.h>
47*7c478bd9Sstevel@tonic-gate #include "utils.h"
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate /* Valid user actions */
50*7c478bd9Sstevel@tonic-gate #define	ACTION_DISABLE		0x01
51*7c478bd9Sstevel@tonic-gate #define	ACTION_ENABLE		0x02
52*7c478bd9Sstevel@tonic-gate #define	ACTION_SET		0x04
53*7c478bd9Sstevel@tonic-gate #define	ACTION_REPLACE		0x08
54*7c478bd9Sstevel@tonic-gate #define	ACTION_DELETE		0x10
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #define	PRCTL_VALUE_WIDTH	4
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /* Maximum string length for deferred errors */
59*7c478bd9Sstevel@tonic-gate #define	GLOBAL_ERR_SZ		1024
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /* allow important process values to be passed together easily */
62*7c478bd9Sstevel@tonic-gate typedef struct pr_info_handle {
63*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *pr;
64*7c478bd9Sstevel@tonic-gate 	pid_t pid;
65*7c478bd9Sstevel@tonic-gate 	psinfo_t psinfo;
66*7c478bd9Sstevel@tonic-gate 	taskid_t taskid;
67*7c478bd9Sstevel@tonic-gate 	projid_t projid;
68*7c478bd9Sstevel@tonic-gate 	char *projname;
69*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
70*7c478bd9Sstevel@tonic-gate 	char *zonename;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate } pr_info_handle_t;
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate /* Structures for list of resource controls */
75*7c478bd9Sstevel@tonic-gate typedef struct prctl_value {
76*7c478bd9Sstevel@tonic-gate 	rctlblk_t *rblk;
77*7c478bd9Sstevel@tonic-gate 	struct prctl_value *next;
78*7c478bd9Sstevel@tonic-gate } prctl_value_t;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate typedef struct prctl_list {
81*7c478bd9Sstevel@tonic-gate 	char *name;
82*7c478bd9Sstevel@tonic-gate 	prctl_value_t *val_list;
83*7c478bd9Sstevel@tonic-gate 	struct prctl_list *next;
84*7c478bd9Sstevel@tonic-gate } prctl_list_t;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static	volatile int	interrupt;
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static	prctl_list_t	*global_rctl_list_head = NULL;
89*7c478bd9Sstevel@tonic-gate static	prctl_list_t	*global_rctl_list_tail = NULL;
90*7c478bd9Sstevel@tonic-gate static	char		global_error[GLOBAL_ERR_SZ];
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate /* global variables that contain commmand line option info */
93*7c478bd9Sstevel@tonic-gate static	int	arg_operation = 0;
94*7c478bd9Sstevel@tonic-gate static	int	arg_force = 0;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate /* String and type from -i */
98*7c478bd9Sstevel@tonic-gate static	rctl_entity_t	arg_entity_type = RCENTITY_PROCESS;
99*7c478bd9Sstevel@tonic-gate static	char	*arg_entity_string = NULL;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate /* -n argument */
102*7c478bd9Sstevel@tonic-gate static  char	*arg_name = NULL;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate static	rctl_entity_t	arg_name_entity = 0;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate /* -t argument value */
107*7c478bd9Sstevel@tonic-gate static	int	arg_priv = 0;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate /* -v argument string */
110*7c478bd9Sstevel@tonic-gate static	char	*arg_valuestring = NULL;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /* global flags of rctl name passed to -n */
113*7c478bd9Sstevel@tonic-gate static	int	arg_global_flags = 0;
114*7c478bd9Sstevel@tonic-gate static	rctl_qty_t	arg_global_max;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate /* appropriate scaling variables determined by rctl unit type */
117*7c478bd9Sstevel@tonic-gate scale_t		*arg_scale;
118*7c478bd9Sstevel@tonic-gate static	char	*arg_unit = NULL;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate /* -v argument string converted to uint64_t */
121*7c478bd9Sstevel@tonic-gate static	uint64_t arg_value = 0;
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate /* if -v argument is scaled value, points to "K", "M", "G", ... */
124*7c478bd9Sstevel@tonic-gate static  char	*arg_modifier = NULL;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate /* -e/-d argument string */
127*7c478bd9Sstevel@tonic-gate static	char	*arg_action_string = NULL;
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate /* Set to RCTL_LOCAL_SIGNAL|DENY based on arg_action_string */
130*7c478bd9Sstevel@tonic-gate static	int	arg_action = 0;
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate /* if -e/-d arg is signal=XXX, set to signal number of XXX */
133*7c478bd9Sstevel@tonic-gate static	int	arg_signal = 0;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate /* -p arg if -p is specified */
136*7c478bd9Sstevel@tonic-gate static	int	arg_pid = -1;
137*7c478bd9Sstevel@tonic-gate static	char	*arg_pid_string = NULL;
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate /* Set to 1 if -P is specified */
140*7c478bd9Sstevel@tonic-gate static	int	arg_parseable_mode = 0;
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate /* interupt handler */
143*7c478bd9Sstevel@tonic-gate static	void	intr(int);
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate static	int	get_rctls(struct ps_prochandle *);
146*7c478bd9Sstevel@tonic-gate static	int	store_rctls(const char *rctlname, void *walk_data);
147*7c478bd9Sstevel@tonic-gate static	prctl_value_t	*store_value_entry(rctlblk_t *rblk, prctl_list_t *list);
148*7c478bd9Sstevel@tonic-gate static	prctl_list_t	*store_list_entry(const char *name);
149*7c478bd9Sstevel@tonic-gate static	void	free_lists();
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate static	int	change_action(rctlblk_t *blk);
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate static	int	prctl_setrctl(struct ps_prochandle *Pr, const char *name,
154*7c478bd9Sstevel@tonic-gate 			rctlblk_t *, rctlblk_t *, uint_t);
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate static	int match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name,
157*7c478bd9Sstevel@tonic-gate 			char *valuestringin, int valuein, rctl_priv_t privin,
158*7c478bd9Sstevel@tonic-gate 			int pidin);
159*7c478bd9Sstevel@tonic-gate static	int	match_rctl_blk(rctlblk_t *rctl, char *valuestringin,
160*7c478bd9Sstevel@tonic-gate 			uint64_t valuein,
161*7c478bd9Sstevel@tonic-gate 			rctl_priv_t privin, int pidin);
162*7c478bd9Sstevel@tonic-gate static	pid_t	regrab_process(pid_t pid, pr_info_handle_t *p, int, int *gret);
163*7c478bd9Sstevel@tonic-gate static	pid_t	grab_process_by_id(char *idname, rctl_entity_t type,
164*7c478bd9Sstevel@tonic-gate 			pr_info_handle_t *p, int, int *gret);
165*7c478bd9Sstevel@tonic-gate static	int	grab_process(pr_info_handle_t *p, int *gret);
166*7c478bd9Sstevel@tonic-gate static	void	release_process(struct ps_prochandle *Pr);
167*7c478bd9Sstevel@tonic-gate static	void	preserve_error(char *format, ...);
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate static	void	print_rctls(pr_info_handle_t *p);
170*7c478bd9Sstevel@tonic-gate static	void	print_priv(rctl_priv_t local_priv, char *format);
171*7c478bd9Sstevel@tonic-gate static	void	print_local_action(int action, int *signalp, char *format);
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate static const char USAGE[] = ""
174*7c478bd9Sstevel@tonic-gate "usage:\n"
175*7c478bd9Sstevel@tonic-gate "    Report resource control values and actions:\n"
176*7c478bd9Sstevel@tonic-gate "	prctl [-P] [-t [basic | privileged | system]\n"
177*7c478bd9Sstevel@tonic-gate "	[-n name] [-i process | task | project | zone] id ...\n"
178*7c478bd9Sstevel@tonic-gate "	-P space delimited output\n"
179*7c478bd9Sstevel@tonic-gate "	-t privilege level of rctl values to get\n"
180*7c478bd9Sstevel@tonic-gate "	-n name of resource control values to get\n"
181*7c478bd9Sstevel@tonic-gate "	-i idtype of operand list\n"
182*7c478bd9Sstevel@tonic-gate "    Manipulate resource control values:\n"
183*7c478bd9Sstevel@tonic-gate "	prctl [-t [basic | privileged | system]\n"
184*7c478bd9Sstevel@tonic-gate "	-n name [-srx] [-v value] [-p pid ] [-e | -d action]\n"
185*7c478bd9Sstevel@tonic-gate "	[-i process | task | project | zone] id ...\n"
186*7c478bd9Sstevel@tonic-gate "	-t privilege level of rctl value to set/replace/delete/modify\n"
187*7c478bd9Sstevel@tonic-gate "	-n name of resource control to set/replace/delete/modify\n"
188*7c478bd9Sstevel@tonic-gate "	-s set new resource control value\n"
189*7c478bd9Sstevel@tonic-gate "	-r replace first rctl value of matching privilege\n"
190*7c478bd9Sstevel@tonic-gate "	-x delete first rctl value of matching privilege, value, and \n"
191*7c478bd9Sstevel@tonic-gate "	   recipient pid\n"
192*7c478bd9Sstevel@tonic-gate "	-v value of rctl to set/replace/delete/modify\n"
193*7c478bd9Sstevel@tonic-gate "	-p recipient pid of rctl to set/replace/delete/modify\n"
194*7c478bd9Sstevel@tonic-gate "	-e enable action of first rctl value of matching privilege,\n"
195*7c478bd9Sstevel@tonic-gate "	   value, and recipient pid\n"
196*7c478bd9Sstevel@tonic-gate "	-d disable action of first rctl value of matching privilege,\n"
197*7c478bd9Sstevel@tonic-gate "	   value, and recipient pid\n"
198*7c478bd9Sstevel@tonic-gate "	-i idtype of operand list\n";
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate static void
202*7c478bd9Sstevel@tonic-gate usage()
203*7c478bd9Sstevel@tonic-gate {
204*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(USAGE));
205*7c478bd9Sstevel@tonic-gate 	exit(2);
206*7c478bd9Sstevel@tonic-gate }
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate int
209*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
210*7c478bd9Sstevel@tonic-gate {
211*7c478bd9Sstevel@tonic-gate 	int flags;
212*7c478bd9Sstevel@tonic-gate 	int opt, errflg = 0;
213*7c478bd9Sstevel@tonic-gate 	rctlblk_t *rctlblkA = NULL;
214*7c478bd9Sstevel@tonic-gate 	rctlblk_t *rctlblkB = NULL;
215*7c478bd9Sstevel@tonic-gate 	rctlblk_t *tmp = NULL;
216*7c478bd9Sstevel@tonic-gate 	pid_t pid;
217*7c478bd9Sstevel@tonic-gate 	char *target_id;
218*7c478bd9Sstevel@tonic-gate 	int search_type;
219*7c478bd9Sstevel@tonic-gate 	int signal;
220*7c478bd9Sstevel@tonic-gate 	int localaction;
221*7c478bd9Sstevel@tonic-gate 	int printed = 0;
222*7c478bd9Sstevel@tonic-gate 	int gret;
223*7c478bd9Sstevel@tonic-gate 	char *end;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
226*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
227*7c478bd9Sstevel@tonic-gate 	(void) setprogname(argv[0]);
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "sPp:Fd:e:i:n:rt:v:x")) != EOF) {
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 		switch (opt) {
232*7c478bd9Sstevel@tonic-gate 		case 'F':	/* force grabbing (no O_EXCL) */
233*7c478bd9Sstevel@tonic-gate 			arg_force = PGRAB_FORCE;
234*7c478bd9Sstevel@tonic-gate 			break;
235*7c478bd9Sstevel@tonic-gate 		case 'i':	/* id type for arguments */
236*7c478bd9Sstevel@tonic-gate 			arg_entity_string = optarg;
237*7c478bd9Sstevel@tonic-gate 			if (strcmp(optarg, "process") == 0 ||
238*7c478bd9Sstevel@tonic-gate 			    strcmp(optarg, "pid") == 0)
239*7c478bd9Sstevel@tonic-gate 				arg_entity_type = RCENTITY_PROCESS;
240*7c478bd9Sstevel@tonic-gate 			else if (strcmp(optarg, "project") == 0 ||
241*7c478bd9Sstevel@tonic-gate 				strcmp(optarg, "projid") == 0)
242*7c478bd9Sstevel@tonic-gate 				arg_entity_type = RCENTITY_PROJECT;
243*7c478bd9Sstevel@tonic-gate 			else if (strcmp(optarg, "task") == 0 ||
244*7c478bd9Sstevel@tonic-gate 				strcmp(optarg, "taskid") == 0)
245*7c478bd9Sstevel@tonic-gate 				arg_entity_type = RCENTITY_TASK;
246*7c478bd9Sstevel@tonic-gate 			else if (strcmp(optarg, "zone") == 0 ||
247*7c478bd9Sstevel@tonic-gate 				strcmp(optarg, "zoneid") == 0)
248*7c478bd9Sstevel@tonic-gate 				arg_entity_type = RCENTITY_ZONE;
249*7c478bd9Sstevel@tonic-gate 			else {
250*7c478bd9Sstevel@tonic-gate 				warn(gettext("unknown idtype %s"), optarg);
251*7c478bd9Sstevel@tonic-gate 				errflg = 1;
252*7c478bd9Sstevel@tonic-gate 			}
253*7c478bd9Sstevel@tonic-gate 			break;
254*7c478bd9Sstevel@tonic-gate 		case 'd':
255*7c478bd9Sstevel@tonic-gate 			arg_action_string = optarg;
256*7c478bd9Sstevel@tonic-gate 			arg_operation |= ACTION_DISABLE;
257*7c478bd9Sstevel@tonic-gate 			break;
258*7c478bd9Sstevel@tonic-gate 		case 'e':
259*7c478bd9Sstevel@tonic-gate 			arg_action_string = optarg;
260*7c478bd9Sstevel@tonic-gate 			arg_operation |= ACTION_ENABLE;
261*7c478bd9Sstevel@tonic-gate 			break;
262*7c478bd9Sstevel@tonic-gate 		case 'n':	/* name of rctl */
263*7c478bd9Sstevel@tonic-gate 			arg_name = optarg;
264*7c478bd9Sstevel@tonic-gate 			if (strncmp(optarg, "process.",
265*7c478bd9Sstevel@tonic-gate 			    strlen("process.")) == 0)
266*7c478bd9Sstevel@tonic-gate 				arg_name_entity = RCENTITY_PROCESS;
267*7c478bd9Sstevel@tonic-gate 			else if (strncmp(optarg, "project.",
268*7c478bd9Sstevel@tonic-gate 			    strlen("project.")) == 0)
269*7c478bd9Sstevel@tonic-gate 				arg_name_entity = RCENTITY_PROJECT;
270*7c478bd9Sstevel@tonic-gate 			else if (strncmp(optarg, "task.",
271*7c478bd9Sstevel@tonic-gate 			    strlen("task.")) == 0)
272*7c478bd9Sstevel@tonic-gate 				arg_name_entity = RCENTITY_TASK;
273*7c478bd9Sstevel@tonic-gate 			else if (strncmp(optarg, "zone.",
274*7c478bd9Sstevel@tonic-gate 			    strlen("zone.")) == 0)
275*7c478bd9Sstevel@tonic-gate 				arg_name_entity = RCENTITY_ZONE;
276*7c478bd9Sstevel@tonic-gate 			break;
277*7c478bd9Sstevel@tonic-gate 		case 'r':
278*7c478bd9Sstevel@tonic-gate 			arg_operation |= ACTION_REPLACE;
279*7c478bd9Sstevel@tonic-gate 			break;
280*7c478bd9Sstevel@tonic-gate 		case 't':	/* rctl type */
281*7c478bd9Sstevel@tonic-gate 			if (strcmp(optarg, "basic") == 0)
282*7c478bd9Sstevel@tonic-gate 				arg_priv = RCPRIV_BASIC;
283*7c478bd9Sstevel@tonic-gate 			else if (strcmp(optarg, "privileged") == 0)
284*7c478bd9Sstevel@tonic-gate 				arg_priv = RCPRIV_PRIVILEGED;
285*7c478bd9Sstevel@tonic-gate 			else if (strcmp(optarg, "priv") == 0)
286*7c478bd9Sstevel@tonic-gate 				arg_priv = RCPRIV_PRIVILEGED;
287*7c478bd9Sstevel@tonic-gate 			else if (strcmp(optarg, "system") == 0)
288*7c478bd9Sstevel@tonic-gate 				arg_priv = RCPRIV_SYSTEM;
289*7c478bd9Sstevel@tonic-gate 			else {
290*7c478bd9Sstevel@tonic-gate 				warn(gettext("unknown privilege %s"), optarg);
291*7c478bd9Sstevel@tonic-gate 				errflg = 1;
292*7c478bd9Sstevel@tonic-gate 			}
293*7c478bd9Sstevel@tonic-gate 			break;
294*7c478bd9Sstevel@tonic-gate 		case 'v':	/* value */
295*7c478bd9Sstevel@tonic-gate 			arg_valuestring = optarg;
296*7c478bd9Sstevel@tonic-gate 			break;
297*7c478bd9Sstevel@tonic-gate 		case 's':
298*7c478bd9Sstevel@tonic-gate 			arg_operation |= ACTION_SET;
299*7c478bd9Sstevel@tonic-gate 			break;
300*7c478bd9Sstevel@tonic-gate 		case 'x':	/* delete */
301*7c478bd9Sstevel@tonic-gate 			arg_operation |= ACTION_DELETE;
302*7c478bd9Sstevel@tonic-gate 			break;
303*7c478bd9Sstevel@tonic-gate 		case 'p':
304*7c478bd9Sstevel@tonic-gate 			errno = 0;
305*7c478bd9Sstevel@tonic-gate 			/* Stick with -1 if arg is "-" */
306*7c478bd9Sstevel@tonic-gate 			if (strcmp("-", optarg) == 0)
307*7c478bd9Sstevel@tonic-gate 				break;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 			arg_pid_string = optarg;
310*7c478bd9Sstevel@tonic-gate 			arg_pid = strtoul(optarg, &end, 10);
311*7c478bd9Sstevel@tonic-gate 			if (errno || *end != '\0' || end == optarg) {
312*7c478bd9Sstevel@tonic-gate 				warn(gettext("invalid pid %s"), optarg);
313*7c478bd9Sstevel@tonic-gate 				errflg = 1;
314*7c478bd9Sstevel@tonic-gate 				break;
315*7c478bd9Sstevel@tonic-gate 			}
316*7c478bd9Sstevel@tonic-gate 			break;
317*7c478bd9Sstevel@tonic-gate 		case 'P':
318*7c478bd9Sstevel@tonic-gate 			arg_parseable_mode = 1;
319*7c478bd9Sstevel@tonic-gate 			break;
320*7c478bd9Sstevel@tonic-gate 		default:
321*7c478bd9Sstevel@tonic-gate 			warn(gettext("unknown option"));
322*7c478bd9Sstevel@tonic-gate 			errflg = 1;
323*7c478bd9Sstevel@tonic-gate 			break;
324*7c478bd9Sstevel@tonic-gate 		}
325*7c478bd9Sstevel@tonic-gate 	}
326*7c478bd9Sstevel@tonic-gate 	argc -= optind;
327*7c478bd9Sstevel@tonic-gate 	argv += optind;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	if (argc < 1) {
330*7c478bd9Sstevel@tonic-gate 		warn(gettext("no arguments specified"));
331*7c478bd9Sstevel@tonic-gate 		errflg = 1;
332*7c478bd9Sstevel@tonic-gate 		goto done_parse;
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate 	/* if -v is specified without -r, -x, -d, or -e, -s is implied */
335*7c478bd9Sstevel@tonic-gate 	if (arg_valuestring &&
336*7c478bd9Sstevel@tonic-gate 	    (!(arg_operation & (ACTION_REPLACE | ACTION_DELETE |
337*7c478bd9Sstevel@tonic-gate 		ACTION_DISABLE | ACTION_ENABLE)))) {
338*7c478bd9Sstevel@tonic-gate 		arg_operation |= ACTION_SET;
339*7c478bd9Sstevel@tonic-gate 	}
340*7c478bd9Sstevel@tonic-gate 	/* operations require -n */
341*7c478bd9Sstevel@tonic-gate 	if (arg_operation && (arg_name == NULL)) {
342*7c478bd9Sstevel@tonic-gate 		warn(gettext("-n is required with -s, -r, -x, -e, or -d"));
343*7c478bd9Sstevel@tonic-gate 		errflg = 1;
344*7c478bd9Sstevel@tonic-gate 		goto done_parse;
345*7c478bd9Sstevel@tonic-gate 	}
346*7c478bd9Sstevel@tonic-gate 	/* enable and disable are exclusive */
347*7c478bd9Sstevel@tonic-gate 	if ((arg_operation & ACTION_ENABLE) &&
348*7c478bd9Sstevel@tonic-gate 	    (arg_operation & ACTION_DISABLE)) {
349*7c478bd9Sstevel@tonic-gate 		warn(gettext("options -d and -e are exclusive"));
350*7c478bd9Sstevel@tonic-gate 		errflg = 1;
351*7c478bd9Sstevel@tonic-gate 		goto done_parse;
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate 	/* -s, -r, and -x are exclusive */
354*7c478bd9Sstevel@tonic-gate 	flags = arg_operation &
355*7c478bd9Sstevel@tonic-gate 	    (ACTION_REPLACE | ACTION_SET | ACTION_DELETE);
356*7c478bd9Sstevel@tonic-gate 	if (flags & (flags - 1)) {
357*7c478bd9Sstevel@tonic-gate 		warn(gettext("options -s, -r, and -x are exclusive"));
358*7c478bd9Sstevel@tonic-gate 		errflg = 1;
359*7c478bd9Sstevel@tonic-gate 		goto done_parse;
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 	/* -e or -d makes no sense with -x */
362*7c478bd9Sstevel@tonic-gate 	if ((arg_operation & ACTION_DELETE) &
363*7c478bd9Sstevel@tonic-gate 	    (arg_operation & (ACTION_ENABLE | ACTION_DISABLE))) {
364*7c478bd9Sstevel@tonic-gate 		warn(gettext("options -e or -d  not allowed with -x"));
365*7c478bd9Sstevel@tonic-gate 		errflg = 1;
366*7c478bd9Sstevel@tonic-gate 		goto done_parse;
367*7c478bd9Sstevel@tonic-gate 	}
368*7c478bd9Sstevel@tonic-gate 	/* if -r is specified -v must be as well */
369*7c478bd9Sstevel@tonic-gate 	if ((arg_operation & ACTION_REPLACE) && (!arg_valuestring)) {
370*7c478bd9Sstevel@tonic-gate 		warn(gettext("option -r requires use of option -v"));
371*7c478bd9Sstevel@tonic-gate 		errflg = 1;
372*7c478bd9Sstevel@tonic-gate 		goto done_parse;
373*7c478bd9Sstevel@tonic-gate 	}
374*7c478bd9Sstevel@tonic-gate 	/* if -s is specified -v must be as well */
375*7c478bd9Sstevel@tonic-gate 	if ((arg_operation & ACTION_SET) && (!arg_valuestring)) {
376*7c478bd9Sstevel@tonic-gate 		warn(gettext("option -s requires use of option -v"));
377*7c478bd9Sstevel@tonic-gate 		errflg = 1;
378*7c478bd9Sstevel@tonic-gate 		goto done_parse;
379*7c478bd9Sstevel@tonic-gate 	}
380*7c478bd9Sstevel@tonic-gate 	/* Specifying a recipient pid on a non-basic rctl makes no sense */
381*7c478bd9Sstevel@tonic-gate 	if (arg_pid != -1 && arg_priv > RCPRIV_BASIC) {
382*7c478bd9Sstevel@tonic-gate 		warn(gettext("option -p not allowed on non-basic rctl"));
383*7c478bd9Sstevel@tonic-gate 		errflg = 1;
384*7c478bd9Sstevel@tonic-gate 		goto done_parse;
385*7c478bd9Sstevel@tonic-gate 	}
386*7c478bd9Sstevel@tonic-gate 	/* Specifying a recipient pid on a privileged rctl makes no sense */
387*7c478bd9Sstevel@tonic-gate 	if (arg_pid != -1 &&
388*7c478bd9Sstevel@tonic-gate 	    arg_priv == RCPRIV_PRIVILEGED) {
389*7c478bd9Sstevel@tonic-gate 		warn(gettext("option -p not allowed with privileged rctl"));
390*7c478bd9Sstevel@tonic-gate 		errflg = 1;
391*7c478bd9Sstevel@tonic-gate 		goto done_parse;
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 	if (arg_operation) {
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 		/* do additional checks if there is an operation */
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 		if (arg_parseable_mode == 1) {
398*7c478bd9Sstevel@tonic-gate 			warn(gettext("-P not valid when manipulating "
399*7c478bd9Sstevel@tonic-gate 			    "resource control values"));
400*7c478bd9Sstevel@tonic-gate 			errflg = 1;
401*7c478bd9Sstevel@tonic-gate 			goto done_parse;
402*7c478bd9Sstevel@tonic-gate 		}
403*7c478bd9Sstevel@tonic-gate 		/* get rctl global flags to determine if actions are valid */
404*7c478bd9Sstevel@tonic-gate 		if ((rctlblkA = calloc(1, rctlblk_size())) == NULL) {
405*7c478bd9Sstevel@tonic-gate 			warn(gettext("malloc failed: %s"),
406*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
407*7c478bd9Sstevel@tonic-gate 			errflg = 1;
408*7c478bd9Sstevel@tonic-gate 			goto done_parse;
409*7c478bd9Sstevel@tonic-gate 		}
410*7c478bd9Sstevel@tonic-gate 		if ((rctlblkB = calloc(1, rctlblk_size())) == NULL) {
411*7c478bd9Sstevel@tonic-gate 			warn(gettext("malloc failed: %s"),
412*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
413*7c478bd9Sstevel@tonic-gate 			errflg = 1;
414*7c478bd9Sstevel@tonic-gate 			goto done_parse;
415*7c478bd9Sstevel@tonic-gate 		}
416*7c478bd9Sstevel@tonic-gate 		/* get system rctl to get global flags and max value */
417*7c478bd9Sstevel@tonic-gate 		if (getrctl(arg_name, NULL, rctlblkA, RCTL_FIRST)) {
418*7c478bd9Sstevel@tonic-gate 			warn(gettext("failed to get resource control "
419*7c478bd9Sstevel@tonic-gate 			    "for %s: %s"), arg_name, strerror(errno));
420*7c478bd9Sstevel@tonic-gate 			errflg = 1;
421*7c478bd9Sstevel@tonic-gate 			goto done_parse;
422*7c478bd9Sstevel@tonic-gate 		}
423*7c478bd9Sstevel@tonic-gate 		while (getrctl(arg_name, rctlblkA, rctlblkB, RCTL_NEXT) == 0) {
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 			/* allow user interrupt */
426*7c478bd9Sstevel@tonic-gate 			if (interrupt) {
427*7c478bd9Sstevel@tonic-gate 				errflg = 1;
428*7c478bd9Sstevel@tonic-gate 				goto done_parse;
429*7c478bd9Sstevel@tonic-gate 			}
430*7c478bd9Sstevel@tonic-gate 			tmp = rctlblkB;
431*7c478bd9Sstevel@tonic-gate 			rctlblkB = rctlblkA;
432*7c478bd9Sstevel@tonic-gate 			rctlblkA = tmp;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 			if (rctlblk_get_privilege(rctlblkA) ==
435*7c478bd9Sstevel@tonic-gate 			    RCPRIV_SYSTEM) {
436*7c478bd9Sstevel@tonic-gate 				break;
437*7c478bd9Sstevel@tonic-gate 			}
438*7c478bd9Sstevel@tonic-gate 		}
439*7c478bd9Sstevel@tonic-gate 		if (rctlblk_get_privilege(rctlblkA) != RCPRIV_SYSTEM) {
440*7c478bd9Sstevel@tonic-gate 			warn(gettext("failed to get system resource control "
441*7c478bd9Sstevel@tonic-gate 			    "for %s: %s"), arg_name, strerror(errno));
442*7c478bd9Sstevel@tonic-gate 			errflg = 1;
443*7c478bd9Sstevel@tonic-gate 			goto done_parse;
444*7c478bd9Sstevel@tonic-gate 		}
445*7c478bd9Sstevel@tonic-gate 		/* figure out the correct scale and unit for this rctl */
446*7c478bd9Sstevel@tonic-gate 		arg_global_flags = rctlblk_get_global_flags(rctlblkA);
447*7c478bd9Sstevel@tonic-gate 		arg_global_max = rctlblk_get_value(rctlblkA);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 		if (arg_global_flags & RCTL_GLOBAL_BYTES) {
450*7c478bd9Sstevel@tonic-gate 			arg_unit = SCALED_UNIT_BYTES;
451*7c478bd9Sstevel@tonic-gate 			arg_scale = scale_binary;
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 		} else if (arg_global_flags & RCTL_GLOBAL_SECONDS) {
454*7c478bd9Sstevel@tonic-gate 			arg_unit = SCALED_UNIT_SECONDS;
455*7c478bd9Sstevel@tonic-gate 			arg_scale = scale_metric;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 		} else {
458*7c478bd9Sstevel@tonic-gate 			arg_unit = SCALED_UNIT_NONE;
459*7c478bd9Sstevel@tonic-gate 			arg_scale = scale_metric;
460*7c478bd9Sstevel@tonic-gate 		}
461*7c478bd9Sstevel@tonic-gate 		/* parse -v value string */
462*7c478bd9Sstevel@tonic-gate 		if (arg_valuestring) {
463*7c478bd9Sstevel@tonic-gate 			if (scaledtouint64(arg_valuestring,
464*7c478bd9Sstevel@tonic-gate 			    &arg_value, NULL, &arg_modifier, NULL,
465*7c478bd9Sstevel@tonic-gate 			    arg_scale, arg_unit,
466*7c478bd9Sstevel@tonic-gate 			    SCALED_ALL_FLAGS)) {
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 				warn(gettext("invalid -v value %s"),
469*7c478bd9Sstevel@tonic-gate 				    arg_valuestring);
470*7c478bd9Sstevel@tonic-gate 				errflg = 1;
471*7c478bd9Sstevel@tonic-gate 				goto done_parse;
472*7c478bd9Sstevel@tonic-gate 			}
473*7c478bd9Sstevel@tonic-gate 			if (arg_value > arg_global_max) {
474*7c478bd9Sstevel@tonic-gate 				warn(gettext("-v value %s exceeds system "
475*7c478bd9Sstevel@tonic-gate 				    "limit for resource control: %s"),
476*7c478bd9Sstevel@tonic-gate 				    arg_valuestring, arg_name);
477*7c478bd9Sstevel@tonic-gate 				errflg = 1;
478*7c478bd9Sstevel@tonic-gate 				goto done_parse;
479*7c478bd9Sstevel@tonic-gate 			}
480*7c478bd9Sstevel@tonic-gate 		}
481*7c478bd9Sstevel@tonic-gate 		/* parse action */
482*7c478bd9Sstevel@tonic-gate 		if (arg_action_string) {
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 			char *sigchr;
485*7c478bd9Sstevel@tonic-gate 			char *iter;
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 			if ((strcmp(arg_action_string,
488*7c478bd9Sstevel@tonic-gate 			    "signal") == 0) ||
489*7c478bd9Sstevel@tonic-gate 			    (strcmp(arg_action_string,
490*7c478bd9Sstevel@tonic-gate 				"sig") == 0)) {
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 				if (arg_operation & ACTION_ENABLE) {
493*7c478bd9Sstevel@tonic-gate 					warn(gettext(
494*7c478bd9Sstevel@tonic-gate 					    "signal name or number must be "
495*7c478bd9Sstevel@tonic-gate 					    "specified with -e"));
496*7c478bd9Sstevel@tonic-gate 					errflg = 1;
497*7c478bd9Sstevel@tonic-gate 					goto done_parse;
498*7c478bd9Sstevel@tonic-gate 				}
499*7c478bd9Sstevel@tonic-gate 				arg_action = RCTL_LOCAL_SIGNAL;
500*7c478bd9Sstevel@tonic-gate 				arg_signal = -1;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 			} else if ((strncmp(arg_action_string,
503*7c478bd9Sstevel@tonic-gate 			    "signal=", strlen("signal=")) == 0) ||
504*7c478bd9Sstevel@tonic-gate 			    (strncmp(arg_action_string,
505*7c478bd9Sstevel@tonic-gate 				"sig=", strlen("sig=")) == 0)) {
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 				arg_action = RCTL_LOCAL_SIGNAL;
508*7c478bd9Sstevel@tonic-gate 				sigchr = strrchr(arg_action_string, '=');
509*7c478bd9Sstevel@tonic-gate 				sigchr++;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 				iter = sigchr;
512*7c478bd9Sstevel@tonic-gate 				while (*iter) {
513*7c478bd9Sstevel@tonic-gate 					*iter = toupper(*iter);
514*7c478bd9Sstevel@tonic-gate 					iter++;
515*7c478bd9Sstevel@tonic-gate 				}
516*7c478bd9Sstevel@tonic-gate 				if (strncmp("SIG", sigchr, 3) == 0)
517*7c478bd9Sstevel@tonic-gate 					sigchr += 3;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 				if (str2sig(sigchr, &arg_signal) != 0) {
521*7c478bd9Sstevel@tonic-gate 					warn(gettext("signal invalid"));
522*7c478bd9Sstevel@tonic-gate 					errflg = 1;
523*7c478bd9Sstevel@tonic-gate 					goto done_parse;
524*7c478bd9Sstevel@tonic-gate 				}
525*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(arg_action_string, "deny") == 0) {
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 				arg_action = RCTL_LOCAL_DENY;
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(arg_action_string, "all") == 0) {
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 				if (arg_operation & ACTION_ENABLE) {
532*7c478bd9Sstevel@tonic-gate 					warn(gettext(
533*7c478bd9Sstevel@tonic-gate 					    "cannot use action 'all' with -e"));
534*7c478bd9Sstevel@tonic-gate 					errflg = 1;
535*7c478bd9Sstevel@tonic-gate 					goto done_parse;
536*7c478bd9Sstevel@tonic-gate 				}
537*7c478bd9Sstevel@tonic-gate 				arg_action = RCTL_LOCAL_DENY |
538*7c478bd9Sstevel@tonic-gate 				    RCTL_LOCAL_SIGNAL;
539*7c478bd9Sstevel@tonic-gate 				arg_signal = -1;
540*7c478bd9Sstevel@tonic-gate 				goto done_parse;
541*7c478bd9Sstevel@tonic-gate 			} else {
542*7c478bd9Sstevel@tonic-gate 				warn(gettext("action invalid"));
543*7c478bd9Sstevel@tonic-gate 				errflg = 1;
544*7c478bd9Sstevel@tonic-gate 				goto done_parse;
545*7c478bd9Sstevel@tonic-gate 			}
546*7c478bd9Sstevel@tonic-gate 		}
547*7c478bd9Sstevel@tonic-gate 		/* cannot manipulate system rctls */
548*7c478bd9Sstevel@tonic-gate 		if (arg_priv == RCPRIV_SYSTEM) {
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 			warn(gettext("cannot modify system values"));
551*7c478bd9Sstevel@tonic-gate 			errflg = 1;
552*7c478bd9Sstevel@tonic-gate 			goto done_parse;
553*7c478bd9Sstevel@tonic-gate 		}
554*7c478bd9Sstevel@tonic-gate 		/* validate that the privilege is allowed */
555*7c478bd9Sstevel@tonic-gate 		if ((arg_priv == RCPRIV_BASIC) &&
556*7c478bd9Sstevel@tonic-gate 		    (arg_global_flags & RCTL_GLOBAL_NOBASIC)) {
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 			warn(gettext("basic values not allowed on rctl %s"),
559*7c478bd9Sstevel@tonic-gate 			    arg_name);
560*7c478bd9Sstevel@tonic-gate 			errflg = 1;
561*7c478bd9Sstevel@tonic-gate 			goto done_parse;
562*7c478bd9Sstevel@tonic-gate 		}
563*7c478bd9Sstevel@tonic-gate 		/* validate that actions are appropriate for given rctl */
564*7c478bd9Sstevel@tonic-gate 		if ((arg_operation & ACTION_ENABLE) &&
565*7c478bd9Sstevel@tonic-gate 		    (arg_action & RCTL_LOCAL_DENY) &&
566*7c478bd9Sstevel@tonic-gate 		    (arg_global_flags & RCTL_GLOBAL_DENY_NEVER)) {
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 			warn(gettext("unable to enable deny on rctl with "
569*7c478bd9Sstevel@tonic-gate 			    "global flag 'no-deny'"));
570*7c478bd9Sstevel@tonic-gate 			errflg = 1;
571*7c478bd9Sstevel@tonic-gate 			goto done_parse;
572*7c478bd9Sstevel@tonic-gate 		}
573*7c478bd9Sstevel@tonic-gate 		if ((arg_operation & ACTION_DISABLE) &&
574*7c478bd9Sstevel@tonic-gate 		    (arg_action & RCTL_LOCAL_DENY) &&
575*7c478bd9Sstevel@tonic-gate 		    (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS)) {
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 			warn(gettext("unable to disable deny on rctl with "
578*7c478bd9Sstevel@tonic-gate 			    "global flag 'deny'"));
579*7c478bd9Sstevel@tonic-gate 			errflg = 1;
580*7c478bd9Sstevel@tonic-gate 			goto done_parse;
581*7c478bd9Sstevel@tonic-gate 		}
582*7c478bd9Sstevel@tonic-gate 		if ((arg_operation & ACTION_ENABLE) &&
583*7c478bd9Sstevel@tonic-gate 		    (arg_action & RCTL_LOCAL_SIGNAL) &&
584*7c478bd9Sstevel@tonic-gate 		    (arg_global_flags & RCTL_GLOBAL_SIGNAL_NEVER)) {
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 			warn(gettext("unable to enable signal on rctl with "
587*7c478bd9Sstevel@tonic-gate 			    "global flag 'no-signal'"));
588*7c478bd9Sstevel@tonic-gate 			errflg = 1;
589*7c478bd9Sstevel@tonic-gate 			goto done_parse;
590*7c478bd9Sstevel@tonic-gate 		}
591*7c478bd9Sstevel@tonic-gate 		/* now set defaults for options not supplied */
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 		/*
594*7c478bd9Sstevel@tonic-gate 		 * default privilege to basic if this is a seting an rctl
595*7c478bd9Sstevel@tonic-gate 		 * operation
596*7c478bd9Sstevel@tonic-gate 		 */
597*7c478bd9Sstevel@tonic-gate 		if (arg_operation & ACTION_SET) {
598*7c478bd9Sstevel@tonic-gate 			if (arg_priv == 0) {
599*7c478bd9Sstevel@tonic-gate 				arg_priv = RCPRIV_BASIC;
600*7c478bd9Sstevel@tonic-gate 			}
601*7c478bd9Sstevel@tonic-gate 		}
602*7c478bd9Sstevel@tonic-gate 		/*
603*7c478bd9Sstevel@tonic-gate 		 * -p is required when set a basic task,
604*7c478bd9Sstevel@tonic-gate 		 * project or zone rctl
605*7c478bd9Sstevel@tonic-gate 		 */
606*7c478bd9Sstevel@tonic-gate 		if ((arg_pid == -1) &&
607*7c478bd9Sstevel@tonic-gate 		    (arg_priv == RCPRIV_BASIC) &&
608*7c478bd9Sstevel@tonic-gate 		    (arg_entity_type != RCENTITY_PROCESS) &&
609*7c478bd9Sstevel@tonic-gate 		    (arg_operation & ACTION_SET) &&
610*7c478bd9Sstevel@tonic-gate 		    (arg_name) &&
611*7c478bd9Sstevel@tonic-gate 		    (arg_name_entity == RCENTITY_TASK ||
612*7c478bd9Sstevel@tonic-gate 		    arg_name_entity == RCENTITY_PROJECT ||
613*7c478bd9Sstevel@tonic-gate 		    arg_name_entity == RCENTITY_ZONE)) {
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 			warn(gettext("-p pid required when setting or "
616*7c478bd9Sstevel@tonic-gate 			    "replacing task or project rctl"));
617*7c478bd9Sstevel@tonic-gate 			errflg = 1;
618*7c478bd9Sstevel@tonic-gate 			goto done_parse;
619*7c478bd9Sstevel@tonic-gate 		}
620*7c478bd9Sstevel@tonic-gate 	} else {
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 		/* validate for list mode */
623*7c478bd9Sstevel@tonic-gate 		/* -p is not valid in list mode */
624*7c478bd9Sstevel@tonic-gate 		if (arg_pid != -1) {
625*7c478bd9Sstevel@tonic-gate 			warn(gettext("-p pid requires -s, -r, -x, -e, or -d"));
626*7c478bd9Sstevel@tonic-gate 			errflg = 1;
627*7c478bd9Sstevel@tonic-gate 			goto done_parse;
628*7c478bd9Sstevel@tonic-gate 		}
629*7c478bd9Sstevel@tonic-gate 	}
630*7c478bd9Sstevel@tonic-gate 	/* getting/setting process rctl on task or project is error */
631*7c478bd9Sstevel@tonic-gate 	if ((arg_name && (arg_name_entity == RCENTITY_PROCESS)) &&
632*7c478bd9Sstevel@tonic-gate 	    ((arg_entity_type == RCENTITY_TASK) ||
633*7c478bd9Sstevel@tonic-gate 	    (arg_entity_type == RCENTITY_PROJECT))) {
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 		warn(gettext("cannot get/set process rctl on task "
636*7c478bd9Sstevel@tonic-gate 		    "or project"));
637*7c478bd9Sstevel@tonic-gate 		errflg = 1;
638*7c478bd9Sstevel@tonic-gate 		goto done_parse;
639*7c478bd9Sstevel@tonic-gate 	}
640*7c478bd9Sstevel@tonic-gate 	/* getting/setting task rctl on project is error */
641*7c478bd9Sstevel@tonic-gate 	if ((arg_name && (arg_name_entity == RCENTITY_TASK)) &&
642*7c478bd9Sstevel@tonic-gate 	    (arg_entity_type == RCENTITY_PROJECT)) {
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		warn(gettext("cannot get/set task rctl on project"));
645*7c478bd9Sstevel@tonic-gate 		errflg = 1;
646*7c478bd9Sstevel@tonic-gate 		goto done_parse;
647*7c478bd9Sstevel@tonic-gate 	}
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate done_parse:
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	/* free any rctlblk's that we may have allocated */
652*7c478bd9Sstevel@tonic-gate 	if (rctlblkA) {
653*7c478bd9Sstevel@tonic-gate 		free(rctlblkA);
654*7c478bd9Sstevel@tonic-gate 		rctlblkA = NULL;
655*7c478bd9Sstevel@tonic-gate 	}
656*7c478bd9Sstevel@tonic-gate 	if (rctlblkB) {
657*7c478bd9Sstevel@tonic-gate 		free(rctlblkB);
658*7c478bd9Sstevel@tonic-gate 		rctlblkB = NULL;
659*7c478bd9Sstevel@tonic-gate 	}
660*7c478bd9Sstevel@tonic-gate 	if (errflg)
661*7c478bd9Sstevel@tonic-gate 		usage();
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	/* catch signals from terminal */
664*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
665*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGHUP, intr);
666*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
667*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGINT, intr);
668*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
669*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGQUIT, intr);
670*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, intr);
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 	while (--argc >= 0 && !interrupt) {
673*7c478bd9Sstevel@tonic-gate 		pr_info_handle_t p;
674*7c478bd9Sstevel@tonic-gate 		char *arg = *argv++;
675*7c478bd9Sstevel@tonic-gate 		int intarg;
676*7c478bd9Sstevel@tonic-gate 		char *end;
677*7c478bd9Sstevel@tonic-gate 		errflg = 0;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 		gret = 0;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 		/* Store int version of arg */
682*7c478bd9Sstevel@tonic-gate 		errno = 0;
683*7c478bd9Sstevel@tonic-gate 		intarg = strtoul(arg, &end, 10);
684*7c478bd9Sstevel@tonic-gate 		if (errno || *end != '\0' || end == arg) {
685*7c478bd9Sstevel@tonic-gate 			intarg = -1;
686*7c478bd9Sstevel@tonic-gate 		}
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 		/*
689*7c478bd9Sstevel@tonic-gate 		 * -p defaults to arg if basic and collective rctl
690*7c478bd9Sstevel@tonic-gate 		 * and -i process is specified
691*7c478bd9Sstevel@tonic-gate 		 */
692*7c478bd9Sstevel@tonic-gate 		if ((arg_pid == -1) &&
693*7c478bd9Sstevel@tonic-gate 		    (arg_priv == RCPRIV_BASIC) &&
694*7c478bd9Sstevel@tonic-gate 		    (arg_entity_type == RCENTITY_PROCESS) &&
695*7c478bd9Sstevel@tonic-gate 		    (arg_name) &&
696*7c478bd9Sstevel@tonic-gate 		    (arg_name_entity == RCENTITY_TASK ||
697*7c478bd9Sstevel@tonic-gate 		    arg_name_entity == RCENTITY_PROJECT)) {
698*7c478bd9Sstevel@tonic-gate 			arg_pid_string = arg;
699*7c478bd9Sstevel@tonic-gate 			errno = 0;
700*7c478bd9Sstevel@tonic-gate 			arg_pid = intarg;
701*7c478bd9Sstevel@tonic-gate 		}
702*7c478bd9Sstevel@tonic-gate 		/* Specifying a recipient pid and -i pid is redundent */
703*7c478bd9Sstevel@tonic-gate 		if (arg_pid != -1 && arg_entity_type == RCENTITY_PROCESS &&
704*7c478bd9Sstevel@tonic-gate 		    arg_pid != intarg) {
705*7c478bd9Sstevel@tonic-gate 			warn(gettext("option -p pid must match -i process"));
706*7c478bd9Sstevel@tonic-gate 			errflg = 1;
707*7c478bd9Sstevel@tonic-gate 			continue;
708*7c478bd9Sstevel@tonic-gate 		}
709*7c478bd9Sstevel@tonic-gate 		/* use recipient pid if we have one */
710*7c478bd9Sstevel@tonic-gate 		if (arg_pid_string != NULL) {
711*7c478bd9Sstevel@tonic-gate 			target_id = arg_pid_string;
712*7c478bd9Sstevel@tonic-gate 			search_type = RCENTITY_PROCESS;
713*7c478bd9Sstevel@tonic-gate 		} else {
714*7c478bd9Sstevel@tonic-gate 			target_id = arg;
715*7c478bd9Sstevel@tonic-gate 			search_type = arg_entity_type;
716*7c478bd9Sstevel@tonic-gate 		}
717*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);	/* process-at-a-time */
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 		if (arg_operation != 0) {
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 			if ((pid = grab_process_by_id(target_id,
722*7c478bd9Sstevel@tonic-gate 			    search_type, &p, arg_priv, &gret)) < 0) {
723*7c478bd9Sstevel@tonic-gate 				/*
724*7c478bd9Sstevel@tonic-gate 				 * Mark that an error occurred so that the
725*7c478bd9Sstevel@tonic-gate 				 * return value can be set, but continue
726*7c478bd9Sstevel@tonic-gate 				 * on with other processes
727*7c478bd9Sstevel@tonic-gate 				 */
728*7c478bd9Sstevel@tonic-gate 				errflg = 1;
729*7c478bd9Sstevel@tonic-gate 				continue;
730*7c478bd9Sstevel@tonic-gate 			}
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 			/*
733*7c478bd9Sstevel@tonic-gate 			 * At this point, the victim process is held.
734*7c478bd9Sstevel@tonic-gate 			 * Do not call any Pgrab-unsafe functions until
735*7c478bd9Sstevel@tonic-gate 			 * the process is released via release_process().
736*7c478bd9Sstevel@tonic-gate 			 */
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 			errflg = get_rctls(p.pr);
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 			if (arg_operation & ACTION_DELETE) {
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 				/* match by privilege, value, and pid */
743*7c478bd9Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkA, arg_name,
744*7c478bd9Sstevel@tonic-gate 				    arg_valuestring, arg_value, arg_priv,
745*7c478bd9Sstevel@tonic-gate 				    arg_pid) != 0 || rctlblkA == NULL) {
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 					if (interrupt)
748*7c478bd9Sstevel@tonic-gate 						goto out;
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext("no matching "
751*7c478bd9Sstevel@tonic-gate 					    "resource control found for "
752*7c478bd9Sstevel@tonic-gate 					    "deletion"));
753*7c478bd9Sstevel@tonic-gate 					errflg = 1;
754*7c478bd9Sstevel@tonic-gate 					goto out;
755*7c478bd9Sstevel@tonic-gate 				}
756*7c478bd9Sstevel@tonic-gate 				/*
757*7c478bd9Sstevel@tonic-gate 				 * grab correct process.  This is neccessary
758*7c478bd9Sstevel@tonic-gate 				 * if the recipient pid does not match the
759*7c478bd9Sstevel@tonic-gate 				 * one we grabbed
760*7c478bd9Sstevel@tonic-gate 				 */
761*7c478bd9Sstevel@tonic-gate 				pid = regrab_process(
762*7c478bd9Sstevel@tonic-gate 				    rctlblk_get_recipient_pid(rctlblkA),
763*7c478bd9Sstevel@tonic-gate 				    &p, arg_priv, &gret);
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 				if (pid < 0) {
766*7c478bd9Sstevel@tonic-gate 					errflg = 1;
767*7c478bd9Sstevel@tonic-gate 					goto out;
768*7c478bd9Sstevel@tonic-gate 				}
769*7c478bd9Sstevel@tonic-gate 				if (prctl_setrctl(p.pr, arg_name, NULL,
770*7c478bd9Sstevel@tonic-gate 				    rctlblkA, RCTL_DELETE) != 0) {
771*7c478bd9Sstevel@tonic-gate 					errflg = 1;
772*7c478bd9Sstevel@tonic-gate 					goto out;
773*7c478bd9Sstevel@tonic-gate 				}
774*7c478bd9Sstevel@tonic-gate 			} else if (arg_operation & ACTION_SET) {
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 				/* match by privilege, value, and pid */
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkA, arg_name,
779*7c478bd9Sstevel@tonic-gate 				    arg_valuestring, arg_value, arg_priv,
780*7c478bd9Sstevel@tonic-gate 				    arg_pid) == 0) {
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 					if (interrupt)
783*7c478bd9Sstevel@tonic-gate 						goto out;
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext("resource "
786*7c478bd9Sstevel@tonic-gate 					    "control already exists"));
787*7c478bd9Sstevel@tonic-gate 					errflg = 1;
788*7c478bd9Sstevel@tonic-gate 					goto out;
789*7c478bd9Sstevel@tonic-gate 				}
790*7c478bd9Sstevel@tonic-gate 				rctlblkB = calloc(1, rctlblk_size());
791*7c478bd9Sstevel@tonic-gate 				if (rctlblkB == NULL) {
792*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext(
793*7c478bd9Sstevel@tonic-gate 					    "malloc failed"), strerror(errno));
794*7c478bd9Sstevel@tonic-gate 					errflg = 1;
795*7c478bd9Sstevel@tonic-gate 					goto out;
796*7c478bd9Sstevel@tonic-gate 				}
797*7c478bd9Sstevel@tonic-gate 				rctlblk_set_value(rctlblkB, arg_value);
798*7c478bd9Sstevel@tonic-gate 				rctlblk_set_privilege(rctlblkB, arg_priv);
799*7c478bd9Sstevel@tonic-gate 				if (change_action(rctlblkB)) {
800*7c478bd9Sstevel@tonic-gate 					errflg = 1;
801*7c478bd9Sstevel@tonic-gate 					goto out;
802*7c478bd9Sstevel@tonic-gate 				}
803*7c478bd9Sstevel@tonic-gate 				if (prctl_setrctl(p.pr, arg_name, NULL,
804*7c478bd9Sstevel@tonic-gate 				    rctlblkB, RCTL_INSERT) != 0) {
805*7c478bd9Sstevel@tonic-gate 					errflg = 1;
806*7c478bd9Sstevel@tonic-gate 					goto out;
807*7c478bd9Sstevel@tonic-gate 				}
808*7c478bd9Sstevel@tonic-gate 			} else if (arg_operation & ACTION_REPLACE) {
809*7c478bd9Sstevel@tonic-gate 				/*
810*7c478bd9Sstevel@tonic-gate 				 * match rctl for deletion by privilege and
811*7c478bd9Sstevel@tonic-gate 				 * pid only
812*7c478bd9Sstevel@tonic-gate 				 */
813*7c478bd9Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkA, arg_name,
814*7c478bd9Sstevel@tonic-gate 				    NULL, 0, arg_priv,
815*7c478bd9Sstevel@tonic-gate 				    arg_pid) != 0 || rctlblkA == NULL) {
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 					if (interrupt)
818*7c478bd9Sstevel@tonic-gate 						goto out;
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext("no matching "
821*7c478bd9Sstevel@tonic-gate 					    "resource control to replace"));
822*7c478bd9Sstevel@tonic-gate 					errflg = 1;
823*7c478bd9Sstevel@tonic-gate 					goto out;
824*7c478bd9Sstevel@tonic-gate 				}
825*7c478bd9Sstevel@tonic-gate 				/*
826*7c478bd9Sstevel@tonic-gate 				 * grab correct process.  This is neccessary
827*7c478bd9Sstevel@tonic-gate 				 * if the recipient pid does not match the
828*7c478bd9Sstevel@tonic-gate 				 * one we grabbed
829*7c478bd9Sstevel@tonic-gate 				 */
830*7c478bd9Sstevel@tonic-gate 				pid = regrab_process(
831*7c478bd9Sstevel@tonic-gate 				    rctlblk_get_recipient_pid(rctlblkA),
832*7c478bd9Sstevel@tonic-gate 				    &p, arg_priv, &gret);
833*7c478bd9Sstevel@tonic-gate 				if (pid < 0) {
834*7c478bd9Sstevel@tonic-gate 					errflg = 1;
835*7c478bd9Sstevel@tonic-gate 					goto out;
836*7c478bd9Sstevel@tonic-gate 				}
837*7c478bd9Sstevel@tonic-gate 				pid = rctlblk_get_recipient_pid(rctlblkA);
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 				/*
840*7c478bd9Sstevel@tonic-gate 				 * match by privilege, value and pid to
841*7c478bd9Sstevel@tonic-gate 				 * check if new rctl  already exists
842*7c478bd9Sstevel@tonic-gate 				 */
843*7c478bd9Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkB, arg_name,
844*7c478bd9Sstevel@tonic-gate 				    arg_valuestring, arg_value, arg_priv,
845*7c478bd9Sstevel@tonic-gate 				    pid) < 0) {
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 					if (interrupt)
848*7c478bd9Sstevel@tonic-gate 						goto out;
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext(
851*7c478bd9Sstevel@tonic-gate 						"Internal Error"));
852*7c478bd9Sstevel@tonic-gate 					errflg = 1;
853*7c478bd9Sstevel@tonic-gate 					goto out;
854*7c478bd9Sstevel@tonic-gate 				}
855*7c478bd9Sstevel@tonic-gate 				/*
856*7c478bd9Sstevel@tonic-gate 				 * If rctl already exists, and it does not
857*7c478bd9Sstevel@tonic-gate 				 *  match the one that we will delete, than
858*7c478bd9Sstevel@tonic-gate 				 *  the replace will fail.
859*7c478bd9Sstevel@tonic-gate 				 */
860*7c478bd9Sstevel@tonic-gate 				if (rctlblkB != NULL &&
861*7c478bd9Sstevel@tonic-gate 				    arg_value !=
862*7c478bd9Sstevel@tonic-gate 					rctlblk_get_value(rctlblkA)) {
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext("replacement "
865*7c478bd9Sstevel@tonic-gate 					    "resource control already "
866*7c478bd9Sstevel@tonic-gate 					    "exists"));
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 					errflg = 1;
869*7c478bd9Sstevel@tonic-gate 					goto out;
870*7c478bd9Sstevel@tonic-gate 				}
871*7c478bd9Sstevel@tonic-gate 				/* create new rctl */
872*7c478bd9Sstevel@tonic-gate 				rctlblkB = calloc(1, rctlblk_size());
873*7c478bd9Sstevel@tonic-gate 				if (rctlblkB == NULL) {
874*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext(
875*7c478bd9Sstevel@tonic-gate 					    "malloc failed"), strerror(errno));
876*7c478bd9Sstevel@tonic-gate 					errflg = 1;
877*7c478bd9Sstevel@tonic-gate 					goto out;
878*7c478bd9Sstevel@tonic-gate 				}
879*7c478bd9Sstevel@tonic-gate 				rctlblk_set_value(rctlblkB, arg_value);
880*7c478bd9Sstevel@tonic-gate 				rctlblk_set_privilege(rctlblkB,
881*7c478bd9Sstevel@tonic-gate 				    rctlblk_get_privilege(rctlblkA));
882*7c478bd9Sstevel@tonic-gate 				if (change_action(rctlblkB)) {
883*7c478bd9Sstevel@tonic-gate 					errflg = 1;
884*7c478bd9Sstevel@tonic-gate 					goto out;
885*7c478bd9Sstevel@tonic-gate 				}
886*7c478bd9Sstevel@tonic-gate 				/* do replacement */
887*7c478bd9Sstevel@tonic-gate 				if (prctl_setrctl(p.pr, arg_name, rctlblkA,
888*7c478bd9Sstevel@tonic-gate 				    rctlblkB, RCTL_REPLACE) != 0) {
889*7c478bd9Sstevel@tonic-gate 					errflg = 1;
890*7c478bd9Sstevel@tonic-gate 					goto out;
891*7c478bd9Sstevel@tonic-gate 				}
892*7c478bd9Sstevel@tonic-gate 			} else if (arg_operation &
893*7c478bd9Sstevel@tonic-gate 			    (ACTION_ENABLE | ACTION_DISABLE)) {
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 				rctlblkB = calloc(1, rctlblk_size());
896*7c478bd9Sstevel@tonic-gate 				if (rctlblkB == NULL) {
897*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext(
898*7c478bd9Sstevel@tonic-gate 					    "malloc failed"), strerror(errno));
899*7c478bd9Sstevel@tonic-gate 					errflg = 1;
900*7c478bd9Sstevel@tonic-gate 					goto out;
901*7c478bd9Sstevel@tonic-gate 				}
902*7c478bd9Sstevel@tonic-gate 				/* match by privilege, value, and pid */
903*7c478bd9Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkA, arg_name,
904*7c478bd9Sstevel@tonic-gate 				    arg_valuestring, arg_value, arg_priv,
905*7c478bd9Sstevel@tonic-gate 				    arg_pid) != 0) {
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 					if (interrupt)
908*7c478bd9Sstevel@tonic-gate 						goto out;
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 					/* if no match, just set new rctl */
911*7c478bd9Sstevel@tonic-gate 					if (arg_priv == 0)
912*7c478bd9Sstevel@tonic-gate 						arg_priv = RCPRIV_BASIC;
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 					if ((arg_priv == RCPRIV_BASIC) &&
915*7c478bd9Sstevel@tonic-gate 					    (arg_entity_type !=
916*7c478bd9Sstevel@tonic-gate 					    RCENTITY_PROCESS) &&
917*7c478bd9Sstevel@tonic-gate 					    (arg_pid_string == NULL)) {
918*7c478bd9Sstevel@tonic-gate 						preserve_error(gettext(
919*7c478bd9Sstevel@tonic-gate 						    "-p required when setting "
920*7c478bd9Sstevel@tonic-gate 						    "basic rctls"));
921*7c478bd9Sstevel@tonic-gate 						errflg = 1;
922*7c478bd9Sstevel@tonic-gate 						goto out;
923*7c478bd9Sstevel@tonic-gate 					}
924*7c478bd9Sstevel@tonic-gate 					rctlblk_set_value(rctlblkB,
925*7c478bd9Sstevel@tonic-gate 					    arg_value);
926*7c478bd9Sstevel@tonic-gate 					rctlblk_set_privilege(
927*7c478bd9Sstevel@tonic-gate 						rctlblkB, arg_priv);
928*7c478bd9Sstevel@tonic-gate 					if (change_action(rctlblkB)) {
929*7c478bd9Sstevel@tonic-gate 						errflg = 1;
930*7c478bd9Sstevel@tonic-gate 						goto out;
931*7c478bd9Sstevel@tonic-gate 					}
932*7c478bd9Sstevel@tonic-gate 					if (prctl_setrctl(p.pr,
933*7c478bd9Sstevel@tonic-gate 					    arg_name, NULL, rctlblkB,
934*7c478bd9Sstevel@tonic-gate 					    RCTL_INSERT) != 0) {
935*7c478bd9Sstevel@tonic-gate 						errflg = 1;
936*7c478bd9Sstevel@tonic-gate 						goto out;
937*7c478bd9Sstevel@tonic-gate 					}
938*7c478bd9Sstevel@tonic-gate 					goto out;
939*7c478bd9Sstevel@tonic-gate 				}
940*7c478bd9Sstevel@tonic-gate 				if (rctlblkA == NULL) {
941*7c478bd9Sstevel@tonic-gate 					preserve_error(gettext("no matching "
942*7c478bd9Sstevel@tonic-gate 					    "resource control found"));
943*7c478bd9Sstevel@tonic-gate 					errflg = 1;
944*7c478bd9Sstevel@tonic-gate 					goto out;
945*7c478bd9Sstevel@tonic-gate 				}
946*7c478bd9Sstevel@tonic-gate 				/*
947*7c478bd9Sstevel@tonic-gate 				 * grab correct process.  This is neccessary
948*7c478bd9Sstevel@tonic-gate 				 * if the recipient pid does not match the
949*7c478bd9Sstevel@tonic-gate 				 * one we grabbed
950*7c478bd9Sstevel@tonic-gate 				 */
951*7c478bd9Sstevel@tonic-gate 				pid = regrab_process(
952*7c478bd9Sstevel@tonic-gate 				    rctlblk_get_recipient_pid(rctlblkA),
953*7c478bd9Sstevel@tonic-gate 				    &p, arg_priv, &gret);
954*7c478bd9Sstevel@tonic-gate 				if (pid < 0) {
955*7c478bd9Sstevel@tonic-gate 					errflg = 1;
956*7c478bd9Sstevel@tonic-gate 					goto out;
957*7c478bd9Sstevel@tonic-gate 				}
958*7c478bd9Sstevel@tonic-gate 				localaction =
959*7c478bd9Sstevel@tonic-gate 				    rctlblk_get_local_action(rctlblkA,
960*7c478bd9Sstevel@tonic-gate 				    &signal);
961*7c478bd9Sstevel@tonic-gate 				rctlblk_set_local_action(rctlblkB, localaction,
962*7c478bd9Sstevel@tonic-gate 				    signal);
963*7c478bd9Sstevel@tonic-gate 				rctlblk_set_privilege(rctlblkB,
964*7c478bd9Sstevel@tonic-gate 					rctlblk_get_privilege(rctlblkA));
965*7c478bd9Sstevel@tonic-gate 				rctlblk_set_value(rctlblkB,
966*7c478bd9Sstevel@tonic-gate 					rctlblk_get_value(rctlblkA));
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 				if (change_action(rctlblkB)) {
969*7c478bd9Sstevel@tonic-gate 					errflg = 1;
970*7c478bd9Sstevel@tonic-gate 					goto out;
971*7c478bd9Sstevel@tonic-gate 				}
972*7c478bd9Sstevel@tonic-gate 				if (prctl_setrctl(p.pr, arg_name, rctlblkA,
973*7c478bd9Sstevel@tonic-gate 				    rctlblkB, RCTL_REPLACE) != 0) {
974*7c478bd9Sstevel@tonic-gate 					errflg = 1;
975*7c478bd9Sstevel@tonic-gate 					goto out;
976*7c478bd9Sstevel@tonic-gate 				}
977*7c478bd9Sstevel@tonic-gate 			}
978*7c478bd9Sstevel@tonic-gate out:
979*7c478bd9Sstevel@tonic-gate 			release_process(p.pr);
980*7c478bd9Sstevel@tonic-gate 			if (rctlblkA)
981*7c478bd9Sstevel@tonic-gate 				free(rctlblkA);
982*7c478bd9Sstevel@tonic-gate 			if (rctlblkB)
983*7c478bd9Sstevel@tonic-gate 				free(rctlblkB);
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate 			/* Print any errors that occurred */
986*7c478bd9Sstevel@tonic-gate 			if (errflg && *global_error != '\0') {
987*7c478bd9Sstevel@tonic-gate 				proc_unctrl_psinfo(&(p.psinfo));
988*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%d:\t%.70s\n",
989*7c478bd9Sstevel@tonic-gate 				    (int)p.pid, p.psinfo.pr_psargs);
990*7c478bd9Sstevel@tonic-gate 				warn("%s\n", global_error);
991*7c478bd9Sstevel@tonic-gate 				break;
992*7c478bd9Sstevel@tonic-gate 			}
993*7c478bd9Sstevel@tonic-gate 		} else {
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 			struct project projent;
996*7c478bd9Sstevel@tonic-gate 			char buf[PROJECT_BUFSZ];
997*7c478bd9Sstevel@tonic-gate 			char zonename[ZONENAME_MAX];
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 			/*
1000*7c478bd9Sstevel@tonic-gate 			 * Hack to allow the user to specify a system
1001*7c478bd9Sstevel@tonic-gate 			 * process.
1002*7c478bd9Sstevel@tonic-gate 			 */
1003*7c478bd9Sstevel@tonic-gate 			gret = G_SYS;
1004*7c478bd9Sstevel@tonic-gate 			pid = grab_process_by_id(
1005*7c478bd9Sstevel@tonic-gate 			    target_id, search_type, &p, RCPRIV_BASIC, &gret);
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate 			/*
1008*7c478bd9Sstevel@tonic-gate 			 * Print system process if user chose specifically
1009*7c478bd9Sstevel@tonic-gate 			 * to inspect a system process.
1010*7c478bd9Sstevel@tonic-gate 			 */
1011*7c478bd9Sstevel@tonic-gate 			if (arg_entity_type == RCENTITY_PROCESS &&
1012*7c478bd9Sstevel@tonic-gate 			    pid < 0 &&
1013*7c478bd9Sstevel@tonic-gate 			    gret == G_SYS) {
1014*7c478bd9Sstevel@tonic-gate 				/*
1015*7c478bd9Sstevel@tonic-gate 				 * Add blank lines between output for
1016*7c478bd9Sstevel@tonic-gate 				 * operands.
1017*7c478bd9Sstevel@tonic-gate 				 */
1018*7c478bd9Sstevel@tonic-gate 				if (printed) {
1019*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stdout, "\n");
1020*7c478bd9Sstevel@tonic-gate 				}
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 				proc_unctrl_psinfo(&(p.psinfo));
1023*7c478bd9Sstevel@tonic-gate 				(void) printf(
1024*7c478bd9Sstevel@tonic-gate 				    "process: %d: %s [ system process ]\n",
1025*7c478bd9Sstevel@tonic-gate 				    (int)p.pid, p.psinfo.pr_psargs);
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate 				printed = 1;
1028*7c478bd9Sstevel@tonic-gate 				continue;
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 			} else if (pid < 0) {
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 				/*
1033*7c478bd9Sstevel@tonic-gate 				 * Mark that an error occurred so that the
1034*7c478bd9Sstevel@tonic-gate 				 * return value can be set, but continue
1035*7c478bd9Sstevel@tonic-gate 				 * on with other processes
1036*7c478bd9Sstevel@tonic-gate 				 */
1037*7c478bd9Sstevel@tonic-gate 				errflg = 1;
1038*7c478bd9Sstevel@tonic-gate 				continue;
1039*7c478bd9Sstevel@tonic-gate 			}
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 			errflg = get_rctls(p.pr);
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 			release_process(p.pr);
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 			/* handle user interrupt of getting rctls */
1046*7c478bd9Sstevel@tonic-gate 			if (interrupt)
1047*7c478bd9Sstevel@tonic-gate 				break;
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 			/* add blank lines between output for operands */
1050*7c478bd9Sstevel@tonic-gate 			if (printed) {
1051*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
1052*7c478bd9Sstevel@tonic-gate 			}
1053*7c478bd9Sstevel@tonic-gate 			/* First print any errors */
1054*7c478bd9Sstevel@tonic-gate 			if (errflg) {
1055*7c478bd9Sstevel@tonic-gate 				warn("%s\n", global_error);
1056*7c478bd9Sstevel@tonic-gate 				free_lists();
1057*7c478bd9Sstevel@tonic-gate 				break;
1058*7c478bd9Sstevel@tonic-gate 			}
1059*7c478bd9Sstevel@tonic-gate 			if (getprojbyid(p.projid, &projent, buf,
1060*7c478bd9Sstevel@tonic-gate 			    sizeof (buf))) {
1061*7c478bd9Sstevel@tonic-gate 				p.projname = projent.pj_name;
1062*7c478bd9Sstevel@tonic-gate 			} else {
1063*7c478bd9Sstevel@tonic-gate 				p.projname = "";
1064*7c478bd9Sstevel@tonic-gate 			}
1065*7c478bd9Sstevel@tonic-gate 			if (getzonenamebyid(p.zoneid, zonename,
1066*7c478bd9Sstevel@tonic-gate 			    sizeof (zonename)) > 0) {
1067*7c478bd9Sstevel@tonic-gate 				p.zonename = zonename;
1068*7c478bd9Sstevel@tonic-gate 			} else {
1069*7c478bd9Sstevel@tonic-gate 				p.zonename = "";
1070*7c478bd9Sstevel@tonic-gate 			}
1071*7c478bd9Sstevel@tonic-gate 			print_rctls(&p);
1072*7c478bd9Sstevel@tonic-gate 			printed = 1;
1073*7c478bd9Sstevel@tonic-gate 			/* Free the resource control lists */
1074*7c478bd9Sstevel@tonic-gate 			free_lists();
1075*7c478bd9Sstevel@tonic-gate 		}
1076*7c478bd9Sstevel@tonic-gate 	}
1077*7c478bd9Sstevel@tonic-gate 	if (interrupt)
1078*7c478bd9Sstevel@tonic-gate 		errflg = 1;
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate 	/*
1081*7c478bd9Sstevel@tonic-gate 	 * return error if one occurred
1082*7c478bd9Sstevel@tonic-gate 	 */
1083*7c478bd9Sstevel@tonic-gate 	return (errflg);
1084*7c478bd9Sstevel@tonic-gate }
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate static void
1088*7c478bd9Sstevel@tonic-gate intr(int sig)
1089*7c478bd9Sstevel@tonic-gate {
1090*7c478bd9Sstevel@tonic-gate 	interrupt = sig;
1091*7c478bd9Sstevel@tonic-gate }
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate /*
1094*7c478bd9Sstevel@tonic-gate  * get_rctls(struct ps_prochandle *, const char *)
1095*7c478bd9Sstevel@tonic-gate  *
1096*7c478bd9Sstevel@tonic-gate  * If controlname is given, store only controls for that named
1097*7c478bd9Sstevel@tonic-gate  * resource. If controlname is NULL, store all controls for all
1098*7c478bd9Sstevel@tonic-gate  * resources.
1099*7c478bd9Sstevel@tonic-gate  *
1100*7c478bd9Sstevel@tonic-gate  * This function is Pgrab-safe.
1101*7c478bd9Sstevel@tonic-gate  */
1102*7c478bd9Sstevel@tonic-gate static int
1103*7c478bd9Sstevel@tonic-gate get_rctls(struct ps_prochandle *Pr)
1104*7c478bd9Sstevel@tonic-gate {
1105*7c478bd9Sstevel@tonic-gate 	int ret = 0;
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 	if (arg_name == NULL) {
1108*7c478bd9Sstevel@tonic-gate 		if (rctl_walk(store_rctls, Pr) != 0)
1109*7c478bd9Sstevel@tonic-gate 			ret = 1;
1110*7c478bd9Sstevel@tonic-gate 	} else {
1111*7c478bd9Sstevel@tonic-gate 		ret = store_rctls(arg_name, Pr);
1112*7c478bd9Sstevel@tonic-gate 	}
1113*7c478bd9Sstevel@tonic-gate 	return (ret);
1114*7c478bd9Sstevel@tonic-gate }
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate /*
1117*7c478bd9Sstevel@tonic-gate  * store_rctls(const char *, void *)
1118*7c478bd9Sstevel@tonic-gate  *
1119*7c478bd9Sstevel@tonic-gate  * Store resource controls for the given name in a linked list.
1120*7c478bd9Sstevel@tonic-gate  * Honor the user's options, and store only the ones they are
1121*7c478bd9Sstevel@tonic-gate  * interested in. If priv is not 0, show only controls that match
1122*7c478bd9Sstevel@tonic-gate  * the given privilege.
1123*7c478bd9Sstevel@tonic-gate  *
1124*7c478bd9Sstevel@tonic-gate  * This function is Pgrab-safe
1125*7c478bd9Sstevel@tonic-gate  */
1126*7c478bd9Sstevel@tonic-gate static int
1127*7c478bd9Sstevel@tonic-gate store_rctls(const char *rctlname, void *walk_data)
1128*7c478bd9Sstevel@tonic-gate {
1129*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *Pr = walk_data;
1130*7c478bd9Sstevel@tonic-gate 	rctlblk_t *rblk2, *rblk_tmp, *rblk1 = NULL;
1131*7c478bd9Sstevel@tonic-gate 	prctl_list_t *list = NULL;
1132*7c478bd9Sstevel@tonic-gate 	rctl_priv_t rblk_priv;
1133*7c478bd9Sstevel@tonic-gate 	rctl_entity_t rblk_entity;
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	if (((rblk1 = calloc(1, rctlblk_size())) == NULL) ||
1136*7c478bd9Sstevel@tonic-gate 	    ((rblk2 = calloc(1, rctlblk_size())) == NULL)) {
1137*7c478bd9Sstevel@tonic-gate 		if (rblk1 != NULL)
1138*7c478bd9Sstevel@tonic-gate 			free(rblk1);
1139*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("malloc failed: %s"),
1140*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
1141*7c478bd9Sstevel@tonic-gate 		return (1);
1142*7c478bd9Sstevel@tonic-gate 	}
1143*7c478bd9Sstevel@tonic-gate 	if (pr_getrctl(Pr, rctlname, NULL, rblk1, RCTL_FIRST)) {
1144*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("failed to get resource control "
1145*7c478bd9Sstevel@tonic-gate 		    "for %s: %s"), rctlname, strerror(errno));
1146*7c478bd9Sstevel@tonic-gate 		free(rblk1);
1147*7c478bd9Sstevel@tonic-gate 		free(rblk2);
1148*7c478bd9Sstevel@tonic-gate 		return (1);
1149*7c478bd9Sstevel@tonic-gate 	}
1150*7c478bd9Sstevel@tonic-gate 	/* Store control if it matches privilege and enity type criteria */
1151*7c478bd9Sstevel@tonic-gate 	rblk_priv = rctlblk_get_privilege(rblk1);
1152*7c478bd9Sstevel@tonic-gate 	rblk_entity = 0;
1153*7c478bd9Sstevel@tonic-gate 	if (strncmp(rctlname, "process.",
1154*7c478bd9Sstevel@tonic-gate 	    strlen("process.")) == 0)
1155*7c478bd9Sstevel@tonic-gate 		rblk_entity = RCENTITY_PROCESS;
1156*7c478bd9Sstevel@tonic-gate 	else if (strncmp(rctlname, "project.",
1157*7c478bd9Sstevel@tonic-gate 	    strlen("project.")) == 0)
1158*7c478bd9Sstevel@tonic-gate 		rblk_entity = RCENTITY_PROJECT;
1159*7c478bd9Sstevel@tonic-gate 	else if (strncmp(rctlname, "task.",
1160*7c478bd9Sstevel@tonic-gate 	    strlen("task.")) == 0)
1161*7c478bd9Sstevel@tonic-gate 		rblk_entity = RCENTITY_TASK;
1162*7c478bd9Sstevel@tonic-gate 	else if (strncmp(rctlname, "zone.",
1163*7c478bd9Sstevel@tonic-gate 	    strlen("zone.")) == 0)
1164*7c478bd9Sstevel@tonic-gate 		rblk_entity = RCENTITY_ZONE;
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 	if (((arg_priv == 0) || (rblk_priv == arg_priv)) &&
1167*7c478bd9Sstevel@tonic-gate 	    ((arg_name == NULL) ||
1168*7c478bd9Sstevel@tonic-gate 		strncmp(rctlname, arg_name,
1169*7c478bd9Sstevel@tonic-gate 		    strlen(arg_name)) == 0) &&
1170*7c478bd9Sstevel@tonic-gate 	    (arg_entity_string == NULL ||
1171*7c478bd9Sstevel@tonic-gate 		rblk_entity >= arg_entity_type)) {
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 		/* Once we know we have some controls, store the name */
1174*7c478bd9Sstevel@tonic-gate 		if ((list = store_list_entry(rctlname)) == NULL) {
1175*7c478bd9Sstevel@tonic-gate 			free(rblk1);
1176*7c478bd9Sstevel@tonic-gate 			free(rblk2);
1177*7c478bd9Sstevel@tonic-gate 			return (1);
1178*7c478bd9Sstevel@tonic-gate 		}
1179*7c478bd9Sstevel@tonic-gate 		if (store_value_entry(rblk1, list) == NULL) {
1180*7c478bd9Sstevel@tonic-gate 			free(rblk1);
1181*7c478bd9Sstevel@tonic-gate 			free(rblk2);
1182*7c478bd9Sstevel@tonic-gate 			return (1);
1183*7c478bd9Sstevel@tonic-gate 		}
1184*7c478bd9Sstevel@tonic-gate 	}
1185*7c478bd9Sstevel@tonic-gate 	while (pr_getrctl(Pr, rctlname, rblk1, rblk2, RCTL_NEXT) == 0) {
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate 		/*
1188*7c478bd9Sstevel@tonic-gate 		 * in case this is stuck for some reason, allow manual
1189*7c478bd9Sstevel@tonic-gate 		 * interrupt
1190*7c478bd9Sstevel@tonic-gate 		 */
1191*7c478bd9Sstevel@tonic-gate 		if (interrupt) {
1192*7c478bd9Sstevel@tonic-gate 			free(rblk1);
1193*7c478bd9Sstevel@tonic-gate 			free(rblk2);
1194*7c478bd9Sstevel@tonic-gate 			return (1);
1195*7c478bd9Sstevel@tonic-gate 		}
1196*7c478bd9Sstevel@tonic-gate 		rblk_priv = rctlblk_get_privilege(rblk2);
1197*7c478bd9Sstevel@tonic-gate 		/*
1198*7c478bd9Sstevel@tonic-gate 		 * Store control if it matches privilege and entity type
1199*7c478bd9Sstevel@tonic-gate 		 * criteria
1200*7c478bd9Sstevel@tonic-gate 		 */
1201*7c478bd9Sstevel@tonic-gate 		if (((arg_priv == 0) || (rblk_priv == arg_priv)) &&
1202*7c478bd9Sstevel@tonic-gate 		    ((arg_name == NULL) ||
1203*7c478bd9Sstevel@tonic-gate 			strncmp(rctlname, arg_name,
1204*7c478bd9Sstevel@tonic-gate 			    strlen(arg_name)) == 0) &&
1205*7c478bd9Sstevel@tonic-gate 		    (arg_entity_string == NULL ||
1206*7c478bd9Sstevel@tonic-gate 			rblk_entity == arg_entity_type)) {
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 			/* May not have created the list yet. */
1209*7c478bd9Sstevel@tonic-gate 			if (list == NULL) {
1210*7c478bd9Sstevel@tonic-gate 				if ((list = store_list_entry(rctlname))
1211*7c478bd9Sstevel@tonic-gate 				    == NULL) {
1212*7c478bd9Sstevel@tonic-gate 					free(rblk1);
1213*7c478bd9Sstevel@tonic-gate 					free(rblk2);
1214*7c478bd9Sstevel@tonic-gate 					return (1);
1215*7c478bd9Sstevel@tonic-gate 				}
1216*7c478bd9Sstevel@tonic-gate 			}
1217*7c478bd9Sstevel@tonic-gate 			if (store_value_entry(rblk2, list) == NULL) {
1218*7c478bd9Sstevel@tonic-gate 				free(rblk1);
1219*7c478bd9Sstevel@tonic-gate 				free(rblk2);
1220*7c478bd9Sstevel@tonic-gate 				return (1);
1221*7c478bd9Sstevel@tonic-gate 			}
1222*7c478bd9Sstevel@tonic-gate 		}
1223*7c478bd9Sstevel@tonic-gate 		rblk_tmp = rblk1;
1224*7c478bd9Sstevel@tonic-gate 		rblk1 = rblk2;
1225*7c478bd9Sstevel@tonic-gate 		rblk2 = rblk_tmp;
1226*7c478bd9Sstevel@tonic-gate 	}
1227*7c478bd9Sstevel@tonic-gate 	free(rblk1);
1228*7c478bd9Sstevel@tonic-gate 	free(rblk2);
1229*7c478bd9Sstevel@tonic-gate 	return (0);
1230*7c478bd9Sstevel@tonic-gate }
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate /*
1233*7c478bd9Sstevel@tonic-gate  * store_value_entry(rctlblk_t *, prctl_list_t *)
1234*7c478bd9Sstevel@tonic-gate  *
1235*7c478bd9Sstevel@tonic-gate  * Store an rblk for a given resource control into the global list.
1236*7c478bd9Sstevel@tonic-gate  *
1237*7c478bd9Sstevel@tonic-gate  * This function is Pgrab-safe.
1238*7c478bd9Sstevel@tonic-gate  */
1239*7c478bd9Sstevel@tonic-gate prctl_value_t *
1240*7c478bd9Sstevel@tonic-gate store_value_entry(rctlblk_t *rblk, prctl_list_t *list)
1241*7c478bd9Sstevel@tonic-gate {
1242*7c478bd9Sstevel@tonic-gate 	prctl_value_t *e = calloc(1, sizeof (prctl_value_t));
1243*7c478bd9Sstevel@tonic-gate 	rctlblk_t *store_blk = calloc(1, rctlblk_size());
1244*7c478bd9Sstevel@tonic-gate 	prctl_value_t *iter = list->val_list;
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	if (e == NULL || store_blk == NULL) {
1247*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("malloc failed %s"),
1248*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
1249*7c478bd9Sstevel@tonic-gate 		if (e != NULL)
1250*7c478bd9Sstevel@tonic-gate 			free(e);
1251*7c478bd9Sstevel@tonic-gate 		if (store_blk != NULL)
1252*7c478bd9Sstevel@tonic-gate 			free(store_blk);
1253*7c478bd9Sstevel@tonic-gate 		return (NULL);
1254*7c478bd9Sstevel@tonic-gate 	}
1255*7c478bd9Sstevel@tonic-gate 	if (iter == NULL)
1256*7c478bd9Sstevel@tonic-gate 		list->val_list = e;
1257*7c478bd9Sstevel@tonic-gate 	else {
1258*7c478bd9Sstevel@tonic-gate 		while (iter->next != NULL) {
1259*7c478bd9Sstevel@tonic-gate 			iter = iter->next;
1260*7c478bd9Sstevel@tonic-gate 		}
1261*7c478bd9Sstevel@tonic-gate 		iter->next = e;
1262*7c478bd9Sstevel@tonic-gate 	}
1263*7c478bd9Sstevel@tonic-gate 	bcopy(rblk, store_blk, rctlblk_size());
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate 	e->rblk = store_blk;
1266*7c478bd9Sstevel@tonic-gate 	e->next = NULL;
1267*7c478bd9Sstevel@tonic-gate 	return (e);
1268*7c478bd9Sstevel@tonic-gate }
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate /*
1271*7c478bd9Sstevel@tonic-gate  * store_list_entry(const char *)
1272*7c478bd9Sstevel@tonic-gate  *
1273*7c478bd9Sstevel@tonic-gate  * Store a new resource control value in the global list. No checking
1274*7c478bd9Sstevel@tonic-gate  * for duplicates done.
1275*7c478bd9Sstevel@tonic-gate  *
1276*7c478bd9Sstevel@tonic-gate  * This function is Pgrab-safe.
1277*7c478bd9Sstevel@tonic-gate  */
1278*7c478bd9Sstevel@tonic-gate prctl_list_t *
1279*7c478bd9Sstevel@tonic-gate store_list_entry(const char *name)
1280*7c478bd9Sstevel@tonic-gate {
1281*7c478bd9Sstevel@tonic-gate 	prctl_list_t *e = calloc(1, sizeof (prctl_list_t));
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	if (e == NULL) {
1284*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("malloc failed %s"),
1285*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
1286*7c478bd9Sstevel@tonic-gate 		return (NULL);
1287*7c478bd9Sstevel@tonic-gate 	}
1288*7c478bd9Sstevel@tonic-gate 	if ((e->name = calloc(1, strlen(name) + 1)) == NULL) {
1289*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("malloc failed %s"),
1290*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
1291*7c478bd9Sstevel@tonic-gate 		free(e);
1292*7c478bd9Sstevel@tonic-gate 		return (NULL);
1293*7c478bd9Sstevel@tonic-gate 	}
1294*7c478bd9Sstevel@tonic-gate 	(void) strcpy(e->name, name);
1295*7c478bd9Sstevel@tonic-gate 	e->val_list = NULL;
1296*7c478bd9Sstevel@tonic-gate 
1297*7c478bd9Sstevel@tonic-gate 	if (global_rctl_list_head == NULL) {
1298*7c478bd9Sstevel@tonic-gate 		global_rctl_list_head = e;
1299*7c478bd9Sstevel@tonic-gate 		global_rctl_list_tail = e;
1300*7c478bd9Sstevel@tonic-gate 	} else {
1301*7c478bd9Sstevel@tonic-gate 		global_rctl_list_tail->next = e;
1302*7c478bd9Sstevel@tonic-gate 		global_rctl_list_tail = e;
1303*7c478bd9Sstevel@tonic-gate 	}
1304*7c478bd9Sstevel@tonic-gate 	e->next = NULL;
1305*7c478bd9Sstevel@tonic-gate 	return (e);
1306*7c478bd9Sstevel@tonic-gate }
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate /*
1309*7c478bd9Sstevel@tonic-gate  * free_lists()
1310*7c478bd9Sstevel@tonic-gate  *
1311*7c478bd9Sstevel@tonic-gate  * Free all resource control blocks and values from the global lists.
1312*7c478bd9Sstevel@tonic-gate  *
1313*7c478bd9Sstevel@tonic-gate  * This function is Pgrab-safe.
1314*7c478bd9Sstevel@tonic-gate  */
1315*7c478bd9Sstevel@tonic-gate void
1316*7c478bd9Sstevel@tonic-gate free_lists()
1317*7c478bd9Sstevel@tonic-gate {
1318*7c478bd9Sstevel@tonic-gate 	prctl_list_t *new_list, *old_list = global_rctl_list_head;
1319*7c478bd9Sstevel@tonic-gate 	prctl_value_t *old_val, *new_val;
1320*7c478bd9Sstevel@tonic-gate 
1321*7c478bd9Sstevel@tonic-gate 	while (old_list != NULL) {
1322*7c478bd9Sstevel@tonic-gate 		old_val = old_list->val_list;
1323*7c478bd9Sstevel@tonic-gate 		while (old_val != NULL) {
1324*7c478bd9Sstevel@tonic-gate 			free(old_val->rblk);
1325*7c478bd9Sstevel@tonic-gate 			new_val = old_val->next;
1326*7c478bd9Sstevel@tonic-gate 			free(old_val);
1327*7c478bd9Sstevel@tonic-gate 			old_val = new_val;
1328*7c478bd9Sstevel@tonic-gate 		}
1329*7c478bd9Sstevel@tonic-gate 		free(old_list->name);
1330*7c478bd9Sstevel@tonic-gate 		new_list = old_list->next;
1331*7c478bd9Sstevel@tonic-gate 		free(old_list);
1332*7c478bd9Sstevel@tonic-gate 		old_list = new_list;
1333*7c478bd9Sstevel@tonic-gate 	}
1334*7c478bd9Sstevel@tonic-gate 	global_rctl_list_head = NULL;
1335*7c478bd9Sstevel@tonic-gate 	global_rctl_list_tail = NULL;
1336*7c478bd9Sstevel@tonic-gate }
1337*7c478bd9Sstevel@tonic-gate 
1338*7c478bd9Sstevel@tonic-gate void
1339*7c478bd9Sstevel@tonic-gate print_heading()
1340*7c478bd9Sstevel@tonic-gate {
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate 	/* print headings */
1343*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%-8s%-16s%-9s%-7s%-28s%10s\n",
1344*7c478bd9Sstevel@tonic-gate 	    "NAME", "PRIVILEGE", "VALUE",
1345*7c478bd9Sstevel@tonic-gate 	    "FLAG", "ACTION", "RECIPIENT");
1346*7c478bd9Sstevel@tonic-gate }
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate /*
1349*7c478bd9Sstevel@tonic-gate  * print_rctls()
1350*7c478bd9Sstevel@tonic-gate  *
1351*7c478bd9Sstevel@tonic-gate  * Print all resource controls from the global list that was
1352*7c478bd9Sstevel@tonic-gate  * previously populated by store_rctls.
1353*7c478bd9Sstevel@tonic-gate  */
1354*7c478bd9Sstevel@tonic-gate void
1355*7c478bd9Sstevel@tonic-gate print_rctls(pr_info_handle_t *p)
1356*7c478bd9Sstevel@tonic-gate {
1357*7c478bd9Sstevel@tonic-gate 	prctl_list_t *iter_list = global_rctl_list_head;
1358*7c478bd9Sstevel@tonic-gate 	prctl_value_t *iter_val;
1359*7c478bd9Sstevel@tonic-gate 	rctl_qty_t  rblk_value;
1360*7c478bd9Sstevel@tonic-gate 	rctl_priv_t rblk_priv;
1361*7c478bd9Sstevel@tonic-gate 	uint_t local_action;
1362*7c478bd9Sstevel@tonic-gate 	int signal, local_flags, global_flags;
1363*7c478bd9Sstevel@tonic-gate 	pid_t pid;
1364*7c478bd9Sstevel@tonic-gate 	char rctl_valuestring[SCALED_STRLEN];
1365*7c478bd9Sstevel@tonic-gate 	char *unit = NULL;
1366*7c478bd9Sstevel@tonic-gate 	scale_t *scale;
1367*7c478bd9Sstevel@tonic-gate 	char *string;
1368*7c478bd9Sstevel@tonic-gate 	int doneheading = 0;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	if (iter_list == NULL)
1371*7c478bd9Sstevel@tonic-gate 		return;
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate 	while (iter_list != NULL) {
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 		if (doneheading == 0 &&
1376*7c478bd9Sstevel@tonic-gate 		    arg_entity_type == RCENTITY_PROCESS) {
1377*7c478bd9Sstevel@tonic-gate 			proc_unctrl_psinfo(&(p->psinfo));
1378*7c478bd9Sstevel@tonic-gate 			doneheading = 1;
1379*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout,
1380*7c478bd9Sstevel@tonic-gate 			    "process: %d: %.70s\n", (int)p->pid,
1381*7c478bd9Sstevel@tonic-gate 			    p->psinfo.pr_psargs);
1382*7c478bd9Sstevel@tonic-gate 			if (!arg_parseable_mode)
1383*7c478bd9Sstevel@tonic-gate 				print_heading();
1384*7c478bd9Sstevel@tonic-gate 		}
1385*7c478bd9Sstevel@tonic-gate 		if (doneheading == 0 &&
1386*7c478bd9Sstevel@tonic-gate 		    arg_entity_type == RCENTITY_TASK) {
1387*7c478bd9Sstevel@tonic-gate 			doneheading = 1;
1388*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "task: %d\n", (int)p->taskid);
1389*7c478bd9Sstevel@tonic-gate 			if (!arg_parseable_mode)
1390*7c478bd9Sstevel@tonic-gate 				print_heading();
1391*7c478bd9Sstevel@tonic-gate 		}
1392*7c478bd9Sstevel@tonic-gate 		if (doneheading == 0 &&
1393*7c478bd9Sstevel@tonic-gate 		    arg_entity_type == RCENTITY_PROJECT) {
1394*7c478bd9Sstevel@tonic-gate 			if (!arg_parseable_mode && doneheading)
1395*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
1396*7c478bd9Sstevel@tonic-gate 			doneheading = 1;
1397*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout,
1398*7c478bd9Sstevel@tonic-gate 			    "project: %d: %.70s\n", (int)p->projid,
1399*7c478bd9Sstevel@tonic-gate 			    p->projname);
1400*7c478bd9Sstevel@tonic-gate 			if (!arg_parseable_mode)
1401*7c478bd9Sstevel@tonic-gate 				print_heading();
1402*7c478bd9Sstevel@tonic-gate 		}
1403*7c478bd9Sstevel@tonic-gate 		if (doneheading == 0 &&
1404*7c478bd9Sstevel@tonic-gate 		    arg_entity_type == RCENTITY_ZONE) {
1405*7c478bd9Sstevel@tonic-gate 			doneheading = 1;
1406*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout,
1407*7c478bd9Sstevel@tonic-gate 			    "zone: %d: %.70s\n", (int)p->zoneid,
1408*7c478bd9Sstevel@tonic-gate 			    p->zonename);
1409*7c478bd9Sstevel@tonic-gate 			if (!arg_parseable_mode)
1410*7c478bd9Sstevel@tonic-gate 				print_heading();
1411*7c478bd9Sstevel@tonic-gate 		}
1412*7c478bd9Sstevel@tonic-gate 		/* only print name once in normal output */
1413*7c478bd9Sstevel@tonic-gate 		if (!arg_parseable_mode)
1414*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "%s\n", iter_list->name);
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 		iter_val = iter_list->val_list;
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate 		/* if for some reason there are no values, skip */
1419*7c478bd9Sstevel@tonic-gate 		if (iter_val == 0)
1420*7c478bd9Sstevel@tonic-gate 			continue;
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 
1423*7c478bd9Sstevel@tonic-gate 		/* get the global flags the first rctl only */
1424*7c478bd9Sstevel@tonic-gate 		global_flags = rctlblk_get_global_flags(iter_val->rblk);
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 		if (global_flags & RCTL_GLOBAL_BYTES) {
1428*7c478bd9Sstevel@tonic-gate 			unit = SCALED_UNIT_BYTES;
1429*7c478bd9Sstevel@tonic-gate 			scale = scale_binary;
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate 		} else if (global_flags & RCTL_GLOBAL_SECONDS) {
1432*7c478bd9Sstevel@tonic-gate 			unit = SCALED_UNIT_SECONDS;
1433*7c478bd9Sstevel@tonic-gate 			scale = scale_metric;
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 		} else {
1436*7c478bd9Sstevel@tonic-gate 			unit = SCALED_UNIT_NONE;
1437*7c478bd9Sstevel@tonic-gate 			scale = scale_metric;
1438*7c478bd9Sstevel@tonic-gate 		}
1439*7c478bd9Sstevel@tonic-gate 		/* iterate over an print all control values */
1440*7c478bd9Sstevel@tonic-gate 		while (iter_val != NULL) {
1441*7c478bd9Sstevel@tonic-gate 
1442*7c478bd9Sstevel@tonic-gate 			/* print name or empty name field */
1443*7c478bd9Sstevel@tonic-gate 			if (!arg_parseable_mode)
1444*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "%8s", "");
1445*7c478bd9Sstevel@tonic-gate 			else
1446*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "%s ", iter_list->name);
1447*7c478bd9Sstevel@tonic-gate 
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 			rblk_priv = rctlblk_get_privilege(iter_val->rblk);
1450*7c478bd9Sstevel@tonic-gate 			if (!arg_parseable_mode)
1451*7c478bd9Sstevel@tonic-gate 				print_priv(rblk_priv, "%-16s");
1452*7c478bd9Sstevel@tonic-gate 			else
1453*7c478bd9Sstevel@tonic-gate 				print_priv(rblk_priv, "%s ");
1454*7c478bd9Sstevel@tonic-gate 
1455*7c478bd9Sstevel@tonic-gate 			rblk_value = rctlblk_get_value(iter_val->rblk);
1456*7c478bd9Sstevel@tonic-gate 			if (arg_parseable_mode) {
1457*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "%llu ", rblk_value);
1458*7c478bd9Sstevel@tonic-gate 
1459*7c478bd9Sstevel@tonic-gate 			} else {
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 				(void) uint64toscaled(rblk_value, 4, "E",
1462*7c478bd9Sstevel@tonic-gate 				    rctl_valuestring, NULL, NULL,
1463*7c478bd9Sstevel@tonic-gate 				    scale, NULL, 0);
1464*7c478bd9Sstevel@tonic-gate 
1465*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "%5s",
1466*7c478bd9Sstevel@tonic-gate 				    rctl_valuestring);
1467*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "%-4s", unit);
1468*7c478bd9Sstevel@tonic-gate 			}
1469*7c478bd9Sstevel@tonic-gate 			local_flags = rctlblk_get_local_flags(iter_val->rblk);
1470*7c478bd9Sstevel@tonic-gate 
1471*7c478bd9Sstevel@tonic-gate 			if (local_flags & RCTL_LOCAL_MAXIMAL) {
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 				if (global_flags & RCTL_GLOBAL_INFINITE) {
1474*7c478bd9Sstevel@tonic-gate 					string = "inf";
1475*7c478bd9Sstevel@tonic-gate 				} else {
1476*7c478bd9Sstevel@tonic-gate 					string = "max";
1477*7c478bd9Sstevel@tonic-gate 				}
1478*7c478bd9Sstevel@tonic-gate 			} else {
1479*7c478bd9Sstevel@tonic-gate 				string = "-";
1480*7c478bd9Sstevel@tonic-gate 			}
1481*7c478bd9Sstevel@tonic-gate 			if (arg_parseable_mode)
1482*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "%s ", string);
1483*7c478bd9Sstevel@tonic-gate 			else
1484*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "%4s%3s",
1485*7c478bd9Sstevel@tonic-gate 				    string, "");
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 			local_action = rctlblk_get_local_action(iter_val->rblk,
1489*7c478bd9Sstevel@tonic-gate 			    &signal);
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 			if (arg_parseable_mode)
1492*7c478bd9Sstevel@tonic-gate 				print_local_action(local_action, &signal,
1493*7c478bd9Sstevel@tonic-gate 				    "%s ");
1494*7c478bd9Sstevel@tonic-gate 			else
1495*7c478bd9Sstevel@tonic-gate 				print_local_action(local_action, &signal,
1496*7c478bd9Sstevel@tonic-gate 				    "%-28s");
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 			pid = rctlblk_get_recipient_pid(iter_val->rblk);
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 			if (arg_parseable_mode) {
1501*7c478bd9Sstevel@tonic-gate 				if (pid < 0) {
1502*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stdout, "%s\n", "-");
1503*7c478bd9Sstevel@tonic-gate 				} else {
1504*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stdout, "%d\n",
1505*7c478bd9Sstevel@tonic-gate 					    (int)pid);
1506*7c478bd9Sstevel@tonic-gate 				}
1507*7c478bd9Sstevel@tonic-gate 			} else {
1508*7c478bd9Sstevel@tonic-gate 				if (pid < 0) {
1509*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stdout, "%10s\n", "-");
1510*7c478bd9Sstevel@tonic-gate 				} else {
1511*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stdout, "%10d\n",
1512*7c478bd9Sstevel@tonic-gate 					    (int)pid);
1513*7c478bd9Sstevel@tonic-gate 				}
1514*7c478bd9Sstevel@tonic-gate 			}
1515*7c478bd9Sstevel@tonic-gate 			iter_val = iter_val->next;
1516*7c478bd9Sstevel@tonic-gate 		}
1517*7c478bd9Sstevel@tonic-gate 		iter_list = iter_list->next;
1518*7c478bd9Sstevel@tonic-gate 	}
1519*7c478bd9Sstevel@tonic-gate }
1520*7c478bd9Sstevel@tonic-gate 
1521*7c478bd9Sstevel@tonic-gate /*
1522*7c478bd9Sstevel@tonic-gate  *
1523*7c478bd9Sstevel@tonic-gate  * match_rctl
1524*7c478bd9Sstevel@tonic-gate  *
1525*7c478bd9Sstevel@tonic-gate  * find the first rctl with matching name, value, priv, and recipient pid
1526*7c478bd9Sstevel@tonic-gate  */
1527*7c478bd9Sstevel@tonic-gate int
1528*7c478bd9Sstevel@tonic-gate match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name,
1529*7c478bd9Sstevel@tonic-gate     char *valuestringin, int valuein, rctl_priv_t privin, int pidin)
1530*7c478bd9Sstevel@tonic-gate {
1531*7c478bd9Sstevel@tonic-gate 	rctlblk_t *next;
1532*7c478bd9Sstevel@tonic-gate 	rctlblk_t *last;
1533*7c478bd9Sstevel@tonic-gate 	rctlblk_t *tmp;
1534*7c478bd9Sstevel@tonic-gate 
1535*7c478bd9Sstevel@tonic-gate 	*rctl = NULL;
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate 	next = calloc(1, rctlblk_size());
1538*7c478bd9Sstevel@tonic-gate 	last = calloc(1, rctlblk_size());
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 	if ((last == NULL) || (next == NULL)) {
1541*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("malloc failed"), strerror(errno));
1542*7c478bd9Sstevel@tonic-gate 		return (-1);
1543*7c478bd9Sstevel@tonic-gate 	}
1544*7c478bd9Sstevel@tonic-gate 	/*
1545*7c478bd9Sstevel@tonic-gate 	 * For this resource name, now iterate through all
1546*7c478bd9Sstevel@tonic-gate 	 * the  controls, looking for a match to the
1547*7c478bd9Sstevel@tonic-gate 	 * user-specified input.
1548*7c478bd9Sstevel@tonic-gate 	 */
1549*7c478bd9Sstevel@tonic-gate 	if (pr_getrctl(Pr, name, NULL, next, RCTL_FIRST)) {
1550*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("failed to get resource control "
1551*7c478bd9Sstevel@tonic-gate 		    "for %s: %s"), name, strerror(errno));
1552*7c478bd9Sstevel@tonic-gate 		return (-1);
1553*7c478bd9Sstevel@tonic-gate 	}
1554*7c478bd9Sstevel@tonic-gate 	if (match_rctl_blk(next, valuestringin, valuein, privin, pidin) == 1) {
1555*7c478bd9Sstevel@tonic-gate 		free(last);
1556*7c478bd9Sstevel@tonic-gate 		*rctl = next;
1557*7c478bd9Sstevel@tonic-gate 		return (0);
1558*7c478bd9Sstevel@tonic-gate 	}
1559*7c478bd9Sstevel@tonic-gate 	tmp = next;
1560*7c478bd9Sstevel@tonic-gate 	next = last;
1561*7c478bd9Sstevel@tonic-gate 	last = tmp;
1562*7c478bd9Sstevel@tonic-gate 
1563*7c478bd9Sstevel@tonic-gate 	while (pr_getrctl(Pr, name, last, next,	RCTL_NEXT) == 0) {
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate 		/* allow user interrupt */
1566*7c478bd9Sstevel@tonic-gate 		if (interrupt)
1567*7c478bd9Sstevel@tonic-gate 			break;
1568*7c478bd9Sstevel@tonic-gate 
1569*7c478bd9Sstevel@tonic-gate 		if (match_rctl_blk(next, valuestringin, valuein, privin, pidin)
1570*7c478bd9Sstevel@tonic-gate 		    == 1) {
1571*7c478bd9Sstevel@tonic-gate 			free(last);
1572*7c478bd9Sstevel@tonic-gate 			*rctl = next;
1573*7c478bd9Sstevel@tonic-gate 			return (0);
1574*7c478bd9Sstevel@tonic-gate 		}
1575*7c478bd9Sstevel@tonic-gate 		tmp = next;
1576*7c478bd9Sstevel@tonic-gate 		next = last;
1577*7c478bd9Sstevel@tonic-gate 		last = tmp;
1578*7c478bd9Sstevel@tonic-gate 	}
1579*7c478bd9Sstevel@tonic-gate 	free(next);
1580*7c478bd9Sstevel@tonic-gate 	free(last);
1581*7c478bd9Sstevel@tonic-gate 
1582*7c478bd9Sstevel@tonic-gate 	return (1);
1583*7c478bd9Sstevel@tonic-gate }
1584*7c478bd9Sstevel@tonic-gate 
1585*7c478bd9Sstevel@tonic-gate /*
1586*7c478bd9Sstevel@tonic-gate  * int match_rctl_blk(rctlblk_t *, char *, uint64, rctl_priv_t, int pid)
1587*7c478bd9Sstevel@tonic-gate  *
1588*7c478bd9Sstevel@tonic-gate  * Input
1589*7c478bd9Sstevel@tonic-gate  *   Must supply a valid rctl, value, privilege, and pid to match on.
1590*7c478bd9Sstevel@tonic-gate  *   If valuestring is NULL, then valuestring and valuein will not be used
1591*7c478bd9Sstevel@tonic-gate  *   If privilege type is 0 it will not be used.
1592*7c478bd9Sstevel@tonic-gate  *   If pid is -1 it will not be used.
1593*7c478bd9Sstevel@tonic-gate  *
1594*7c478bd9Sstevel@tonic-gate  * Return values
1595*7c478bd9Sstevel@tonic-gate  *   Returns 1 if a matching rctl given matches the parameters specified, and
1596*7c478bd9Sstevel@tonic-gate  *   0 if they do not.
1597*7c478bd9Sstevel@tonic-gate  *
1598*7c478bd9Sstevel@tonic-gate  * This function is Pgrab-safe.
1599*7c478bd9Sstevel@tonic-gate  */
1600*7c478bd9Sstevel@tonic-gate int
1601*7c478bd9Sstevel@tonic-gate match_rctl_blk(rctlblk_t *rctl, char *valuestringin,
1602*7c478bd9Sstevel@tonic-gate     uint64_t valuein, rctl_priv_t privin, int pidin)
1603*7c478bd9Sstevel@tonic-gate {
1604*7c478bd9Sstevel@tonic-gate 
1605*7c478bd9Sstevel@tonic-gate 	rctl_qty_t value;
1606*7c478bd9Sstevel@tonic-gate 	rctl_priv_t priv;
1607*7c478bd9Sstevel@tonic-gate 	pid_t pid;
1608*7c478bd9Sstevel@tonic-gate 	int valuematch = 1;
1609*7c478bd9Sstevel@tonic-gate 	int privmatch = 1;
1610*7c478bd9Sstevel@tonic-gate 	int pidmatch = 1;
1611*7c478bd9Sstevel@tonic-gate 
1612*7c478bd9Sstevel@tonic-gate 	value = rctlblk_get_value(rctl);
1613*7c478bd9Sstevel@tonic-gate 	priv = rctlblk_get_privilege(rctl);
1614*7c478bd9Sstevel@tonic-gate 	pid = rctlblk_get_recipient_pid(rctl);
1615*7c478bd9Sstevel@tonic-gate 
1616*7c478bd9Sstevel@tonic-gate 	if (valuestringin) {
1617*7c478bd9Sstevel@tonic-gate 
1618*7c478bd9Sstevel@tonic-gate 		if (arg_modifier == NULL) {
1619*7c478bd9Sstevel@tonic-gate 			valuematch = (valuein == value);
1620*7c478bd9Sstevel@tonic-gate 		} else {
1621*7c478bd9Sstevel@tonic-gate 			valuematch = scaledequint64(valuestringin, value,
1622*7c478bd9Sstevel@tonic-gate 			    PRCTL_VALUE_WIDTH,
1623*7c478bd9Sstevel@tonic-gate 			    arg_scale, arg_unit,
1624*7c478bd9Sstevel@tonic-gate 			    SCALED_ALL_FLAGS);
1625*7c478bd9Sstevel@tonic-gate 		}
1626*7c478bd9Sstevel@tonic-gate 	}
1627*7c478bd9Sstevel@tonic-gate 	if (privin != 0) {
1628*7c478bd9Sstevel@tonic-gate 		privmatch = (privin == priv);
1629*7c478bd9Sstevel@tonic-gate 	}
1630*7c478bd9Sstevel@tonic-gate 	if (pidin != -1) {
1631*7c478bd9Sstevel@tonic-gate 		pidmatch = (pidin == pid);
1632*7c478bd9Sstevel@tonic-gate 	}
1633*7c478bd9Sstevel@tonic-gate 	return (valuematch && privmatch && pidmatch);
1634*7c478bd9Sstevel@tonic-gate }
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate static int
1637*7c478bd9Sstevel@tonic-gate change_action(rctlblk_t *blk)
1638*7c478bd9Sstevel@tonic-gate {
1639*7c478bd9Sstevel@tonic-gate 	int signal = 0;
1640*7c478bd9Sstevel@tonic-gate 	int action;
1641*7c478bd9Sstevel@tonic-gate 
1642*7c478bd9Sstevel@tonic-gate 	action = rctlblk_get_local_action(blk, &signal);
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 	if (arg_operation & ACTION_ENABLE) {
1645*7c478bd9Sstevel@tonic-gate 
1646*7c478bd9Sstevel@tonic-gate 		if (arg_action & RCTL_LOCAL_SIGNAL) {
1647*7c478bd9Sstevel@tonic-gate 			signal = arg_signal;
1648*7c478bd9Sstevel@tonic-gate 		}
1649*7c478bd9Sstevel@tonic-gate 		action = action | arg_action;
1650*7c478bd9Sstevel@tonic-gate 		/* add local action */
1651*7c478bd9Sstevel@tonic-gate 		rctlblk_set_local_action(blk, action, signal);
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate 	} else if (arg_operation & ACTION_DISABLE) {
1654*7c478bd9Sstevel@tonic-gate 
1655*7c478bd9Sstevel@tonic-gate 		/*
1656*7c478bd9Sstevel@tonic-gate 		 * if deleting signal and signal number is specified,
1657*7c478bd9Sstevel@tonic-gate 		 * then signal number must match
1658*7c478bd9Sstevel@tonic-gate 		 */
1659*7c478bd9Sstevel@tonic-gate 		if ((arg_action & RCTL_LOCAL_SIGNAL) &&
1660*7c478bd9Sstevel@tonic-gate 		    (arg_signal != -1)) {
1661*7c478bd9Sstevel@tonic-gate 			if (arg_signal != signal) {
1662*7c478bd9Sstevel@tonic-gate 				preserve_error(gettext("signal name or number "
1663*7c478bd9Sstevel@tonic-gate 				    "does not match existing action"));
1664*7c478bd9Sstevel@tonic-gate 				return (-1);
1665*7c478bd9Sstevel@tonic-gate 			}
1666*7c478bd9Sstevel@tonic-gate 		}
1667*7c478bd9Sstevel@tonic-gate 		/* remove local action */
1668*7c478bd9Sstevel@tonic-gate 		action = action & (~arg_action);
1669*7c478bd9Sstevel@tonic-gate 		rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0);
1670*7c478bd9Sstevel@tonic-gate 		rctlblk_set_local_action(blk, action, signal);
1671*7c478bd9Sstevel@tonic-gate 	}
1672*7c478bd9Sstevel@tonic-gate 	/* enable deny if it must be enabled */
1673*7c478bd9Sstevel@tonic-gate 	if (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS) {
1674*7c478bd9Sstevel@tonic-gate 		rctlblk_set_local_action(blk, RCTL_LOCAL_DENY | action,
1675*7c478bd9Sstevel@tonic-gate 		signal);
1676*7c478bd9Sstevel@tonic-gate 	}
1677*7c478bd9Sstevel@tonic-gate 	return (0);
1678*7c478bd9Sstevel@tonic-gate }
1679*7c478bd9Sstevel@tonic-gate 
1680*7c478bd9Sstevel@tonic-gate /*
1681*7c478bd9Sstevel@tonic-gate  * prctl_setrctl
1682*7c478bd9Sstevel@tonic-gate  *
1683*7c478bd9Sstevel@tonic-gate  * Input
1684*7c478bd9Sstevel@tonic-gate  *   This function expects that input has been validated. In the
1685*7c478bd9Sstevel@tonic-gate  *   case of a replace operation, both old_rblk and new_rblk must
1686*7c478bd9Sstevel@tonic-gate  *   be valid resource controls. If a resource control is being
1687*7c478bd9Sstevel@tonic-gate  *   created, only new_rblk must be supplied. If a resource control
1688*7c478bd9Sstevel@tonic-gate  *   is being deleted, only new_rblk must be supplied.
1689*7c478bd9Sstevel@tonic-gate  *
1690*7c478bd9Sstevel@tonic-gate  * If the privilege is a priviliged type, at this time, the process
1691*7c478bd9Sstevel@tonic-gate  * tries to take on superuser privileges.
1692*7c478bd9Sstevel@tonic-gate  */
1693*7c478bd9Sstevel@tonic-gate int
1694*7c478bd9Sstevel@tonic-gate prctl_setrctl(struct ps_prochandle *Pr, const char *name,
1695*7c478bd9Sstevel@tonic-gate     rctlblk_t *old_rblk, rctlblk_t *new_rblk, uint_t flags)
1696*7c478bd9Sstevel@tonic-gate {
1697*7c478bd9Sstevel@tonic-gate 	int ret = 0;
1698*7c478bd9Sstevel@tonic-gate 	rctl_priv_t rblk_priv;
1699*7c478bd9Sstevel@tonic-gate 	psinfo_t psinfo;
1700*7c478bd9Sstevel@tonic-gate 	zoneid_t oldzoneid = GLOBAL_ZONEID;
1701*7c478bd9Sstevel@tonic-gate 	prpriv_t *old_prpriv = NULL, *new_prpriv = NULL;
1702*7c478bd9Sstevel@tonic-gate 	priv_set_t *eset, *pset;
1703*7c478bd9Sstevel@tonic-gate 	boolean_t relinquish_failed = B_FALSE;
1704*7c478bd9Sstevel@tonic-gate 
1705*7c478bd9Sstevel@tonic-gate 	rblk_priv = rctlblk_get_privilege(new_rblk);
1706*7c478bd9Sstevel@tonic-gate 
1707*7c478bd9Sstevel@tonic-gate 	if (rblk_priv == RCPRIV_SYSTEM) {
1708*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("cannot modify system values"));
1709*7c478bd9Sstevel@tonic-gate 		return (1);
1710*7c478bd9Sstevel@tonic-gate 	}
1711*7c478bd9Sstevel@tonic-gate 	if (rblk_priv == RCPRIV_PRIVILEGED) {
1712*7c478bd9Sstevel@tonic-gate 		new_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid);
1713*7c478bd9Sstevel@tonic-gate 		if (new_prpriv == NULL) {
1714*7c478bd9Sstevel@tonic-gate 			preserve_error(gettext("cannot get process privileges "
1715*7c478bd9Sstevel@tonic-gate 			    "for pid %d: %s"), Pstatus(Pr)->pr_pid,
1716*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
1717*7c478bd9Sstevel@tonic-gate 			return (1);
1718*7c478bd9Sstevel@tonic-gate 		}
1719*7c478bd9Sstevel@tonic-gate 		/*
1720*7c478bd9Sstevel@tonic-gate 		 * We only have to change the process privileges if it doesn't
1721*7c478bd9Sstevel@tonic-gate 		 * already have PRIV_SYS_RESOURCE.  In addition, we want to make
1722*7c478bd9Sstevel@tonic-gate 		 * sure that we don't leave a process with elevated privileges,
1723*7c478bd9Sstevel@tonic-gate 		 * so we make sure the process dies if we exit unexpectedly.
1724*7c478bd9Sstevel@tonic-gate 		 */
1725*7c478bd9Sstevel@tonic-gate 		eset = (priv_set_t *)
1726*7c478bd9Sstevel@tonic-gate 		    &new_prpriv->pr_sets[new_prpriv->pr_setsize *
1727*7c478bd9Sstevel@tonic-gate 		    priv_getsetbyname(PRIV_EFFECTIVE)];
1728*7c478bd9Sstevel@tonic-gate 		pset = (priv_set_t *)
1729*7c478bd9Sstevel@tonic-gate 		    &new_prpriv->pr_sets[new_prpriv->pr_setsize *
1730*7c478bd9Sstevel@tonic-gate 		    priv_getsetbyname(PRIV_PERMITTED)];
1731*7c478bd9Sstevel@tonic-gate 		if (!priv_ismember(eset, PRIV_SYS_RESOURCE)) {
1732*7c478bd9Sstevel@tonic-gate 			/* Keep track of original privileges */
1733*7c478bd9Sstevel@tonic-gate 			old_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid);
1734*7c478bd9Sstevel@tonic-gate 			if (old_prpriv == NULL) {
1735*7c478bd9Sstevel@tonic-gate 				preserve_error(gettext("cannot get process "
1736*7c478bd9Sstevel@tonic-gate 				    "privileges for pid %d: %s"),
1737*7c478bd9Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
1738*7c478bd9Sstevel@tonic-gate 				free(new_prpriv);
1739*7c478bd9Sstevel@tonic-gate 				return (1);
1740*7c478bd9Sstevel@tonic-gate 			}
1741*7c478bd9Sstevel@tonic-gate 			(void) priv_addset(eset, PRIV_SYS_RESOURCE);
1742*7c478bd9Sstevel@tonic-gate 			(void) priv_addset(pset, PRIV_SYS_RESOURCE);
1743*7c478bd9Sstevel@tonic-gate 			if (Psetflags(Pr, PR_KLC) != 0 ||
1744*7c478bd9Sstevel@tonic-gate 			    Psetpriv(Pr, new_prpriv) != 0) {
1745*7c478bd9Sstevel@tonic-gate 				preserve_error(gettext("cannot set process "
1746*7c478bd9Sstevel@tonic-gate 				    "privileges for pid %d: %s"),
1747*7c478bd9Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
1748*7c478bd9Sstevel@tonic-gate 				(void) Punsetflags(Pr, PR_KLC);
1749*7c478bd9Sstevel@tonic-gate 				free(new_prpriv);
1750*7c478bd9Sstevel@tonic-gate 				free(old_prpriv);
1751*7c478bd9Sstevel@tonic-gate 				return (1);
1752*7c478bd9Sstevel@tonic-gate 			}
1753*7c478bd9Sstevel@tonic-gate 		}
1754*7c478bd9Sstevel@tonic-gate 		/*
1755*7c478bd9Sstevel@tonic-gate 		 * If this is a zone.* rctl, it requires more than
1756*7c478bd9Sstevel@tonic-gate 		 * PRIV_SYS_RESOURCE: it wants the process to have global-zone
1757*7c478bd9Sstevel@tonic-gate 		 * credentials.  We temporarily grant non-global zone processes
1758*7c478bd9Sstevel@tonic-gate 		 * these credentials, and make sure the process dies if we exit
1759*7c478bd9Sstevel@tonic-gate 		 * unexpectedly.
1760*7c478bd9Sstevel@tonic-gate 		 */
1761*7c478bd9Sstevel@tonic-gate 		if (arg_name &&
1762*7c478bd9Sstevel@tonic-gate 		    arg_name_entity == RCENTITY_ZONE &&
1763*7c478bd9Sstevel@tonic-gate 		    getzoneid() == GLOBAL_ZONEID &&
1764*7c478bd9Sstevel@tonic-gate 		    proc_get_psinfo(Pstatus(Pr)->pr_pid, &psinfo) == 0 &&
1765*7c478bd9Sstevel@tonic-gate 		    (oldzoneid = psinfo.pr_zoneid) != GLOBAL_ZONEID) {
1766*7c478bd9Sstevel@tonic-gate 			/*
1767*7c478bd9Sstevel@tonic-gate 			 * We need to give this process superuser
1768*7c478bd9Sstevel@tonic-gate 			 * ("super-zone") privileges.
1769*7c478bd9Sstevel@tonic-gate 			 *
1770*7c478bd9Sstevel@tonic-gate 			 * Must never return without setting this back!
1771*7c478bd9Sstevel@tonic-gate 			 */
1772*7c478bd9Sstevel@tonic-gate 			if (Psetflags(Pr, PR_KLC) != 0 ||
1773*7c478bd9Sstevel@tonic-gate 			    Psetzoneid(Pr, GLOBAL_ZONEID) < 0) {
1774*7c478bd9Sstevel@tonic-gate 				preserve_error(gettext(
1775*7c478bd9Sstevel@tonic-gate 				    "cannot set global-zone "
1776*7c478bd9Sstevel@tonic-gate 				    "privileges for pid %d: %s"),
1777*7c478bd9Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
1778*7c478bd9Sstevel@tonic-gate 				/*
1779*7c478bd9Sstevel@tonic-gate 				 * We couldn't set the zoneid to begin with, so
1780*7c478bd9Sstevel@tonic-gate 				 * there's no point in warning the user about
1781*7c478bd9Sstevel@tonic-gate 				 * trying to un-set it.
1782*7c478bd9Sstevel@tonic-gate 				 */
1783*7c478bd9Sstevel@tonic-gate 				oldzoneid = GLOBAL_ZONEID;
1784*7c478bd9Sstevel@tonic-gate 				ret = 1;
1785*7c478bd9Sstevel@tonic-gate 				goto bail;
1786*7c478bd9Sstevel@tonic-gate 			}
1787*7c478bd9Sstevel@tonic-gate 		}
1788*7c478bd9Sstevel@tonic-gate 	}
1789*7c478bd9Sstevel@tonic-gate 	/* Now, actually populate the rctlblk in the kernel */
1790*7c478bd9Sstevel@tonic-gate 	if (flags == RCTL_REPLACE) {
1791*7c478bd9Sstevel@tonic-gate 		/*
1792*7c478bd9Sstevel@tonic-gate 		 * Replace should be a delete followed by an insert. This
1793*7c478bd9Sstevel@tonic-gate 		 * allows us to replace rctl value blocks which match in
1794*7c478bd9Sstevel@tonic-gate 		 * privilege and value, but have updated actions, etc.
1795*7c478bd9Sstevel@tonic-gate 		 * setrctl() doesn't allow a direct replace, but we
1796*7c478bd9Sstevel@tonic-gate 		 * should do the right thing for the user in the command.
1797*7c478bd9Sstevel@tonic-gate 		 */
1798*7c478bd9Sstevel@tonic-gate 		if (pr_setrctl(Pr, name, NULL,
1799*7c478bd9Sstevel@tonic-gate 		    old_rblk, RCTL_DELETE)) {
1800*7c478bd9Sstevel@tonic-gate 			preserve_error(gettext("failed to delete resource "
1801*7c478bd9Sstevel@tonic-gate 			    "control %s for pid %d: %s"), name,
1802*7c478bd9Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid, strerror(errno));
1803*7c478bd9Sstevel@tonic-gate 			ret = 1;
1804*7c478bd9Sstevel@tonic-gate 			goto bail;
1805*7c478bd9Sstevel@tonic-gate 		}
1806*7c478bd9Sstevel@tonic-gate 		if (pr_setrctl(Pr, name, NULL,
1807*7c478bd9Sstevel@tonic-gate 		    new_rblk, RCTL_INSERT)) {
1808*7c478bd9Sstevel@tonic-gate 			preserve_error(gettext("failed to insert resource "
1809*7c478bd9Sstevel@tonic-gate 			    "control %s for pid %d: %s"), name,
1810*7c478bd9Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid, strerror(errno));
1811*7c478bd9Sstevel@tonic-gate 			ret = 1;
1812*7c478bd9Sstevel@tonic-gate 			goto bail;
1813*7c478bd9Sstevel@tonic-gate 		}
1814*7c478bd9Sstevel@tonic-gate 	} else if (flags == RCTL_INSERT) {
1815*7c478bd9Sstevel@tonic-gate 		if (pr_setrctl(Pr, name, NULL,
1816*7c478bd9Sstevel@tonic-gate 		    new_rblk, RCTL_INSERT)) {
1817*7c478bd9Sstevel@tonic-gate 			preserve_error(gettext("failed to create resource "
1818*7c478bd9Sstevel@tonic-gate 			    "control %s for pid %d: %s"), name,
1819*7c478bd9Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid, strerror(errno));
1820*7c478bd9Sstevel@tonic-gate 			ret = 1;
1821*7c478bd9Sstevel@tonic-gate 			goto bail;
1822*7c478bd9Sstevel@tonic-gate 		}
1823*7c478bd9Sstevel@tonic-gate 	} else if (flags == RCTL_DELETE) {
1824*7c478bd9Sstevel@tonic-gate 		if (pr_setrctl(Pr, name, NULL,
1825*7c478bd9Sstevel@tonic-gate 		    new_rblk, RCTL_DELETE)) {
1826*7c478bd9Sstevel@tonic-gate 			preserve_error(gettext("failed to delete resource "
1827*7c478bd9Sstevel@tonic-gate 			    "control %s for pid %d: %s"), name,
1828*7c478bd9Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid, strerror(errno));
1829*7c478bd9Sstevel@tonic-gate 			ret = 1;
1830*7c478bd9Sstevel@tonic-gate 			goto bail;
1831*7c478bd9Sstevel@tonic-gate 		}
1832*7c478bd9Sstevel@tonic-gate 	}
1833*7c478bd9Sstevel@tonic-gate bail:
1834*7c478bd9Sstevel@tonic-gate 	if (oldzoneid != GLOBAL_ZONEID) {
1835*7c478bd9Sstevel@tonic-gate 		if (Psetzoneid(Pr, oldzoneid) != 0)
1836*7c478bd9Sstevel@tonic-gate 			relinquish_failed = B_TRUE;
1837*7c478bd9Sstevel@tonic-gate 	}
1838*7c478bd9Sstevel@tonic-gate 	if (old_prpriv != NULL) {
1839*7c478bd9Sstevel@tonic-gate 		if (Psetpriv(Pr, old_prpriv) != 0)
1840*7c478bd9Sstevel@tonic-gate 			relinquish_failed = B_TRUE;
1841*7c478bd9Sstevel@tonic-gate 		free(old_prpriv);
1842*7c478bd9Sstevel@tonic-gate 	}
1843*7c478bd9Sstevel@tonic-gate 	if (relinquish_failed) {
1844*7c478bd9Sstevel@tonic-gate 		/*
1845*7c478bd9Sstevel@tonic-gate 		 * If this failed, we can't leave a process hanging
1846*7c478bd9Sstevel@tonic-gate 		 * around with elevated privileges, so we'll have to
1847*7c478bd9Sstevel@tonic-gate 		 * release the process from libproc, knowing that it
1848*7c478bd9Sstevel@tonic-gate 		 * will be killed (since we set PR_KLC).
1849*7c478bd9Sstevel@tonic-gate 		 */
1850*7c478bd9Sstevel@tonic-gate 		Pdestroy_agent(Pr);
1851*7c478bd9Sstevel@tonic-gate 		preserve_error(gettext("cannot relinquish privileges "
1852*7c478bd9Sstevel@tonic-gate 			    "for pid %d. The process was killed."),
1853*7c478bd9Sstevel@tonic-gate 		    Pstatus(Pr)->pr_pid);
1854*7c478bd9Sstevel@tonic-gate 	} else {
1855*7c478bd9Sstevel@tonic-gate 		if (Punsetflags(Pr, PR_KLC) != 0)
1856*7c478bd9Sstevel@tonic-gate 			preserve_error(gettext("cannot relinquish privileges "
1857*7c478bd9Sstevel@tonic-gate 			    "for pid %d. The process was killed."),
1858*7c478bd9Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid);
1859*7c478bd9Sstevel@tonic-gate 	}
1860*7c478bd9Sstevel@tonic-gate 	if (new_prpriv != NULL)
1861*7c478bd9Sstevel@tonic-gate 		free(new_prpriv);
1862*7c478bd9Sstevel@tonic-gate 
1863*7c478bd9Sstevel@tonic-gate 	return (ret);
1864*7c478bd9Sstevel@tonic-gate }
1865*7c478bd9Sstevel@tonic-gate 
1866*7c478bd9Sstevel@tonic-gate void
1867*7c478bd9Sstevel@tonic-gate print_priv(rctl_priv_t local_priv, char *format)
1868*7c478bd9Sstevel@tonic-gate {
1869*7c478bd9Sstevel@tonic-gate 	char pstring[11];
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 	switch (local_priv) {
1872*7c478bd9Sstevel@tonic-gate 	case RCPRIV_BASIC:
1873*7c478bd9Sstevel@tonic-gate 		(void) strcpy(pstring, "basic");
1874*7c478bd9Sstevel@tonic-gate 		break;
1875*7c478bd9Sstevel@tonic-gate 	case RCPRIV_PRIVILEGED:
1876*7c478bd9Sstevel@tonic-gate 		(void) strcpy(pstring, "privileged");
1877*7c478bd9Sstevel@tonic-gate 		break;
1878*7c478bd9Sstevel@tonic-gate 	case RCPRIV_SYSTEM:
1879*7c478bd9Sstevel@tonic-gate 		(void) strcpy(pstring, "system");
1880*7c478bd9Sstevel@tonic-gate 		break;
1881*7c478bd9Sstevel@tonic-gate 	default:
1882*7c478bd9Sstevel@tonic-gate 		(void) sprintf(pstring, "%d", local_priv);
1883*7c478bd9Sstevel@tonic-gate 		break;
1884*7c478bd9Sstevel@tonic-gate 	}
1885*7c478bd9Sstevel@tonic-gate 	/* LINTED */
1886*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, format, pstring);
1887*7c478bd9Sstevel@tonic-gate }
1888*7c478bd9Sstevel@tonic-gate 
1889*7c478bd9Sstevel@tonic-gate void
1890*7c478bd9Sstevel@tonic-gate print_local_action(int action, int *signalp, char *format)
1891*7c478bd9Sstevel@tonic-gate {
1892*7c478bd9Sstevel@tonic-gate 	char sig[SIG2STR_MAX];
1893*7c478bd9Sstevel@tonic-gate 	char sigstring[SIG2STR_MAX + 7];
1894*7c478bd9Sstevel@tonic-gate 	char astring[5 + SIG2STR_MAX + 7];
1895*7c478bd9Sstevel@tonic-gate 	int set = 0;
1896*7c478bd9Sstevel@tonic-gate 
1897*7c478bd9Sstevel@tonic-gate 	astring[0] = '\0';
1898*7c478bd9Sstevel@tonic-gate 
1899*7c478bd9Sstevel@tonic-gate 	if (action == RCTL_LOCAL_NOACTION) {
1900*7c478bd9Sstevel@tonic-gate 		(void) strcat(astring, "none");
1901*7c478bd9Sstevel@tonic-gate 		set++;
1902*7c478bd9Sstevel@tonic-gate 	}
1903*7c478bd9Sstevel@tonic-gate 	if (action & RCTL_LOCAL_DENY) {
1904*7c478bd9Sstevel@tonic-gate 		(void) strcat(astring, "deny");
1905*7c478bd9Sstevel@tonic-gate 		set++;
1906*7c478bd9Sstevel@tonic-gate 	}
1907*7c478bd9Sstevel@tonic-gate 	if ((action & RCTL_LOCAL_DENY) &&
1908*7c478bd9Sstevel@tonic-gate 	    (action & RCTL_LOCAL_SIGNAL)) {
1909*7c478bd9Sstevel@tonic-gate 		(void) strcat(astring, ",");
1910*7c478bd9Sstevel@tonic-gate 	}
1911*7c478bd9Sstevel@tonic-gate 	if (action & RCTL_LOCAL_SIGNAL) {
1912*7c478bd9Sstevel@tonic-gate 		if (sig2str(*signalp, sig))
1913*7c478bd9Sstevel@tonic-gate 			(void) snprintf(sigstring, sizeof (astring),
1914*7c478bd9Sstevel@tonic-gate 			    "signal=%d", *signalp);
1915*7c478bd9Sstevel@tonic-gate 		else
1916*7c478bd9Sstevel@tonic-gate 			(void) snprintf(sigstring, sizeof (astring),
1917*7c478bd9Sstevel@tonic-gate 			    "signal=%s", sig);
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate 		(void) strcat(astring, sigstring);
1920*7c478bd9Sstevel@tonic-gate 		set++;
1921*7c478bd9Sstevel@tonic-gate 	}
1922*7c478bd9Sstevel@tonic-gate 	if (set)
1923*7c478bd9Sstevel@tonic-gate 		/* LINTED */
1924*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, format, astring);
1925*7c478bd9Sstevel@tonic-gate 	else
1926*7c478bd9Sstevel@tonic-gate 		/* LINTED */
1927*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, format, action);
1928*7c478bd9Sstevel@tonic-gate }
1929*7c478bd9Sstevel@tonic-gate 
1930*7c478bd9Sstevel@tonic-gate /*
1931*7c478bd9Sstevel@tonic-gate  * This function is used to grab the process matching the recipient pid
1932*7c478bd9Sstevel@tonic-gate  */
1933*7c478bd9Sstevel@tonic-gate pid_t
1934*7c478bd9Sstevel@tonic-gate regrab_process(pid_t pid, pr_info_handle_t *p, int priv, int *gret)
1935*7c478bd9Sstevel@tonic-gate {
1936*7c478bd9Sstevel@tonic-gate 
1937*7c478bd9Sstevel@tonic-gate 	char pidstring[24];
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 	gret = 0;
1940*7c478bd9Sstevel@tonic-gate 	if (pid == -1)
1941*7c478bd9Sstevel@tonic-gate 		return (p->pid);
1942*7c478bd9Sstevel@tonic-gate 	if (p->pid == pid)
1943*7c478bd9Sstevel@tonic-gate 		return (p->pid);
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate 	release_process(p->pr);
1946*7c478bd9Sstevel@tonic-gate 	(void) memset(p, 0, sizeof (*p));
1947*7c478bd9Sstevel@tonic-gate 
1948*7c478bd9Sstevel@tonic-gate 	(void) snprintf(pidstring, 24, "%d", pid);
1949*7c478bd9Sstevel@tonic-gate 	return (grab_process_by_id(
1950*7c478bd9Sstevel@tonic-gate 	    pidstring, RCENTITY_PROCESS, p, priv, gret));
1951*7c478bd9Sstevel@tonic-gate }
1952*7c478bd9Sstevel@tonic-gate 
1953*7c478bd9Sstevel@tonic-gate /*
1954*7c478bd9Sstevel@tonic-gate  * int grab_process_by_id(char *, rctl_entity_t, pr_info_handle_t *, int, int *)
1955*7c478bd9Sstevel@tonic-gate  *
1956*7c478bd9Sstevel@tonic-gate  * Input
1957*7c478bd9Sstevel@tonic-gate  *    Supply a non-NULL string containing:
1958*7c478bd9Sstevel@tonic-gate  *	- logical project/zone name or project/zone number if type is
1959*7c478bd9Sstevel@tonic-gate  *	RCENTITY_PROJECT or RCENTITY_ZONE
1960*7c478bd9Sstevel@tonic-gate  *	- task number if type is RCENTITY_TYPE
1961*7c478bd9Sstevel@tonic-gate  *	- a pid if type is RCENTITY_PID
1962*7c478bd9Sstevel@tonic-gate  *    Also supply an un-allocated prochandle, and an allocated info_handle.
1963*7c478bd9Sstevel@tonic-gate  *    This function assumes that the type is set.
1964*7c478bd9Sstevel@tonic-gate  *    If priv is not RCPRIV_BASIC, the grabbed process is required to have
1965*7c478bd9Sstevel@tonic-gate  *    PRIV_SYS_RESOURCE in it's limit set.
1966*7c478bd9Sstevel@tonic-gate  *
1967*7c478bd9Sstevel@tonic-gate  * Return Values
1968*7c478bd9Sstevel@tonic-gate  *    Returns 0 on success and 1 on failure. If there is a process
1969*7c478bd9Sstevel@tonic-gate  *    running under the specified id, success is returned, and
1970*7c478bd9Sstevel@tonic-gate  *    Pr is pointed to the process. Success will be returned and Pr
1971*7c478bd9Sstevel@tonic-gate  *    set to NULL if the matching process is our own.
1972*7c478bd9Sstevel@tonic-gate  *    If success is returned, psinfo will be valid, and pid will
1973*7c478bd9Sstevel@tonic-gate  *    be the process number. The process will also be held at the
1974*7c478bd9Sstevel@tonic-gate  *    end, so release_process should be used by the caller.
1975*7c478bd9Sstevel@tonic-gate  *
1976*7c478bd9Sstevel@tonic-gate  * This function assumes that signals are caught already so that libproc
1977*7c478bd9Sstevel@tonic-gate  * can be safely used.
1978*7c478bd9Sstevel@tonic-gate  *
1979*7c478bd9Sstevel@tonic-gate  * Return Values
1980*7c478bd9Sstevel@tonic-gate  *	pid - Process found and grabbed
1981*7c478bd9Sstevel@tonic-gate  *	-1 - Error
1982*7c478bd9Sstevel@tonic-gate  */
1983*7c478bd9Sstevel@tonic-gate pid_t
1984*7c478bd9Sstevel@tonic-gate grab_process_by_id(char *idname, rctl_entity_t type, pr_info_handle_t *p,
1985*7c478bd9Sstevel@tonic-gate     int priv, int *gret)
1986*7c478bd9Sstevel@tonic-gate {
1987*7c478bd9Sstevel@tonic-gate 	char prbuf[PROJECT_BUFSZ];
1988*7c478bd9Sstevel@tonic-gate 	projid_t projid;
1989*7c478bd9Sstevel@tonic-gate 	taskid_t taskid;
1990*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
1991*7c478bd9Sstevel@tonic-gate 	zoneid_t zone_self;
1992*7c478bd9Sstevel@tonic-gate 	struct project proj;
1993*7c478bd9Sstevel@tonic-gate 	DIR *dirp;
1994*7c478bd9Sstevel@tonic-gate 	struct dirent *dentp;
1995*7c478bd9Sstevel@tonic-gate 	int found = 0;
1996*7c478bd9Sstevel@tonic-gate 	int pid_self;
1997*7c478bd9Sstevel@tonic-gate 	int ret;
1998*7c478bd9Sstevel@tonic-gate 	int gret_in;
1999*7c478bd9Sstevel@tonic-gate 	int intidname;
2000*7c478bd9Sstevel@tonic-gate 	char *end;
2001*7c478bd9Sstevel@tonic-gate 	prpriv_t *prpriv;
2002*7c478bd9Sstevel@tonic-gate 	priv_set_t *prset;
2003*7c478bd9Sstevel@tonic-gate 
2004*7c478bd9Sstevel@tonic-gate 	gret_in = *gret;
2005*7c478bd9Sstevel@tonic-gate 
2006*7c478bd9Sstevel@tonic-gate 	/* get our pid se we do not try to operate on self */
2007*7c478bd9Sstevel@tonic-gate 	pid_self = getpid();
2008*7c478bd9Sstevel@tonic-gate 
2009*7c478bd9Sstevel@tonic-gate 	/* Store integer version of id */
2010*7c478bd9Sstevel@tonic-gate 	intidname = strtoul(idname, &end, 10);
2011*7c478bd9Sstevel@tonic-gate 	if (errno || *end != '\0' || end == idname) {
2012*7c478bd9Sstevel@tonic-gate 		intidname = -1;
2013*7c478bd9Sstevel@tonic-gate 	}
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate 	/*
2016*7c478bd9Sstevel@tonic-gate 	 * get our zoneid so we don't try to operate on a project in
2017*7c478bd9Sstevel@tonic-gate 	 * another zone
2018*7c478bd9Sstevel@tonic-gate 	 */
2019*7c478bd9Sstevel@tonic-gate 	zone_self = getzoneid();
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate 	if (idname == NULL || strcmp(idname, "") == 0) {
2022*7c478bd9Sstevel@tonic-gate 		warn(gettext("id name cannot be nuint64\n"));
2023*7c478bd9Sstevel@tonic-gate 		return (-1);
2024*7c478bd9Sstevel@tonic-gate 	}
2025*7c478bd9Sstevel@tonic-gate 	/*
2026*7c478bd9Sstevel@tonic-gate 	 * Set up zoneid, projid or taskid, as appropriate, so that comparisons
2027*7c478bd9Sstevel@tonic-gate 	 * can be done later with the input.
2028*7c478bd9Sstevel@tonic-gate 	 */
2029*7c478bd9Sstevel@tonic-gate 	if (type == RCENTITY_ZONE) {
2030*7c478bd9Sstevel@tonic-gate 		if (zone_get_id(idname, &zoneid) != 0) {
2031*7c478bd9Sstevel@tonic-gate 			warn(gettext("%s: unknown zone\n"), idname);
2032*7c478bd9Sstevel@tonic-gate 			return (-1);
2033*7c478bd9Sstevel@tonic-gate 		}
2034*7c478bd9Sstevel@tonic-gate 	} else if (type == RCENTITY_PROJECT) {
2035*7c478bd9Sstevel@tonic-gate 		if (getprojbyname(idname, &proj, prbuf, PROJECT_BUFSZ)
2036*7c478bd9Sstevel@tonic-gate 		    == NULL) {
2037*7c478bd9Sstevel@tonic-gate 			if (getprojbyid(intidname, &proj, prbuf,
2038*7c478bd9Sstevel@tonic-gate 			    PROJECT_BUFSZ) == NULL) {
2039*7c478bd9Sstevel@tonic-gate 				warn(gettext("%s: cannot find project\n"),
2040*7c478bd9Sstevel@tonic-gate 				    idname);
2041*7c478bd9Sstevel@tonic-gate 				return (-1);
2042*7c478bd9Sstevel@tonic-gate 			}
2043*7c478bd9Sstevel@tonic-gate 		}
2044*7c478bd9Sstevel@tonic-gate 		projid = proj.pj_projid;
2045*7c478bd9Sstevel@tonic-gate 	} else if (type == RCENTITY_TASK) {
2046*7c478bd9Sstevel@tonic-gate 		taskid = (taskid_t)atol(idname);
2047*7c478bd9Sstevel@tonic-gate 	}
2048*7c478bd9Sstevel@tonic-gate 	/*
2049*7c478bd9Sstevel@tonic-gate 	 * Projects and tasks need to search through /proc for
2050*7c478bd9Sstevel@tonic-gate 	 * a parent process.
2051*7c478bd9Sstevel@tonic-gate 	 */
2052*7c478bd9Sstevel@tonic-gate 	if (type == RCENTITY_ZONE || type == RCENTITY_PROJECT ||
2053*7c478bd9Sstevel@tonic-gate 	    type == RCENTITY_TASK) {
2054*7c478bd9Sstevel@tonic-gate 		if ((dirp = opendir("/proc")) == NULL) {
2055*7c478bd9Sstevel@tonic-gate 			warn(gettext("%s: cannot open /proc directory\n"),
2056*7c478bd9Sstevel@tonic-gate 			    idname);
2057*7c478bd9Sstevel@tonic-gate 			return (-1);
2058*7c478bd9Sstevel@tonic-gate 		}
2059*7c478bd9Sstevel@tonic-gate 		/*
2060*7c478bd9Sstevel@tonic-gate 		 * Look through all processes in /proc. For each process,
2061*7c478bd9Sstevel@tonic-gate 		 * check if the pr_projid in their psinfo matches the
2062*7c478bd9Sstevel@tonic-gate 		 * specified id.
2063*7c478bd9Sstevel@tonic-gate 		 */
2064*7c478bd9Sstevel@tonic-gate 		while (dentp = readdir(dirp)) {
2065*7c478bd9Sstevel@tonic-gate 			p->pid = atoi(dentp->d_name);
2066*7c478bd9Sstevel@tonic-gate 
2067*7c478bd9Sstevel@tonic-gate 			/* Skip self */
2068*7c478bd9Sstevel@tonic-gate 			if (p->pid == pid_self)
2069*7c478bd9Sstevel@tonic-gate 				continue;
2070*7c478bd9Sstevel@tonic-gate 
2071*7c478bd9Sstevel@tonic-gate 			if (proc_get_psinfo(p->pid, &(p->psinfo)) != 0)
2072*7c478bd9Sstevel@tonic-gate 				continue;
2073*7c478bd9Sstevel@tonic-gate 
2074*7c478bd9Sstevel@tonic-gate 			/* Skip process if it is not what we are looking for */
2075*7c478bd9Sstevel@tonic-gate 			if (type == RCENTITY_ZONE &&
2076*7c478bd9Sstevel@tonic-gate 			    (p->psinfo).pr_zoneid != zoneid) {
2077*7c478bd9Sstevel@tonic-gate 				continue;
2078*7c478bd9Sstevel@tonic-gate 			} if (type == RCENTITY_PROJECT &&
2079*7c478bd9Sstevel@tonic-gate 			    ((p->psinfo).pr_projid != projid ||
2080*7c478bd9Sstevel@tonic-gate 			    (p->psinfo).pr_zoneid != zone_self)) {
2081*7c478bd9Sstevel@tonic-gate 				continue;
2082*7c478bd9Sstevel@tonic-gate 			} else if (type == RCENTITY_TASK &&
2083*7c478bd9Sstevel@tonic-gate 			    (p->psinfo).pr_taskid != taskid) {
2084*7c478bd9Sstevel@tonic-gate 				continue;
2085*7c478bd9Sstevel@tonic-gate 			}
2086*7c478bd9Sstevel@tonic-gate 			/* attempt to grab process */
2087*7c478bd9Sstevel@tonic-gate 			if (grab_process(p, gret) != 0)
2088*7c478bd9Sstevel@tonic-gate 				continue;
2089*7c478bd9Sstevel@tonic-gate 
2090*7c478bd9Sstevel@tonic-gate 			/*
2091*7c478bd9Sstevel@tonic-gate 			 * Re-confirm that this process is still running as
2092*7c478bd9Sstevel@tonic-gate 			 * part	of the specified project or task.  If it
2093*7c478bd9Sstevel@tonic-gate 			 * doesn't match, release the process and return an
2094*7c478bd9Sstevel@tonic-gate 			 * error. This should only be done if the Pr struct is
2095*7c478bd9Sstevel@tonic-gate 			 * not NULL.
2096*7c478bd9Sstevel@tonic-gate 			 */
2097*7c478bd9Sstevel@tonic-gate 			if (type == RCENTITY_PROJECT) {
2098*7c478bd9Sstevel@tonic-gate 				if (pr_getprojid(p->pr) != projid ||
2099*7c478bd9Sstevel@tonic-gate 				    pr_getzoneid(p->pr) != zone_self) {
2100*7c478bd9Sstevel@tonic-gate 					release_process(p->pr);
2101*7c478bd9Sstevel@tonic-gate 					continue;
2102*7c478bd9Sstevel@tonic-gate 				}
2103*7c478bd9Sstevel@tonic-gate 			} else if (type == RCENTITY_TASK) {
2104*7c478bd9Sstevel@tonic-gate 				if (pr_gettaskid(p->pr) != taskid) {
2105*7c478bd9Sstevel@tonic-gate 					release_process(p->pr);
2106*7c478bd9Sstevel@tonic-gate 					continue;
2107*7c478bd9Sstevel@tonic-gate 				}
2108*7c478bd9Sstevel@tonic-gate 			} else if (type == RCENTITY_ZONE) {
2109*7c478bd9Sstevel@tonic-gate 				if (pr_getzoneid(p->pr) != zoneid) {
2110*7c478bd9Sstevel@tonic-gate 					release_process(p->pr);
2111*7c478bd9Sstevel@tonic-gate 					continue;
2112*7c478bd9Sstevel@tonic-gate 				}
2113*7c478bd9Sstevel@tonic-gate 			}
2114*7c478bd9Sstevel@tonic-gate 
2115*7c478bd9Sstevel@tonic-gate 			/*
2116*7c478bd9Sstevel@tonic-gate 			 * If we are setting a privileged resource control,
2117*7c478bd9Sstevel@tonic-gate 			 * verify that process has PRIV_SYS_RESOURCE in it's
2118*7c478bd9Sstevel@tonic-gate 			 * limit set.  If it does not, then we will not be
2119*7c478bd9Sstevel@tonic-gate 			 * able to give this process the privilege it needs
2120*7c478bd9Sstevel@tonic-gate 			 * to set the resource control.
2121*7c478bd9Sstevel@tonic-gate 			 */
2122*7c478bd9Sstevel@tonic-gate 			if (priv != RCPRIV_BASIC) {
2123*7c478bd9Sstevel@tonic-gate 				prpriv = proc_get_priv(p->pid);
2124*7c478bd9Sstevel@tonic-gate 				if (prpriv == NULL) {
2125*7c478bd9Sstevel@tonic-gate 					release_process(p->pr);
2126*7c478bd9Sstevel@tonic-gate 					continue;
2127*7c478bd9Sstevel@tonic-gate 				}
2128*7c478bd9Sstevel@tonic-gate 				prset = (priv_set_t *)
2129*7c478bd9Sstevel@tonic-gate 				    &prpriv->pr_sets[prpriv->pr_setsize *
2130*7c478bd9Sstevel@tonic-gate 				    priv_getsetbyname(PRIV_LIMIT)];
2131*7c478bd9Sstevel@tonic-gate 				if (!priv_ismember(prset, PRIV_SYS_RESOURCE)) {
2132*7c478bd9Sstevel@tonic-gate 					release_process(p->pr);
2133*7c478bd9Sstevel@tonic-gate 					continue;
2134*7c478bd9Sstevel@tonic-gate 				}
2135*7c478bd9Sstevel@tonic-gate 			}
2136*7c478bd9Sstevel@tonic-gate 			found = 1;
2137*7c478bd9Sstevel@tonic-gate 
2138*7c478bd9Sstevel@tonic-gate 			p->taskid = pr_gettaskid(p->pr);
2139*7c478bd9Sstevel@tonic-gate 			p->projid = pr_getprojid(p->pr);
2140*7c478bd9Sstevel@tonic-gate 			p->zoneid = pr_getzoneid(p->pr);
2141*7c478bd9Sstevel@tonic-gate 
2142*7c478bd9Sstevel@tonic-gate 			break;
2143*7c478bd9Sstevel@tonic-gate 		}
2144*7c478bd9Sstevel@tonic-gate 		(void) closedir(dirp);
2145*7c478bd9Sstevel@tonic-gate 
2146*7c478bd9Sstevel@tonic-gate 		if (found == 0) {
2147*7c478bd9Sstevel@tonic-gate 			warn(gettext("%s: No controllable process found in "
2148*7c478bd9Sstevel@tonic-gate 			    "task, project, or zone.\n"), idname);
2149*7c478bd9Sstevel@tonic-gate 			return (-1);
2150*7c478bd9Sstevel@tonic-gate 		}
2151*7c478bd9Sstevel@tonic-gate 		return (p->pid);
2152*7c478bd9Sstevel@tonic-gate 
2153*7c478bd9Sstevel@tonic-gate 	} else if (type == RCENTITY_PROCESS) {
2154*7c478bd9Sstevel@tonic-gate 
2155*7c478bd9Sstevel@tonic-gate 		/* fail if self */
2156*7c478bd9Sstevel@tonic-gate 		if (p->pid == pid_self) {
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate 			warn(gettext("%s: cannot control self"), idname);
2159*7c478bd9Sstevel@tonic-gate 			return (-1);
2160*7c478bd9Sstevel@tonic-gate 		}
2161*7c478bd9Sstevel@tonic-gate 		/*
2162*7c478bd9Sstevel@tonic-gate 		 * Process types need to be set up with the correct pid
2163*7c478bd9Sstevel@tonic-gate 		 * and psinfo structure.
2164*7c478bd9Sstevel@tonic-gate 		 */
2165*7c478bd9Sstevel@tonic-gate 		if ((p->pid = proc_arg_psinfo(idname, PR_ARG_PIDS,
2166*7c478bd9Sstevel@tonic-gate 		    &(p->psinfo), gret)) == -1) {
2167*7c478bd9Sstevel@tonic-gate 			warn(gettext("%s: cannot examine: %s"), idname,
2168*7c478bd9Sstevel@tonic-gate 			    Pgrab_error(*gret));
2169*7c478bd9Sstevel@tonic-gate 			return (-1);
2170*7c478bd9Sstevel@tonic-gate 		}
2171*7c478bd9Sstevel@tonic-gate 		/* grab process */
2172*7c478bd9Sstevel@tonic-gate 		ret = grab_process(p, gret);
2173*7c478bd9Sstevel@tonic-gate 		if (ret == 1) {
2174*7c478bd9Sstevel@tonic-gate 			/* Don't print error if G_SYS is allowed */
2175*7c478bd9Sstevel@tonic-gate 			if (gret_in == G_SYS && *gret == G_SYS) {
2176*7c478bd9Sstevel@tonic-gate 				return (-1);
2177*7c478bd9Sstevel@tonic-gate 			} else {
2178*7c478bd9Sstevel@tonic-gate 				warn(gettext("%s: cannot control: %s"), idname,
2179*7c478bd9Sstevel@tonic-gate 				    Pgrab_error(*gret));
2180*7c478bd9Sstevel@tonic-gate 				return (-1);
2181*7c478bd9Sstevel@tonic-gate 			}
2182*7c478bd9Sstevel@tonic-gate 		} else if (ret == 2) {
2183*7c478bd9Sstevel@tonic-gate 			ret = errno;
2184*7c478bd9Sstevel@tonic-gate 			warn(gettext("%s: cannot control: %s"), idname,
2185*7c478bd9Sstevel@tonic-gate 			    strerror(ret));
2186*7c478bd9Sstevel@tonic-gate 			return (-1);
2187*7c478bd9Sstevel@tonic-gate 		}
2188*7c478bd9Sstevel@tonic-gate 		p->taskid = pr_gettaskid(p->pr);
2189*7c478bd9Sstevel@tonic-gate 		p->projid = pr_getprojid(p->pr);
2190*7c478bd9Sstevel@tonic-gate 		p->zoneid = pr_getzoneid(p->pr);
2191*7c478bd9Sstevel@tonic-gate 
2192*7c478bd9Sstevel@tonic-gate 		return (p->pid);
2193*7c478bd9Sstevel@tonic-gate 
2194*7c478bd9Sstevel@tonic-gate 	} else {
2195*7c478bd9Sstevel@tonic-gate 		warn(gettext("%s: unknown resource entity type %d\n"), idname,
2196*7c478bd9Sstevel@tonic-gate 		    type);
2197*7c478bd9Sstevel@tonic-gate 		return (-1);
2198*7c478bd9Sstevel@tonic-gate 	}
2199*7c478bd9Sstevel@tonic-gate }
2200*7c478bd9Sstevel@tonic-gate 
2201*7c478bd9Sstevel@tonic-gate /*
2202*7c478bd9Sstevel@tonic-gate  * Do the work required to manipulate a process through libproc.
2203*7c478bd9Sstevel@tonic-gate  * If grab_process() returns no errors (0), then release_process()
2204*7c478bd9Sstevel@tonic-gate  * must eventually be called.
2205*7c478bd9Sstevel@tonic-gate  *
2206*7c478bd9Sstevel@tonic-gate  * Return values:
2207*7c478bd9Sstevel@tonic-gate  *	0 Successful creation of agent thread
2208*7c478bd9Sstevel@tonic-gate  *	1 Error grabbing
2209*7c478bd9Sstevel@tonic-gate  *	2 Error creating agent
2210*7c478bd9Sstevel@tonic-gate  */
2211*7c478bd9Sstevel@tonic-gate int
2212*7c478bd9Sstevel@tonic-gate grab_process(pr_info_handle_t *p, int *gret)
2213*7c478bd9Sstevel@tonic-gate {
2214*7c478bd9Sstevel@tonic-gate 
2215*7c478bd9Sstevel@tonic-gate 	if ((p->pr = Pgrab(p->pid, arg_force, gret)) != NULL) {
2216*7c478bd9Sstevel@tonic-gate 
2217*7c478bd9Sstevel@tonic-gate 		if (Psetflags(p->pr, PR_RLC) != 0) {
2218*7c478bd9Sstevel@tonic-gate 			Prelease(p->pr, 0);
2219*7c478bd9Sstevel@tonic-gate 			return (1);
2220*7c478bd9Sstevel@tonic-gate 		}
2221*7c478bd9Sstevel@tonic-gate 		if (Pcreate_agent(p->pr) == 0) {
2222*7c478bd9Sstevel@tonic-gate 			return (0);
2223*7c478bd9Sstevel@tonic-gate 
2224*7c478bd9Sstevel@tonic-gate 		} else {
2225*7c478bd9Sstevel@tonic-gate 			Prelease(p->pr, 0);
2226*7c478bd9Sstevel@tonic-gate 			return (2);
2227*7c478bd9Sstevel@tonic-gate 		}
2228*7c478bd9Sstevel@tonic-gate 	} else {
2229*7c478bd9Sstevel@tonic-gate 		return (1);
2230*7c478bd9Sstevel@tonic-gate 	}
2231*7c478bd9Sstevel@tonic-gate }
2232*7c478bd9Sstevel@tonic-gate 
2233*7c478bd9Sstevel@tonic-gate /*
2234*7c478bd9Sstevel@tonic-gate  * Release the specified process. This destroys the agent
2235*7c478bd9Sstevel@tonic-gate  * and releases the process. If the process is NULL, nothing
2236*7c478bd9Sstevel@tonic-gate  * is done. This function should only be called if grab_process()
2237*7c478bd9Sstevel@tonic-gate  * has previously been called and returned success.
2238*7c478bd9Sstevel@tonic-gate  *
2239*7c478bd9Sstevel@tonic-gate  * This function is Pgrab-safe.
2240*7c478bd9Sstevel@tonic-gate  */
2241*7c478bd9Sstevel@tonic-gate void
2242*7c478bd9Sstevel@tonic-gate release_process(struct ps_prochandle *Pr)
2243*7c478bd9Sstevel@tonic-gate {
2244*7c478bd9Sstevel@tonic-gate 	if (Pr == NULL)
2245*7c478bd9Sstevel@tonic-gate 		return;
2246*7c478bd9Sstevel@tonic-gate 
2247*7c478bd9Sstevel@tonic-gate 	Pdestroy_agent(Pr);
2248*7c478bd9Sstevel@tonic-gate 	Prelease(Pr, 0);
2249*7c478bd9Sstevel@tonic-gate }
2250*7c478bd9Sstevel@tonic-gate 
2251*7c478bd9Sstevel@tonic-gate /*
2252*7c478bd9Sstevel@tonic-gate  * preserve_error(char *, ...)
2253*7c478bd9Sstevel@tonic-gate  *
2254*7c478bd9Sstevel@tonic-gate  * preserve_error() should be called rather than warn() by any
2255*7c478bd9Sstevel@tonic-gate  * function that is called while the victim process is held by Pgrab.
2256*7c478bd9Sstevel@tonic-gate  * It will save the error until the process has been un-controlled
2257*7c478bd9Sstevel@tonic-gate  * and output is reasonable again.
2258*7c478bd9Sstevel@tonic-gate  *
2259*7c478bd9Sstevel@tonic-gate  * Note that multiple errors are not stored. Any error in these
2260*7c478bd9Sstevel@tonic-gate  * sections should be critical and return immediately.
2261*7c478bd9Sstevel@tonic-gate  *
2262*7c478bd9Sstevel@tonic-gate  * This function is Pgrab-safe.
2263*7c478bd9Sstevel@tonic-gate  *
2264*7c478bd9Sstevel@tonic-gate  * Since this function may copy untrusted command line arguments to
2265*7c478bd9Sstevel@tonic-gate  * global_error, security practices require that global_error never be
2266*7c478bd9Sstevel@tonic-gate  * printed directly.  Use printf("%s\n", global_error) or equivalent.
2267*7c478bd9Sstevel@tonic-gate  */
2268*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
2269*7c478bd9Sstevel@tonic-gate void
2270*7c478bd9Sstevel@tonic-gate preserve_error(char *format, ...)
2271*7c478bd9Sstevel@tonic-gate {
2272*7c478bd9Sstevel@tonic-gate 	va_list alist;
2273*7c478bd9Sstevel@tonic-gate 
2274*7c478bd9Sstevel@tonic-gate 	va_start(alist, format);
2275*7c478bd9Sstevel@tonic-gate 
2276*7c478bd9Sstevel@tonic-gate 	/*
2277*7c478bd9Sstevel@tonic-gate 	 * GLOBAL_ERR_SZ is pretty big. If the error is longer
2278*7c478bd9Sstevel@tonic-gate 	 * than that, just truncate it, rather than chance missing
2279*7c478bd9Sstevel@tonic-gate 	 * the error altogether.
2280*7c478bd9Sstevel@tonic-gate 	 */
2281*7c478bd9Sstevel@tonic-gate 	(void) vsnprintf(global_error, GLOBAL_ERR_SZ-1, format, alist);
2282*7c478bd9Sstevel@tonic-gate 
2283*7c478bd9Sstevel@tonic-gate 	va_end(alist);
2284*7c478bd9Sstevel@tonic-gate }
2285