xref: /onnv-gate/usr/src/cmd/prctl/prctl.c (revision 13093:48f2dbca79a2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58617SMenno.Lageman@Sun.COM  * Common Development and Distribution License (the "License").
68617SMenno.Lageman@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*13093SRoger.Faulkner@Oracle.COM 
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <unistd.h>
270Sstevel@tonic-gate #include <rctl.h>
280Sstevel@tonic-gate #include <libproc.h>
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <libintl.h>
310Sstevel@tonic-gate #include <locale.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <signal.h>
340Sstevel@tonic-gate #include <strings.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <project.h>
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <dirent.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <sys/varargs.h>
420Sstevel@tonic-gate #include <priv.h>
430Sstevel@tonic-gate #include <zone.h>
440Sstevel@tonic-gate #include "utils.h"
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /* Valid user actions */
470Sstevel@tonic-gate #define	ACTION_DISABLE		0x01
480Sstevel@tonic-gate #define	ACTION_ENABLE		0x02
490Sstevel@tonic-gate #define	ACTION_SET		0x04
500Sstevel@tonic-gate #define	ACTION_REPLACE		0x08
510Sstevel@tonic-gate #define	ACTION_DELETE		0x10
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #define	PRCTL_VALUE_WIDTH	4
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /* Maximum string length for deferred errors */
560Sstevel@tonic-gate #define	GLOBAL_ERR_SZ		1024
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /* allow important process values to be passed together easily */
590Sstevel@tonic-gate typedef struct pr_info_handle {
600Sstevel@tonic-gate 	struct ps_prochandle *pr;
610Sstevel@tonic-gate 	pid_t pid;
620Sstevel@tonic-gate 	psinfo_t psinfo;
630Sstevel@tonic-gate 	taskid_t taskid;
640Sstevel@tonic-gate 	projid_t projid;
650Sstevel@tonic-gate 	char *projname;
660Sstevel@tonic-gate 	zoneid_t zoneid;
670Sstevel@tonic-gate 	char *zonename;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate } pr_info_handle_t;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /* Structures for list of resource controls */
720Sstevel@tonic-gate typedef struct prctl_value {
730Sstevel@tonic-gate 	rctlblk_t *rblk;
740Sstevel@tonic-gate 	struct prctl_value *next;
750Sstevel@tonic-gate } prctl_value_t;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate typedef struct prctl_list {
780Sstevel@tonic-gate 	char *name;
7910307SMenno.Lageman@Sun.COM 	rctl_qty_t *usage;
800Sstevel@tonic-gate 	prctl_value_t *val_list;
810Sstevel@tonic-gate 	struct prctl_list *next;
820Sstevel@tonic-gate } prctl_list_t;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate static	volatile int	interrupt;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate static	prctl_list_t	*global_rctl_list_head = NULL;
870Sstevel@tonic-gate static	prctl_list_t	*global_rctl_list_tail = NULL;
880Sstevel@tonic-gate static	char		global_error[GLOBAL_ERR_SZ];
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /* global variables that contain commmand line option info */
910Sstevel@tonic-gate static	int	arg_operation = 0;
920Sstevel@tonic-gate static	int	arg_force = 0;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /* String and type from -i */
960Sstevel@tonic-gate static	rctl_entity_t	arg_entity_type = RCENTITY_PROCESS;
970Sstevel@tonic-gate static	char	*arg_entity_string = NULL;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /* -n argument */
1000Sstevel@tonic-gate static  char	*arg_name = NULL;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static	rctl_entity_t	arg_name_entity = 0;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /* -t argument value */
1050Sstevel@tonic-gate static	int	arg_priv = 0;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /* -v argument string */
1080Sstevel@tonic-gate static	char	*arg_valuestring = NULL;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /* global flags of rctl name passed to -n */
1110Sstevel@tonic-gate static	int	arg_global_flags = 0;
1120Sstevel@tonic-gate static	rctl_qty_t	arg_global_max;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /* appropriate scaling variables determined by rctl unit type */
1150Sstevel@tonic-gate scale_t		*arg_scale;
1160Sstevel@tonic-gate static	char	*arg_unit = NULL;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /* -v argument string converted to uint64_t */
1190Sstevel@tonic-gate static	uint64_t arg_value = 0;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /* if -v argument is scaled value, points to "K", "M", "G", ... */
1220Sstevel@tonic-gate static  char	*arg_modifier = NULL;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /* -e/-d argument string */
1250Sstevel@tonic-gate static	char	*arg_action_string = NULL;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate /* Set to RCTL_LOCAL_SIGNAL|DENY based on arg_action_string */
1280Sstevel@tonic-gate static	int	arg_action = 0;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /* if -e/-d arg is signal=XXX, set to signal number of XXX */
1310Sstevel@tonic-gate static	int	arg_signal = 0;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /* -p arg if -p is specified */
1340Sstevel@tonic-gate static	int	arg_pid = -1;
1350Sstevel@tonic-gate static	char	*arg_pid_string = NULL;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate /* Set to 1 if -P is specified */
1380Sstevel@tonic-gate static	int	arg_parseable_mode = 0;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /* interupt handler */
1410Sstevel@tonic-gate static	void	intr(int);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate static	int	get_rctls(struct ps_prochandle *);
1440Sstevel@tonic-gate static	int	store_rctls(const char *rctlname, void *walk_data);
1450Sstevel@tonic-gate static	prctl_value_t	*store_value_entry(rctlblk_t *rblk, prctl_list_t *list);
1460Sstevel@tonic-gate static	prctl_list_t	*store_list_entry(const char *name);
1470Sstevel@tonic-gate static	void	free_lists();
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate static	int	change_action(rctlblk_t *blk);
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate static	int	prctl_setrctl(struct ps_prochandle *Pr, const char *name,
1520Sstevel@tonic-gate 			rctlblk_t *, rctlblk_t *, uint_t);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate static	int match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name,
1550Sstevel@tonic-gate 			char *valuestringin, int valuein, rctl_priv_t privin,
1560Sstevel@tonic-gate 			int pidin);
1570Sstevel@tonic-gate static	int	match_rctl_blk(rctlblk_t *rctl, char *valuestringin,
1580Sstevel@tonic-gate 			uint64_t valuein,
1590Sstevel@tonic-gate 			rctl_priv_t privin, int pidin);
1600Sstevel@tonic-gate static	pid_t	regrab_process(pid_t pid, pr_info_handle_t *p, int, int *gret);
1610Sstevel@tonic-gate static	pid_t	grab_process_by_id(char *idname, rctl_entity_t type,
1620Sstevel@tonic-gate 			pr_info_handle_t *p, int, int *gret);
1630Sstevel@tonic-gate static	int	grab_process(pr_info_handle_t *p, int *gret);
1640Sstevel@tonic-gate static	void	release_process(struct ps_prochandle *Pr);
1650Sstevel@tonic-gate static	void	preserve_error(char *format, ...);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate static	void	print_rctls(pr_info_handle_t *p);
1680Sstevel@tonic-gate static	void	print_priv(rctl_priv_t local_priv, char *format);
1690Sstevel@tonic-gate static	void	print_local_action(int action, int *signalp, char *format);
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate static const char USAGE[] = ""
1720Sstevel@tonic-gate "usage:\n"
1730Sstevel@tonic-gate "    Report resource control values and actions:\n"
1740Sstevel@tonic-gate "	prctl [-P] [-t [basic | privileged | system]\n"
1750Sstevel@tonic-gate "	[-n name] [-i process | task | project | zone] id ...\n"
1760Sstevel@tonic-gate "	-P space delimited output\n"
1770Sstevel@tonic-gate "	-t privilege level of rctl values to get\n"
1780Sstevel@tonic-gate "	-n name of resource control values to get\n"
1790Sstevel@tonic-gate "	-i idtype of operand list\n"
1800Sstevel@tonic-gate "    Manipulate resource control values:\n"
1810Sstevel@tonic-gate "	prctl [-t [basic | privileged | system]\n"
1820Sstevel@tonic-gate "	-n name [-srx] [-v value] [-p pid ] [-e | -d action]\n"
1830Sstevel@tonic-gate "	[-i process | task | project | zone] id ...\n"
1840Sstevel@tonic-gate "	-t privilege level of rctl value to set/replace/delete/modify\n"
1850Sstevel@tonic-gate "	-n name of resource control to set/replace/delete/modify\n"
1860Sstevel@tonic-gate "	-s set new resource control value\n"
1870Sstevel@tonic-gate "	-r replace first rctl value of matching privilege\n"
1880Sstevel@tonic-gate "	-x delete first rctl value of matching privilege, value, and \n"
1890Sstevel@tonic-gate "	   recipient pid\n"
1900Sstevel@tonic-gate "	-v value of rctl to set/replace/delete/modify\n"
1910Sstevel@tonic-gate "	-p recipient pid of rctl to set/replace/delete/modify\n"
1920Sstevel@tonic-gate "	-e enable action of first rctl value of matching privilege,\n"
1930Sstevel@tonic-gate "	   value, and recipient pid\n"
1940Sstevel@tonic-gate "	-d disable action of first rctl value of matching privilege,\n"
1950Sstevel@tonic-gate "	   value, and recipient pid\n"
1960Sstevel@tonic-gate "	-i idtype of operand list\n";
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate static void
usage()2000Sstevel@tonic-gate usage()
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(USAGE));
2030Sstevel@tonic-gate 	exit(2);
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate int
main(int argc,char ** argv)2070Sstevel@tonic-gate main(int argc, char **argv)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	int flags;
2100Sstevel@tonic-gate 	int opt, errflg = 0;
2110Sstevel@tonic-gate 	rctlblk_t *rctlblkA = NULL;
2120Sstevel@tonic-gate 	rctlblk_t *rctlblkB = NULL;
2130Sstevel@tonic-gate 	rctlblk_t *tmp = NULL;
2140Sstevel@tonic-gate 	pid_t pid;
2150Sstevel@tonic-gate 	char *target_id;
2160Sstevel@tonic-gate 	int search_type;
2170Sstevel@tonic-gate 	int signal;
2180Sstevel@tonic-gate 	int localaction;
2190Sstevel@tonic-gate 	int printed = 0;
2200Sstevel@tonic-gate 	int gret;
2210Sstevel@tonic-gate 	char *end;
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2240Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
225*13093SRoger.Faulkner@Oracle.COM 	(void) setpname(argv[0]);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "sPp:Fd:e:i:n:rt:v:x")) != EOF) {
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 		switch (opt) {
2300Sstevel@tonic-gate 		case 'F':	/* force grabbing (no O_EXCL) */
2310Sstevel@tonic-gate 			arg_force = PGRAB_FORCE;
2320Sstevel@tonic-gate 			break;
2330Sstevel@tonic-gate 		case 'i':	/* id type for arguments */
2340Sstevel@tonic-gate 			arg_entity_string = optarg;
2350Sstevel@tonic-gate 			if (strcmp(optarg, "process") == 0 ||
2360Sstevel@tonic-gate 			    strcmp(optarg, "pid") == 0)
2370Sstevel@tonic-gate 				arg_entity_type = RCENTITY_PROCESS;
2380Sstevel@tonic-gate 			else if (strcmp(optarg, "project") == 0 ||
2398617SMenno.Lageman@Sun.COM 			    strcmp(optarg, "projid") == 0)
2400Sstevel@tonic-gate 				arg_entity_type = RCENTITY_PROJECT;
2410Sstevel@tonic-gate 			else if (strcmp(optarg, "task") == 0 ||
2428617SMenno.Lageman@Sun.COM 			    strcmp(optarg, "taskid") == 0)
2430Sstevel@tonic-gate 				arg_entity_type = RCENTITY_TASK;
2440Sstevel@tonic-gate 			else if (strcmp(optarg, "zone") == 0 ||
2458617SMenno.Lageman@Sun.COM 			    strcmp(optarg, "zoneid") == 0)
2460Sstevel@tonic-gate 				arg_entity_type = RCENTITY_ZONE;
2470Sstevel@tonic-gate 			else {
2480Sstevel@tonic-gate 				warn(gettext("unknown idtype %s"), optarg);
2490Sstevel@tonic-gate 				errflg = 1;
2500Sstevel@tonic-gate 			}
2510Sstevel@tonic-gate 			break;
2520Sstevel@tonic-gate 		case 'd':
2530Sstevel@tonic-gate 			arg_action_string = optarg;
2540Sstevel@tonic-gate 			arg_operation |= ACTION_DISABLE;
2550Sstevel@tonic-gate 			break;
2560Sstevel@tonic-gate 		case 'e':
2570Sstevel@tonic-gate 			arg_action_string = optarg;
2580Sstevel@tonic-gate 			arg_operation |= ACTION_ENABLE;
2590Sstevel@tonic-gate 			break;
2600Sstevel@tonic-gate 		case 'n':	/* name of rctl */
2610Sstevel@tonic-gate 			arg_name = optarg;
2620Sstevel@tonic-gate 			if (strncmp(optarg, "process.",
2630Sstevel@tonic-gate 			    strlen("process.")) == 0)
2640Sstevel@tonic-gate 				arg_name_entity = RCENTITY_PROCESS;
2650Sstevel@tonic-gate 			else if (strncmp(optarg, "project.",
2660Sstevel@tonic-gate 			    strlen("project.")) == 0)
2670Sstevel@tonic-gate 				arg_name_entity = RCENTITY_PROJECT;
2680Sstevel@tonic-gate 			else if (strncmp(optarg, "task.",
2690Sstevel@tonic-gate 			    strlen("task.")) == 0)
2700Sstevel@tonic-gate 				arg_name_entity = RCENTITY_TASK;
2710Sstevel@tonic-gate 			else if (strncmp(optarg, "zone.",
2720Sstevel@tonic-gate 			    strlen("zone.")) == 0)
2730Sstevel@tonic-gate 				arg_name_entity = RCENTITY_ZONE;
2740Sstevel@tonic-gate 			break;
2750Sstevel@tonic-gate 		case 'r':
2760Sstevel@tonic-gate 			arg_operation |= ACTION_REPLACE;
2770Sstevel@tonic-gate 			break;
2780Sstevel@tonic-gate 		case 't':	/* rctl type */
2790Sstevel@tonic-gate 			if (strcmp(optarg, "basic") == 0)
2800Sstevel@tonic-gate 				arg_priv = RCPRIV_BASIC;
2810Sstevel@tonic-gate 			else if (strcmp(optarg, "privileged") == 0)
2820Sstevel@tonic-gate 				arg_priv = RCPRIV_PRIVILEGED;
2830Sstevel@tonic-gate 			else if (strcmp(optarg, "priv") == 0)
2840Sstevel@tonic-gate 				arg_priv = RCPRIV_PRIVILEGED;
2850Sstevel@tonic-gate 			else if (strcmp(optarg, "system") == 0)
2860Sstevel@tonic-gate 				arg_priv = RCPRIV_SYSTEM;
2870Sstevel@tonic-gate 			else {
2880Sstevel@tonic-gate 				warn(gettext("unknown privilege %s"), optarg);
2890Sstevel@tonic-gate 				errflg = 1;
2900Sstevel@tonic-gate 			}
2910Sstevel@tonic-gate 			break;
2920Sstevel@tonic-gate 		case 'v':	/* value */
2930Sstevel@tonic-gate 			arg_valuestring = optarg;
2940Sstevel@tonic-gate 			break;
2950Sstevel@tonic-gate 		case 's':
2960Sstevel@tonic-gate 			arg_operation |= ACTION_SET;
2970Sstevel@tonic-gate 			break;
2980Sstevel@tonic-gate 		case 'x':	/* delete */
2990Sstevel@tonic-gate 			arg_operation |= ACTION_DELETE;
3000Sstevel@tonic-gate 			break;
3010Sstevel@tonic-gate 		case 'p':
3020Sstevel@tonic-gate 			errno = 0;
3030Sstevel@tonic-gate 			/* Stick with -1 if arg is "-" */
3040Sstevel@tonic-gate 			if (strcmp("-", optarg) == 0)
3050Sstevel@tonic-gate 				break;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 			arg_pid_string = optarg;
3080Sstevel@tonic-gate 			arg_pid = strtoul(optarg, &end, 10);
3090Sstevel@tonic-gate 			if (errno || *end != '\0' || end == optarg) {
3100Sstevel@tonic-gate 				warn(gettext("invalid pid %s"), optarg);
3110Sstevel@tonic-gate 				errflg = 1;
3120Sstevel@tonic-gate 				break;
3130Sstevel@tonic-gate 			}
3140Sstevel@tonic-gate 			break;
3150Sstevel@tonic-gate 		case 'P':
3160Sstevel@tonic-gate 			arg_parseable_mode = 1;
3170Sstevel@tonic-gate 			break;
3180Sstevel@tonic-gate 		default:
3190Sstevel@tonic-gate 			warn(gettext("unknown option"));
3200Sstevel@tonic-gate 			errflg = 1;
3210Sstevel@tonic-gate 			break;
3220Sstevel@tonic-gate 		}
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 	argc -= optind;
3250Sstevel@tonic-gate 	argv += optind;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	if (argc < 1) {
3280Sstevel@tonic-gate 		warn(gettext("no arguments specified"));
3290Sstevel@tonic-gate 		errflg = 1;
3300Sstevel@tonic-gate 		goto done_parse;
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 	/* if -v is specified without -r, -x, -d, or -e, -s is implied */
3330Sstevel@tonic-gate 	if (arg_valuestring &&
3340Sstevel@tonic-gate 	    (!(arg_operation & (ACTION_REPLACE | ACTION_DELETE |
3358617SMenno.Lageman@Sun.COM 	    ACTION_DISABLE | ACTION_ENABLE)))) {
3360Sstevel@tonic-gate 		arg_operation |= ACTION_SET;
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 	/* operations require -n */
3390Sstevel@tonic-gate 	if (arg_operation && (arg_name == NULL)) {
3400Sstevel@tonic-gate 		warn(gettext("-n is required with -s, -r, -x, -e, or -d"));
3410Sstevel@tonic-gate 		errflg = 1;
3420Sstevel@tonic-gate 		goto done_parse;
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 	/* enable and disable are exclusive */
3450Sstevel@tonic-gate 	if ((arg_operation & ACTION_ENABLE) &&
3460Sstevel@tonic-gate 	    (arg_operation & ACTION_DISABLE)) {
3470Sstevel@tonic-gate 		warn(gettext("options -d and -e are exclusive"));
3480Sstevel@tonic-gate 		errflg = 1;
3490Sstevel@tonic-gate 		goto done_parse;
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 	/* -s, -r, and -x are exclusive */
3520Sstevel@tonic-gate 	flags = arg_operation &
3530Sstevel@tonic-gate 	    (ACTION_REPLACE | ACTION_SET | ACTION_DELETE);
3540Sstevel@tonic-gate 	if (flags & (flags - 1)) {
3550Sstevel@tonic-gate 		warn(gettext("options -s, -r, and -x are exclusive"));
3560Sstevel@tonic-gate 		errflg = 1;
3570Sstevel@tonic-gate 		goto done_parse;
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 	/* -e or -d makes no sense with -x */
3600Sstevel@tonic-gate 	if ((arg_operation & ACTION_DELETE) &
3610Sstevel@tonic-gate 	    (arg_operation & (ACTION_ENABLE | ACTION_DISABLE))) {
3620Sstevel@tonic-gate 		warn(gettext("options -e or -d  not allowed with -x"));
3630Sstevel@tonic-gate 		errflg = 1;
3640Sstevel@tonic-gate 		goto done_parse;
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 	/* if -r is specified -v must be as well */
3670Sstevel@tonic-gate 	if ((arg_operation & ACTION_REPLACE) && (!arg_valuestring)) {
3680Sstevel@tonic-gate 		warn(gettext("option -r requires use of option -v"));
3690Sstevel@tonic-gate 		errflg = 1;
3700Sstevel@tonic-gate 		goto done_parse;
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 	/* if -s is specified -v must be as well */
3730Sstevel@tonic-gate 	if ((arg_operation & ACTION_SET) && (!arg_valuestring)) {
3740Sstevel@tonic-gate 		warn(gettext("option -s requires use of option -v"));
3750Sstevel@tonic-gate 		errflg = 1;
3760Sstevel@tonic-gate 		goto done_parse;
3770Sstevel@tonic-gate 	}
3780Sstevel@tonic-gate 	/* Specifying a recipient pid on a non-basic rctl makes no sense */
3790Sstevel@tonic-gate 	if (arg_pid != -1 && arg_priv > RCPRIV_BASIC) {
3800Sstevel@tonic-gate 		warn(gettext("option -p not allowed on non-basic rctl"));
3810Sstevel@tonic-gate 		errflg = 1;
3820Sstevel@tonic-gate 		goto done_parse;
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 	/* Specifying a recipient pid on a privileged rctl makes no sense */
3850Sstevel@tonic-gate 	if (arg_pid != -1 &&
3860Sstevel@tonic-gate 	    arg_priv == RCPRIV_PRIVILEGED) {
3870Sstevel@tonic-gate 		warn(gettext("option -p not allowed with privileged rctl"));
3880Sstevel@tonic-gate 		errflg = 1;
3890Sstevel@tonic-gate 		goto done_parse;
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 	if (arg_operation) {
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 		/* do additional checks if there is an operation */
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		if (arg_parseable_mode == 1) {
3960Sstevel@tonic-gate 			warn(gettext("-P not valid when manipulating "
3970Sstevel@tonic-gate 			    "resource control values"));
3980Sstevel@tonic-gate 			errflg = 1;
3990Sstevel@tonic-gate 			goto done_parse;
4000Sstevel@tonic-gate 		}
4010Sstevel@tonic-gate 		/* get rctl global flags to determine if actions are valid */
4020Sstevel@tonic-gate 		if ((rctlblkA = calloc(1, rctlblk_size())) == NULL) {
4030Sstevel@tonic-gate 			warn(gettext("malloc failed: %s"),
4040Sstevel@tonic-gate 			    strerror(errno));
4050Sstevel@tonic-gate 			errflg = 1;
4060Sstevel@tonic-gate 			goto done_parse;
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 		if ((rctlblkB = calloc(1, rctlblk_size())) == NULL) {
4090Sstevel@tonic-gate 			warn(gettext("malloc failed: %s"),
4100Sstevel@tonic-gate 			    strerror(errno));
4110Sstevel@tonic-gate 			errflg = 1;
4120Sstevel@tonic-gate 			goto done_parse;
4130Sstevel@tonic-gate 		}
4140Sstevel@tonic-gate 		/* get system rctl to get global flags and max value */
4150Sstevel@tonic-gate 		if (getrctl(arg_name, NULL, rctlblkA, RCTL_FIRST)) {
4160Sstevel@tonic-gate 			warn(gettext("failed to get resource control "
4170Sstevel@tonic-gate 			    "for %s: %s"), arg_name, strerror(errno));
4180Sstevel@tonic-gate 			errflg = 1;
4190Sstevel@tonic-gate 			goto done_parse;
4200Sstevel@tonic-gate 		}
4210Sstevel@tonic-gate 		while (getrctl(arg_name, rctlblkA, rctlblkB, RCTL_NEXT) == 0) {
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 			/* allow user interrupt */
4240Sstevel@tonic-gate 			if (interrupt) {
4250Sstevel@tonic-gate 				errflg = 1;
4260Sstevel@tonic-gate 				goto done_parse;
4270Sstevel@tonic-gate 			}
4280Sstevel@tonic-gate 			tmp = rctlblkB;
4290Sstevel@tonic-gate 			rctlblkB = rctlblkA;
4300Sstevel@tonic-gate 			rctlblkA = tmp;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 			if (rctlblk_get_privilege(rctlblkA) ==
4330Sstevel@tonic-gate 			    RCPRIV_SYSTEM) {
4340Sstevel@tonic-gate 				break;
4350Sstevel@tonic-gate 			}
4360Sstevel@tonic-gate 		}
4370Sstevel@tonic-gate 		if (rctlblk_get_privilege(rctlblkA) != RCPRIV_SYSTEM) {
4380Sstevel@tonic-gate 			warn(gettext("failed to get system resource control "
4390Sstevel@tonic-gate 			    "for %s: %s"), arg_name, strerror(errno));
4400Sstevel@tonic-gate 			errflg = 1;
4410Sstevel@tonic-gate 			goto done_parse;
4420Sstevel@tonic-gate 		}
4430Sstevel@tonic-gate 		/* figure out the correct scale and unit for this rctl */
4440Sstevel@tonic-gate 		arg_global_flags = rctlblk_get_global_flags(rctlblkA);
4450Sstevel@tonic-gate 		arg_global_max = rctlblk_get_value(rctlblkA);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 		if (arg_global_flags & RCTL_GLOBAL_BYTES) {
4480Sstevel@tonic-gate 			arg_unit = SCALED_UNIT_BYTES;
4490Sstevel@tonic-gate 			arg_scale = scale_binary;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 		} else if (arg_global_flags & RCTL_GLOBAL_SECONDS) {
4520Sstevel@tonic-gate 			arg_unit = SCALED_UNIT_SECONDS;
4530Sstevel@tonic-gate 			arg_scale = scale_metric;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		} else {
4560Sstevel@tonic-gate 			arg_unit = SCALED_UNIT_NONE;
4570Sstevel@tonic-gate 			arg_scale = scale_metric;
4580Sstevel@tonic-gate 		}
4590Sstevel@tonic-gate 		/* parse -v value string */
4600Sstevel@tonic-gate 		if (arg_valuestring) {
4610Sstevel@tonic-gate 			if (scaledtouint64(arg_valuestring,
4620Sstevel@tonic-gate 			    &arg_value, NULL, &arg_modifier, NULL,
4630Sstevel@tonic-gate 			    arg_scale, arg_unit,
4640Sstevel@tonic-gate 			    SCALED_ALL_FLAGS)) {
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 				warn(gettext("invalid -v value %s"),
4670Sstevel@tonic-gate 				    arg_valuestring);
4680Sstevel@tonic-gate 				errflg = 1;
4690Sstevel@tonic-gate 				goto done_parse;
4700Sstevel@tonic-gate 			}
4710Sstevel@tonic-gate 			if (arg_value > arg_global_max) {
4720Sstevel@tonic-gate 				warn(gettext("-v value %s exceeds system "
4730Sstevel@tonic-gate 				    "limit for resource control: %s"),
4740Sstevel@tonic-gate 				    arg_valuestring, arg_name);
4750Sstevel@tonic-gate 				errflg = 1;
4760Sstevel@tonic-gate 				goto done_parse;
4770Sstevel@tonic-gate 			}
4780Sstevel@tonic-gate 		}
4790Sstevel@tonic-gate 		/* parse action */
4800Sstevel@tonic-gate 		if (arg_action_string) {
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 			char *sigchr;
4830Sstevel@tonic-gate 			char *iter;
4840Sstevel@tonic-gate 
4858617SMenno.Lageman@Sun.COM 			if ((strcmp(arg_action_string, "signal") == 0) ||
4868617SMenno.Lageman@Sun.COM 			    (strcmp(arg_action_string, "sig") == 0)) {
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 				if (arg_operation & ACTION_ENABLE) {
4890Sstevel@tonic-gate 					warn(gettext(
4900Sstevel@tonic-gate 					    "signal name or number must be "
4910Sstevel@tonic-gate 					    "specified with -e"));
4920Sstevel@tonic-gate 					errflg = 1;
4930Sstevel@tonic-gate 					goto done_parse;
4940Sstevel@tonic-gate 				}
4950Sstevel@tonic-gate 				arg_action = RCTL_LOCAL_SIGNAL;
4960Sstevel@tonic-gate 				arg_signal = -1;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 			} else if ((strncmp(arg_action_string,
4990Sstevel@tonic-gate 			    "signal=", strlen("signal=")) == 0) ||
5000Sstevel@tonic-gate 			    (strncmp(arg_action_string,
5018617SMenno.Lageman@Sun.COM 			    "sig=", strlen("sig=")) == 0)) {
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 				arg_action = RCTL_LOCAL_SIGNAL;
5040Sstevel@tonic-gate 				sigchr = strrchr(arg_action_string, '=');
5050Sstevel@tonic-gate 				sigchr++;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 				iter = sigchr;
5080Sstevel@tonic-gate 				while (*iter) {
5090Sstevel@tonic-gate 					*iter = toupper(*iter);
5100Sstevel@tonic-gate 					iter++;
5110Sstevel@tonic-gate 				}
5120Sstevel@tonic-gate 				if (strncmp("SIG", sigchr, 3) == 0)
5130Sstevel@tonic-gate 					sigchr += 3;
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 				if (str2sig(sigchr, &arg_signal) != 0) {
5170Sstevel@tonic-gate 					warn(gettext("signal invalid"));
5180Sstevel@tonic-gate 					errflg = 1;
5190Sstevel@tonic-gate 					goto done_parse;
5200Sstevel@tonic-gate 				}
5210Sstevel@tonic-gate 			} else if (strcmp(arg_action_string, "deny") == 0) {
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 				arg_action = RCTL_LOCAL_DENY;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 			} else if (strcmp(arg_action_string, "all") == 0) {
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 				if (arg_operation & ACTION_ENABLE) {
5280Sstevel@tonic-gate 					warn(gettext(
5290Sstevel@tonic-gate 					    "cannot use action 'all' with -e"));
5300Sstevel@tonic-gate 					errflg = 1;
5310Sstevel@tonic-gate 					goto done_parse;
5320Sstevel@tonic-gate 				}
5330Sstevel@tonic-gate 				arg_action = RCTL_LOCAL_DENY |
5340Sstevel@tonic-gate 				    RCTL_LOCAL_SIGNAL;
5350Sstevel@tonic-gate 				arg_signal = -1;
5360Sstevel@tonic-gate 				goto done_parse;
5370Sstevel@tonic-gate 			} else {
5380Sstevel@tonic-gate 				warn(gettext("action invalid"));
5390Sstevel@tonic-gate 				errflg = 1;
5400Sstevel@tonic-gate 				goto done_parse;
5410Sstevel@tonic-gate 			}
5420Sstevel@tonic-gate 		}
5430Sstevel@tonic-gate 		/* cannot manipulate system rctls */
5440Sstevel@tonic-gate 		if (arg_priv == RCPRIV_SYSTEM) {
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 			warn(gettext("cannot modify system values"));
5470Sstevel@tonic-gate 			errflg = 1;
5480Sstevel@tonic-gate 			goto done_parse;
5490Sstevel@tonic-gate 		}
5500Sstevel@tonic-gate 		/* validate that the privilege is allowed */
5510Sstevel@tonic-gate 		if ((arg_priv == RCPRIV_BASIC) &&
5520Sstevel@tonic-gate 		    (arg_global_flags & RCTL_GLOBAL_NOBASIC)) {
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 			warn(gettext("basic values not allowed on rctl %s"),
5550Sstevel@tonic-gate 			    arg_name);
5560Sstevel@tonic-gate 			errflg = 1;
5570Sstevel@tonic-gate 			goto done_parse;
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 		/* validate that actions are appropriate for given rctl */
5600Sstevel@tonic-gate 		if ((arg_operation & ACTION_ENABLE) &&
5610Sstevel@tonic-gate 		    (arg_action & RCTL_LOCAL_DENY) &&
5620Sstevel@tonic-gate 		    (arg_global_flags & RCTL_GLOBAL_DENY_NEVER)) {
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 			warn(gettext("unable to enable deny on rctl with "
5650Sstevel@tonic-gate 			    "global flag 'no-deny'"));
5660Sstevel@tonic-gate 			errflg = 1;
5670Sstevel@tonic-gate 			goto done_parse;
5680Sstevel@tonic-gate 		}
5690Sstevel@tonic-gate 		if ((arg_operation & ACTION_DISABLE) &&
5700Sstevel@tonic-gate 		    (arg_action & RCTL_LOCAL_DENY) &&
5710Sstevel@tonic-gate 		    (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS)) {
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 			warn(gettext("unable to disable deny on rctl with "
5740Sstevel@tonic-gate 			    "global flag 'deny'"));
5750Sstevel@tonic-gate 			errflg = 1;
5760Sstevel@tonic-gate 			goto done_parse;
5770Sstevel@tonic-gate 		}
5780Sstevel@tonic-gate 		if ((arg_operation & ACTION_ENABLE) &&
5790Sstevel@tonic-gate 		    (arg_action & RCTL_LOCAL_SIGNAL) &&
5800Sstevel@tonic-gate 		    (arg_global_flags & RCTL_GLOBAL_SIGNAL_NEVER)) {
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 			warn(gettext("unable to enable signal on rctl with "
5830Sstevel@tonic-gate 			    "global flag 'no-signal'"));
5840Sstevel@tonic-gate 			errflg = 1;
5850Sstevel@tonic-gate 			goto done_parse;
5860Sstevel@tonic-gate 		}
5870Sstevel@tonic-gate 		/* now set defaults for options not supplied */
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 		/*
5900Sstevel@tonic-gate 		 * default privilege to basic if this is a seting an rctl
5910Sstevel@tonic-gate 		 * operation
5920Sstevel@tonic-gate 		 */
5930Sstevel@tonic-gate 		if (arg_operation & ACTION_SET) {
5940Sstevel@tonic-gate 			if (arg_priv == 0) {
5950Sstevel@tonic-gate 				arg_priv = RCPRIV_BASIC;
5960Sstevel@tonic-gate 			}
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 		/*
5990Sstevel@tonic-gate 		 * -p is required when set a basic task,
6000Sstevel@tonic-gate 		 * project or zone rctl
6010Sstevel@tonic-gate 		 */
6020Sstevel@tonic-gate 		if ((arg_pid == -1) &&
6030Sstevel@tonic-gate 		    (arg_priv == RCPRIV_BASIC) &&
6040Sstevel@tonic-gate 		    (arg_entity_type != RCENTITY_PROCESS) &&
6050Sstevel@tonic-gate 		    (arg_operation & ACTION_SET) &&
6060Sstevel@tonic-gate 		    (arg_name) &&
6070Sstevel@tonic-gate 		    (arg_name_entity == RCENTITY_TASK ||
6080Sstevel@tonic-gate 		    arg_name_entity == RCENTITY_PROJECT ||
6090Sstevel@tonic-gate 		    arg_name_entity == RCENTITY_ZONE)) {
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 			warn(gettext("-p pid required when setting or "
6120Sstevel@tonic-gate 			    "replacing task or project rctl"));
6130Sstevel@tonic-gate 			errflg = 1;
6140Sstevel@tonic-gate 			goto done_parse;
6150Sstevel@tonic-gate 		}
6160Sstevel@tonic-gate 	} else {
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 		/* validate for list mode */
6190Sstevel@tonic-gate 		/* -p is not valid in list mode */
6200Sstevel@tonic-gate 		if (arg_pid != -1) {
6210Sstevel@tonic-gate 			warn(gettext("-p pid requires -s, -r, -x, -e, or -d"));
6220Sstevel@tonic-gate 			errflg = 1;
6230Sstevel@tonic-gate 			goto done_parse;
6240Sstevel@tonic-gate 		}
6250Sstevel@tonic-gate 	}
6260Sstevel@tonic-gate 	/* getting/setting process rctl on task or project is error */
6270Sstevel@tonic-gate 	if ((arg_name && (arg_name_entity == RCENTITY_PROCESS)) &&
6280Sstevel@tonic-gate 	    ((arg_entity_type == RCENTITY_TASK) ||
6290Sstevel@tonic-gate 	    (arg_entity_type == RCENTITY_PROJECT))) {
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 		warn(gettext("cannot get/set process rctl on task "
6320Sstevel@tonic-gate 		    "or project"));
6330Sstevel@tonic-gate 		errflg = 1;
6340Sstevel@tonic-gate 		goto done_parse;
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 	/* getting/setting task rctl on project is error */
6370Sstevel@tonic-gate 	if ((arg_name && (arg_name_entity == RCENTITY_TASK)) &&
6380Sstevel@tonic-gate 	    (arg_entity_type == RCENTITY_PROJECT)) {
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 		warn(gettext("cannot get/set task rctl on project"));
6410Sstevel@tonic-gate 		errflg = 1;
6420Sstevel@tonic-gate 		goto done_parse;
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate done_parse:
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	/* free any rctlblk's that we may have allocated */
6480Sstevel@tonic-gate 	if (rctlblkA) {
6490Sstevel@tonic-gate 		free(rctlblkA);
6500Sstevel@tonic-gate 		rctlblkA = NULL;
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 	if (rctlblkB) {
6530Sstevel@tonic-gate 		free(rctlblkB);
6540Sstevel@tonic-gate 		rctlblkB = NULL;
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 	if (errflg)
6570Sstevel@tonic-gate 		usage();
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	/* catch signals from terminal */
6600Sstevel@tonic-gate 	if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
6610Sstevel@tonic-gate 		(void) sigset(SIGHUP, intr);
6620Sstevel@tonic-gate 	if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
6630Sstevel@tonic-gate 		(void) sigset(SIGINT, intr);
6640Sstevel@tonic-gate 	if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
6650Sstevel@tonic-gate 		(void) sigset(SIGQUIT, intr);
6660Sstevel@tonic-gate 	(void) sigset(SIGTERM, intr);
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	while (--argc >= 0 && !interrupt) {
6690Sstevel@tonic-gate 		pr_info_handle_t p;
6700Sstevel@tonic-gate 		char *arg = *argv++;
6710Sstevel@tonic-gate 		int intarg;
6720Sstevel@tonic-gate 		char *end;
6730Sstevel@tonic-gate 		errflg = 0;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 		gret = 0;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 		/* Store int version of arg */
6780Sstevel@tonic-gate 		errno = 0;
6790Sstevel@tonic-gate 		intarg = strtoul(arg, &end, 10);
6800Sstevel@tonic-gate 		if (errno || *end != '\0' || end == arg) {
6810Sstevel@tonic-gate 			intarg = -1;
6820Sstevel@tonic-gate 		}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 		/*
6850Sstevel@tonic-gate 		 * -p defaults to arg if basic and collective rctl
6860Sstevel@tonic-gate 		 * and -i process is specified
6870Sstevel@tonic-gate 		 */
6880Sstevel@tonic-gate 		if ((arg_pid == -1) &&
6890Sstevel@tonic-gate 		    (arg_priv == RCPRIV_BASIC) &&
6900Sstevel@tonic-gate 		    (arg_entity_type == RCENTITY_PROCESS) &&
6910Sstevel@tonic-gate 		    (arg_name) &&
6920Sstevel@tonic-gate 		    (arg_name_entity == RCENTITY_TASK ||
6930Sstevel@tonic-gate 		    arg_name_entity == RCENTITY_PROJECT)) {
6940Sstevel@tonic-gate 			arg_pid_string = arg;
6950Sstevel@tonic-gate 			errno = 0;
6960Sstevel@tonic-gate 			arg_pid = intarg;
6970Sstevel@tonic-gate 		}
6980Sstevel@tonic-gate 		/* Specifying a recipient pid and -i pid is redundent */
6990Sstevel@tonic-gate 		if (arg_pid != -1 && arg_entity_type == RCENTITY_PROCESS &&
7000Sstevel@tonic-gate 		    arg_pid != intarg) {
7010Sstevel@tonic-gate 			warn(gettext("option -p pid must match -i process"));
7020Sstevel@tonic-gate 			errflg = 1;
7030Sstevel@tonic-gate 			continue;
7040Sstevel@tonic-gate 		}
7050Sstevel@tonic-gate 		/* use recipient pid if we have one */
7060Sstevel@tonic-gate 		if (arg_pid_string != NULL) {
7070Sstevel@tonic-gate 			target_id = arg_pid_string;
7080Sstevel@tonic-gate 			search_type = RCENTITY_PROCESS;
7090Sstevel@tonic-gate 		} else {
7100Sstevel@tonic-gate 			target_id = arg;
7110Sstevel@tonic-gate 			search_type = arg_entity_type;
7120Sstevel@tonic-gate 		}
7130Sstevel@tonic-gate 		(void) fflush(stdout);	/* process-at-a-time */
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 		if (arg_operation != 0) {
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 			if ((pid = grab_process_by_id(target_id,
7180Sstevel@tonic-gate 			    search_type, &p, arg_priv, &gret)) < 0) {
7190Sstevel@tonic-gate 				/*
7200Sstevel@tonic-gate 				 * Mark that an error occurred so that the
7210Sstevel@tonic-gate 				 * return value can be set, but continue
7220Sstevel@tonic-gate 				 * on with other processes
7230Sstevel@tonic-gate 				 */
7240Sstevel@tonic-gate 				errflg = 1;
7250Sstevel@tonic-gate 				continue;
7260Sstevel@tonic-gate 			}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 			/*
7290Sstevel@tonic-gate 			 * At this point, the victim process is held.
7300Sstevel@tonic-gate 			 * Do not call any Pgrab-unsafe functions until
7310Sstevel@tonic-gate 			 * the process is released via release_process().
7320Sstevel@tonic-gate 			 */
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 			errflg = get_rctls(p.pr);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 			if (arg_operation & ACTION_DELETE) {
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 				/* match by privilege, value, and pid */
7390Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkA, arg_name,
7400Sstevel@tonic-gate 				    arg_valuestring, arg_value, arg_priv,
7410Sstevel@tonic-gate 				    arg_pid) != 0 || rctlblkA == NULL) {
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 					if (interrupt)
7440Sstevel@tonic-gate 						goto out;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 					preserve_error(gettext("no matching "
7470Sstevel@tonic-gate 					    "resource control found for "
7480Sstevel@tonic-gate 					    "deletion"));
7490Sstevel@tonic-gate 					errflg = 1;
7500Sstevel@tonic-gate 					goto out;
7510Sstevel@tonic-gate 				}
7520Sstevel@tonic-gate 				/*
7530Sstevel@tonic-gate 				 * grab correct process.  This is neccessary
7540Sstevel@tonic-gate 				 * if the recipient pid does not match the
7550Sstevel@tonic-gate 				 * one we grabbed
7560Sstevel@tonic-gate 				 */
7570Sstevel@tonic-gate 				pid = regrab_process(
7580Sstevel@tonic-gate 				    rctlblk_get_recipient_pid(rctlblkA),
7590Sstevel@tonic-gate 				    &p, arg_priv, &gret);
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 				if (pid < 0) {
7620Sstevel@tonic-gate 					errflg = 1;
7630Sstevel@tonic-gate 					goto out;
7640Sstevel@tonic-gate 				}
7650Sstevel@tonic-gate 				if (prctl_setrctl(p.pr, arg_name, NULL,
7660Sstevel@tonic-gate 				    rctlblkA, RCTL_DELETE) != 0) {
7670Sstevel@tonic-gate 					errflg = 1;
7680Sstevel@tonic-gate 					goto out;
7690Sstevel@tonic-gate 				}
7700Sstevel@tonic-gate 			} else if (arg_operation & ACTION_SET) {
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 				/* match by privilege, value, and pid */
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkA, arg_name,
7750Sstevel@tonic-gate 				    arg_valuestring, arg_value, arg_priv,
7760Sstevel@tonic-gate 				    arg_pid) == 0) {
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 					if (interrupt)
7790Sstevel@tonic-gate 						goto out;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 					preserve_error(gettext("resource "
7820Sstevel@tonic-gate 					    "control already exists"));
7830Sstevel@tonic-gate 					errflg = 1;
7840Sstevel@tonic-gate 					goto out;
7850Sstevel@tonic-gate 				}
7860Sstevel@tonic-gate 				rctlblkB = calloc(1, rctlblk_size());
7870Sstevel@tonic-gate 				if (rctlblkB == NULL) {
7880Sstevel@tonic-gate 					preserve_error(gettext(
7890Sstevel@tonic-gate 					    "malloc failed"), strerror(errno));
7900Sstevel@tonic-gate 					errflg = 1;
7910Sstevel@tonic-gate 					goto out;
7920Sstevel@tonic-gate 				}
7930Sstevel@tonic-gate 				rctlblk_set_value(rctlblkB, arg_value);
7940Sstevel@tonic-gate 				rctlblk_set_privilege(rctlblkB, arg_priv);
7950Sstevel@tonic-gate 				if (change_action(rctlblkB)) {
7960Sstevel@tonic-gate 					errflg = 1;
7970Sstevel@tonic-gate 					goto out;
7980Sstevel@tonic-gate 				}
7990Sstevel@tonic-gate 				if (prctl_setrctl(p.pr, arg_name, NULL,
8000Sstevel@tonic-gate 				    rctlblkB, RCTL_INSERT) != 0) {
8010Sstevel@tonic-gate 					errflg = 1;
8020Sstevel@tonic-gate 					goto out;
8030Sstevel@tonic-gate 				}
8040Sstevel@tonic-gate 			} else if (arg_operation & ACTION_REPLACE) {
8050Sstevel@tonic-gate 				/*
8060Sstevel@tonic-gate 				 * match rctl for deletion by privilege and
8070Sstevel@tonic-gate 				 * pid only
8080Sstevel@tonic-gate 				 */
8090Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkA, arg_name,
8100Sstevel@tonic-gate 				    NULL, 0, arg_priv,
8110Sstevel@tonic-gate 				    arg_pid) != 0 || rctlblkA == NULL) {
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 					if (interrupt)
8140Sstevel@tonic-gate 						goto out;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 					preserve_error(gettext("no matching "
8170Sstevel@tonic-gate 					    "resource control to replace"));
8180Sstevel@tonic-gate 					errflg = 1;
8190Sstevel@tonic-gate 					goto out;
8200Sstevel@tonic-gate 				}
8210Sstevel@tonic-gate 				/*
8220Sstevel@tonic-gate 				 * grab correct process.  This is neccessary
8230Sstevel@tonic-gate 				 * if the recipient pid does not match the
8240Sstevel@tonic-gate 				 * one we grabbed
8250Sstevel@tonic-gate 				 */
8260Sstevel@tonic-gate 				pid = regrab_process(
8270Sstevel@tonic-gate 				    rctlblk_get_recipient_pid(rctlblkA),
8280Sstevel@tonic-gate 				    &p, arg_priv, &gret);
8290Sstevel@tonic-gate 				if (pid < 0) {
8300Sstevel@tonic-gate 					errflg = 1;
8310Sstevel@tonic-gate 					goto out;
8320Sstevel@tonic-gate 				}
8330Sstevel@tonic-gate 				pid = rctlblk_get_recipient_pid(rctlblkA);
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 				/*
8360Sstevel@tonic-gate 				 * match by privilege, value and pid to
8370Sstevel@tonic-gate 				 * check if new rctl  already exists
8380Sstevel@tonic-gate 				 */
8390Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkB, arg_name,
8400Sstevel@tonic-gate 				    arg_valuestring, arg_value, arg_priv,
8410Sstevel@tonic-gate 				    pid) < 0) {
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 					if (interrupt)
8440Sstevel@tonic-gate 						goto out;
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 					preserve_error(gettext(
8478617SMenno.Lageman@Sun.COM 					    "Internal Error"));
8480Sstevel@tonic-gate 					errflg = 1;
8490Sstevel@tonic-gate 					goto out;
8500Sstevel@tonic-gate 				}
8510Sstevel@tonic-gate 				/*
8520Sstevel@tonic-gate 				 * If rctl already exists, and it does not
8530Sstevel@tonic-gate 				 *  match the one that we will delete, than
8540Sstevel@tonic-gate 				 *  the replace will fail.
8550Sstevel@tonic-gate 				 */
8560Sstevel@tonic-gate 				if (rctlblkB != NULL &&
8578617SMenno.Lageman@Sun.COM 				    arg_value != rctlblk_get_value(rctlblkA)) {
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 					preserve_error(gettext("replacement "
8600Sstevel@tonic-gate 					    "resource control already "
8610Sstevel@tonic-gate 					    "exists"));
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 					errflg = 1;
8640Sstevel@tonic-gate 					goto out;
8650Sstevel@tonic-gate 				}
8660Sstevel@tonic-gate 				/* create new rctl */
8670Sstevel@tonic-gate 				rctlblkB = calloc(1, rctlblk_size());
8680Sstevel@tonic-gate 				if (rctlblkB == NULL) {
8690Sstevel@tonic-gate 					preserve_error(gettext(
8700Sstevel@tonic-gate 					    "malloc failed"), strerror(errno));
8710Sstevel@tonic-gate 					errflg = 1;
8720Sstevel@tonic-gate 					goto out;
8730Sstevel@tonic-gate 				}
8748617SMenno.Lageman@Sun.COM 				localaction =
8758617SMenno.Lageman@Sun.COM 				    rctlblk_get_local_action(rctlblkA, &signal);
8768617SMenno.Lageman@Sun.COM 				rctlblk_set_local_action(rctlblkB, localaction,
8778617SMenno.Lageman@Sun.COM 				    signal);
8780Sstevel@tonic-gate 				rctlblk_set_value(rctlblkB, arg_value);
8790Sstevel@tonic-gate 				rctlblk_set_privilege(rctlblkB,
8800Sstevel@tonic-gate 				    rctlblk_get_privilege(rctlblkA));
8810Sstevel@tonic-gate 				if (change_action(rctlblkB)) {
8820Sstevel@tonic-gate 					errflg = 1;
8830Sstevel@tonic-gate 					goto out;
8840Sstevel@tonic-gate 				}
8850Sstevel@tonic-gate 				/* do replacement */
8860Sstevel@tonic-gate 				if (prctl_setrctl(p.pr, arg_name, rctlblkA,
8870Sstevel@tonic-gate 				    rctlblkB, RCTL_REPLACE) != 0) {
8880Sstevel@tonic-gate 					errflg = 1;
8890Sstevel@tonic-gate 					goto out;
8900Sstevel@tonic-gate 				}
8910Sstevel@tonic-gate 			} else if (arg_operation &
8920Sstevel@tonic-gate 			    (ACTION_ENABLE | ACTION_DISABLE)) {
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 				rctlblkB = calloc(1, rctlblk_size());
8950Sstevel@tonic-gate 				if (rctlblkB == NULL) {
8960Sstevel@tonic-gate 					preserve_error(gettext(
8970Sstevel@tonic-gate 					    "malloc failed"), strerror(errno));
8980Sstevel@tonic-gate 					errflg = 1;
8990Sstevel@tonic-gate 					goto out;
9000Sstevel@tonic-gate 				}
9010Sstevel@tonic-gate 				/* match by privilege, value, and pid */
9020Sstevel@tonic-gate 				if (match_rctl(p.pr, &rctlblkA, arg_name,
9030Sstevel@tonic-gate 				    arg_valuestring, arg_value, arg_priv,
9040Sstevel@tonic-gate 				    arg_pid) != 0) {
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 					if (interrupt)
9070Sstevel@tonic-gate 						goto out;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 					/* if no match, just set new rctl */
9100Sstevel@tonic-gate 					if (arg_priv == 0)
9110Sstevel@tonic-gate 						arg_priv = RCPRIV_BASIC;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 					if ((arg_priv == RCPRIV_BASIC) &&
9140Sstevel@tonic-gate 					    (arg_entity_type !=
9150Sstevel@tonic-gate 					    RCENTITY_PROCESS) &&
9160Sstevel@tonic-gate 					    (arg_pid_string == NULL)) {
9170Sstevel@tonic-gate 						preserve_error(gettext(
9180Sstevel@tonic-gate 						    "-p required when setting "
9190Sstevel@tonic-gate 						    "basic rctls"));
9200Sstevel@tonic-gate 						errflg = 1;
9210Sstevel@tonic-gate 						goto out;
9220Sstevel@tonic-gate 					}
9230Sstevel@tonic-gate 					rctlblk_set_value(rctlblkB,
9240Sstevel@tonic-gate 					    arg_value);
9250Sstevel@tonic-gate 					rctlblk_set_privilege(
9268617SMenno.Lageman@Sun.COM 					    rctlblkB, arg_priv);
9270Sstevel@tonic-gate 					if (change_action(rctlblkB)) {
9280Sstevel@tonic-gate 						errflg = 1;
9290Sstevel@tonic-gate 						goto out;
9300Sstevel@tonic-gate 					}
9310Sstevel@tonic-gate 					if (prctl_setrctl(p.pr,
9320Sstevel@tonic-gate 					    arg_name, NULL, rctlblkB,
9330Sstevel@tonic-gate 					    RCTL_INSERT) != 0) {
9340Sstevel@tonic-gate 						errflg = 1;
9350Sstevel@tonic-gate 						goto out;
9360Sstevel@tonic-gate 					}
9370Sstevel@tonic-gate 					goto out;
9380Sstevel@tonic-gate 				}
9390Sstevel@tonic-gate 				if (rctlblkA == NULL) {
9400Sstevel@tonic-gate 					preserve_error(gettext("no matching "
9410Sstevel@tonic-gate 					    "resource control found"));
9420Sstevel@tonic-gate 					errflg = 1;
9430Sstevel@tonic-gate 					goto out;
9440Sstevel@tonic-gate 				}
9450Sstevel@tonic-gate 				/*
9460Sstevel@tonic-gate 				 * grab correct process.  This is neccessary
9470Sstevel@tonic-gate 				 * if the recipient pid does not match the
9480Sstevel@tonic-gate 				 * one we grabbed
9490Sstevel@tonic-gate 				 */
9500Sstevel@tonic-gate 				pid = regrab_process(
9510Sstevel@tonic-gate 				    rctlblk_get_recipient_pid(rctlblkA),
9520Sstevel@tonic-gate 				    &p, arg_priv, &gret);
9530Sstevel@tonic-gate 				if (pid < 0) {
9540Sstevel@tonic-gate 					errflg = 1;
9550Sstevel@tonic-gate 					goto out;
9560Sstevel@tonic-gate 				}
9570Sstevel@tonic-gate 				localaction =
9580Sstevel@tonic-gate 				    rctlblk_get_local_action(rctlblkA,
9590Sstevel@tonic-gate 				    &signal);
9600Sstevel@tonic-gate 				rctlblk_set_local_action(rctlblkB, localaction,
9610Sstevel@tonic-gate 				    signal);
9620Sstevel@tonic-gate 				rctlblk_set_privilege(rctlblkB,
9638617SMenno.Lageman@Sun.COM 				    rctlblk_get_privilege(rctlblkA));
9640Sstevel@tonic-gate 				rctlblk_set_value(rctlblkB,
9658617SMenno.Lageman@Sun.COM 				    rctlblk_get_value(rctlblkA));
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 				if (change_action(rctlblkB)) {
9680Sstevel@tonic-gate 					errflg = 1;
9690Sstevel@tonic-gate 					goto out;
9700Sstevel@tonic-gate 				}
9710Sstevel@tonic-gate 				if (prctl_setrctl(p.pr, arg_name, rctlblkA,
9720Sstevel@tonic-gate 				    rctlblkB, RCTL_REPLACE) != 0) {
9730Sstevel@tonic-gate 					errflg = 1;
9740Sstevel@tonic-gate 					goto out;
9750Sstevel@tonic-gate 				}
9760Sstevel@tonic-gate 			}
9770Sstevel@tonic-gate out:
9780Sstevel@tonic-gate 			release_process(p.pr);
9790Sstevel@tonic-gate 			if (rctlblkA)
9800Sstevel@tonic-gate 				free(rctlblkA);
9810Sstevel@tonic-gate 			if (rctlblkB)
9820Sstevel@tonic-gate 				free(rctlblkB);
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 			/* Print any errors that occurred */
9850Sstevel@tonic-gate 			if (errflg && *global_error != '\0') {
9860Sstevel@tonic-gate 				proc_unctrl_psinfo(&(p.psinfo));
9870Sstevel@tonic-gate 				(void) fprintf(stderr, "%d:\t%.70s\n",
9880Sstevel@tonic-gate 				    (int)p.pid, p.psinfo.pr_psargs);
9890Sstevel@tonic-gate 				warn("%s\n", global_error);
9900Sstevel@tonic-gate 				break;
9910Sstevel@tonic-gate 			}
9920Sstevel@tonic-gate 		} else {
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 			struct project projent;
9950Sstevel@tonic-gate 			char buf[PROJECT_BUFSZ];
9960Sstevel@tonic-gate 			char zonename[ZONENAME_MAX];
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 			/*
9990Sstevel@tonic-gate 			 * Hack to allow the user to specify a system
10000Sstevel@tonic-gate 			 * process.
10010Sstevel@tonic-gate 			 */
10020Sstevel@tonic-gate 			gret = G_SYS;
10030Sstevel@tonic-gate 			pid = grab_process_by_id(
10040Sstevel@tonic-gate 			    target_id, search_type, &p, RCPRIV_BASIC, &gret);
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 			/*
10070Sstevel@tonic-gate 			 * Print system process if user chose specifically
10080Sstevel@tonic-gate 			 * to inspect a system process.
10090Sstevel@tonic-gate 			 */
10100Sstevel@tonic-gate 			if (arg_entity_type == RCENTITY_PROCESS &&
10110Sstevel@tonic-gate 			    pid < 0 &&
10120Sstevel@tonic-gate 			    gret == G_SYS) {
10130Sstevel@tonic-gate 				/*
10140Sstevel@tonic-gate 				 * Add blank lines between output for
10150Sstevel@tonic-gate 				 * operands.
10160Sstevel@tonic-gate 				 */
10170Sstevel@tonic-gate 				if (printed) {
10180Sstevel@tonic-gate 					(void) fprintf(stdout, "\n");
10190Sstevel@tonic-gate 				}
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 				proc_unctrl_psinfo(&(p.psinfo));
10220Sstevel@tonic-gate 				(void) printf(
10230Sstevel@tonic-gate 				    "process: %d: %s [ system process ]\n",
10240Sstevel@tonic-gate 				    (int)p.pid, p.psinfo.pr_psargs);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 				printed = 1;
10270Sstevel@tonic-gate 				continue;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 			} else if (pid < 0) {
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 				/*
10320Sstevel@tonic-gate 				 * Mark that an error occurred so that the
10330Sstevel@tonic-gate 				 * return value can be set, but continue
10340Sstevel@tonic-gate 				 * on with other processes
10350Sstevel@tonic-gate 				 */
10360Sstevel@tonic-gate 				errflg = 1;
10370Sstevel@tonic-gate 				continue;
10380Sstevel@tonic-gate 			}
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 			errflg = get_rctls(p.pr);
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 			release_process(p.pr);
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 			/* handle user interrupt of getting rctls */
10450Sstevel@tonic-gate 			if (interrupt)
10460Sstevel@tonic-gate 				break;
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 			/* add blank lines between output for operands */
10490Sstevel@tonic-gate 			if (printed) {
10500Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
10510Sstevel@tonic-gate 			}
10520Sstevel@tonic-gate 			/* First print any errors */
10530Sstevel@tonic-gate 			if (errflg) {
10540Sstevel@tonic-gate 				warn("%s\n", global_error);
10550Sstevel@tonic-gate 				free_lists();
10560Sstevel@tonic-gate 				break;
10570Sstevel@tonic-gate 			}
10580Sstevel@tonic-gate 			if (getprojbyid(p.projid, &projent, buf,
10590Sstevel@tonic-gate 			    sizeof (buf))) {
10600Sstevel@tonic-gate 				p.projname = projent.pj_name;
10610Sstevel@tonic-gate 			} else {
10620Sstevel@tonic-gate 				p.projname = "";
10630Sstevel@tonic-gate 			}
10640Sstevel@tonic-gate 			if (getzonenamebyid(p.zoneid, zonename,
10650Sstevel@tonic-gate 			    sizeof (zonename)) > 0) {
10660Sstevel@tonic-gate 				p.zonename = zonename;
10670Sstevel@tonic-gate 			} else {
10680Sstevel@tonic-gate 				p.zonename = "";
10690Sstevel@tonic-gate 			}
10700Sstevel@tonic-gate 			print_rctls(&p);
10710Sstevel@tonic-gate 			printed = 1;
10720Sstevel@tonic-gate 			/* Free the resource control lists */
10730Sstevel@tonic-gate 			free_lists();
10740Sstevel@tonic-gate 		}
10750Sstevel@tonic-gate 	}
10760Sstevel@tonic-gate 	if (interrupt)
10770Sstevel@tonic-gate 		errflg = 1;
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	/*
10800Sstevel@tonic-gate 	 * return error if one occurred
10810Sstevel@tonic-gate 	 */
10820Sstevel@tonic-gate 	return (errflg);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate static void
intr(int sig)10870Sstevel@tonic-gate intr(int sig)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	interrupt = sig;
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate /*
10930Sstevel@tonic-gate  * get_rctls(struct ps_prochandle *, const char *)
10940Sstevel@tonic-gate  *
10950Sstevel@tonic-gate  * If controlname is given, store only controls for that named
10960Sstevel@tonic-gate  * resource. If controlname is NULL, store all controls for all
10970Sstevel@tonic-gate  * resources.
10980Sstevel@tonic-gate  *
10990Sstevel@tonic-gate  * This function is Pgrab-safe.
11000Sstevel@tonic-gate  */
11010Sstevel@tonic-gate static int
get_rctls(struct ps_prochandle * Pr)11020Sstevel@tonic-gate get_rctls(struct ps_prochandle *Pr)
11030Sstevel@tonic-gate {
11040Sstevel@tonic-gate 	int ret = 0;
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	if (arg_name == NULL) {
11070Sstevel@tonic-gate 		if (rctl_walk(store_rctls, Pr) != 0)
11080Sstevel@tonic-gate 			ret = 1;
11090Sstevel@tonic-gate 	} else {
11100Sstevel@tonic-gate 		ret = store_rctls(arg_name, Pr);
11110Sstevel@tonic-gate 	}
11120Sstevel@tonic-gate 	return (ret);
11130Sstevel@tonic-gate }
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate /*
11160Sstevel@tonic-gate  * store_rctls(const char *, void *)
11170Sstevel@tonic-gate  *
11180Sstevel@tonic-gate  * Store resource controls for the given name in a linked list.
11190Sstevel@tonic-gate  * Honor the user's options, and store only the ones they are
11200Sstevel@tonic-gate  * interested in. If priv is not 0, show only controls that match
11210Sstevel@tonic-gate  * the given privilege.
11220Sstevel@tonic-gate  *
11230Sstevel@tonic-gate  * This function is Pgrab-safe
11240Sstevel@tonic-gate  */
11250Sstevel@tonic-gate static int
store_rctls(const char * rctlname,void * walk_data)11260Sstevel@tonic-gate store_rctls(const char *rctlname, void *walk_data)
11270Sstevel@tonic-gate {
11280Sstevel@tonic-gate 	struct ps_prochandle *Pr = walk_data;
11290Sstevel@tonic-gate 	rctlblk_t *rblk2, *rblk_tmp, *rblk1 = NULL;
11300Sstevel@tonic-gate 	prctl_list_t *list = NULL;
11310Sstevel@tonic-gate 	rctl_priv_t rblk_priv;
11320Sstevel@tonic-gate 	rctl_entity_t rblk_entity;
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	if (((rblk1 = calloc(1, rctlblk_size())) == NULL) ||
11350Sstevel@tonic-gate 	    ((rblk2 = calloc(1, rctlblk_size())) == NULL)) {
11360Sstevel@tonic-gate 		if (rblk1 != NULL)
11370Sstevel@tonic-gate 			free(rblk1);
11380Sstevel@tonic-gate 		preserve_error(gettext("malloc failed: %s"),
11390Sstevel@tonic-gate 		    strerror(errno));
11400Sstevel@tonic-gate 		return (1);
11410Sstevel@tonic-gate 	}
11420Sstevel@tonic-gate 	if (pr_getrctl(Pr, rctlname, NULL, rblk1, RCTL_FIRST)) {
11430Sstevel@tonic-gate 		preserve_error(gettext("failed to get resource control "
11440Sstevel@tonic-gate 		    "for %s: %s"), rctlname, strerror(errno));
11450Sstevel@tonic-gate 		free(rblk1);
11460Sstevel@tonic-gate 		free(rblk2);
11470Sstevel@tonic-gate 		return (1);
11480Sstevel@tonic-gate 	}
11490Sstevel@tonic-gate 	/* Store control if it matches privilege and enity type criteria */
11500Sstevel@tonic-gate 	rblk_priv = rctlblk_get_privilege(rblk1);
11510Sstevel@tonic-gate 	rblk_entity = 0;
11520Sstevel@tonic-gate 	if (strncmp(rctlname, "process.",
11530Sstevel@tonic-gate 	    strlen("process.")) == 0)
11540Sstevel@tonic-gate 		rblk_entity = RCENTITY_PROCESS;
11550Sstevel@tonic-gate 	else if (strncmp(rctlname, "project.",
11560Sstevel@tonic-gate 	    strlen("project.")) == 0)
11570Sstevel@tonic-gate 		rblk_entity = RCENTITY_PROJECT;
11580Sstevel@tonic-gate 	else if (strncmp(rctlname, "task.",
11590Sstevel@tonic-gate 	    strlen("task.")) == 0)
11600Sstevel@tonic-gate 		rblk_entity = RCENTITY_TASK;
11610Sstevel@tonic-gate 	else if (strncmp(rctlname, "zone.",
11620Sstevel@tonic-gate 	    strlen("zone.")) == 0)
11630Sstevel@tonic-gate 		rblk_entity = RCENTITY_ZONE;
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	if (((arg_priv == 0) || (rblk_priv == arg_priv)) &&
11660Sstevel@tonic-gate 	    ((arg_name == NULL) ||
11678617SMenno.Lageman@Sun.COM 	    strncmp(rctlname, arg_name, strlen(arg_name)) == 0) &&
11688617SMenno.Lageman@Sun.COM 	    (arg_entity_string == NULL || rblk_entity >= arg_entity_type)) {
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 		/* Once we know we have some controls, store the name */
11710Sstevel@tonic-gate 		if ((list = store_list_entry(rctlname)) == NULL) {
11720Sstevel@tonic-gate 			free(rblk1);
11730Sstevel@tonic-gate 			free(rblk2);
11740Sstevel@tonic-gate 			return (1);
11750Sstevel@tonic-gate 		}
11760Sstevel@tonic-gate 		if (store_value_entry(rblk1, list) == NULL) {
11770Sstevel@tonic-gate 			free(rblk1);
11780Sstevel@tonic-gate 			free(rblk2);
11790Sstevel@tonic-gate 			return (1);
11800Sstevel@tonic-gate 		}
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 	while (pr_getrctl(Pr, rctlname, rblk1, rblk2, RCTL_NEXT) == 0) {
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 		/*
11850Sstevel@tonic-gate 		 * in case this is stuck for some reason, allow manual
11860Sstevel@tonic-gate 		 * interrupt
11870Sstevel@tonic-gate 		 */
11880Sstevel@tonic-gate 		if (interrupt) {
11890Sstevel@tonic-gate 			free(rblk1);
11900Sstevel@tonic-gate 			free(rblk2);
11910Sstevel@tonic-gate 			return (1);
11920Sstevel@tonic-gate 		}
11930Sstevel@tonic-gate 		rblk_priv = rctlblk_get_privilege(rblk2);
11940Sstevel@tonic-gate 		/*
11950Sstevel@tonic-gate 		 * Store control if it matches privilege and entity type
11960Sstevel@tonic-gate 		 * criteria
11970Sstevel@tonic-gate 		 */
11980Sstevel@tonic-gate 		if (((arg_priv == 0) || (rblk_priv == arg_priv)) &&
11990Sstevel@tonic-gate 		    ((arg_name == NULL) ||
12008617SMenno.Lageman@Sun.COM 		    strncmp(rctlname, arg_name, strlen(arg_name)) == 0) &&
12010Sstevel@tonic-gate 		    (arg_entity_string == NULL ||
12028617SMenno.Lageman@Sun.COM 		    rblk_entity == arg_entity_type)) {
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 			/* May not have created the list yet. */
12050Sstevel@tonic-gate 			if (list == NULL) {
12060Sstevel@tonic-gate 				if ((list = store_list_entry(rctlname))
12070Sstevel@tonic-gate 				    == NULL) {
12080Sstevel@tonic-gate 					free(rblk1);
12090Sstevel@tonic-gate 					free(rblk2);
12100Sstevel@tonic-gate 					return (1);
12110Sstevel@tonic-gate 				}
12120Sstevel@tonic-gate 			}
12130Sstevel@tonic-gate 			if (store_value_entry(rblk2, list) == NULL) {
12140Sstevel@tonic-gate 				free(rblk1);
12150Sstevel@tonic-gate 				free(rblk2);
12160Sstevel@tonic-gate 				return (1);
12170Sstevel@tonic-gate 			}
12180Sstevel@tonic-gate 		}
12190Sstevel@tonic-gate 		rblk_tmp = rblk1;
12200Sstevel@tonic-gate 		rblk1 = rblk2;
12210Sstevel@tonic-gate 		rblk2 = rblk_tmp;
12220Sstevel@tonic-gate 	}
122310307SMenno.Lageman@Sun.COM 
122410307SMenno.Lageman@Sun.COM 	/*
122510307SMenno.Lageman@Sun.COM 	 * Get the current usage for the resource control if it matched the
122610307SMenno.Lageman@Sun.COM 	 * privilege and entity type criteria.
122710307SMenno.Lageman@Sun.COM 	 */
122810307SMenno.Lageman@Sun.COM 	if (list != NULL) {
122910307SMenno.Lageman@Sun.COM 		if (pr_getrctl(Pr, rctlname, NULL, rblk2, RCTL_USAGE) == 0) {
123010307SMenno.Lageman@Sun.COM 			list->usage = (rctl_qty_t *)malloc(sizeof (rctl_qty_t));
123110307SMenno.Lageman@Sun.COM 			if (list->usage == NULL) {
123210307SMenno.Lageman@Sun.COM 				preserve_error(gettext("malloc failed: %s"),
123310307SMenno.Lageman@Sun.COM 				    strerror(errno));
123410307SMenno.Lageman@Sun.COM 				free(rblk1);
123510307SMenno.Lageman@Sun.COM 				free(rblk2);
123610307SMenno.Lageman@Sun.COM 				return (1);
123710307SMenno.Lageman@Sun.COM 			}
123810307SMenno.Lageman@Sun.COM 			*list->usage = rctlblk_get_value(rblk2);
123910307SMenno.Lageman@Sun.COM 		} else {
124010307SMenno.Lageman@Sun.COM 			list->usage = NULL;
124110307SMenno.Lageman@Sun.COM 			if (errno != ENOTSUP) {
124210307SMenno.Lageman@Sun.COM 				preserve_error(gettext("failed to get "
124310307SMenno.Lageman@Sun.COM 				    "resource control usage for %s: %s"),
124410307SMenno.Lageman@Sun.COM 				    rctlname, strerror(errno));
124510307SMenno.Lageman@Sun.COM 				free(rblk1);
124610307SMenno.Lageman@Sun.COM 				free(rblk2);
124710307SMenno.Lageman@Sun.COM 				return (1);
124810307SMenno.Lageman@Sun.COM 			}
124910307SMenno.Lageman@Sun.COM 		}
125010307SMenno.Lageman@Sun.COM 	}
12510Sstevel@tonic-gate 	free(rblk1);
12520Sstevel@tonic-gate 	free(rblk2);
12530Sstevel@tonic-gate 	return (0);
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate /*
12570Sstevel@tonic-gate  * store_value_entry(rctlblk_t *, prctl_list_t *)
12580Sstevel@tonic-gate  *
12590Sstevel@tonic-gate  * Store an rblk for a given resource control into the global list.
12600Sstevel@tonic-gate  *
12610Sstevel@tonic-gate  * This function is Pgrab-safe.
12620Sstevel@tonic-gate  */
12630Sstevel@tonic-gate prctl_value_t *
store_value_entry(rctlblk_t * rblk,prctl_list_t * list)12640Sstevel@tonic-gate store_value_entry(rctlblk_t *rblk, prctl_list_t *list)
12650Sstevel@tonic-gate {
12660Sstevel@tonic-gate 	prctl_value_t *e = calloc(1, sizeof (prctl_value_t));
12670Sstevel@tonic-gate 	rctlblk_t *store_blk = calloc(1, rctlblk_size());
12680Sstevel@tonic-gate 	prctl_value_t *iter = list->val_list;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	if (e == NULL || store_blk == NULL) {
12710Sstevel@tonic-gate 		preserve_error(gettext("malloc failed %s"),
12720Sstevel@tonic-gate 		    strerror(errno));
12730Sstevel@tonic-gate 		if (e != NULL)
12740Sstevel@tonic-gate 			free(e);
12750Sstevel@tonic-gate 		if (store_blk != NULL)
12760Sstevel@tonic-gate 			free(store_blk);
12770Sstevel@tonic-gate 		return (NULL);
12780Sstevel@tonic-gate 	}
12790Sstevel@tonic-gate 	if (iter == NULL)
12800Sstevel@tonic-gate 		list->val_list = e;
12810Sstevel@tonic-gate 	else {
12820Sstevel@tonic-gate 		while (iter->next != NULL) {
12830Sstevel@tonic-gate 			iter = iter->next;
12840Sstevel@tonic-gate 		}
12850Sstevel@tonic-gate 		iter->next = e;
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 	bcopy(rblk, store_blk, rctlblk_size());
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	e->rblk = store_blk;
12900Sstevel@tonic-gate 	e->next = NULL;
12910Sstevel@tonic-gate 	return (e);
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate /*
12950Sstevel@tonic-gate  * store_list_entry(const char *)
12960Sstevel@tonic-gate  *
12970Sstevel@tonic-gate  * Store a new resource control value in the global list. No checking
12980Sstevel@tonic-gate  * for duplicates done.
12990Sstevel@tonic-gate  *
13000Sstevel@tonic-gate  * This function is Pgrab-safe.
13010Sstevel@tonic-gate  */
13020Sstevel@tonic-gate prctl_list_t *
store_list_entry(const char * name)13030Sstevel@tonic-gate store_list_entry(const char *name)
13040Sstevel@tonic-gate {
13050Sstevel@tonic-gate 	prctl_list_t *e = calloc(1, sizeof (prctl_list_t));
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	if (e == NULL) {
13080Sstevel@tonic-gate 		preserve_error(gettext("malloc failed %s"),
13090Sstevel@tonic-gate 		    strerror(errno));
13100Sstevel@tonic-gate 		return (NULL);
13110Sstevel@tonic-gate 	}
13120Sstevel@tonic-gate 	if ((e->name = calloc(1, strlen(name) + 1)) == NULL) {
13130Sstevel@tonic-gate 		preserve_error(gettext("malloc failed %s"),
13140Sstevel@tonic-gate 		    strerror(errno));
13150Sstevel@tonic-gate 		free(e);
13160Sstevel@tonic-gate 		return (NULL);
13170Sstevel@tonic-gate 	}
13180Sstevel@tonic-gate 	(void) strcpy(e->name, name);
13190Sstevel@tonic-gate 	e->val_list = NULL;
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	if (global_rctl_list_head == NULL) {
13220Sstevel@tonic-gate 		global_rctl_list_head = e;
13230Sstevel@tonic-gate 		global_rctl_list_tail = e;
13240Sstevel@tonic-gate 	} else {
13250Sstevel@tonic-gate 		global_rctl_list_tail->next = e;
13260Sstevel@tonic-gate 		global_rctl_list_tail = e;
13270Sstevel@tonic-gate 	}
13280Sstevel@tonic-gate 	e->next = NULL;
13290Sstevel@tonic-gate 	return (e);
13300Sstevel@tonic-gate }
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate /*
13330Sstevel@tonic-gate  * free_lists()
13340Sstevel@tonic-gate  *
13350Sstevel@tonic-gate  * Free all resource control blocks and values from the global lists.
13360Sstevel@tonic-gate  *
13370Sstevel@tonic-gate  * This function is Pgrab-safe.
13380Sstevel@tonic-gate  */
13390Sstevel@tonic-gate void
free_lists()13400Sstevel@tonic-gate free_lists()
13410Sstevel@tonic-gate {
13420Sstevel@tonic-gate 	prctl_list_t *new_list, *old_list = global_rctl_list_head;
13430Sstevel@tonic-gate 	prctl_value_t *old_val, *new_val;
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	while (old_list != NULL) {
13460Sstevel@tonic-gate 		old_val = old_list->val_list;
13470Sstevel@tonic-gate 		while (old_val != NULL) {
13480Sstevel@tonic-gate 			free(old_val->rblk);
13490Sstevel@tonic-gate 			new_val = old_val->next;
13500Sstevel@tonic-gate 			free(old_val);
13510Sstevel@tonic-gate 			old_val = new_val;
13520Sstevel@tonic-gate 		}
13530Sstevel@tonic-gate 		free(old_list->name);
135410307SMenno.Lageman@Sun.COM 		free(old_list->usage);
13550Sstevel@tonic-gate 		new_list = old_list->next;
13560Sstevel@tonic-gate 		free(old_list);
13570Sstevel@tonic-gate 		old_list = new_list;
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 	global_rctl_list_head = NULL;
13600Sstevel@tonic-gate 	global_rctl_list_tail = NULL;
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate void
print_heading()13640Sstevel@tonic-gate print_heading()
13650Sstevel@tonic-gate {
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	/* print headings */
13680Sstevel@tonic-gate 	(void) fprintf(stdout, "%-8s%-16s%-9s%-7s%-28s%10s\n",
13690Sstevel@tonic-gate 	    "NAME", "PRIVILEGE", "VALUE",
13700Sstevel@tonic-gate 	    "FLAG", "ACTION", "RECIPIENT");
13710Sstevel@tonic-gate }
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate /*
13740Sstevel@tonic-gate  * print_rctls()
13750Sstevel@tonic-gate  *
13760Sstevel@tonic-gate  * Print all resource controls from the global list that was
13770Sstevel@tonic-gate  * previously populated by store_rctls.
13780Sstevel@tonic-gate  */
13790Sstevel@tonic-gate void
print_rctls(pr_info_handle_t * p)13800Sstevel@tonic-gate print_rctls(pr_info_handle_t *p)
13810Sstevel@tonic-gate {
13820Sstevel@tonic-gate 	prctl_list_t *iter_list = global_rctl_list_head;
13830Sstevel@tonic-gate 	prctl_value_t *iter_val;
13840Sstevel@tonic-gate 	rctl_qty_t  rblk_value;
13850Sstevel@tonic-gate 	rctl_priv_t rblk_priv;
13860Sstevel@tonic-gate 	uint_t local_action;
13870Sstevel@tonic-gate 	int signal, local_flags, global_flags;
13880Sstevel@tonic-gate 	pid_t pid;
13890Sstevel@tonic-gate 	char rctl_valuestring[SCALED_STRLEN];
13900Sstevel@tonic-gate 	char *unit = NULL;
13910Sstevel@tonic-gate 	scale_t *scale;
13920Sstevel@tonic-gate 	char *string;
13930Sstevel@tonic-gate 	int doneheading = 0;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	if (iter_list == NULL)
13960Sstevel@tonic-gate 		return;
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	while (iter_list != NULL) {
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 		if (doneheading == 0 &&
14010Sstevel@tonic-gate 		    arg_entity_type == RCENTITY_PROCESS) {
14020Sstevel@tonic-gate 			proc_unctrl_psinfo(&(p->psinfo));
14030Sstevel@tonic-gate 			doneheading = 1;
14040Sstevel@tonic-gate 			(void) fprintf(stdout,
14050Sstevel@tonic-gate 			    "process: %d: %.70s\n", (int)p->pid,
14060Sstevel@tonic-gate 			    p->psinfo.pr_psargs);
14070Sstevel@tonic-gate 			if (!arg_parseable_mode)
14080Sstevel@tonic-gate 				print_heading();
14090Sstevel@tonic-gate 		}
14100Sstevel@tonic-gate 		if (doneheading == 0 &&
14110Sstevel@tonic-gate 		    arg_entity_type == RCENTITY_TASK) {
14120Sstevel@tonic-gate 			doneheading = 1;
14130Sstevel@tonic-gate 			(void) fprintf(stdout, "task: %d\n", (int)p->taskid);
14140Sstevel@tonic-gate 			if (!arg_parseable_mode)
14150Sstevel@tonic-gate 				print_heading();
14160Sstevel@tonic-gate 		}
14170Sstevel@tonic-gate 		if (doneheading == 0 &&
14180Sstevel@tonic-gate 		    arg_entity_type == RCENTITY_PROJECT) {
14190Sstevel@tonic-gate 			if (!arg_parseable_mode && doneheading)
14200Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
14210Sstevel@tonic-gate 			doneheading = 1;
14220Sstevel@tonic-gate 			(void) fprintf(stdout,
14230Sstevel@tonic-gate 			    "project: %d: %.70s\n", (int)p->projid,
14240Sstevel@tonic-gate 			    p->projname);
14250Sstevel@tonic-gate 			if (!arg_parseable_mode)
14260Sstevel@tonic-gate 				print_heading();
14270Sstevel@tonic-gate 		}
14280Sstevel@tonic-gate 		if (doneheading == 0 &&
14290Sstevel@tonic-gate 		    arg_entity_type == RCENTITY_ZONE) {
14300Sstevel@tonic-gate 			doneheading = 1;
14310Sstevel@tonic-gate 			(void) fprintf(stdout,
14320Sstevel@tonic-gate 			    "zone: %d: %.70s\n", (int)p->zoneid,
14330Sstevel@tonic-gate 			    p->zonename);
14340Sstevel@tonic-gate 			if (!arg_parseable_mode)
14350Sstevel@tonic-gate 				print_heading();
14360Sstevel@tonic-gate 		}
14370Sstevel@tonic-gate 		/* only print name once in normal output */
14380Sstevel@tonic-gate 		if (!arg_parseable_mode)
14390Sstevel@tonic-gate 			(void) fprintf(stdout, "%s\n", iter_list->name);
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 		iter_val = iter_list->val_list;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 		/* if for some reason there are no values, skip */
14440Sstevel@tonic-gate 		if (iter_val == 0)
14450Sstevel@tonic-gate 			continue;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 		/* get the global flags the first rctl only */
14490Sstevel@tonic-gate 		global_flags = rctlblk_get_global_flags(iter_val->rblk);
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 		if (global_flags & RCTL_GLOBAL_BYTES) {
14530Sstevel@tonic-gate 			unit = SCALED_UNIT_BYTES;
14540Sstevel@tonic-gate 			scale = scale_binary;
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 		} else if (global_flags & RCTL_GLOBAL_SECONDS) {
14570Sstevel@tonic-gate 			unit = SCALED_UNIT_SECONDS;
14580Sstevel@tonic-gate 			scale = scale_metric;
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 		} else {
14610Sstevel@tonic-gate 			unit = SCALED_UNIT_NONE;
14620Sstevel@tonic-gate 			scale = scale_metric;
14630Sstevel@tonic-gate 		}
146410307SMenno.Lageman@Sun.COM 
146510307SMenno.Lageman@Sun.COM 		/* print the current usage for the rctl if available */
146610307SMenno.Lageman@Sun.COM 		if (iter_list->usage != NULL) {
146710307SMenno.Lageman@Sun.COM 			rblk_value = *(iter_list->usage);
146810307SMenno.Lageman@Sun.COM 			if (!arg_parseable_mode) {
146910307SMenno.Lageman@Sun.COM 				(void) uint64toscaled(rblk_value, 4, "E",
147010307SMenno.Lageman@Sun.COM 				    rctl_valuestring, NULL, NULL,
147110307SMenno.Lageman@Sun.COM 				    scale, NULL, 0);
147210307SMenno.Lageman@Sun.COM 
147310307SMenno.Lageman@Sun.COM 				(void) fprintf(stdout, "%8s%-16s%5s%-4s\n",
147410307SMenno.Lageman@Sun.COM 				    "", "usage", rctl_valuestring, unit);
147510307SMenno.Lageman@Sun.COM 			} else {
147610307SMenno.Lageman@Sun.COM 				(void) fprintf(stdout, "%s %s %llu - - -\n",
147710307SMenno.Lageman@Sun.COM 				    iter_list->name, "usage", rblk_value);
147810307SMenno.Lageman@Sun.COM 			}
147910307SMenno.Lageman@Sun.COM 		}
148010307SMenno.Lageman@Sun.COM 
14810Sstevel@tonic-gate 		/* iterate over an print all control values */
14820Sstevel@tonic-gate 		while (iter_val != NULL) {
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 			/* print name or empty name field */
14850Sstevel@tonic-gate 			if (!arg_parseable_mode)
14860Sstevel@tonic-gate 				(void) fprintf(stdout, "%8s", "");
14870Sstevel@tonic-gate 			else
14880Sstevel@tonic-gate 				(void) fprintf(stdout, "%s ", iter_list->name);
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 			rblk_priv = rctlblk_get_privilege(iter_val->rblk);
14920Sstevel@tonic-gate 			if (!arg_parseable_mode)
14930Sstevel@tonic-gate 				print_priv(rblk_priv, "%-16s");
14940Sstevel@tonic-gate 			else
14950Sstevel@tonic-gate 				print_priv(rblk_priv, "%s ");
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 			rblk_value = rctlblk_get_value(iter_val->rblk);
14980Sstevel@tonic-gate 			if (arg_parseable_mode) {
14990Sstevel@tonic-gate 				(void) fprintf(stdout, "%llu ", rblk_value);
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 			} else {
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 				(void) uint64toscaled(rblk_value, 4, "E",
15040Sstevel@tonic-gate 				    rctl_valuestring, NULL, NULL,
15050Sstevel@tonic-gate 				    scale, NULL, 0);
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 				(void) fprintf(stdout, "%5s",
15080Sstevel@tonic-gate 				    rctl_valuestring);
15090Sstevel@tonic-gate 				(void) fprintf(stdout, "%-4s", unit);
15100Sstevel@tonic-gate 			}
15110Sstevel@tonic-gate 			local_flags = rctlblk_get_local_flags(iter_val->rblk);
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 			if (local_flags & RCTL_LOCAL_MAXIMAL) {
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 				if (global_flags & RCTL_GLOBAL_INFINITE) {
15160Sstevel@tonic-gate 					string = "inf";
15170Sstevel@tonic-gate 				} else {
15180Sstevel@tonic-gate 					string = "max";
15190Sstevel@tonic-gate 				}
15200Sstevel@tonic-gate 			} else {
15210Sstevel@tonic-gate 				string = "-";
15220Sstevel@tonic-gate 			}
15230Sstevel@tonic-gate 			if (arg_parseable_mode)
15240Sstevel@tonic-gate 				(void) fprintf(stdout, "%s ", string);
15250Sstevel@tonic-gate 			else
15260Sstevel@tonic-gate 				(void) fprintf(stdout, "%4s%3s",
15270Sstevel@tonic-gate 				    string, "");
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 			local_action = rctlblk_get_local_action(iter_val->rblk,
15310Sstevel@tonic-gate 			    &signal);
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 			if (arg_parseable_mode)
15340Sstevel@tonic-gate 				print_local_action(local_action, &signal,
15350Sstevel@tonic-gate 				    "%s ");
15360Sstevel@tonic-gate 			else
15370Sstevel@tonic-gate 				print_local_action(local_action, &signal,
15380Sstevel@tonic-gate 				    "%-28s");
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 			pid = rctlblk_get_recipient_pid(iter_val->rblk);
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 			if (arg_parseable_mode) {
15430Sstevel@tonic-gate 				if (pid < 0) {
15440Sstevel@tonic-gate 					(void) fprintf(stdout, "%s\n", "-");
15450Sstevel@tonic-gate 				} else {
15460Sstevel@tonic-gate 					(void) fprintf(stdout, "%d\n",
15470Sstevel@tonic-gate 					    (int)pid);
15480Sstevel@tonic-gate 				}
15490Sstevel@tonic-gate 			} else {
15500Sstevel@tonic-gate 				if (pid < 0) {
15510Sstevel@tonic-gate 					(void) fprintf(stdout, "%10s\n", "-");
15520Sstevel@tonic-gate 				} else {
15530Sstevel@tonic-gate 					(void) fprintf(stdout, "%10d\n",
15540Sstevel@tonic-gate 					    (int)pid);
15550Sstevel@tonic-gate 				}
15560Sstevel@tonic-gate 			}
15570Sstevel@tonic-gate 			iter_val = iter_val->next;
15580Sstevel@tonic-gate 		}
15590Sstevel@tonic-gate 		iter_list = iter_list->next;
15600Sstevel@tonic-gate 	}
15610Sstevel@tonic-gate }
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate /*
15640Sstevel@tonic-gate  *
15650Sstevel@tonic-gate  * match_rctl
15660Sstevel@tonic-gate  *
15670Sstevel@tonic-gate  * find the first rctl with matching name, value, priv, and recipient pid
15680Sstevel@tonic-gate  */
15690Sstevel@tonic-gate int
match_rctl(struct ps_prochandle * Pr,rctlblk_t ** rctl,char * name,char * valuestringin,int valuein,rctl_priv_t privin,int pidin)15700Sstevel@tonic-gate match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name,
15710Sstevel@tonic-gate     char *valuestringin, int valuein, rctl_priv_t privin, int pidin)
15720Sstevel@tonic-gate {
15730Sstevel@tonic-gate 	rctlblk_t *next;
15740Sstevel@tonic-gate 	rctlblk_t *last;
15750Sstevel@tonic-gate 	rctlblk_t *tmp;
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate 	*rctl = NULL;
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	next = calloc(1, rctlblk_size());
15800Sstevel@tonic-gate 	last = calloc(1, rctlblk_size());
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	if ((last == NULL) || (next == NULL)) {
15830Sstevel@tonic-gate 		preserve_error(gettext("malloc failed"), strerror(errno));
15840Sstevel@tonic-gate 		return (-1);
15850Sstevel@tonic-gate 	}
15860Sstevel@tonic-gate 	/*
15870Sstevel@tonic-gate 	 * For this resource name, now iterate through all
15880Sstevel@tonic-gate 	 * the  controls, looking for a match to the
15890Sstevel@tonic-gate 	 * user-specified input.
15900Sstevel@tonic-gate 	 */
15910Sstevel@tonic-gate 	if (pr_getrctl(Pr, name, NULL, next, RCTL_FIRST)) {
15920Sstevel@tonic-gate 		preserve_error(gettext("failed to get resource control "
15930Sstevel@tonic-gate 		    "for %s: %s"), name, strerror(errno));
15940Sstevel@tonic-gate 		return (-1);
15950Sstevel@tonic-gate 	}
15960Sstevel@tonic-gate 	if (match_rctl_blk(next, valuestringin, valuein, privin, pidin) == 1) {
15970Sstevel@tonic-gate 		free(last);
15980Sstevel@tonic-gate 		*rctl = next;
15990Sstevel@tonic-gate 		return (0);
16000Sstevel@tonic-gate 	}
16010Sstevel@tonic-gate 	tmp = next;
16020Sstevel@tonic-gate 	next = last;
16030Sstevel@tonic-gate 	last = tmp;
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	while (pr_getrctl(Pr, name, last, next,	RCTL_NEXT) == 0) {
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 		/* allow user interrupt */
16080Sstevel@tonic-gate 		if (interrupt)
16090Sstevel@tonic-gate 			break;
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 		if (match_rctl_blk(next, valuestringin, valuein, privin, pidin)
16120Sstevel@tonic-gate 		    == 1) {
16130Sstevel@tonic-gate 			free(last);
16140Sstevel@tonic-gate 			*rctl = next;
16150Sstevel@tonic-gate 			return (0);
16160Sstevel@tonic-gate 		}
16170Sstevel@tonic-gate 		tmp = next;
16180Sstevel@tonic-gate 		next = last;
16190Sstevel@tonic-gate 		last = tmp;
16200Sstevel@tonic-gate 	}
16210Sstevel@tonic-gate 	free(next);
16220Sstevel@tonic-gate 	free(last);
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	return (1);
16250Sstevel@tonic-gate }
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate /*
16280Sstevel@tonic-gate  * int match_rctl_blk(rctlblk_t *, char *, uint64, rctl_priv_t, int pid)
16290Sstevel@tonic-gate  *
16300Sstevel@tonic-gate  * Input
16310Sstevel@tonic-gate  *   Must supply a valid rctl, value, privilege, and pid to match on.
16320Sstevel@tonic-gate  *   If valuestring is NULL, then valuestring and valuein will not be used
16330Sstevel@tonic-gate  *   If privilege type is 0 it will not be used.
16340Sstevel@tonic-gate  *   If pid is -1 it will not be used.
16350Sstevel@tonic-gate  *
16360Sstevel@tonic-gate  * Return values
16370Sstevel@tonic-gate  *   Returns 1 if a matching rctl given matches the parameters specified, and
16380Sstevel@tonic-gate  *   0 if they do not.
16390Sstevel@tonic-gate  *
16400Sstevel@tonic-gate  * This function is Pgrab-safe.
16410Sstevel@tonic-gate  */
16420Sstevel@tonic-gate int
match_rctl_blk(rctlblk_t * rctl,char * valuestringin,uint64_t valuein,rctl_priv_t privin,int pidin)16430Sstevel@tonic-gate match_rctl_blk(rctlblk_t *rctl, char *valuestringin,
16440Sstevel@tonic-gate     uint64_t valuein, rctl_priv_t privin, int pidin)
16450Sstevel@tonic-gate {
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	rctl_qty_t value;
16480Sstevel@tonic-gate 	rctl_priv_t priv;
16490Sstevel@tonic-gate 	pid_t pid;
16500Sstevel@tonic-gate 	int valuematch = 1;
16510Sstevel@tonic-gate 	int privmatch = 1;
16520Sstevel@tonic-gate 	int pidmatch = 1;
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	value = rctlblk_get_value(rctl);
16550Sstevel@tonic-gate 	priv = rctlblk_get_privilege(rctl);
16560Sstevel@tonic-gate 	pid = rctlblk_get_recipient_pid(rctl);
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 	if (valuestringin) {
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 		if (arg_modifier == NULL) {
16610Sstevel@tonic-gate 			valuematch = (valuein == value);
16620Sstevel@tonic-gate 		} else {
16630Sstevel@tonic-gate 			valuematch = scaledequint64(valuestringin, value,
16640Sstevel@tonic-gate 			    PRCTL_VALUE_WIDTH,
16650Sstevel@tonic-gate 			    arg_scale, arg_unit,
16660Sstevel@tonic-gate 			    SCALED_ALL_FLAGS);
16670Sstevel@tonic-gate 		}
16680Sstevel@tonic-gate 	}
16690Sstevel@tonic-gate 	if (privin != 0) {
16700Sstevel@tonic-gate 		privmatch = (privin == priv);
16710Sstevel@tonic-gate 	}
16720Sstevel@tonic-gate 	if (pidin != -1) {
16730Sstevel@tonic-gate 		pidmatch = (pidin == pid);
16740Sstevel@tonic-gate 	}
16750Sstevel@tonic-gate 	return (valuematch && privmatch && pidmatch);
16760Sstevel@tonic-gate }
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate static int
change_action(rctlblk_t * blk)16790Sstevel@tonic-gate change_action(rctlblk_t *blk)
16800Sstevel@tonic-gate {
16810Sstevel@tonic-gate 	int signal = 0;
16820Sstevel@tonic-gate 	int action;
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	action = rctlblk_get_local_action(blk, &signal);
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate 	if (arg_operation & ACTION_ENABLE) {
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 		if (arg_action & RCTL_LOCAL_SIGNAL) {
16890Sstevel@tonic-gate 			signal = arg_signal;
16900Sstevel@tonic-gate 		}
16910Sstevel@tonic-gate 		action = action | arg_action;
16920Sstevel@tonic-gate 		/* add local action */
16930Sstevel@tonic-gate 		rctlblk_set_local_action(blk, action, signal);
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 	} else if (arg_operation & ACTION_DISABLE) {
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 		/*
16980Sstevel@tonic-gate 		 * if deleting signal and signal number is specified,
16990Sstevel@tonic-gate 		 * then signal number must match
17000Sstevel@tonic-gate 		 */
17010Sstevel@tonic-gate 		if ((arg_action & RCTL_LOCAL_SIGNAL) &&
17020Sstevel@tonic-gate 		    (arg_signal != -1)) {
17030Sstevel@tonic-gate 			if (arg_signal != signal) {
17040Sstevel@tonic-gate 				preserve_error(gettext("signal name or number "
17050Sstevel@tonic-gate 				    "does not match existing action"));
17060Sstevel@tonic-gate 				return (-1);
17070Sstevel@tonic-gate 			}
17080Sstevel@tonic-gate 		}
17090Sstevel@tonic-gate 		/* remove local action */
17100Sstevel@tonic-gate 		action = action & (~arg_action);
17110Sstevel@tonic-gate 		rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0);
17120Sstevel@tonic-gate 		rctlblk_set_local_action(blk, action, signal);
17130Sstevel@tonic-gate 	}
17140Sstevel@tonic-gate 	/* enable deny if it must be enabled */
17150Sstevel@tonic-gate 	if (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS) {
17160Sstevel@tonic-gate 		rctlblk_set_local_action(blk, RCTL_LOCAL_DENY | action,
17178617SMenno.Lageman@Sun.COM 		    signal);
17180Sstevel@tonic-gate 	}
17190Sstevel@tonic-gate 	return (0);
17200Sstevel@tonic-gate }
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate /*
17230Sstevel@tonic-gate  * prctl_setrctl
17240Sstevel@tonic-gate  *
17250Sstevel@tonic-gate  * Input
17260Sstevel@tonic-gate  *   This function expects that input has been validated. In the
17270Sstevel@tonic-gate  *   case of a replace operation, both old_rblk and new_rblk must
17280Sstevel@tonic-gate  *   be valid resource controls. If a resource control is being
17290Sstevel@tonic-gate  *   created, only new_rblk must be supplied. If a resource control
17300Sstevel@tonic-gate  *   is being deleted, only new_rblk must be supplied.
17310Sstevel@tonic-gate  *
17320Sstevel@tonic-gate  * If the privilege is a priviliged type, at this time, the process
17330Sstevel@tonic-gate  * tries to take on superuser privileges.
17340Sstevel@tonic-gate  */
17350Sstevel@tonic-gate int
prctl_setrctl(struct ps_prochandle * Pr,const char * name,rctlblk_t * old_rblk,rctlblk_t * new_rblk,uint_t flags)17360Sstevel@tonic-gate prctl_setrctl(struct ps_prochandle *Pr, const char *name,
17370Sstevel@tonic-gate     rctlblk_t *old_rblk, rctlblk_t *new_rblk, uint_t flags)
17380Sstevel@tonic-gate {
17390Sstevel@tonic-gate 	int ret = 0;
17400Sstevel@tonic-gate 	rctl_priv_t rblk_priv;
17410Sstevel@tonic-gate 	psinfo_t psinfo;
17420Sstevel@tonic-gate 	zoneid_t oldzoneid = GLOBAL_ZONEID;
17430Sstevel@tonic-gate 	prpriv_t *old_prpriv = NULL, *new_prpriv = NULL;
17440Sstevel@tonic-gate 	priv_set_t *eset, *pset;
17450Sstevel@tonic-gate 	boolean_t relinquish_failed = B_FALSE;
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	rblk_priv = rctlblk_get_privilege(new_rblk);
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	if (rblk_priv == RCPRIV_SYSTEM) {
17500Sstevel@tonic-gate 		preserve_error(gettext("cannot modify system values"));
17510Sstevel@tonic-gate 		return (1);
17520Sstevel@tonic-gate 	}
17530Sstevel@tonic-gate 	if (rblk_priv == RCPRIV_PRIVILEGED) {
17540Sstevel@tonic-gate 		new_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid);
17550Sstevel@tonic-gate 		if (new_prpriv == NULL) {
17560Sstevel@tonic-gate 			preserve_error(gettext("cannot get process privileges "
17570Sstevel@tonic-gate 			    "for pid %d: %s"), Pstatus(Pr)->pr_pid,
17580Sstevel@tonic-gate 			    strerror(errno));
17590Sstevel@tonic-gate 			return (1);
17600Sstevel@tonic-gate 		}
17610Sstevel@tonic-gate 		/*
17620Sstevel@tonic-gate 		 * We only have to change the process privileges if it doesn't
17630Sstevel@tonic-gate 		 * already have PRIV_SYS_RESOURCE.  In addition, we want to make
17640Sstevel@tonic-gate 		 * sure that we don't leave a process with elevated privileges,
17650Sstevel@tonic-gate 		 * so we make sure the process dies if we exit unexpectedly.
17660Sstevel@tonic-gate 		 */
17670Sstevel@tonic-gate 		eset = (priv_set_t *)
17680Sstevel@tonic-gate 		    &new_prpriv->pr_sets[new_prpriv->pr_setsize *
17690Sstevel@tonic-gate 		    priv_getsetbyname(PRIV_EFFECTIVE)];
17700Sstevel@tonic-gate 		pset = (priv_set_t *)
17710Sstevel@tonic-gate 		    &new_prpriv->pr_sets[new_prpriv->pr_setsize *
17720Sstevel@tonic-gate 		    priv_getsetbyname(PRIV_PERMITTED)];
17730Sstevel@tonic-gate 		if (!priv_ismember(eset, PRIV_SYS_RESOURCE)) {
17740Sstevel@tonic-gate 			/* Keep track of original privileges */
17750Sstevel@tonic-gate 			old_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid);
17760Sstevel@tonic-gate 			if (old_prpriv == NULL) {
17770Sstevel@tonic-gate 				preserve_error(gettext("cannot get process "
17780Sstevel@tonic-gate 				    "privileges for pid %d: %s"),
17790Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
17800Sstevel@tonic-gate 				free(new_prpriv);
17810Sstevel@tonic-gate 				return (1);
17820Sstevel@tonic-gate 			}
17830Sstevel@tonic-gate 			(void) priv_addset(eset, PRIV_SYS_RESOURCE);
17840Sstevel@tonic-gate 			(void) priv_addset(pset, PRIV_SYS_RESOURCE);
17850Sstevel@tonic-gate 			if (Psetflags(Pr, PR_KLC) != 0 ||
17860Sstevel@tonic-gate 			    Psetpriv(Pr, new_prpriv) != 0) {
17870Sstevel@tonic-gate 				preserve_error(gettext("cannot set process "
17880Sstevel@tonic-gate 				    "privileges for pid %d: %s"),
17890Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
17900Sstevel@tonic-gate 				(void) Punsetflags(Pr, PR_KLC);
17910Sstevel@tonic-gate 				free(new_prpriv);
17920Sstevel@tonic-gate 				free(old_prpriv);
17930Sstevel@tonic-gate 				return (1);
17940Sstevel@tonic-gate 			}
17950Sstevel@tonic-gate 		}
17960Sstevel@tonic-gate 		/*
17970Sstevel@tonic-gate 		 * If this is a zone.* rctl, it requires more than
17980Sstevel@tonic-gate 		 * PRIV_SYS_RESOURCE: it wants the process to have global-zone
17990Sstevel@tonic-gate 		 * credentials.  We temporarily grant non-global zone processes
18000Sstevel@tonic-gate 		 * these credentials, and make sure the process dies if we exit
18010Sstevel@tonic-gate 		 * unexpectedly.
18020Sstevel@tonic-gate 		 */
18030Sstevel@tonic-gate 		if (arg_name &&
18040Sstevel@tonic-gate 		    arg_name_entity == RCENTITY_ZONE &&
18050Sstevel@tonic-gate 		    getzoneid() == GLOBAL_ZONEID &&
18060Sstevel@tonic-gate 		    proc_get_psinfo(Pstatus(Pr)->pr_pid, &psinfo) == 0 &&
18070Sstevel@tonic-gate 		    (oldzoneid = psinfo.pr_zoneid) != GLOBAL_ZONEID) {
18080Sstevel@tonic-gate 			/*
18090Sstevel@tonic-gate 			 * We need to give this process superuser
18100Sstevel@tonic-gate 			 * ("super-zone") privileges.
18110Sstevel@tonic-gate 			 *
18120Sstevel@tonic-gate 			 * Must never return without setting this back!
18130Sstevel@tonic-gate 			 */
18140Sstevel@tonic-gate 			if (Psetflags(Pr, PR_KLC) != 0 ||
18150Sstevel@tonic-gate 			    Psetzoneid(Pr, GLOBAL_ZONEID) < 0) {
18160Sstevel@tonic-gate 				preserve_error(gettext(
18170Sstevel@tonic-gate 				    "cannot set global-zone "
18180Sstevel@tonic-gate 				    "privileges for pid %d: %s"),
18190Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
18200Sstevel@tonic-gate 				/*
18210Sstevel@tonic-gate 				 * We couldn't set the zoneid to begin with, so
18220Sstevel@tonic-gate 				 * there's no point in warning the user about
18230Sstevel@tonic-gate 				 * trying to un-set it.
18240Sstevel@tonic-gate 				 */
18250Sstevel@tonic-gate 				oldzoneid = GLOBAL_ZONEID;
18260Sstevel@tonic-gate 				ret = 1;
18270Sstevel@tonic-gate 				goto bail;
18280Sstevel@tonic-gate 			}
18290Sstevel@tonic-gate 		}
18300Sstevel@tonic-gate 	}
18310Sstevel@tonic-gate 	/* Now, actually populate the rctlblk in the kernel */
18320Sstevel@tonic-gate 	if (flags == RCTL_REPLACE) {
18330Sstevel@tonic-gate 		/*
18340Sstevel@tonic-gate 		 * Replace should be a delete followed by an insert. This
18350Sstevel@tonic-gate 		 * allows us to replace rctl value blocks which match in
18360Sstevel@tonic-gate 		 * privilege and value, but have updated actions, etc.
18370Sstevel@tonic-gate 		 * setrctl() doesn't allow a direct replace, but we
18380Sstevel@tonic-gate 		 * should do the right thing for the user in the command.
18390Sstevel@tonic-gate 		 */
18400Sstevel@tonic-gate 		if (pr_setrctl(Pr, name, NULL,
18410Sstevel@tonic-gate 		    old_rblk, RCTL_DELETE)) {
18420Sstevel@tonic-gate 			preserve_error(gettext("failed to delete resource "
18430Sstevel@tonic-gate 			    "control %s for pid %d: %s"), name,
18440Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid, strerror(errno));
18450Sstevel@tonic-gate 			ret = 1;
18460Sstevel@tonic-gate 			goto bail;
18470Sstevel@tonic-gate 		}
18480Sstevel@tonic-gate 		if (pr_setrctl(Pr, name, NULL,
18490Sstevel@tonic-gate 		    new_rblk, RCTL_INSERT)) {
18500Sstevel@tonic-gate 			preserve_error(gettext("failed to insert resource "
18510Sstevel@tonic-gate 			    "control %s for pid %d: %s"), name,
18520Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid, strerror(errno));
18530Sstevel@tonic-gate 			ret = 1;
18540Sstevel@tonic-gate 			goto bail;
18550Sstevel@tonic-gate 		}
18560Sstevel@tonic-gate 	} else if (flags == RCTL_INSERT) {
18570Sstevel@tonic-gate 		if (pr_setrctl(Pr, name, NULL,
18580Sstevel@tonic-gate 		    new_rblk, RCTL_INSERT)) {
18590Sstevel@tonic-gate 			preserve_error(gettext("failed to create resource "
18600Sstevel@tonic-gate 			    "control %s for pid %d: %s"), name,
18610Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid, strerror(errno));
18620Sstevel@tonic-gate 			ret = 1;
18630Sstevel@tonic-gate 			goto bail;
18640Sstevel@tonic-gate 		}
18650Sstevel@tonic-gate 	} else if (flags == RCTL_DELETE) {
18660Sstevel@tonic-gate 		if (pr_setrctl(Pr, name, NULL,
18670Sstevel@tonic-gate 		    new_rblk, RCTL_DELETE)) {
18680Sstevel@tonic-gate 			preserve_error(gettext("failed to delete resource "
18690Sstevel@tonic-gate 			    "control %s for pid %d: %s"), name,
18700Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid, strerror(errno));
18710Sstevel@tonic-gate 			ret = 1;
18720Sstevel@tonic-gate 			goto bail;
18730Sstevel@tonic-gate 		}
18740Sstevel@tonic-gate 	}
18750Sstevel@tonic-gate bail:
18760Sstevel@tonic-gate 	if (oldzoneid != GLOBAL_ZONEID) {
18770Sstevel@tonic-gate 		if (Psetzoneid(Pr, oldzoneid) != 0)
18780Sstevel@tonic-gate 			relinquish_failed = B_TRUE;
18790Sstevel@tonic-gate 	}
18800Sstevel@tonic-gate 	if (old_prpriv != NULL) {
18810Sstevel@tonic-gate 		if (Psetpriv(Pr, old_prpriv) != 0)
18820Sstevel@tonic-gate 			relinquish_failed = B_TRUE;
18830Sstevel@tonic-gate 		free(old_prpriv);
18840Sstevel@tonic-gate 	}
18850Sstevel@tonic-gate 	if (relinquish_failed) {
18860Sstevel@tonic-gate 		/*
18870Sstevel@tonic-gate 		 * If this failed, we can't leave a process hanging
18880Sstevel@tonic-gate 		 * around with elevated privileges, so we'll have to
18890Sstevel@tonic-gate 		 * release the process from libproc, knowing that it
18900Sstevel@tonic-gate 		 * will be killed (since we set PR_KLC).
18910Sstevel@tonic-gate 		 */
18920Sstevel@tonic-gate 		Pdestroy_agent(Pr);
18930Sstevel@tonic-gate 		preserve_error(gettext("cannot relinquish privileges "
18948617SMenno.Lageman@Sun.COM 		    "for pid %d. The process was killed."),
18950Sstevel@tonic-gate 		    Pstatus(Pr)->pr_pid);
18960Sstevel@tonic-gate 	} else {
18970Sstevel@tonic-gate 		if (Punsetflags(Pr, PR_KLC) != 0)
18980Sstevel@tonic-gate 			preserve_error(gettext("cannot relinquish privileges "
18990Sstevel@tonic-gate 			    "for pid %d. The process was killed."),
19000Sstevel@tonic-gate 			    Pstatus(Pr)->pr_pid);
19010Sstevel@tonic-gate 	}
19020Sstevel@tonic-gate 	if (new_prpriv != NULL)
19030Sstevel@tonic-gate 		free(new_prpriv);
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 	return (ret);
19060Sstevel@tonic-gate }
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate void
print_priv(rctl_priv_t local_priv,char * format)19090Sstevel@tonic-gate print_priv(rctl_priv_t local_priv, char *format)
19100Sstevel@tonic-gate {
19110Sstevel@tonic-gate 	char pstring[11];
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	switch (local_priv) {
19140Sstevel@tonic-gate 	case RCPRIV_BASIC:
19150Sstevel@tonic-gate 		(void) strcpy(pstring, "basic");
19160Sstevel@tonic-gate 		break;
19170Sstevel@tonic-gate 	case RCPRIV_PRIVILEGED:
19180Sstevel@tonic-gate 		(void) strcpy(pstring, "privileged");
19190Sstevel@tonic-gate 		break;
19200Sstevel@tonic-gate 	case RCPRIV_SYSTEM:
19210Sstevel@tonic-gate 		(void) strcpy(pstring, "system");
19220Sstevel@tonic-gate 		break;
19230Sstevel@tonic-gate 	default:
19240Sstevel@tonic-gate 		(void) sprintf(pstring, "%d", local_priv);
19250Sstevel@tonic-gate 		break;
19260Sstevel@tonic-gate 	}
19270Sstevel@tonic-gate 	/* LINTED */
19280Sstevel@tonic-gate 	(void) fprintf(stdout, format, pstring);
19290Sstevel@tonic-gate }
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate void
print_local_action(int action,int * signalp,char * format)19320Sstevel@tonic-gate print_local_action(int action, int *signalp, char *format)
19330Sstevel@tonic-gate {
19340Sstevel@tonic-gate 	char sig[SIG2STR_MAX];
19350Sstevel@tonic-gate 	char sigstring[SIG2STR_MAX + 7];
19360Sstevel@tonic-gate 	char astring[5 + SIG2STR_MAX + 7];
19370Sstevel@tonic-gate 	int set = 0;
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	astring[0] = '\0';
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 	if (action == RCTL_LOCAL_NOACTION) {
19420Sstevel@tonic-gate 		(void) strcat(astring, "none");
19430Sstevel@tonic-gate 		set++;
19440Sstevel@tonic-gate 	}
19450Sstevel@tonic-gate 	if (action & RCTL_LOCAL_DENY) {
19460Sstevel@tonic-gate 		(void) strcat(astring, "deny");
19470Sstevel@tonic-gate 		set++;
19480Sstevel@tonic-gate 	}
19490Sstevel@tonic-gate 	if ((action & RCTL_LOCAL_DENY) &&
19500Sstevel@tonic-gate 	    (action & RCTL_LOCAL_SIGNAL)) {
19510Sstevel@tonic-gate 		(void) strcat(astring, ",");
19520Sstevel@tonic-gate 	}
19530Sstevel@tonic-gate 	if (action & RCTL_LOCAL_SIGNAL) {
19540Sstevel@tonic-gate 		if (sig2str(*signalp, sig))
19550Sstevel@tonic-gate 			(void) snprintf(sigstring, sizeof (astring),
19560Sstevel@tonic-gate 			    "signal=%d", *signalp);
19570Sstevel@tonic-gate 		else
19580Sstevel@tonic-gate 			(void) snprintf(sigstring, sizeof (astring),
19590Sstevel@tonic-gate 			    "signal=%s", sig);
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 		(void) strcat(astring, sigstring);
19620Sstevel@tonic-gate 		set++;
19630Sstevel@tonic-gate 	}
19640Sstevel@tonic-gate 	if (set)
19650Sstevel@tonic-gate 		/* LINTED */
19660Sstevel@tonic-gate 		(void) fprintf(stdout, format, astring);
19670Sstevel@tonic-gate 	else
19680Sstevel@tonic-gate 		/* LINTED */
19690Sstevel@tonic-gate 		(void) fprintf(stdout, format, action);
19700Sstevel@tonic-gate }
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate /*
19730Sstevel@tonic-gate  * This function is used to grab the process matching the recipient pid
19740Sstevel@tonic-gate  */
19750Sstevel@tonic-gate pid_t
regrab_process(pid_t pid,pr_info_handle_t * p,int priv,int * gret)19760Sstevel@tonic-gate regrab_process(pid_t pid, pr_info_handle_t *p, int priv, int *gret)
19770Sstevel@tonic-gate {
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate 	char pidstring[24];
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate 	gret = 0;
19820Sstevel@tonic-gate 	if (pid == -1)
19830Sstevel@tonic-gate 		return (p->pid);
19840Sstevel@tonic-gate 	if (p->pid == pid)
19850Sstevel@tonic-gate 		return (p->pid);
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	release_process(p->pr);
19880Sstevel@tonic-gate 	(void) memset(p, 0, sizeof (*p));
19890Sstevel@tonic-gate 
19900Sstevel@tonic-gate 	(void) snprintf(pidstring, 24, "%d", pid);
19910Sstevel@tonic-gate 	return (grab_process_by_id(
19920Sstevel@tonic-gate 	    pidstring, RCENTITY_PROCESS, p, priv, gret));
19930Sstevel@tonic-gate }
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate /*
19960Sstevel@tonic-gate  * int grab_process_by_id(char *, rctl_entity_t, pr_info_handle_t *, int, int *)
19970Sstevel@tonic-gate  *
19980Sstevel@tonic-gate  * Input
19990Sstevel@tonic-gate  *    Supply a non-NULL string containing:
20000Sstevel@tonic-gate  *	- logical project/zone name or project/zone number if type is
20010Sstevel@tonic-gate  *	RCENTITY_PROJECT or RCENTITY_ZONE
20020Sstevel@tonic-gate  *	- task number if type is RCENTITY_TYPE
20030Sstevel@tonic-gate  *	- a pid if type is RCENTITY_PID
20040Sstevel@tonic-gate  *    Also supply an un-allocated prochandle, and an allocated info_handle.
20050Sstevel@tonic-gate  *    This function assumes that the type is set.
20060Sstevel@tonic-gate  *    If priv is not RCPRIV_BASIC, the grabbed process is required to have
20070Sstevel@tonic-gate  *    PRIV_SYS_RESOURCE in it's limit set.
20080Sstevel@tonic-gate  *
20090Sstevel@tonic-gate  * Return Values
20100Sstevel@tonic-gate  *    Returns 0 on success and 1 on failure. If there is a process
20110Sstevel@tonic-gate  *    running under the specified id, success is returned, and
20120Sstevel@tonic-gate  *    Pr is pointed to the process. Success will be returned and Pr
20130Sstevel@tonic-gate  *    set to NULL if the matching process is our own.
20140Sstevel@tonic-gate  *    If success is returned, psinfo will be valid, and pid will
20150Sstevel@tonic-gate  *    be the process number. The process will also be held at the
20160Sstevel@tonic-gate  *    end, so release_process should be used by the caller.
20170Sstevel@tonic-gate  *
20180Sstevel@tonic-gate  * This function assumes that signals are caught already so that libproc
20190Sstevel@tonic-gate  * can be safely used.
20200Sstevel@tonic-gate  *
20210Sstevel@tonic-gate  * Return Values
20220Sstevel@tonic-gate  *	pid - Process found and grabbed
20230Sstevel@tonic-gate  *	-1 - Error
20240Sstevel@tonic-gate  */
20250Sstevel@tonic-gate pid_t
grab_process_by_id(char * idname,rctl_entity_t type,pr_info_handle_t * p,int priv,int * gret)20260Sstevel@tonic-gate grab_process_by_id(char *idname, rctl_entity_t type, pr_info_handle_t *p,
20270Sstevel@tonic-gate     int priv, int *gret)
20280Sstevel@tonic-gate {
20290Sstevel@tonic-gate 	char prbuf[PROJECT_BUFSZ];
20300Sstevel@tonic-gate 	projid_t projid;
20310Sstevel@tonic-gate 	taskid_t taskid;
20320Sstevel@tonic-gate 	zoneid_t zoneid;
20330Sstevel@tonic-gate 	zoneid_t zone_self;
20340Sstevel@tonic-gate 	struct project proj;
20350Sstevel@tonic-gate 	DIR *dirp;
20360Sstevel@tonic-gate 	struct dirent *dentp;
20370Sstevel@tonic-gate 	int found = 0;
20380Sstevel@tonic-gate 	int pid_self;
20390Sstevel@tonic-gate 	int ret;
20400Sstevel@tonic-gate 	int gret_in;
20410Sstevel@tonic-gate 	int intidname;
20420Sstevel@tonic-gate 	char *end;
20430Sstevel@tonic-gate 	prpriv_t *prpriv;
20440Sstevel@tonic-gate 	priv_set_t *prset;
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	gret_in = *gret;
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 	/* get our pid se we do not try to operate on self */
20490Sstevel@tonic-gate 	pid_self = getpid();
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 	/* Store integer version of id */
20520Sstevel@tonic-gate 	intidname = strtoul(idname, &end, 10);
20530Sstevel@tonic-gate 	if (errno || *end != '\0' || end == idname) {
20540Sstevel@tonic-gate 		intidname = -1;
20550Sstevel@tonic-gate 	}
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	/*
20580Sstevel@tonic-gate 	 * get our zoneid so we don't try to operate on a project in
20590Sstevel@tonic-gate 	 * another zone
20600Sstevel@tonic-gate 	 */
20610Sstevel@tonic-gate 	zone_self = getzoneid();
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	if (idname == NULL || strcmp(idname, "") == 0) {
20640Sstevel@tonic-gate 		warn(gettext("id name cannot be nuint64\n"));
20650Sstevel@tonic-gate 		return (-1);
20660Sstevel@tonic-gate 	}
20670Sstevel@tonic-gate 	/*
20680Sstevel@tonic-gate 	 * Set up zoneid, projid or taskid, as appropriate, so that comparisons
20690Sstevel@tonic-gate 	 * can be done later with the input.
20700Sstevel@tonic-gate 	 */
20710Sstevel@tonic-gate 	if (type == RCENTITY_ZONE) {
20720Sstevel@tonic-gate 		if (zone_get_id(idname, &zoneid) != 0) {
20730Sstevel@tonic-gate 			warn(gettext("%s: unknown zone\n"), idname);
20740Sstevel@tonic-gate 			return (-1);
20750Sstevel@tonic-gate 		}
20760Sstevel@tonic-gate 	} else if (type == RCENTITY_PROJECT) {
20770Sstevel@tonic-gate 		if (getprojbyname(idname, &proj, prbuf, PROJECT_BUFSZ)
20780Sstevel@tonic-gate 		    == NULL) {
20790Sstevel@tonic-gate 			if (getprojbyid(intidname, &proj, prbuf,
20800Sstevel@tonic-gate 			    PROJECT_BUFSZ) == NULL) {
20810Sstevel@tonic-gate 				warn(gettext("%s: cannot find project\n"),
20820Sstevel@tonic-gate 				    idname);
20830Sstevel@tonic-gate 				return (-1);
20840Sstevel@tonic-gate 			}
20850Sstevel@tonic-gate 		}
20860Sstevel@tonic-gate 		projid = proj.pj_projid;
20870Sstevel@tonic-gate 	} else if (type == RCENTITY_TASK) {
20880Sstevel@tonic-gate 		taskid = (taskid_t)atol(idname);
20890Sstevel@tonic-gate 	}
20900Sstevel@tonic-gate 	/*
20910Sstevel@tonic-gate 	 * Projects and tasks need to search through /proc for
20920Sstevel@tonic-gate 	 * a parent process.
20930Sstevel@tonic-gate 	 */
20940Sstevel@tonic-gate 	if (type == RCENTITY_ZONE || type == RCENTITY_PROJECT ||
20950Sstevel@tonic-gate 	    type == RCENTITY_TASK) {
20960Sstevel@tonic-gate 		if ((dirp = opendir("/proc")) == NULL) {
20970Sstevel@tonic-gate 			warn(gettext("%s: cannot open /proc directory\n"),
20980Sstevel@tonic-gate 			    idname);
20990Sstevel@tonic-gate 			return (-1);
21000Sstevel@tonic-gate 		}
21010Sstevel@tonic-gate 		/*
21020Sstevel@tonic-gate 		 * Look through all processes in /proc. For each process,
21030Sstevel@tonic-gate 		 * check if the pr_projid in their psinfo matches the
21040Sstevel@tonic-gate 		 * specified id.
21050Sstevel@tonic-gate 		 */
21060Sstevel@tonic-gate 		while (dentp = readdir(dirp)) {
21070Sstevel@tonic-gate 			p->pid = atoi(dentp->d_name);
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate 			/* Skip self */
21100Sstevel@tonic-gate 			if (p->pid == pid_self)
21110Sstevel@tonic-gate 				continue;
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate 			if (proc_get_psinfo(p->pid, &(p->psinfo)) != 0)
21140Sstevel@tonic-gate 				continue;
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate 			/* Skip process if it is not what we are looking for */
21170Sstevel@tonic-gate 			if (type == RCENTITY_ZONE &&
21180Sstevel@tonic-gate 			    (p->psinfo).pr_zoneid != zoneid) {
21190Sstevel@tonic-gate 				continue;
21208617SMenno.Lageman@Sun.COM 			} else if (type == RCENTITY_PROJECT &&
21210Sstevel@tonic-gate 			    ((p->psinfo).pr_projid != projid ||
21220Sstevel@tonic-gate 			    (p->psinfo).pr_zoneid != zone_self)) {
21230Sstevel@tonic-gate 				continue;
21240Sstevel@tonic-gate 			} else if (type == RCENTITY_TASK &&
21250Sstevel@tonic-gate 			    (p->psinfo).pr_taskid != taskid) {
21260Sstevel@tonic-gate 				continue;
21270Sstevel@tonic-gate 			}
21280Sstevel@tonic-gate 			/* attempt to grab process */
21290Sstevel@tonic-gate 			if (grab_process(p, gret) != 0)
21300Sstevel@tonic-gate 				continue;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 			/*
21330Sstevel@tonic-gate 			 * Re-confirm that this process is still running as
21340Sstevel@tonic-gate 			 * part	of the specified project or task.  If it
21350Sstevel@tonic-gate 			 * doesn't match, release the process and return an
21360Sstevel@tonic-gate 			 * error. This should only be done if the Pr struct is
21370Sstevel@tonic-gate 			 * not NULL.
21380Sstevel@tonic-gate 			 */
21390Sstevel@tonic-gate 			if (type == RCENTITY_PROJECT) {
21400Sstevel@tonic-gate 				if (pr_getprojid(p->pr) != projid ||
21410Sstevel@tonic-gate 				    pr_getzoneid(p->pr) != zone_self) {
21420Sstevel@tonic-gate 					release_process(p->pr);
21430Sstevel@tonic-gate 					continue;
21440Sstevel@tonic-gate 				}
21450Sstevel@tonic-gate 			} else if (type == RCENTITY_TASK) {
21460Sstevel@tonic-gate 				if (pr_gettaskid(p->pr) != taskid) {
21470Sstevel@tonic-gate 					release_process(p->pr);
21480Sstevel@tonic-gate 					continue;
21490Sstevel@tonic-gate 				}
21500Sstevel@tonic-gate 			} else if (type == RCENTITY_ZONE) {
21510Sstevel@tonic-gate 				if (pr_getzoneid(p->pr) != zoneid) {
21520Sstevel@tonic-gate 					release_process(p->pr);
21530Sstevel@tonic-gate 					continue;
21540Sstevel@tonic-gate 				}
21550Sstevel@tonic-gate 			}
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 			/*
21580Sstevel@tonic-gate 			 * If we are setting a privileged resource control,
21590Sstevel@tonic-gate 			 * verify that process has PRIV_SYS_RESOURCE in it's
21600Sstevel@tonic-gate 			 * limit set.  If it does not, then we will not be
21610Sstevel@tonic-gate 			 * able to give this process the privilege it needs
21620Sstevel@tonic-gate 			 * to set the resource control.
21630Sstevel@tonic-gate 			 */
21640Sstevel@tonic-gate 			if (priv != RCPRIV_BASIC) {
21650Sstevel@tonic-gate 				prpriv = proc_get_priv(p->pid);
21660Sstevel@tonic-gate 				if (prpriv == NULL) {
21670Sstevel@tonic-gate 					release_process(p->pr);
21680Sstevel@tonic-gate 					continue;
21690Sstevel@tonic-gate 				}
21700Sstevel@tonic-gate 				prset = (priv_set_t *)
21710Sstevel@tonic-gate 				    &prpriv->pr_sets[prpriv->pr_setsize *
21720Sstevel@tonic-gate 				    priv_getsetbyname(PRIV_LIMIT)];
21730Sstevel@tonic-gate 				if (!priv_ismember(prset, PRIV_SYS_RESOURCE)) {
21740Sstevel@tonic-gate 					release_process(p->pr);
21750Sstevel@tonic-gate 					continue;
21760Sstevel@tonic-gate 				}
21770Sstevel@tonic-gate 			}
21780Sstevel@tonic-gate 			found = 1;
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 			p->taskid = pr_gettaskid(p->pr);
21810Sstevel@tonic-gate 			p->projid = pr_getprojid(p->pr);
21820Sstevel@tonic-gate 			p->zoneid = pr_getzoneid(p->pr);
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 			break;
21850Sstevel@tonic-gate 		}
21860Sstevel@tonic-gate 		(void) closedir(dirp);
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 		if (found == 0) {
21890Sstevel@tonic-gate 			warn(gettext("%s: No controllable process found in "
21900Sstevel@tonic-gate 			    "task, project, or zone.\n"), idname);
21910Sstevel@tonic-gate 			return (-1);
21920Sstevel@tonic-gate 		}
21930Sstevel@tonic-gate 		return (p->pid);
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 	} else if (type == RCENTITY_PROCESS) {
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 		/* fail if self */
21980Sstevel@tonic-gate 		if (p->pid == pid_self) {
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 			warn(gettext("%s: cannot control self"), idname);
22010Sstevel@tonic-gate 			return (-1);
22020Sstevel@tonic-gate 		}
22030Sstevel@tonic-gate 		/*
22040Sstevel@tonic-gate 		 * Process types need to be set up with the correct pid
22050Sstevel@tonic-gate 		 * and psinfo structure.
22060Sstevel@tonic-gate 		 */
22070Sstevel@tonic-gate 		if ((p->pid = proc_arg_psinfo(idname, PR_ARG_PIDS,
22080Sstevel@tonic-gate 		    &(p->psinfo), gret)) == -1) {
22090Sstevel@tonic-gate 			warn(gettext("%s: cannot examine: %s"), idname,
22100Sstevel@tonic-gate 			    Pgrab_error(*gret));
22110Sstevel@tonic-gate 			return (-1);
22120Sstevel@tonic-gate 		}
22130Sstevel@tonic-gate 		/* grab process */
22140Sstevel@tonic-gate 		ret = grab_process(p, gret);
22150Sstevel@tonic-gate 		if (ret == 1) {
22160Sstevel@tonic-gate 			/* Don't print error if G_SYS is allowed */
22170Sstevel@tonic-gate 			if (gret_in == G_SYS && *gret == G_SYS) {
22180Sstevel@tonic-gate 				return (-1);
22190Sstevel@tonic-gate 			} else {
22200Sstevel@tonic-gate 				warn(gettext("%s: cannot control: %s"), idname,
22210Sstevel@tonic-gate 				    Pgrab_error(*gret));
22220Sstevel@tonic-gate 				return (-1);
22230Sstevel@tonic-gate 			}
22240Sstevel@tonic-gate 		} else if (ret == 2) {
22250Sstevel@tonic-gate 			ret = errno;
22260Sstevel@tonic-gate 			warn(gettext("%s: cannot control: %s"), idname,
22270Sstevel@tonic-gate 			    strerror(ret));
22280Sstevel@tonic-gate 			return (-1);
22290Sstevel@tonic-gate 		}
22300Sstevel@tonic-gate 		p->taskid = pr_gettaskid(p->pr);
22310Sstevel@tonic-gate 		p->projid = pr_getprojid(p->pr);
22320Sstevel@tonic-gate 		p->zoneid = pr_getzoneid(p->pr);
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 		return (p->pid);
22350Sstevel@tonic-gate 
22360Sstevel@tonic-gate 	} else {
22370Sstevel@tonic-gate 		warn(gettext("%s: unknown resource entity type %d\n"), idname,
22380Sstevel@tonic-gate 		    type);
22390Sstevel@tonic-gate 		return (-1);
22400Sstevel@tonic-gate 	}
22410Sstevel@tonic-gate }
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate /*
22440Sstevel@tonic-gate  * Do the work required to manipulate a process through libproc.
22450Sstevel@tonic-gate  * If grab_process() returns no errors (0), then release_process()
22460Sstevel@tonic-gate  * must eventually be called.
22470Sstevel@tonic-gate  *
22480Sstevel@tonic-gate  * Return values:
22490Sstevel@tonic-gate  *	0 Successful creation of agent thread
22500Sstevel@tonic-gate  *	1 Error grabbing
22510Sstevel@tonic-gate  *	2 Error creating agent
22520Sstevel@tonic-gate  */
22530Sstevel@tonic-gate int
grab_process(pr_info_handle_t * p,int * gret)22540Sstevel@tonic-gate grab_process(pr_info_handle_t *p, int *gret)
22550Sstevel@tonic-gate {
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate 	if ((p->pr = Pgrab(p->pid, arg_force, gret)) != NULL) {
22580Sstevel@tonic-gate 
22590Sstevel@tonic-gate 		if (Psetflags(p->pr, PR_RLC) != 0) {
22600Sstevel@tonic-gate 			Prelease(p->pr, 0);
22610Sstevel@tonic-gate 			return (1);
22620Sstevel@tonic-gate 		}
22630Sstevel@tonic-gate 		if (Pcreate_agent(p->pr) == 0) {
22640Sstevel@tonic-gate 			return (0);
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 		} else {
22670Sstevel@tonic-gate 			Prelease(p->pr, 0);
22680Sstevel@tonic-gate 			return (2);
22690Sstevel@tonic-gate 		}
22700Sstevel@tonic-gate 	} else {
22710Sstevel@tonic-gate 		return (1);
22720Sstevel@tonic-gate 	}
22730Sstevel@tonic-gate }
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate /*
22760Sstevel@tonic-gate  * Release the specified process. This destroys the agent
22770Sstevel@tonic-gate  * and releases the process. If the process is NULL, nothing
22780Sstevel@tonic-gate  * is done. This function should only be called if grab_process()
22790Sstevel@tonic-gate  * has previously been called and returned success.
22800Sstevel@tonic-gate  *
22810Sstevel@tonic-gate  * This function is Pgrab-safe.
22820Sstevel@tonic-gate  */
22830Sstevel@tonic-gate void
release_process(struct ps_prochandle * Pr)22840Sstevel@tonic-gate release_process(struct ps_prochandle *Pr)
22850Sstevel@tonic-gate {
22860Sstevel@tonic-gate 	if (Pr == NULL)
22870Sstevel@tonic-gate 		return;
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	Pdestroy_agent(Pr);
22900Sstevel@tonic-gate 	Prelease(Pr, 0);
22910Sstevel@tonic-gate }
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate /*
22940Sstevel@tonic-gate  * preserve_error(char *, ...)
22950Sstevel@tonic-gate  *
22960Sstevel@tonic-gate  * preserve_error() should be called rather than warn() by any
22970Sstevel@tonic-gate  * function that is called while the victim process is held by Pgrab.
22980Sstevel@tonic-gate  * It will save the error until the process has been un-controlled
22990Sstevel@tonic-gate  * and output is reasonable again.
23000Sstevel@tonic-gate  *
23010Sstevel@tonic-gate  * Note that multiple errors are not stored. Any error in these
23020Sstevel@tonic-gate  * sections should be critical and return immediately.
23030Sstevel@tonic-gate  *
23040Sstevel@tonic-gate  * This function is Pgrab-safe.
23050Sstevel@tonic-gate  *
23060Sstevel@tonic-gate  * Since this function may copy untrusted command line arguments to
23070Sstevel@tonic-gate  * global_error, security practices require that global_error never be
23080Sstevel@tonic-gate  * printed directly.  Use printf("%s\n", global_error) or equivalent.
23090Sstevel@tonic-gate  */
23100Sstevel@tonic-gate /*PRINTFLIKE1*/
23110Sstevel@tonic-gate void
preserve_error(char * format,...)23120Sstevel@tonic-gate preserve_error(char *format, ...)
23130Sstevel@tonic-gate {
23140Sstevel@tonic-gate 	va_list alist;
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	va_start(alist, format);
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 	/*
23190Sstevel@tonic-gate 	 * GLOBAL_ERR_SZ is pretty big. If the error is longer
23200Sstevel@tonic-gate 	 * than that, just truncate it, rather than chance missing
23210Sstevel@tonic-gate 	 * the error altogether.
23220Sstevel@tonic-gate 	 */
23230Sstevel@tonic-gate 	(void) vsnprintf(global_error, GLOBAL_ERR_SZ-1, format, alist);
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 	va_end(alist);
23260Sstevel@tonic-gate }
2327