17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5c3ea2840SMenno Lageman * Common Development and Distribution License (the "License"). 6c3ea2840SMenno Lageman * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22c3ea2840SMenno Lageman * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <unistd.h> 287c478bd9Sstevel@tonic-gate #include <rctl.h> 297c478bd9Sstevel@tonic-gate #include <libproc.h> 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <libintl.h> 327c478bd9Sstevel@tonic-gate #include <locale.h> 337c478bd9Sstevel@tonic-gate #include <string.h> 347c478bd9Sstevel@tonic-gate #include <signal.h> 357c478bd9Sstevel@tonic-gate #include <strings.h> 367c478bd9Sstevel@tonic-gate #include <ctype.h> 377c478bd9Sstevel@tonic-gate #include <project.h> 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <dirent.h> 407c478bd9Sstevel@tonic-gate #include <errno.h> 417c478bd9Sstevel@tonic-gate #include <stdlib.h> 427c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 437c478bd9Sstevel@tonic-gate #include <priv.h> 447c478bd9Sstevel@tonic-gate #include <zone.h> 457c478bd9Sstevel@tonic-gate #include "utils.h" 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* Valid user actions */ 487c478bd9Sstevel@tonic-gate #define ACTION_DISABLE 0x01 497c478bd9Sstevel@tonic-gate #define ACTION_ENABLE 0x02 507c478bd9Sstevel@tonic-gate #define ACTION_SET 0x04 517c478bd9Sstevel@tonic-gate #define ACTION_REPLACE 0x08 527c478bd9Sstevel@tonic-gate #define ACTION_DELETE 0x10 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #define PRCTL_VALUE_WIDTH 4 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* Maximum string length for deferred errors */ 577c478bd9Sstevel@tonic-gate #define GLOBAL_ERR_SZ 1024 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* allow important process values to be passed together easily */ 607c478bd9Sstevel@tonic-gate typedef struct pr_info_handle { 617c478bd9Sstevel@tonic-gate struct ps_prochandle *pr; 627c478bd9Sstevel@tonic-gate pid_t pid; 637c478bd9Sstevel@tonic-gate psinfo_t psinfo; 647c478bd9Sstevel@tonic-gate taskid_t taskid; 657c478bd9Sstevel@tonic-gate projid_t projid; 667c478bd9Sstevel@tonic-gate char *projname; 677c478bd9Sstevel@tonic-gate zoneid_t zoneid; 687c478bd9Sstevel@tonic-gate char *zonename; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate } pr_info_handle_t; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* Structures for list of resource controls */ 737c478bd9Sstevel@tonic-gate typedef struct prctl_value { 747c478bd9Sstevel@tonic-gate rctlblk_t *rblk; 757c478bd9Sstevel@tonic-gate struct prctl_value *next; 767c478bd9Sstevel@tonic-gate } prctl_value_t; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate typedef struct prctl_list { 797c478bd9Sstevel@tonic-gate char *name; 80*12835672SMenno Lageman rctl_qty_t *usage; 817c478bd9Sstevel@tonic-gate prctl_value_t *val_list; 827c478bd9Sstevel@tonic-gate struct prctl_list *next; 837c478bd9Sstevel@tonic-gate } prctl_list_t; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate static volatile int interrupt; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate static prctl_list_t *global_rctl_list_head = NULL; 887c478bd9Sstevel@tonic-gate static prctl_list_t *global_rctl_list_tail = NULL; 897c478bd9Sstevel@tonic-gate static char global_error[GLOBAL_ERR_SZ]; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* global variables that contain commmand line option info */ 927c478bd9Sstevel@tonic-gate static int arg_operation = 0; 937c478bd9Sstevel@tonic-gate static int arg_force = 0; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* String and type from -i */ 977c478bd9Sstevel@tonic-gate static rctl_entity_t arg_entity_type = RCENTITY_PROCESS; 987c478bd9Sstevel@tonic-gate static char *arg_entity_string = NULL; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* -n argument */ 1017c478bd9Sstevel@tonic-gate static char *arg_name = NULL; 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate static rctl_entity_t arg_name_entity = 0; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* -t argument value */ 1067c478bd9Sstevel@tonic-gate static int arg_priv = 0; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* -v argument string */ 1097c478bd9Sstevel@tonic-gate static char *arg_valuestring = NULL; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* global flags of rctl name passed to -n */ 1127c478bd9Sstevel@tonic-gate static int arg_global_flags = 0; 1137c478bd9Sstevel@tonic-gate static rctl_qty_t arg_global_max; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* appropriate scaling variables determined by rctl unit type */ 1167c478bd9Sstevel@tonic-gate scale_t *arg_scale; 1177c478bd9Sstevel@tonic-gate static char *arg_unit = NULL; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* -v argument string converted to uint64_t */ 1207c478bd9Sstevel@tonic-gate static uint64_t arg_value = 0; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate /* if -v argument is scaled value, points to "K", "M", "G", ... */ 1237c478bd9Sstevel@tonic-gate static char *arg_modifier = NULL; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* -e/-d argument string */ 1267c478bd9Sstevel@tonic-gate static char *arg_action_string = NULL; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* Set to RCTL_LOCAL_SIGNAL|DENY based on arg_action_string */ 1297c478bd9Sstevel@tonic-gate static int arg_action = 0; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* if -e/-d arg is signal=XXX, set to signal number of XXX */ 1327c478bd9Sstevel@tonic-gate static int arg_signal = 0; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* -p arg if -p is specified */ 1357c478bd9Sstevel@tonic-gate static int arg_pid = -1; 1367c478bd9Sstevel@tonic-gate static char *arg_pid_string = NULL; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* Set to 1 if -P is specified */ 1397c478bd9Sstevel@tonic-gate static int arg_parseable_mode = 0; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* interupt handler */ 1427c478bd9Sstevel@tonic-gate static void intr(int); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate static int get_rctls(struct ps_prochandle *); 1457c478bd9Sstevel@tonic-gate static int store_rctls(const char *rctlname, void *walk_data); 1467c478bd9Sstevel@tonic-gate static prctl_value_t *store_value_entry(rctlblk_t *rblk, prctl_list_t *list); 1477c478bd9Sstevel@tonic-gate static prctl_list_t *store_list_entry(const char *name); 1487c478bd9Sstevel@tonic-gate static void free_lists(); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate static int change_action(rctlblk_t *blk); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate static int prctl_setrctl(struct ps_prochandle *Pr, const char *name, 1537c478bd9Sstevel@tonic-gate rctlblk_t *, rctlblk_t *, uint_t); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate static int match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name, 1567c478bd9Sstevel@tonic-gate char *valuestringin, int valuein, rctl_priv_t privin, 1577c478bd9Sstevel@tonic-gate int pidin); 1587c478bd9Sstevel@tonic-gate static int match_rctl_blk(rctlblk_t *rctl, char *valuestringin, 1597c478bd9Sstevel@tonic-gate uint64_t valuein, 1607c478bd9Sstevel@tonic-gate rctl_priv_t privin, int pidin); 1617c478bd9Sstevel@tonic-gate static pid_t regrab_process(pid_t pid, pr_info_handle_t *p, int, int *gret); 1627c478bd9Sstevel@tonic-gate static pid_t grab_process_by_id(char *idname, rctl_entity_t type, 1637c478bd9Sstevel@tonic-gate pr_info_handle_t *p, int, int *gret); 1647c478bd9Sstevel@tonic-gate static int grab_process(pr_info_handle_t *p, int *gret); 1657c478bd9Sstevel@tonic-gate static void release_process(struct ps_prochandle *Pr); 1667c478bd9Sstevel@tonic-gate static void preserve_error(char *format, ...); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate static void print_rctls(pr_info_handle_t *p); 1697c478bd9Sstevel@tonic-gate static void print_priv(rctl_priv_t local_priv, char *format); 1707c478bd9Sstevel@tonic-gate static void print_local_action(int action, int *signalp, char *format); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static const char USAGE[] = "" 1737c478bd9Sstevel@tonic-gate "usage:\n" 1747c478bd9Sstevel@tonic-gate " Report resource control values and actions:\n" 1757c478bd9Sstevel@tonic-gate " prctl [-P] [-t [basic | privileged | system]\n" 1767c478bd9Sstevel@tonic-gate " [-n name] [-i process | task | project | zone] id ...\n" 1777c478bd9Sstevel@tonic-gate " -P space delimited output\n" 1787c478bd9Sstevel@tonic-gate " -t privilege level of rctl values to get\n" 1797c478bd9Sstevel@tonic-gate " -n name of resource control values to get\n" 1807c478bd9Sstevel@tonic-gate " -i idtype of operand list\n" 1817c478bd9Sstevel@tonic-gate " Manipulate resource control values:\n" 1827c478bd9Sstevel@tonic-gate " prctl [-t [basic | privileged | system]\n" 1837c478bd9Sstevel@tonic-gate " -n name [-srx] [-v value] [-p pid ] [-e | -d action]\n" 1847c478bd9Sstevel@tonic-gate " [-i process | task | project | zone] id ...\n" 1857c478bd9Sstevel@tonic-gate " -t privilege level of rctl value to set/replace/delete/modify\n" 1867c478bd9Sstevel@tonic-gate " -n name of resource control to set/replace/delete/modify\n" 1877c478bd9Sstevel@tonic-gate " -s set new resource control value\n" 1887c478bd9Sstevel@tonic-gate " -r replace first rctl value of matching privilege\n" 1897c478bd9Sstevel@tonic-gate " -x delete first rctl value of matching privilege, value, and \n" 1907c478bd9Sstevel@tonic-gate " recipient pid\n" 1917c478bd9Sstevel@tonic-gate " -v value of rctl to set/replace/delete/modify\n" 1927c478bd9Sstevel@tonic-gate " -p recipient pid of rctl to set/replace/delete/modify\n" 1937c478bd9Sstevel@tonic-gate " -e enable action of first rctl value of matching privilege,\n" 1947c478bd9Sstevel@tonic-gate " value, and recipient pid\n" 1957c478bd9Sstevel@tonic-gate " -d disable action of first rctl value of matching privilege,\n" 1967c478bd9Sstevel@tonic-gate " value, and recipient pid\n" 1977c478bd9Sstevel@tonic-gate " -i idtype of operand list\n"; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate static void 2017c478bd9Sstevel@tonic-gate usage() 2027c478bd9Sstevel@tonic-gate { 2037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(USAGE)); 2047c478bd9Sstevel@tonic-gate exit(2); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate int 2087c478bd9Sstevel@tonic-gate main(int argc, char **argv) 2097c478bd9Sstevel@tonic-gate { 2107c478bd9Sstevel@tonic-gate int flags; 2117c478bd9Sstevel@tonic-gate int opt, errflg = 0; 2127c478bd9Sstevel@tonic-gate rctlblk_t *rctlblkA = NULL; 2137c478bd9Sstevel@tonic-gate rctlblk_t *rctlblkB = NULL; 2147c478bd9Sstevel@tonic-gate rctlblk_t *tmp = NULL; 2157c478bd9Sstevel@tonic-gate pid_t pid; 2167c478bd9Sstevel@tonic-gate char *target_id; 2177c478bd9Sstevel@tonic-gate int search_type; 2187c478bd9Sstevel@tonic-gate int signal; 2197c478bd9Sstevel@tonic-gate int localaction; 2207c478bd9Sstevel@tonic-gate int printed = 0; 2217c478bd9Sstevel@tonic-gate int gret; 2227c478bd9Sstevel@tonic-gate char *end; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2257c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2267c478bd9Sstevel@tonic-gate (void) setprogname(argv[0]); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "sPp:Fd:e:i:n:rt:v:x")) != EOF) { 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate switch (opt) { 2317c478bd9Sstevel@tonic-gate case 'F': /* force grabbing (no O_EXCL) */ 2327c478bd9Sstevel@tonic-gate arg_force = PGRAB_FORCE; 2337c478bd9Sstevel@tonic-gate break; 2347c478bd9Sstevel@tonic-gate case 'i': /* id type for arguments */ 2357c478bd9Sstevel@tonic-gate arg_entity_string = optarg; 2367c478bd9Sstevel@tonic-gate if (strcmp(optarg, "process") == 0 || 2377c478bd9Sstevel@tonic-gate strcmp(optarg, "pid") == 0) 2387c478bd9Sstevel@tonic-gate arg_entity_type = RCENTITY_PROCESS; 2397c478bd9Sstevel@tonic-gate else if (strcmp(optarg, "project") == 0 || 2407c478bd9Sstevel@tonic-gate strcmp(optarg, "projid") == 0) 2417c478bd9Sstevel@tonic-gate arg_entity_type = RCENTITY_PROJECT; 2427c478bd9Sstevel@tonic-gate else if (strcmp(optarg, "task") == 0 || 2437c478bd9Sstevel@tonic-gate strcmp(optarg, "taskid") == 0) 2447c478bd9Sstevel@tonic-gate arg_entity_type = RCENTITY_TASK; 2457c478bd9Sstevel@tonic-gate else if (strcmp(optarg, "zone") == 0 || 2467c478bd9Sstevel@tonic-gate strcmp(optarg, "zoneid") == 0) 2477c478bd9Sstevel@tonic-gate arg_entity_type = RCENTITY_ZONE; 2487c478bd9Sstevel@tonic-gate else { 2497c478bd9Sstevel@tonic-gate warn(gettext("unknown idtype %s"), optarg); 2507c478bd9Sstevel@tonic-gate errflg = 1; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate break; 2537c478bd9Sstevel@tonic-gate case 'd': 2547c478bd9Sstevel@tonic-gate arg_action_string = optarg; 2557c478bd9Sstevel@tonic-gate arg_operation |= ACTION_DISABLE; 2567c478bd9Sstevel@tonic-gate break; 2577c478bd9Sstevel@tonic-gate case 'e': 2587c478bd9Sstevel@tonic-gate arg_action_string = optarg; 2597c478bd9Sstevel@tonic-gate arg_operation |= ACTION_ENABLE; 2607c478bd9Sstevel@tonic-gate break; 2617c478bd9Sstevel@tonic-gate case 'n': /* name of rctl */ 2627c478bd9Sstevel@tonic-gate arg_name = optarg; 2637c478bd9Sstevel@tonic-gate if (strncmp(optarg, "process.", 2647c478bd9Sstevel@tonic-gate strlen("process.")) == 0) 2657c478bd9Sstevel@tonic-gate arg_name_entity = RCENTITY_PROCESS; 2667c478bd9Sstevel@tonic-gate else if (strncmp(optarg, "project.", 2677c478bd9Sstevel@tonic-gate strlen("project.")) == 0) 2687c478bd9Sstevel@tonic-gate arg_name_entity = RCENTITY_PROJECT; 2697c478bd9Sstevel@tonic-gate else if (strncmp(optarg, "task.", 2707c478bd9Sstevel@tonic-gate strlen("task.")) == 0) 2717c478bd9Sstevel@tonic-gate arg_name_entity = RCENTITY_TASK; 2727c478bd9Sstevel@tonic-gate else if (strncmp(optarg, "zone.", 2737c478bd9Sstevel@tonic-gate strlen("zone.")) == 0) 2747c478bd9Sstevel@tonic-gate arg_name_entity = RCENTITY_ZONE; 2757c478bd9Sstevel@tonic-gate break; 2767c478bd9Sstevel@tonic-gate case 'r': 2777c478bd9Sstevel@tonic-gate arg_operation |= ACTION_REPLACE; 2787c478bd9Sstevel@tonic-gate break; 2797c478bd9Sstevel@tonic-gate case 't': /* rctl type */ 2807c478bd9Sstevel@tonic-gate if (strcmp(optarg, "basic") == 0) 2817c478bd9Sstevel@tonic-gate arg_priv = RCPRIV_BASIC; 2827c478bd9Sstevel@tonic-gate else if (strcmp(optarg, "privileged") == 0) 2837c478bd9Sstevel@tonic-gate arg_priv = RCPRIV_PRIVILEGED; 2847c478bd9Sstevel@tonic-gate else if (strcmp(optarg, "priv") == 0) 2857c478bd9Sstevel@tonic-gate arg_priv = RCPRIV_PRIVILEGED; 2867c478bd9Sstevel@tonic-gate else if (strcmp(optarg, "system") == 0) 2877c478bd9Sstevel@tonic-gate arg_priv = RCPRIV_SYSTEM; 2887c478bd9Sstevel@tonic-gate else { 2897c478bd9Sstevel@tonic-gate warn(gettext("unknown privilege %s"), optarg); 2907c478bd9Sstevel@tonic-gate errflg = 1; 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate case 'v': /* value */ 2947c478bd9Sstevel@tonic-gate arg_valuestring = optarg; 2957c478bd9Sstevel@tonic-gate break; 2967c478bd9Sstevel@tonic-gate case 's': 2977c478bd9Sstevel@tonic-gate arg_operation |= ACTION_SET; 2987c478bd9Sstevel@tonic-gate break; 2997c478bd9Sstevel@tonic-gate case 'x': /* delete */ 3007c478bd9Sstevel@tonic-gate arg_operation |= ACTION_DELETE; 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate case 'p': 3037c478bd9Sstevel@tonic-gate errno = 0; 3047c478bd9Sstevel@tonic-gate /* Stick with -1 if arg is "-" */ 3057c478bd9Sstevel@tonic-gate if (strcmp("-", optarg) == 0) 3067c478bd9Sstevel@tonic-gate break; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate arg_pid_string = optarg; 3097c478bd9Sstevel@tonic-gate arg_pid = strtoul(optarg, &end, 10); 3107c478bd9Sstevel@tonic-gate if (errno || *end != '\0' || end == optarg) { 3117c478bd9Sstevel@tonic-gate warn(gettext("invalid pid %s"), optarg); 3127c478bd9Sstevel@tonic-gate errflg = 1; 3137c478bd9Sstevel@tonic-gate break; 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate break; 3167c478bd9Sstevel@tonic-gate case 'P': 3177c478bd9Sstevel@tonic-gate arg_parseable_mode = 1; 3187c478bd9Sstevel@tonic-gate break; 3197c478bd9Sstevel@tonic-gate default: 3207c478bd9Sstevel@tonic-gate warn(gettext("unknown option")); 3217c478bd9Sstevel@tonic-gate errflg = 1; 3227c478bd9Sstevel@tonic-gate break; 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate argc -= optind; 3267c478bd9Sstevel@tonic-gate argv += optind; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate if (argc < 1) { 3297c478bd9Sstevel@tonic-gate warn(gettext("no arguments specified")); 3307c478bd9Sstevel@tonic-gate errflg = 1; 3317c478bd9Sstevel@tonic-gate goto done_parse; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate /* if -v is specified without -r, -x, -d, or -e, -s is implied */ 3347c478bd9Sstevel@tonic-gate if (arg_valuestring && 3357c478bd9Sstevel@tonic-gate (!(arg_operation & (ACTION_REPLACE | ACTION_DELETE | 3367c478bd9Sstevel@tonic-gate ACTION_DISABLE | ACTION_ENABLE)))) { 3377c478bd9Sstevel@tonic-gate arg_operation |= ACTION_SET; 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate /* operations require -n */ 3407c478bd9Sstevel@tonic-gate if (arg_operation && (arg_name == NULL)) { 3417c478bd9Sstevel@tonic-gate warn(gettext("-n is required with -s, -r, -x, -e, or -d")); 3427c478bd9Sstevel@tonic-gate errflg = 1; 3437c478bd9Sstevel@tonic-gate goto done_parse; 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate /* enable and disable are exclusive */ 3467c478bd9Sstevel@tonic-gate if ((arg_operation & ACTION_ENABLE) && 3477c478bd9Sstevel@tonic-gate (arg_operation & ACTION_DISABLE)) { 3487c478bd9Sstevel@tonic-gate warn(gettext("options -d and -e are exclusive")); 3497c478bd9Sstevel@tonic-gate errflg = 1; 3507c478bd9Sstevel@tonic-gate goto done_parse; 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate /* -s, -r, and -x are exclusive */ 3537c478bd9Sstevel@tonic-gate flags = arg_operation & 3547c478bd9Sstevel@tonic-gate (ACTION_REPLACE | ACTION_SET | ACTION_DELETE); 3557c478bd9Sstevel@tonic-gate if (flags & (flags - 1)) { 3567c478bd9Sstevel@tonic-gate warn(gettext("options -s, -r, and -x are exclusive")); 3577c478bd9Sstevel@tonic-gate errflg = 1; 3587c478bd9Sstevel@tonic-gate goto done_parse; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate /* -e or -d makes no sense with -x */ 3617c478bd9Sstevel@tonic-gate if ((arg_operation & ACTION_DELETE) & 3627c478bd9Sstevel@tonic-gate (arg_operation & (ACTION_ENABLE | ACTION_DISABLE))) { 3637c478bd9Sstevel@tonic-gate warn(gettext("options -e or -d not allowed with -x")); 3647c478bd9Sstevel@tonic-gate errflg = 1; 3657c478bd9Sstevel@tonic-gate goto done_parse; 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate /* if -r is specified -v must be as well */ 3687c478bd9Sstevel@tonic-gate if ((arg_operation & ACTION_REPLACE) && (!arg_valuestring)) { 3697c478bd9Sstevel@tonic-gate warn(gettext("option -r requires use of option -v")); 3707c478bd9Sstevel@tonic-gate errflg = 1; 3717c478bd9Sstevel@tonic-gate goto done_parse; 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate /* if -s is specified -v must be as well */ 3747c478bd9Sstevel@tonic-gate if ((arg_operation & ACTION_SET) && (!arg_valuestring)) { 3757c478bd9Sstevel@tonic-gate warn(gettext("option -s requires use of option -v")); 3767c478bd9Sstevel@tonic-gate errflg = 1; 3777c478bd9Sstevel@tonic-gate goto done_parse; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate /* Specifying a recipient pid on a non-basic rctl makes no sense */ 3807c478bd9Sstevel@tonic-gate if (arg_pid != -1 && arg_priv > RCPRIV_BASIC) { 3817c478bd9Sstevel@tonic-gate warn(gettext("option -p not allowed on non-basic rctl")); 3827c478bd9Sstevel@tonic-gate errflg = 1; 3837c478bd9Sstevel@tonic-gate goto done_parse; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate /* Specifying a recipient pid on a privileged rctl makes no sense */ 3867c478bd9Sstevel@tonic-gate if (arg_pid != -1 && 3877c478bd9Sstevel@tonic-gate arg_priv == RCPRIV_PRIVILEGED) { 3887c478bd9Sstevel@tonic-gate warn(gettext("option -p not allowed with privileged rctl")); 3897c478bd9Sstevel@tonic-gate errflg = 1; 3907c478bd9Sstevel@tonic-gate goto done_parse; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate if (arg_operation) { 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* do additional checks if there is an operation */ 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (arg_parseable_mode == 1) { 3977c478bd9Sstevel@tonic-gate warn(gettext("-P not valid when manipulating " 3987c478bd9Sstevel@tonic-gate "resource control values")); 3997c478bd9Sstevel@tonic-gate errflg = 1; 4007c478bd9Sstevel@tonic-gate goto done_parse; 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate /* get rctl global flags to determine if actions are valid */ 4037c478bd9Sstevel@tonic-gate if ((rctlblkA = calloc(1, rctlblk_size())) == NULL) { 4047c478bd9Sstevel@tonic-gate warn(gettext("malloc failed: %s"), 4057c478bd9Sstevel@tonic-gate strerror(errno)); 4067c478bd9Sstevel@tonic-gate errflg = 1; 4077c478bd9Sstevel@tonic-gate goto done_parse; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate if ((rctlblkB = calloc(1, rctlblk_size())) == NULL) { 4107c478bd9Sstevel@tonic-gate warn(gettext("malloc failed: %s"), 4117c478bd9Sstevel@tonic-gate strerror(errno)); 4127c478bd9Sstevel@tonic-gate errflg = 1; 4137c478bd9Sstevel@tonic-gate goto done_parse; 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate /* get system rctl to get global flags and max value */ 4167c478bd9Sstevel@tonic-gate if (getrctl(arg_name, NULL, rctlblkA, RCTL_FIRST)) { 4177c478bd9Sstevel@tonic-gate warn(gettext("failed to get resource control " 4187c478bd9Sstevel@tonic-gate "for %s: %s"), arg_name, strerror(errno)); 4197c478bd9Sstevel@tonic-gate errflg = 1; 4207c478bd9Sstevel@tonic-gate goto done_parse; 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate while (getrctl(arg_name, rctlblkA, rctlblkB, RCTL_NEXT) == 0) { 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* allow user interrupt */ 4257c478bd9Sstevel@tonic-gate if (interrupt) { 4267c478bd9Sstevel@tonic-gate errflg = 1; 4277c478bd9Sstevel@tonic-gate goto done_parse; 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate tmp = rctlblkB; 4307c478bd9Sstevel@tonic-gate rctlblkB = rctlblkA; 4317c478bd9Sstevel@tonic-gate rctlblkA = tmp; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate if (rctlblk_get_privilege(rctlblkA) == 4347c478bd9Sstevel@tonic-gate RCPRIV_SYSTEM) { 4357c478bd9Sstevel@tonic-gate break; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate if (rctlblk_get_privilege(rctlblkA) != RCPRIV_SYSTEM) { 4397c478bd9Sstevel@tonic-gate warn(gettext("failed to get system resource control " 4407c478bd9Sstevel@tonic-gate "for %s: %s"), arg_name, strerror(errno)); 4417c478bd9Sstevel@tonic-gate errflg = 1; 4427c478bd9Sstevel@tonic-gate goto done_parse; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate /* figure out the correct scale and unit for this rctl */ 4457c478bd9Sstevel@tonic-gate arg_global_flags = rctlblk_get_global_flags(rctlblkA); 4467c478bd9Sstevel@tonic-gate arg_global_max = rctlblk_get_value(rctlblkA); 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate if (arg_global_flags & RCTL_GLOBAL_BYTES) { 4497c478bd9Sstevel@tonic-gate arg_unit = SCALED_UNIT_BYTES; 4507c478bd9Sstevel@tonic-gate arg_scale = scale_binary; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate } else if (arg_global_flags & RCTL_GLOBAL_SECONDS) { 4537c478bd9Sstevel@tonic-gate arg_unit = SCALED_UNIT_SECONDS; 4547c478bd9Sstevel@tonic-gate arg_scale = scale_metric; 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate } else { 4577c478bd9Sstevel@tonic-gate arg_unit = SCALED_UNIT_NONE; 4587c478bd9Sstevel@tonic-gate arg_scale = scale_metric; 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate /* parse -v value string */ 4617c478bd9Sstevel@tonic-gate if (arg_valuestring) { 4627c478bd9Sstevel@tonic-gate if (scaledtouint64(arg_valuestring, 4637c478bd9Sstevel@tonic-gate &arg_value, NULL, &arg_modifier, NULL, 4647c478bd9Sstevel@tonic-gate arg_scale, arg_unit, 4657c478bd9Sstevel@tonic-gate SCALED_ALL_FLAGS)) { 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate warn(gettext("invalid -v value %s"), 4687c478bd9Sstevel@tonic-gate arg_valuestring); 4697c478bd9Sstevel@tonic-gate errflg = 1; 4707c478bd9Sstevel@tonic-gate goto done_parse; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate if (arg_value > arg_global_max) { 4737c478bd9Sstevel@tonic-gate warn(gettext("-v value %s exceeds system " 4747c478bd9Sstevel@tonic-gate "limit for resource control: %s"), 4757c478bd9Sstevel@tonic-gate arg_valuestring, arg_name); 4767c478bd9Sstevel@tonic-gate errflg = 1; 4777c478bd9Sstevel@tonic-gate goto done_parse; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate /* parse action */ 4817c478bd9Sstevel@tonic-gate if (arg_action_string) { 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate char *sigchr; 4847c478bd9Sstevel@tonic-gate char *iter; 4857c478bd9Sstevel@tonic-gate 486c3ea2840SMenno Lageman if ((strcmp(arg_action_string, "signal") == 0) || 487c3ea2840SMenno Lageman (strcmp(arg_action_string, "sig") == 0)) { 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate if (arg_operation & ACTION_ENABLE) { 4907c478bd9Sstevel@tonic-gate warn(gettext( 4917c478bd9Sstevel@tonic-gate "signal name or number must be " 4927c478bd9Sstevel@tonic-gate "specified with -e")); 4937c478bd9Sstevel@tonic-gate errflg = 1; 4947c478bd9Sstevel@tonic-gate goto done_parse; 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate arg_action = RCTL_LOCAL_SIGNAL; 4977c478bd9Sstevel@tonic-gate arg_signal = -1; 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate } else if ((strncmp(arg_action_string, 5007c478bd9Sstevel@tonic-gate "signal=", strlen("signal=")) == 0) || 5017c478bd9Sstevel@tonic-gate (strncmp(arg_action_string, 5027c478bd9Sstevel@tonic-gate "sig=", strlen("sig=")) == 0)) { 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate arg_action = RCTL_LOCAL_SIGNAL; 5057c478bd9Sstevel@tonic-gate sigchr = strrchr(arg_action_string, '='); 5067c478bd9Sstevel@tonic-gate sigchr++; 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate iter = sigchr; 5097c478bd9Sstevel@tonic-gate while (*iter) { 5107c478bd9Sstevel@tonic-gate *iter = toupper(*iter); 5117c478bd9Sstevel@tonic-gate iter++; 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate if (strncmp("SIG", sigchr, 3) == 0) 5147c478bd9Sstevel@tonic-gate sigchr += 3; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate if (str2sig(sigchr, &arg_signal) != 0) { 5187c478bd9Sstevel@tonic-gate warn(gettext("signal invalid")); 5197c478bd9Sstevel@tonic-gate errflg = 1; 5207c478bd9Sstevel@tonic-gate goto done_parse; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate } else if (strcmp(arg_action_string, "deny") == 0) { 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate arg_action = RCTL_LOCAL_DENY; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate } else if (strcmp(arg_action_string, "all") == 0) { 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate if (arg_operation & ACTION_ENABLE) { 5297c478bd9Sstevel@tonic-gate warn(gettext( 5307c478bd9Sstevel@tonic-gate "cannot use action 'all' with -e")); 5317c478bd9Sstevel@tonic-gate errflg = 1; 5327c478bd9Sstevel@tonic-gate goto done_parse; 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate arg_action = RCTL_LOCAL_DENY | 5357c478bd9Sstevel@tonic-gate RCTL_LOCAL_SIGNAL; 5367c478bd9Sstevel@tonic-gate arg_signal = -1; 5377c478bd9Sstevel@tonic-gate goto done_parse; 5387c478bd9Sstevel@tonic-gate } else { 5397c478bd9Sstevel@tonic-gate warn(gettext("action invalid")); 5407c478bd9Sstevel@tonic-gate errflg = 1; 5417c478bd9Sstevel@tonic-gate goto done_parse; 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate /* cannot manipulate system rctls */ 5457c478bd9Sstevel@tonic-gate if (arg_priv == RCPRIV_SYSTEM) { 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate warn(gettext("cannot modify system values")); 5487c478bd9Sstevel@tonic-gate errflg = 1; 5497c478bd9Sstevel@tonic-gate goto done_parse; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate /* validate that the privilege is allowed */ 5527c478bd9Sstevel@tonic-gate if ((arg_priv == RCPRIV_BASIC) && 5537c478bd9Sstevel@tonic-gate (arg_global_flags & RCTL_GLOBAL_NOBASIC)) { 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate warn(gettext("basic values not allowed on rctl %s"), 5567c478bd9Sstevel@tonic-gate arg_name); 5577c478bd9Sstevel@tonic-gate errflg = 1; 5587c478bd9Sstevel@tonic-gate goto done_parse; 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate /* validate that actions are appropriate for given rctl */ 5617c478bd9Sstevel@tonic-gate if ((arg_operation & ACTION_ENABLE) && 5627c478bd9Sstevel@tonic-gate (arg_action & RCTL_LOCAL_DENY) && 5637c478bd9Sstevel@tonic-gate (arg_global_flags & RCTL_GLOBAL_DENY_NEVER)) { 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate warn(gettext("unable to enable deny on rctl with " 5667c478bd9Sstevel@tonic-gate "global flag 'no-deny'")); 5677c478bd9Sstevel@tonic-gate errflg = 1; 5687c478bd9Sstevel@tonic-gate goto done_parse; 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate if ((arg_operation & ACTION_DISABLE) && 5717c478bd9Sstevel@tonic-gate (arg_action & RCTL_LOCAL_DENY) && 5727c478bd9Sstevel@tonic-gate (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS)) { 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate warn(gettext("unable to disable deny on rctl with " 5757c478bd9Sstevel@tonic-gate "global flag 'deny'")); 5767c478bd9Sstevel@tonic-gate errflg = 1; 5777c478bd9Sstevel@tonic-gate goto done_parse; 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate if ((arg_operation & ACTION_ENABLE) && 5807c478bd9Sstevel@tonic-gate (arg_action & RCTL_LOCAL_SIGNAL) && 5817c478bd9Sstevel@tonic-gate (arg_global_flags & RCTL_GLOBAL_SIGNAL_NEVER)) { 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate warn(gettext("unable to enable signal on rctl with " 5847c478bd9Sstevel@tonic-gate "global flag 'no-signal'")); 5857c478bd9Sstevel@tonic-gate errflg = 1; 5867c478bd9Sstevel@tonic-gate goto done_parse; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate /* now set defaults for options not supplied */ 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * default privilege to basic if this is a seting an rctl 5927c478bd9Sstevel@tonic-gate * operation 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate if (arg_operation & ACTION_SET) { 5957c478bd9Sstevel@tonic-gate if (arg_priv == 0) { 5967c478bd9Sstevel@tonic-gate arg_priv = RCPRIV_BASIC; 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * -p is required when set a basic task, 6017c478bd9Sstevel@tonic-gate * project or zone rctl 6027c478bd9Sstevel@tonic-gate */ 6037c478bd9Sstevel@tonic-gate if ((arg_pid == -1) && 6047c478bd9Sstevel@tonic-gate (arg_priv == RCPRIV_BASIC) && 6057c478bd9Sstevel@tonic-gate (arg_entity_type != RCENTITY_PROCESS) && 6067c478bd9Sstevel@tonic-gate (arg_operation & ACTION_SET) && 6077c478bd9Sstevel@tonic-gate (arg_name) && 6087c478bd9Sstevel@tonic-gate (arg_name_entity == RCENTITY_TASK || 6097c478bd9Sstevel@tonic-gate arg_name_entity == RCENTITY_PROJECT || 6107c478bd9Sstevel@tonic-gate arg_name_entity == RCENTITY_ZONE)) { 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate warn(gettext("-p pid required when setting or " 6137c478bd9Sstevel@tonic-gate "replacing task or project rctl")); 6147c478bd9Sstevel@tonic-gate errflg = 1; 6157c478bd9Sstevel@tonic-gate goto done_parse; 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate } else { 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* validate for list mode */ 6207c478bd9Sstevel@tonic-gate /* -p is not valid in list mode */ 6217c478bd9Sstevel@tonic-gate if (arg_pid != -1) { 6227c478bd9Sstevel@tonic-gate warn(gettext("-p pid requires -s, -r, -x, -e, or -d")); 6237c478bd9Sstevel@tonic-gate errflg = 1; 6247c478bd9Sstevel@tonic-gate goto done_parse; 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate /* getting/setting process rctl on task or project is error */ 6287c478bd9Sstevel@tonic-gate if ((arg_name && (arg_name_entity == RCENTITY_PROCESS)) && 6297c478bd9Sstevel@tonic-gate ((arg_entity_type == RCENTITY_TASK) || 6307c478bd9Sstevel@tonic-gate (arg_entity_type == RCENTITY_PROJECT))) { 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate warn(gettext("cannot get/set process rctl on task " 6337c478bd9Sstevel@tonic-gate "or project")); 6347c478bd9Sstevel@tonic-gate errflg = 1; 6357c478bd9Sstevel@tonic-gate goto done_parse; 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate /* getting/setting task rctl on project is error */ 6387c478bd9Sstevel@tonic-gate if ((arg_name && (arg_name_entity == RCENTITY_TASK)) && 6397c478bd9Sstevel@tonic-gate (arg_entity_type == RCENTITY_PROJECT)) { 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate warn(gettext("cannot get/set task rctl on project")); 6427c478bd9Sstevel@tonic-gate errflg = 1; 6437c478bd9Sstevel@tonic-gate goto done_parse; 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate done_parse: 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate /* free any rctlblk's that we may have allocated */ 6497c478bd9Sstevel@tonic-gate if (rctlblkA) { 6507c478bd9Sstevel@tonic-gate free(rctlblkA); 6517c478bd9Sstevel@tonic-gate rctlblkA = NULL; 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate if (rctlblkB) { 6547c478bd9Sstevel@tonic-gate free(rctlblkB); 6557c478bd9Sstevel@tonic-gate rctlblkB = NULL; 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate if (errflg) 6587c478bd9Sstevel@tonic-gate usage(); 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate /* catch signals from terminal */ 6617c478bd9Sstevel@tonic-gate if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 6627c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, intr); 6637c478bd9Sstevel@tonic-gate if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 6647c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, intr); 6657c478bd9Sstevel@tonic-gate if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 6667c478bd9Sstevel@tonic-gate (void) sigset(SIGQUIT, intr); 6677c478bd9Sstevel@tonic-gate (void) sigset(SIGTERM, intr); 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate while (--argc >= 0 && !interrupt) { 6707c478bd9Sstevel@tonic-gate pr_info_handle_t p; 6717c478bd9Sstevel@tonic-gate char *arg = *argv++; 6727c478bd9Sstevel@tonic-gate int intarg; 6737c478bd9Sstevel@tonic-gate char *end; 6747c478bd9Sstevel@tonic-gate errflg = 0; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate gret = 0; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* Store int version of arg */ 6797c478bd9Sstevel@tonic-gate errno = 0; 6807c478bd9Sstevel@tonic-gate intarg = strtoul(arg, &end, 10); 6817c478bd9Sstevel@tonic-gate if (errno || *end != '\0' || end == arg) { 6827c478bd9Sstevel@tonic-gate intarg = -1; 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * -p defaults to arg if basic and collective rctl 6877c478bd9Sstevel@tonic-gate * and -i process is specified 6887c478bd9Sstevel@tonic-gate */ 6897c478bd9Sstevel@tonic-gate if ((arg_pid == -1) && 6907c478bd9Sstevel@tonic-gate (arg_priv == RCPRIV_BASIC) && 6917c478bd9Sstevel@tonic-gate (arg_entity_type == RCENTITY_PROCESS) && 6927c478bd9Sstevel@tonic-gate (arg_name) && 6937c478bd9Sstevel@tonic-gate (arg_name_entity == RCENTITY_TASK || 6947c478bd9Sstevel@tonic-gate arg_name_entity == RCENTITY_PROJECT)) { 6957c478bd9Sstevel@tonic-gate arg_pid_string = arg; 6967c478bd9Sstevel@tonic-gate errno = 0; 6977c478bd9Sstevel@tonic-gate arg_pid = intarg; 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate /* Specifying a recipient pid and -i pid is redundent */ 7007c478bd9Sstevel@tonic-gate if (arg_pid != -1 && arg_entity_type == RCENTITY_PROCESS && 7017c478bd9Sstevel@tonic-gate arg_pid != intarg) { 7027c478bd9Sstevel@tonic-gate warn(gettext("option -p pid must match -i process")); 7037c478bd9Sstevel@tonic-gate errflg = 1; 7047c478bd9Sstevel@tonic-gate continue; 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate /* use recipient pid if we have one */ 7077c478bd9Sstevel@tonic-gate if (arg_pid_string != NULL) { 7087c478bd9Sstevel@tonic-gate target_id = arg_pid_string; 7097c478bd9Sstevel@tonic-gate search_type = RCENTITY_PROCESS; 7107c478bd9Sstevel@tonic-gate } else { 7117c478bd9Sstevel@tonic-gate target_id = arg; 7127c478bd9Sstevel@tonic-gate search_type = arg_entity_type; 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate (void) fflush(stdout); /* process-at-a-time */ 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (arg_operation != 0) { 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate if ((pid = grab_process_by_id(target_id, 7197c478bd9Sstevel@tonic-gate search_type, &p, arg_priv, &gret)) < 0) { 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * Mark that an error occurred so that the 7227c478bd9Sstevel@tonic-gate * return value can be set, but continue 7237c478bd9Sstevel@tonic-gate * on with other processes 7247c478bd9Sstevel@tonic-gate */ 7257c478bd9Sstevel@tonic-gate errflg = 1; 7267c478bd9Sstevel@tonic-gate continue; 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * At this point, the victim process is held. 7317c478bd9Sstevel@tonic-gate * Do not call any Pgrab-unsafe functions until 7327c478bd9Sstevel@tonic-gate * the process is released via release_process(). 7337c478bd9Sstevel@tonic-gate */ 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate errflg = get_rctls(p.pr); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate if (arg_operation & ACTION_DELETE) { 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate /* match by privilege, value, and pid */ 7407c478bd9Sstevel@tonic-gate if (match_rctl(p.pr, &rctlblkA, arg_name, 7417c478bd9Sstevel@tonic-gate arg_valuestring, arg_value, arg_priv, 7427c478bd9Sstevel@tonic-gate arg_pid) != 0 || rctlblkA == NULL) { 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate if (interrupt) 7457c478bd9Sstevel@tonic-gate goto out; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate preserve_error(gettext("no matching " 7487c478bd9Sstevel@tonic-gate "resource control found for " 7497c478bd9Sstevel@tonic-gate "deletion")); 7507c478bd9Sstevel@tonic-gate errflg = 1; 7517c478bd9Sstevel@tonic-gate goto out; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * grab correct process. This is neccessary 7557c478bd9Sstevel@tonic-gate * if the recipient pid does not match the 7567c478bd9Sstevel@tonic-gate * one we grabbed 7577c478bd9Sstevel@tonic-gate */ 7587c478bd9Sstevel@tonic-gate pid = regrab_process( 7597c478bd9Sstevel@tonic-gate rctlblk_get_recipient_pid(rctlblkA), 7607c478bd9Sstevel@tonic-gate &p, arg_priv, &gret); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate if (pid < 0) { 7637c478bd9Sstevel@tonic-gate errflg = 1; 7647c478bd9Sstevel@tonic-gate goto out; 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate if (prctl_setrctl(p.pr, arg_name, NULL, 7677c478bd9Sstevel@tonic-gate rctlblkA, RCTL_DELETE) != 0) { 7687c478bd9Sstevel@tonic-gate errflg = 1; 7697c478bd9Sstevel@tonic-gate goto out; 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate } else if (arg_operation & ACTION_SET) { 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate /* match by privilege, value, and pid */ 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate if (match_rctl(p.pr, &rctlblkA, arg_name, 7767c478bd9Sstevel@tonic-gate arg_valuestring, arg_value, arg_priv, 7777c478bd9Sstevel@tonic-gate arg_pid) == 0) { 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate if (interrupt) 7807c478bd9Sstevel@tonic-gate goto out; 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate preserve_error(gettext("resource " 7837c478bd9Sstevel@tonic-gate "control already exists")); 7847c478bd9Sstevel@tonic-gate errflg = 1; 7857c478bd9Sstevel@tonic-gate goto out; 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate rctlblkB = calloc(1, rctlblk_size()); 7887c478bd9Sstevel@tonic-gate if (rctlblkB == NULL) { 7897c478bd9Sstevel@tonic-gate preserve_error(gettext( 7907c478bd9Sstevel@tonic-gate "malloc failed"), strerror(errno)); 7917c478bd9Sstevel@tonic-gate errflg = 1; 7927c478bd9Sstevel@tonic-gate goto out; 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate rctlblk_set_value(rctlblkB, arg_value); 7957c478bd9Sstevel@tonic-gate rctlblk_set_privilege(rctlblkB, arg_priv); 7967c478bd9Sstevel@tonic-gate if (change_action(rctlblkB)) { 7977c478bd9Sstevel@tonic-gate errflg = 1; 7987c478bd9Sstevel@tonic-gate goto out; 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate if (prctl_setrctl(p.pr, arg_name, NULL, 8017c478bd9Sstevel@tonic-gate rctlblkB, RCTL_INSERT) != 0) { 8027c478bd9Sstevel@tonic-gate errflg = 1; 8037c478bd9Sstevel@tonic-gate goto out; 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate } else if (arg_operation & ACTION_REPLACE) { 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * match rctl for deletion by privilege and 8087c478bd9Sstevel@tonic-gate * pid only 8097c478bd9Sstevel@tonic-gate */ 8107c478bd9Sstevel@tonic-gate if (match_rctl(p.pr, &rctlblkA, arg_name, 8117c478bd9Sstevel@tonic-gate NULL, 0, arg_priv, 8127c478bd9Sstevel@tonic-gate arg_pid) != 0 || rctlblkA == NULL) { 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if (interrupt) 8157c478bd9Sstevel@tonic-gate goto out; 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate preserve_error(gettext("no matching " 8187c478bd9Sstevel@tonic-gate "resource control to replace")); 8197c478bd9Sstevel@tonic-gate errflg = 1; 8207c478bd9Sstevel@tonic-gate goto out; 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * grab correct process. This is neccessary 8247c478bd9Sstevel@tonic-gate * if the recipient pid does not match the 8257c478bd9Sstevel@tonic-gate * one we grabbed 8267c478bd9Sstevel@tonic-gate */ 8277c478bd9Sstevel@tonic-gate pid = regrab_process( 8287c478bd9Sstevel@tonic-gate rctlblk_get_recipient_pid(rctlblkA), 8297c478bd9Sstevel@tonic-gate &p, arg_priv, &gret); 8307c478bd9Sstevel@tonic-gate if (pid < 0) { 8317c478bd9Sstevel@tonic-gate errflg = 1; 8327c478bd9Sstevel@tonic-gate goto out; 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate pid = rctlblk_get_recipient_pid(rctlblkA); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate /* 8377c478bd9Sstevel@tonic-gate * match by privilege, value and pid to 8387c478bd9Sstevel@tonic-gate * check if new rctl already exists 8397c478bd9Sstevel@tonic-gate */ 8407c478bd9Sstevel@tonic-gate if (match_rctl(p.pr, &rctlblkB, arg_name, 8417c478bd9Sstevel@tonic-gate arg_valuestring, arg_value, arg_priv, 8427c478bd9Sstevel@tonic-gate pid) < 0) { 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if (interrupt) 8457c478bd9Sstevel@tonic-gate goto out; 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate preserve_error(gettext( 8487c478bd9Sstevel@tonic-gate "Internal Error")); 8497c478bd9Sstevel@tonic-gate errflg = 1; 8507c478bd9Sstevel@tonic-gate goto out; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate /* 8537c478bd9Sstevel@tonic-gate * If rctl already exists, and it does not 8547c478bd9Sstevel@tonic-gate * match the one that we will delete, than 8557c478bd9Sstevel@tonic-gate * the replace will fail. 8567c478bd9Sstevel@tonic-gate */ 8577c478bd9Sstevel@tonic-gate if (rctlblkB != NULL && 858c3ea2840SMenno Lageman arg_value != rctlblk_get_value(rctlblkA)) { 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate preserve_error(gettext("replacement " 8617c478bd9Sstevel@tonic-gate "resource control already " 8627c478bd9Sstevel@tonic-gate "exists")); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate errflg = 1; 8657c478bd9Sstevel@tonic-gate goto out; 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate /* create new rctl */ 8687c478bd9Sstevel@tonic-gate rctlblkB = calloc(1, rctlblk_size()); 8697c478bd9Sstevel@tonic-gate if (rctlblkB == NULL) { 8707c478bd9Sstevel@tonic-gate preserve_error(gettext( 8717c478bd9Sstevel@tonic-gate "malloc failed"), strerror(errno)); 8727c478bd9Sstevel@tonic-gate errflg = 1; 8737c478bd9Sstevel@tonic-gate goto out; 8747c478bd9Sstevel@tonic-gate } 875c3ea2840SMenno Lageman localaction = 876c3ea2840SMenno Lageman rctlblk_get_local_action(rctlblkA, &signal); 877c3ea2840SMenno Lageman rctlblk_set_local_action(rctlblkB, localaction, 878c3ea2840SMenno Lageman signal); 8797c478bd9Sstevel@tonic-gate rctlblk_set_value(rctlblkB, arg_value); 8807c478bd9Sstevel@tonic-gate rctlblk_set_privilege(rctlblkB, 8817c478bd9Sstevel@tonic-gate rctlblk_get_privilege(rctlblkA)); 8827c478bd9Sstevel@tonic-gate if (change_action(rctlblkB)) { 8837c478bd9Sstevel@tonic-gate errflg = 1; 8847c478bd9Sstevel@tonic-gate goto out; 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate /* do replacement */ 8877c478bd9Sstevel@tonic-gate if (prctl_setrctl(p.pr, arg_name, rctlblkA, 8887c478bd9Sstevel@tonic-gate rctlblkB, RCTL_REPLACE) != 0) { 8897c478bd9Sstevel@tonic-gate errflg = 1; 8907c478bd9Sstevel@tonic-gate goto out; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate } else if (arg_operation & 8937c478bd9Sstevel@tonic-gate (ACTION_ENABLE | ACTION_DISABLE)) { 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate rctlblkB = calloc(1, rctlblk_size()); 8967c478bd9Sstevel@tonic-gate if (rctlblkB == NULL) { 8977c478bd9Sstevel@tonic-gate preserve_error(gettext( 8987c478bd9Sstevel@tonic-gate "malloc failed"), strerror(errno)); 8997c478bd9Sstevel@tonic-gate errflg = 1; 9007c478bd9Sstevel@tonic-gate goto out; 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate /* match by privilege, value, and pid */ 9037c478bd9Sstevel@tonic-gate if (match_rctl(p.pr, &rctlblkA, arg_name, 9047c478bd9Sstevel@tonic-gate arg_valuestring, arg_value, arg_priv, 9057c478bd9Sstevel@tonic-gate arg_pid) != 0) { 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate if (interrupt) 9087c478bd9Sstevel@tonic-gate goto out; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate /* if no match, just set new rctl */ 9117c478bd9Sstevel@tonic-gate if (arg_priv == 0) 9127c478bd9Sstevel@tonic-gate arg_priv = RCPRIV_BASIC; 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate if ((arg_priv == RCPRIV_BASIC) && 9157c478bd9Sstevel@tonic-gate (arg_entity_type != 9167c478bd9Sstevel@tonic-gate RCENTITY_PROCESS) && 9177c478bd9Sstevel@tonic-gate (arg_pid_string == NULL)) { 9187c478bd9Sstevel@tonic-gate preserve_error(gettext( 9197c478bd9Sstevel@tonic-gate "-p required when setting " 9207c478bd9Sstevel@tonic-gate "basic rctls")); 9217c478bd9Sstevel@tonic-gate errflg = 1; 9227c478bd9Sstevel@tonic-gate goto out; 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate rctlblk_set_value(rctlblkB, 9257c478bd9Sstevel@tonic-gate arg_value); 9267c478bd9Sstevel@tonic-gate rctlblk_set_privilege( 9277c478bd9Sstevel@tonic-gate rctlblkB, arg_priv); 9287c478bd9Sstevel@tonic-gate if (change_action(rctlblkB)) { 9297c478bd9Sstevel@tonic-gate errflg = 1; 9307c478bd9Sstevel@tonic-gate goto out; 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate if (prctl_setrctl(p.pr, 9337c478bd9Sstevel@tonic-gate arg_name, NULL, rctlblkB, 9347c478bd9Sstevel@tonic-gate RCTL_INSERT) != 0) { 9357c478bd9Sstevel@tonic-gate errflg = 1; 9367c478bd9Sstevel@tonic-gate goto out; 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate goto out; 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate if (rctlblkA == NULL) { 9417c478bd9Sstevel@tonic-gate preserve_error(gettext("no matching " 9427c478bd9Sstevel@tonic-gate "resource control found")); 9437c478bd9Sstevel@tonic-gate errflg = 1; 9447c478bd9Sstevel@tonic-gate goto out; 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * grab correct process. This is neccessary 9487c478bd9Sstevel@tonic-gate * if the recipient pid does not match the 9497c478bd9Sstevel@tonic-gate * one we grabbed 9507c478bd9Sstevel@tonic-gate */ 9517c478bd9Sstevel@tonic-gate pid = regrab_process( 9527c478bd9Sstevel@tonic-gate rctlblk_get_recipient_pid(rctlblkA), 9537c478bd9Sstevel@tonic-gate &p, arg_priv, &gret); 9547c478bd9Sstevel@tonic-gate if (pid < 0) { 9557c478bd9Sstevel@tonic-gate errflg = 1; 9567c478bd9Sstevel@tonic-gate goto out; 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate localaction = 9597c478bd9Sstevel@tonic-gate rctlblk_get_local_action(rctlblkA, 9607c478bd9Sstevel@tonic-gate &signal); 9617c478bd9Sstevel@tonic-gate rctlblk_set_local_action(rctlblkB, localaction, 9627c478bd9Sstevel@tonic-gate signal); 9637c478bd9Sstevel@tonic-gate rctlblk_set_privilege(rctlblkB, 9647c478bd9Sstevel@tonic-gate rctlblk_get_privilege(rctlblkA)); 9657c478bd9Sstevel@tonic-gate rctlblk_set_value(rctlblkB, 9667c478bd9Sstevel@tonic-gate rctlblk_get_value(rctlblkA)); 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate if (change_action(rctlblkB)) { 9697c478bd9Sstevel@tonic-gate errflg = 1; 9707c478bd9Sstevel@tonic-gate goto out; 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate if (prctl_setrctl(p.pr, arg_name, rctlblkA, 9737c478bd9Sstevel@tonic-gate rctlblkB, RCTL_REPLACE) != 0) { 9747c478bd9Sstevel@tonic-gate errflg = 1; 9757c478bd9Sstevel@tonic-gate goto out; 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate out: 9797c478bd9Sstevel@tonic-gate release_process(p.pr); 9807c478bd9Sstevel@tonic-gate if (rctlblkA) 9817c478bd9Sstevel@tonic-gate free(rctlblkA); 9827c478bd9Sstevel@tonic-gate if (rctlblkB) 9837c478bd9Sstevel@tonic-gate free(rctlblkB); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* Print any errors that occurred */ 9867c478bd9Sstevel@tonic-gate if (errflg && *global_error != '\0') { 9877c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&(p.psinfo)); 9887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%d:\t%.70s\n", 9897c478bd9Sstevel@tonic-gate (int)p.pid, p.psinfo.pr_psargs); 9907c478bd9Sstevel@tonic-gate warn("%s\n", global_error); 9917c478bd9Sstevel@tonic-gate break; 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate } else { 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate struct project projent; 9967c478bd9Sstevel@tonic-gate char buf[PROJECT_BUFSZ]; 9977c478bd9Sstevel@tonic-gate char zonename[ZONENAME_MAX]; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate /* 10007c478bd9Sstevel@tonic-gate * Hack to allow the user to specify a system 10017c478bd9Sstevel@tonic-gate * process. 10027c478bd9Sstevel@tonic-gate */ 10037c478bd9Sstevel@tonic-gate gret = G_SYS; 10047c478bd9Sstevel@tonic-gate pid = grab_process_by_id( 10057c478bd9Sstevel@tonic-gate target_id, search_type, &p, RCPRIV_BASIC, &gret); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * Print system process if user chose specifically 10097c478bd9Sstevel@tonic-gate * to inspect a system process. 10107c478bd9Sstevel@tonic-gate */ 10117c478bd9Sstevel@tonic-gate if (arg_entity_type == RCENTITY_PROCESS && 10127c478bd9Sstevel@tonic-gate pid < 0 && 10137c478bd9Sstevel@tonic-gate gret == G_SYS) { 10147c478bd9Sstevel@tonic-gate /* 10157c478bd9Sstevel@tonic-gate * Add blank lines between output for 10167c478bd9Sstevel@tonic-gate * operands. 10177c478bd9Sstevel@tonic-gate */ 10187c478bd9Sstevel@tonic-gate if (printed) { 10197c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&(p.psinfo)); 10237c478bd9Sstevel@tonic-gate (void) printf( 10247c478bd9Sstevel@tonic-gate "process: %d: %s [ system process ]\n", 10257c478bd9Sstevel@tonic-gate (int)p.pid, p.psinfo.pr_psargs); 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate printed = 1; 10287c478bd9Sstevel@tonic-gate continue; 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate } else if (pid < 0) { 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* 10337c478bd9Sstevel@tonic-gate * Mark that an error occurred so that the 10347c478bd9Sstevel@tonic-gate * return value can be set, but continue 10357c478bd9Sstevel@tonic-gate * on with other processes 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate errflg = 1; 10387c478bd9Sstevel@tonic-gate continue; 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate errflg = get_rctls(p.pr); 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate release_process(p.pr); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate /* handle user interrupt of getting rctls */ 10467c478bd9Sstevel@tonic-gate if (interrupt) 10477c478bd9Sstevel@tonic-gate break; 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate /* add blank lines between output for operands */ 10507c478bd9Sstevel@tonic-gate if (printed) { 10517c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate /* First print any errors */ 10547c478bd9Sstevel@tonic-gate if (errflg) { 10557c478bd9Sstevel@tonic-gate warn("%s\n", global_error); 10567c478bd9Sstevel@tonic-gate free_lists(); 10577c478bd9Sstevel@tonic-gate break; 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate if (getprojbyid(p.projid, &projent, buf, 10607c478bd9Sstevel@tonic-gate sizeof (buf))) { 10617c478bd9Sstevel@tonic-gate p.projname = projent.pj_name; 10627c478bd9Sstevel@tonic-gate } else { 10637c478bd9Sstevel@tonic-gate p.projname = ""; 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate if (getzonenamebyid(p.zoneid, zonename, 10667c478bd9Sstevel@tonic-gate sizeof (zonename)) > 0) { 10677c478bd9Sstevel@tonic-gate p.zonename = zonename; 10687c478bd9Sstevel@tonic-gate } else { 10697c478bd9Sstevel@tonic-gate p.zonename = ""; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate print_rctls(&p); 10727c478bd9Sstevel@tonic-gate printed = 1; 10737c478bd9Sstevel@tonic-gate /* Free the resource control lists */ 10747c478bd9Sstevel@tonic-gate free_lists(); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate if (interrupt) 10787c478bd9Sstevel@tonic-gate errflg = 1; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* 10817c478bd9Sstevel@tonic-gate * return error if one occurred 10827c478bd9Sstevel@tonic-gate */ 10837c478bd9Sstevel@tonic-gate return (errflg); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate static void 10887c478bd9Sstevel@tonic-gate intr(int sig) 10897c478bd9Sstevel@tonic-gate { 10907c478bd9Sstevel@tonic-gate interrupt = sig; 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate /* 10947c478bd9Sstevel@tonic-gate * get_rctls(struct ps_prochandle *, const char *) 10957c478bd9Sstevel@tonic-gate * 10967c478bd9Sstevel@tonic-gate * If controlname is given, store only controls for that named 10977c478bd9Sstevel@tonic-gate * resource. If controlname is NULL, store all controls for all 10987c478bd9Sstevel@tonic-gate * resources. 10997c478bd9Sstevel@tonic-gate * 11007c478bd9Sstevel@tonic-gate * This function is Pgrab-safe. 11017c478bd9Sstevel@tonic-gate */ 11027c478bd9Sstevel@tonic-gate static int 11037c478bd9Sstevel@tonic-gate get_rctls(struct ps_prochandle *Pr) 11047c478bd9Sstevel@tonic-gate { 11057c478bd9Sstevel@tonic-gate int ret = 0; 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate if (arg_name == NULL) { 11087c478bd9Sstevel@tonic-gate if (rctl_walk(store_rctls, Pr) != 0) 11097c478bd9Sstevel@tonic-gate ret = 1; 11107c478bd9Sstevel@tonic-gate } else { 11117c478bd9Sstevel@tonic-gate ret = store_rctls(arg_name, Pr); 11127c478bd9Sstevel@tonic-gate } 11137c478bd9Sstevel@tonic-gate return (ret); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate /* 11177c478bd9Sstevel@tonic-gate * store_rctls(const char *, void *) 11187c478bd9Sstevel@tonic-gate * 11197c478bd9Sstevel@tonic-gate * Store resource controls for the given name in a linked list. 11207c478bd9Sstevel@tonic-gate * Honor the user's options, and store only the ones they are 11217c478bd9Sstevel@tonic-gate * interested in. If priv is not 0, show only controls that match 11227c478bd9Sstevel@tonic-gate * the given privilege. 11237c478bd9Sstevel@tonic-gate * 11247c478bd9Sstevel@tonic-gate * This function is Pgrab-safe 11257c478bd9Sstevel@tonic-gate */ 11267c478bd9Sstevel@tonic-gate static int 11277c478bd9Sstevel@tonic-gate store_rctls(const char *rctlname, void *walk_data) 11287c478bd9Sstevel@tonic-gate { 11297c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = walk_data; 11307c478bd9Sstevel@tonic-gate rctlblk_t *rblk2, *rblk_tmp, *rblk1 = NULL; 11317c478bd9Sstevel@tonic-gate prctl_list_t *list = NULL; 11327c478bd9Sstevel@tonic-gate rctl_priv_t rblk_priv; 11337c478bd9Sstevel@tonic-gate rctl_entity_t rblk_entity; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate if (((rblk1 = calloc(1, rctlblk_size())) == NULL) || 11367c478bd9Sstevel@tonic-gate ((rblk2 = calloc(1, rctlblk_size())) == NULL)) { 11377c478bd9Sstevel@tonic-gate if (rblk1 != NULL) 11387c478bd9Sstevel@tonic-gate free(rblk1); 11397c478bd9Sstevel@tonic-gate preserve_error(gettext("malloc failed: %s"), 11407c478bd9Sstevel@tonic-gate strerror(errno)); 11417c478bd9Sstevel@tonic-gate return (1); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate if (pr_getrctl(Pr, rctlname, NULL, rblk1, RCTL_FIRST)) { 11447c478bd9Sstevel@tonic-gate preserve_error(gettext("failed to get resource control " 11457c478bd9Sstevel@tonic-gate "for %s: %s"), rctlname, strerror(errno)); 11467c478bd9Sstevel@tonic-gate free(rblk1); 11477c478bd9Sstevel@tonic-gate free(rblk2); 11487c478bd9Sstevel@tonic-gate return (1); 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate /* Store control if it matches privilege and enity type criteria */ 11517c478bd9Sstevel@tonic-gate rblk_priv = rctlblk_get_privilege(rblk1); 11527c478bd9Sstevel@tonic-gate rblk_entity = 0; 11537c478bd9Sstevel@tonic-gate if (strncmp(rctlname, "process.", 11547c478bd9Sstevel@tonic-gate strlen("process.")) == 0) 11557c478bd9Sstevel@tonic-gate rblk_entity = RCENTITY_PROCESS; 11567c478bd9Sstevel@tonic-gate else if (strncmp(rctlname, "project.", 11577c478bd9Sstevel@tonic-gate strlen("project.")) == 0) 11587c478bd9Sstevel@tonic-gate rblk_entity = RCENTITY_PROJECT; 11597c478bd9Sstevel@tonic-gate else if (strncmp(rctlname, "task.", 11607c478bd9Sstevel@tonic-gate strlen("task.")) == 0) 11617c478bd9Sstevel@tonic-gate rblk_entity = RCENTITY_TASK; 11627c478bd9Sstevel@tonic-gate else if (strncmp(rctlname, "zone.", 11637c478bd9Sstevel@tonic-gate strlen("zone.")) == 0) 11647c478bd9Sstevel@tonic-gate rblk_entity = RCENTITY_ZONE; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate if (((arg_priv == 0) || (rblk_priv == arg_priv)) && 11677c478bd9Sstevel@tonic-gate ((arg_name == NULL) || 1168c3ea2840SMenno Lageman strncmp(rctlname, arg_name, strlen(arg_name)) == 0) && 1169c3ea2840SMenno Lageman (arg_entity_string == NULL || rblk_entity >= arg_entity_type)) { 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate /* Once we know we have some controls, store the name */ 11727c478bd9Sstevel@tonic-gate if ((list = store_list_entry(rctlname)) == NULL) { 11737c478bd9Sstevel@tonic-gate free(rblk1); 11747c478bd9Sstevel@tonic-gate free(rblk2); 11757c478bd9Sstevel@tonic-gate return (1); 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate if (store_value_entry(rblk1, list) == NULL) { 11787c478bd9Sstevel@tonic-gate free(rblk1); 11797c478bd9Sstevel@tonic-gate free(rblk2); 11807c478bd9Sstevel@tonic-gate return (1); 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate while (pr_getrctl(Pr, rctlname, rblk1, rblk2, RCTL_NEXT) == 0) { 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate /* 11867c478bd9Sstevel@tonic-gate * in case this is stuck for some reason, allow manual 11877c478bd9Sstevel@tonic-gate * interrupt 11887c478bd9Sstevel@tonic-gate */ 11897c478bd9Sstevel@tonic-gate if (interrupt) { 11907c478bd9Sstevel@tonic-gate free(rblk1); 11917c478bd9Sstevel@tonic-gate free(rblk2); 11927c478bd9Sstevel@tonic-gate return (1); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate rblk_priv = rctlblk_get_privilege(rblk2); 11957c478bd9Sstevel@tonic-gate /* 11967c478bd9Sstevel@tonic-gate * Store control if it matches privilege and entity type 11977c478bd9Sstevel@tonic-gate * criteria 11987c478bd9Sstevel@tonic-gate */ 11997c478bd9Sstevel@tonic-gate if (((arg_priv == 0) || (rblk_priv == arg_priv)) && 12007c478bd9Sstevel@tonic-gate ((arg_name == NULL) || 1201c3ea2840SMenno Lageman strncmp(rctlname, arg_name, strlen(arg_name)) == 0) && 12027c478bd9Sstevel@tonic-gate (arg_entity_string == NULL || 12037c478bd9Sstevel@tonic-gate rblk_entity == arg_entity_type)) { 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /* May not have created the list yet. */ 12067c478bd9Sstevel@tonic-gate if (list == NULL) { 12077c478bd9Sstevel@tonic-gate if ((list = store_list_entry(rctlname)) 12087c478bd9Sstevel@tonic-gate == NULL) { 12097c478bd9Sstevel@tonic-gate free(rblk1); 12107c478bd9Sstevel@tonic-gate free(rblk2); 12117c478bd9Sstevel@tonic-gate return (1); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate if (store_value_entry(rblk2, list) == NULL) { 12157c478bd9Sstevel@tonic-gate free(rblk1); 12167c478bd9Sstevel@tonic-gate free(rblk2); 12177c478bd9Sstevel@tonic-gate return (1); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate rblk_tmp = rblk1; 12217c478bd9Sstevel@tonic-gate rblk1 = rblk2; 12227c478bd9Sstevel@tonic-gate rblk2 = rblk_tmp; 12237c478bd9Sstevel@tonic-gate } 1224*12835672SMenno Lageman 1225*12835672SMenno Lageman /* 1226*12835672SMenno Lageman * Get the current usage for the resource control if it matched the 1227*12835672SMenno Lageman * privilege and entity type criteria. 1228*12835672SMenno Lageman */ 1229*12835672SMenno Lageman if (list != NULL) { 1230*12835672SMenno Lageman if (pr_getrctl(Pr, rctlname, NULL, rblk2, RCTL_USAGE) == 0) { 1231*12835672SMenno Lageman list->usage = (rctl_qty_t *)malloc(sizeof (rctl_qty_t)); 1232*12835672SMenno Lageman if (list->usage == NULL) { 1233*12835672SMenno Lageman preserve_error(gettext("malloc failed: %s"), 1234*12835672SMenno Lageman strerror(errno)); 1235*12835672SMenno Lageman free(rblk1); 1236*12835672SMenno Lageman free(rblk2); 1237*12835672SMenno Lageman return (1); 1238*12835672SMenno Lageman } 1239*12835672SMenno Lageman *list->usage = rctlblk_get_value(rblk2); 1240*12835672SMenno Lageman } else { 1241*12835672SMenno Lageman list->usage = NULL; 1242*12835672SMenno Lageman if (errno != ENOTSUP) { 1243*12835672SMenno Lageman preserve_error(gettext("failed to get " 1244*12835672SMenno Lageman "resource control usage for %s: %s"), 1245*12835672SMenno Lageman rctlname, strerror(errno)); 1246*12835672SMenno Lageman free(rblk1); 1247*12835672SMenno Lageman free(rblk2); 1248*12835672SMenno Lageman return (1); 1249*12835672SMenno Lageman } 1250*12835672SMenno Lageman } 1251*12835672SMenno Lageman } 12527c478bd9Sstevel@tonic-gate free(rblk1); 12537c478bd9Sstevel@tonic-gate free(rblk2); 12547c478bd9Sstevel@tonic-gate return (0); 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * store_value_entry(rctlblk_t *, prctl_list_t *) 12597c478bd9Sstevel@tonic-gate * 12607c478bd9Sstevel@tonic-gate * Store an rblk for a given resource control into the global list. 12617c478bd9Sstevel@tonic-gate * 12627c478bd9Sstevel@tonic-gate * This function is Pgrab-safe. 12637c478bd9Sstevel@tonic-gate */ 12647c478bd9Sstevel@tonic-gate prctl_value_t * 12657c478bd9Sstevel@tonic-gate store_value_entry(rctlblk_t *rblk, prctl_list_t *list) 12667c478bd9Sstevel@tonic-gate { 12677c478bd9Sstevel@tonic-gate prctl_value_t *e = calloc(1, sizeof (prctl_value_t)); 12687c478bd9Sstevel@tonic-gate rctlblk_t *store_blk = calloc(1, rctlblk_size()); 12697c478bd9Sstevel@tonic-gate prctl_value_t *iter = list->val_list; 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate if (e == NULL || store_blk == NULL) { 12727c478bd9Sstevel@tonic-gate preserve_error(gettext("malloc failed %s"), 12737c478bd9Sstevel@tonic-gate strerror(errno)); 12747c478bd9Sstevel@tonic-gate if (e != NULL) 12757c478bd9Sstevel@tonic-gate free(e); 12767c478bd9Sstevel@tonic-gate if (store_blk != NULL) 12777c478bd9Sstevel@tonic-gate free(store_blk); 12787c478bd9Sstevel@tonic-gate return (NULL); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate if (iter == NULL) 12817c478bd9Sstevel@tonic-gate list->val_list = e; 12827c478bd9Sstevel@tonic-gate else { 12837c478bd9Sstevel@tonic-gate while (iter->next != NULL) { 12847c478bd9Sstevel@tonic-gate iter = iter->next; 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate iter->next = e; 12877c478bd9Sstevel@tonic-gate } 12887c478bd9Sstevel@tonic-gate bcopy(rblk, store_blk, rctlblk_size()); 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate e->rblk = store_blk; 12917c478bd9Sstevel@tonic-gate e->next = NULL; 12927c478bd9Sstevel@tonic-gate return (e); 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate /* 12967c478bd9Sstevel@tonic-gate * store_list_entry(const char *) 12977c478bd9Sstevel@tonic-gate * 12987c478bd9Sstevel@tonic-gate * Store a new resource control value in the global list. No checking 12997c478bd9Sstevel@tonic-gate * for duplicates done. 13007c478bd9Sstevel@tonic-gate * 13017c478bd9Sstevel@tonic-gate * This function is Pgrab-safe. 13027c478bd9Sstevel@tonic-gate */ 13037c478bd9Sstevel@tonic-gate prctl_list_t * 13047c478bd9Sstevel@tonic-gate store_list_entry(const char *name) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate prctl_list_t *e = calloc(1, sizeof (prctl_list_t)); 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate if (e == NULL) { 13097c478bd9Sstevel@tonic-gate preserve_error(gettext("malloc failed %s"), 13107c478bd9Sstevel@tonic-gate strerror(errno)); 13117c478bd9Sstevel@tonic-gate return (NULL); 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate if ((e->name = calloc(1, strlen(name) + 1)) == NULL) { 13147c478bd9Sstevel@tonic-gate preserve_error(gettext("malloc failed %s"), 13157c478bd9Sstevel@tonic-gate strerror(errno)); 13167c478bd9Sstevel@tonic-gate free(e); 13177c478bd9Sstevel@tonic-gate return (NULL); 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate (void) strcpy(e->name, name); 13207c478bd9Sstevel@tonic-gate e->val_list = NULL; 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate if (global_rctl_list_head == NULL) { 13237c478bd9Sstevel@tonic-gate global_rctl_list_head = e; 13247c478bd9Sstevel@tonic-gate global_rctl_list_tail = e; 13257c478bd9Sstevel@tonic-gate } else { 13267c478bd9Sstevel@tonic-gate global_rctl_list_tail->next = e; 13277c478bd9Sstevel@tonic-gate global_rctl_list_tail = e; 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate e->next = NULL; 13307c478bd9Sstevel@tonic-gate return (e); 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate /* 13347c478bd9Sstevel@tonic-gate * free_lists() 13357c478bd9Sstevel@tonic-gate * 13367c478bd9Sstevel@tonic-gate * Free all resource control blocks and values from the global lists. 13377c478bd9Sstevel@tonic-gate * 13387c478bd9Sstevel@tonic-gate * This function is Pgrab-safe. 13397c478bd9Sstevel@tonic-gate */ 13407c478bd9Sstevel@tonic-gate void 13417c478bd9Sstevel@tonic-gate free_lists() 13427c478bd9Sstevel@tonic-gate { 13437c478bd9Sstevel@tonic-gate prctl_list_t *new_list, *old_list = global_rctl_list_head; 13447c478bd9Sstevel@tonic-gate prctl_value_t *old_val, *new_val; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate while (old_list != NULL) { 13477c478bd9Sstevel@tonic-gate old_val = old_list->val_list; 13487c478bd9Sstevel@tonic-gate while (old_val != NULL) { 13497c478bd9Sstevel@tonic-gate free(old_val->rblk); 13507c478bd9Sstevel@tonic-gate new_val = old_val->next; 13517c478bd9Sstevel@tonic-gate free(old_val); 13527c478bd9Sstevel@tonic-gate old_val = new_val; 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate free(old_list->name); 1355*12835672SMenno Lageman free(old_list->usage); 13567c478bd9Sstevel@tonic-gate new_list = old_list->next; 13577c478bd9Sstevel@tonic-gate free(old_list); 13587c478bd9Sstevel@tonic-gate old_list = new_list; 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate global_rctl_list_head = NULL; 13617c478bd9Sstevel@tonic-gate global_rctl_list_tail = NULL; 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate void 13657c478bd9Sstevel@tonic-gate print_heading() 13667c478bd9Sstevel@tonic-gate { 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate /* print headings */ 13697c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%-8s%-16s%-9s%-7s%-28s%10s\n", 13707c478bd9Sstevel@tonic-gate "NAME", "PRIVILEGE", "VALUE", 13717c478bd9Sstevel@tonic-gate "FLAG", "ACTION", "RECIPIENT"); 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate /* 13757c478bd9Sstevel@tonic-gate * print_rctls() 13767c478bd9Sstevel@tonic-gate * 13777c478bd9Sstevel@tonic-gate * Print all resource controls from the global list that was 13787c478bd9Sstevel@tonic-gate * previously populated by store_rctls. 13797c478bd9Sstevel@tonic-gate */ 13807c478bd9Sstevel@tonic-gate void 13817c478bd9Sstevel@tonic-gate print_rctls(pr_info_handle_t *p) 13827c478bd9Sstevel@tonic-gate { 13837c478bd9Sstevel@tonic-gate prctl_list_t *iter_list = global_rctl_list_head; 13847c478bd9Sstevel@tonic-gate prctl_value_t *iter_val; 13857c478bd9Sstevel@tonic-gate rctl_qty_t rblk_value; 13867c478bd9Sstevel@tonic-gate rctl_priv_t rblk_priv; 13877c478bd9Sstevel@tonic-gate uint_t local_action; 13887c478bd9Sstevel@tonic-gate int signal, local_flags, global_flags; 13897c478bd9Sstevel@tonic-gate pid_t pid; 13907c478bd9Sstevel@tonic-gate char rctl_valuestring[SCALED_STRLEN]; 13917c478bd9Sstevel@tonic-gate char *unit = NULL; 13927c478bd9Sstevel@tonic-gate scale_t *scale; 13937c478bd9Sstevel@tonic-gate char *string; 13947c478bd9Sstevel@tonic-gate int doneheading = 0; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate if (iter_list == NULL) 13977c478bd9Sstevel@tonic-gate return; 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate while (iter_list != NULL) { 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate if (doneheading == 0 && 14027c478bd9Sstevel@tonic-gate arg_entity_type == RCENTITY_PROCESS) { 14037c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&(p->psinfo)); 14047c478bd9Sstevel@tonic-gate doneheading = 1; 14057c478bd9Sstevel@tonic-gate (void) fprintf(stdout, 14067c478bd9Sstevel@tonic-gate "process: %d: %.70s\n", (int)p->pid, 14077c478bd9Sstevel@tonic-gate p->psinfo.pr_psargs); 14087c478bd9Sstevel@tonic-gate if (!arg_parseable_mode) 14097c478bd9Sstevel@tonic-gate print_heading(); 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate if (doneheading == 0 && 14127c478bd9Sstevel@tonic-gate arg_entity_type == RCENTITY_TASK) { 14137c478bd9Sstevel@tonic-gate doneheading = 1; 14147c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "task: %d\n", (int)p->taskid); 14157c478bd9Sstevel@tonic-gate if (!arg_parseable_mode) 14167c478bd9Sstevel@tonic-gate print_heading(); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate if (doneheading == 0 && 14197c478bd9Sstevel@tonic-gate arg_entity_type == RCENTITY_PROJECT) { 14207c478bd9Sstevel@tonic-gate if (!arg_parseable_mode && doneheading) 14217c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 14227c478bd9Sstevel@tonic-gate doneheading = 1; 14237c478bd9Sstevel@tonic-gate (void) fprintf(stdout, 14247c478bd9Sstevel@tonic-gate "project: %d: %.70s\n", (int)p->projid, 14257c478bd9Sstevel@tonic-gate p->projname); 14267c478bd9Sstevel@tonic-gate if (!arg_parseable_mode) 14277c478bd9Sstevel@tonic-gate print_heading(); 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate if (doneheading == 0 && 14307c478bd9Sstevel@tonic-gate arg_entity_type == RCENTITY_ZONE) { 14317c478bd9Sstevel@tonic-gate doneheading = 1; 14327c478bd9Sstevel@tonic-gate (void) fprintf(stdout, 14337c478bd9Sstevel@tonic-gate "zone: %d: %.70s\n", (int)p->zoneid, 14347c478bd9Sstevel@tonic-gate p->zonename); 14357c478bd9Sstevel@tonic-gate if (!arg_parseable_mode) 14367c478bd9Sstevel@tonic-gate print_heading(); 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate /* only print name once in normal output */ 14397c478bd9Sstevel@tonic-gate if (!arg_parseable_mode) 14407c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s\n", iter_list->name); 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate iter_val = iter_list->val_list; 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate /* if for some reason there are no values, skip */ 14457c478bd9Sstevel@tonic-gate if (iter_val == 0) 14467c478bd9Sstevel@tonic-gate continue; 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate /* get the global flags the first rctl only */ 14507c478bd9Sstevel@tonic-gate global_flags = rctlblk_get_global_flags(iter_val->rblk); 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if (global_flags & RCTL_GLOBAL_BYTES) { 14547c478bd9Sstevel@tonic-gate unit = SCALED_UNIT_BYTES; 14557c478bd9Sstevel@tonic-gate scale = scale_binary; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate } else if (global_flags & RCTL_GLOBAL_SECONDS) { 14587c478bd9Sstevel@tonic-gate unit = SCALED_UNIT_SECONDS; 14597c478bd9Sstevel@tonic-gate scale = scale_metric; 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate } else { 14627c478bd9Sstevel@tonic-gate unit = SCALED_UNIT_NONE; 14637c478bd9Sstevel@tonic-gate scale = scale_metric; 14647c478bd9Sstevel@tonic-gate } 1465*12835672SMenno Lageman 1466*12835672SMenno Lageman /* print the current usage for the rctl if available */ 1467*12835672SMenno Lageman if (iter_list->usage != NULL) { 1468*12835672SMenno Lageman rblk_value = *(iter_list->usage); 1469*12835672SMenno Lageman if (!arg_parseable_mode) { 1470*12835672SMenno Lageman (void) uint64toscaled(rblk_value, 4, "E", 1471*12835672SMenno Lageman rctl_valuestring, NULL, NULL, 1472*12835672SMenno Lageman scale, NULL, 0); 1473*12835672SMenno Lageman 1474*12835672SMenno Lageman (void) fprintf(stdout, "%8s%-16s%5s%-4s\n", 1475*12835672SMenno Lageman "", "usage", rctl_valuestring, unit); 1476*12835672SMenno Lageman } else { 1477*12835672SMenno Lageman (void) fprintf(stdout, "%s %s %llu - - -\n", 1478*12835672SMenno Lageman iter_list->name, "usage", rblk_value); 1479*12835672SMenno Lageman } 1480*12835672SMenno Lageman } 1481*12835672SMenno Lageman 14827c478bd9Sstevel@tonic-gate /* iterate over an print all control values */ 14837c478bd9Sstevel@tonic-gate while (iter_val != NULL) { 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate /* print name or empty name field */ 14867c478bd9Sstevel@tonic-gate if (!arg_parseable_mode) 14877c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%8s", ""); 14887c478bd9Sstevel@tonic-gate else 14897c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s ", iter_list->name); 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate rblk_priv = rctlblk_get_privilege(iter_val->rblk); 14937c478bd9Sstevel@tonic-gate if (!arg_parseable_mode) 14947c478bd9Sstevel@tonic-gate print_priv(rblk_priv, "%-16s"); 14957c478bd9Sstevel@tonic-gate else 14967c478bd9Sstevel@tonic-gate print_priv(rblk_priv, "%s "); 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate rblk_value = rctlblk_get_value(iter_val->rblk); 14997c478bd9Sstevel@tonic-gate if (arg_parseable_mode) { 15007c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%llu ", rblk_value); 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate } else { 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate (void) uint64toscaled(rblk_value, 4, "E", 15057c478bd9Sstevel@tonic-gate rctl_valuestring, NULL, NULL, 15067c478bd9Sstevel@tonic-gate scale, NULL, 0); 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%5s", 15097c478bd9Sstevel@tonic-gate rctl_valuestring); 15107c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%-4s", unit); 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate local_flags = rctlblk_get_local_flags(iter_val->rblk); 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate if (local_flags & RCTL_LOCAL_MAXIMAL) { 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate if (global_flags & RCTL_GLOBAL_INFINITE) { 15177c478bd9Sstevel@tonic-gate string = "inf"; 15187c478bd9Sstevel@tonic-gate } else { 15197c478bd9Sstevel@tonic-gate string = "max"; 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate } else { 15227c478bd9Sstevel@tonic-gate string = "-"; 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate if (arg_parseable_mode) 15257c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s ", string); 15267c478bd9Sstevel@tonic-gate else 15277c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%4s%3s", 15287c478bd9Sstevel@tonic-gate string, ""); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate local_action = rctlblk_get_local_action(iter_val->rblk, 15327c478bd9Sstevel@tonic-gate &signal); 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate if (arg_parseable_mode) 15357c478bd9Sstevel@tonic-gate print_local_action(local_action, &signal, 15367c478bd9Sstevel@tonic-gate "%s "); 15377c478bd9Sstevel@tonic-gate else 15387c478bd9Sstevel@tonic-gate print_local_action(local_action, &signal, 15397c478bd9Sstevel@tonic-gate "%-28s"); 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate pid = rctlblk_get_recipient_pid(iter_val->rblk); 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate if (arg_parseable_mode) { 15447c478bd9Sstevel@tonic-gate if (pid < 0) { 15457c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s\n", "-"); 15467c478bd9Sstevel@tonic-gate } else { 15477c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%d\n", 15487c478bd9Sstevel@tonic-gate (int)pid); 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate } else { 15517c478bd9Sstevel@tonic-gate if (pid < 0) { 15527c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%10s\n", "-"); 15537c478bd9Sstevel@tonic-gate } else { 15547c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%10d\n", 15557c478bd9Sstevel@tonic-gate (int)pid); 15567c478bd9Sstevel@tonic-gate } 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate iter_val = iter_val->next; 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate iter_list = iter_list->next; 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* 15657c478bd9Sstevel@tonic-gate * 15667c478bd9Sstevel@tonic-gate * match_rctl 15677c478bd9Sstevel@tonic-gate * 15687c478bd9Sstevel@tonic-gate * find the first rctl with matching name, value, priv, and recipient pid 15697c478bd9Sstevel@tonic-gate */ 15707c478bd9Sstevel@tonic-gate int 15717c478bd9Sstevel@tonic-gate match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name, 15727c478bd9Sstevel@tonic-gate char *valuestringin, int valuein, rctl_priv_t privin, int pidin) 15737c478bd9Sstevel@tonic-gate { 15747c478bd9Sstevel@tonic-gate rctlblk_t *next; 15757c478bd9Sstevel@tonic-gate rctlblk_t *last; 15767c478bd9Sstevel@tonic-gate rctlblk_t *tmp; 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate *rctl = NULL; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate next = calloc(1, rctlblk_size()); 15817c478bd9Sstevel@tonic-gate last = calloc(1, rctlblk_size()); 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate if ((last == NULL) || (next == NULL)) { 15847c478bd9Sstevel@tonic-gate preserve_error(gettext("malloc failed"), strerror(errno)); 15857c478bd9Sstevel@tonic-gate return (-1); 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate /* 15887c478bd9Sstevel@tonic-gate * For this resource name, now iterate through all 15897c478bd9Sstevel@tonic-gate * the controls, looking for a match to the 15907c478bd9Sstevel@tonic-gate * user-specified input. 15917c478bd9Sstevel@tonic-gate */ 15927c478bd9Sstevel@tonic-gate if (pr_getrctl(Pr, name, NULL, next, RCTL_FIRST)) { 15937c478bd9Sstevel@tonic-gate preserve_error(gettext("failed to get resource control " 15947c478bd9Sstevel@tonic-gate "for %s: %s"), name, strerror(errno)); 15957c478bd9Sstevel@tonic-gate return (-1); 15967c478bd9Sstevel@tonic-gate } 15977c478bd9Sstevel@tonic-gate if (match_rctl_blk(next, valuestringin, valuein, privin, pidin) == 1) { 15987c478bd9Sstevel@tonic-gate free(last); 15997c478bd9Sstevel@tonic-gate *rctl = next; 16007c478bd9Sstevel@tonic-gate return (0); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate tmp = next; 16037c478bd9Sstevel@tonic-gate next = last; 16047c478bd9Sstevel@tonic-gate last = tmp; 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate while (pr_getrctl(Pr, name, last, next, RCTL_NEXT) == 0) { 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate /* allow user interrupt */ 16097c478bd9Sstevel@tonic-gate if (interrupt) 16107c478bd9Sstevel@tonic-gate break; 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate if (match_rctl_blk(next, valuestringin, valuein, privin, pidin) 16137c478bd9Sstevel@tonic-gate == 1) { 16147c478bd9Sstevel@tonic-gate free(last); 16157c478bd9Sstevel@tonic-gate *rctl = next; 16167c478bd9Sstevel@tonic-gate return (0); 16177c478bd9Sstevel@tonic-gate } 16187c478bd9Sstevel@tonic-gate tmp = next; 16197c478bd9Sstevel@tonic-gate next = last; 16207c478bd9Sstevel@tonic-gate last = tmp; 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate free(next); 16237c478bd9Sstevel@tonic-gate free(last); 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate return (1); 16267c478bd9Sstevel@tonic-gate } 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate /* 16297c478bd9Sstevel@tonic-gate * int match_rctl_blk(rctlblk_t *, char *, uint64, rctl_priv_t, int pid) 16307c478bd9Sstevel@tonic-gate * 16317c478bd9Sstevel@tonic-gate * Input 16327c478bd9Sstevel@tonic-gate * Must supply a valid rctl, value, privilege, and pid to match on. 16337c478bd9Sstevel@tonic-gate * If valuestring is NULL, then valuestring and valuein will not be used 16347c478bd9Sstevel@tonic-gate * If privilege type is 0 it will not be used. 16357c478bd9Sstevel@tonic-gate * If pid is -1 it will not be used. 16367c478bd9Sstevel@tonic-gate * 16377c478bd9Sstevel@tonic-gate * Return values 16387c478bd9Sstevel@tonic-gate * Returns 1 if a matching rctl given matches the parameters specified, and 16397c478bd9Sstevel@tonic-gate * 0 if they do not. 16407c478bd9Sstevel@tonic-gate * 16417c478bd9Sstevel@tonic-gate * This function is Pgrab-safe. 16427c478bd9Sstevel@tonic-gate */ 16437c478bd9Sstevel@tonic-gate int 16447c478bd9Sstevel@tonic-gate match_rctl_blk(rctlblk_t *rctl, char *valuestringin, 16457c478bd9Sstevel@tonic-gate uint64_t valuein, rctl_priv_t privin, int pidin) 16467c478bd9Sstevel@tonic-gate { 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate rctl_qty_t value; 16497c478bd9Sstevel@tonic-gate rctl_priv_t priv; 16507c478bd9Sstevel@tonic-gate pid_t pid; 16517c478bd9Sstevel@tonic-gate int valuematch = 1; 16527c478bd9Sstevel@tonic-gate int privmatch = 1; 16537c478bd9Sstevel@tonic-gate int pidmatch = 1; 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate value = rctlblk_get_value(rctl); 16567c478bd9Sstevel@tonic-gate priv = rctlblk_get_privilege(rctl); 16577c478bd9Sstevel@tonic-gate pid = rctlblk_get_recipient_pid(rctl); 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate if (valuestringin) { 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate if (arg_modifier == NULL) { 16627c478bd9Sstevel@tonic-gate valuematch = (valuein == value); 16637c478bd9Sstevel@tonic-gate } else { 16647c478bd9Sstevel@tonic-gate valuematch = scaledequint64(valuestringin, value, 16657c478bd9Sstevel@tonic-gate PRCTL_VALUE_WIDTH, 16667c478bd9Sstevel@tonic-gate arg_scale, arg_unit, 16677c478bd9Sstevel@tonic-gate SCALED_ALL_FLAGS); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate if (privin != 0) { 16717c478bd9Sstevel@tonic-gate privmatch = (privin == priv); 16727c478bd9Sstevel@tonic-gate } 16737c478bd9Sstevel@tonic-gate if (pidin != -1) { 16747c478bd9Sstevel@tonic-gate pidmatch = (pidin == pid); 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate return (valuematch && privmatch && pidmatch); 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate static int 16807c478bd9Sstevel@tonic-gate change_action(rctlblk_t *blk) 16817c478bd9Sstevel@tonic-gate { 16827c478bd9Sstevel@tonic-gate int signal = 0; 16837c478bd9Sstevel@tonic-gate int action; 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate action = rctlblk_get_local_action(blk, &signal); 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate if (arg_operation & ACTION_ENABLE) { 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate if (arg_action & RCTL_LOCAL_SIGNAL) { 16907c478bd9Sstevel@tonic-gate signal = arg_signal; 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate action = action | arg_action; 16937c478bd9Sstevel@tonic-gate /* add local action */ 16947c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, action, signal); 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate } else if (arg_operation & ACTION_DISABLE) { 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate /* 16997c478bd9Sstevel@tonic-gate * if deleting signal and signal number is specified, 17007c478bd9Sstevel@tonic-gate * then signal number must match 17017c478bd9Sstevel@tonic-gate */ 17027c478bd9Sstevel@tonic-gate if ((arg_action & RCTL_LOCAL_SIGNAL) && 17037c478bd9Sstevel@tonic-gate (arg_signal != -1)) { 17047c478bd9Sstevel@tonic-gate if (arg_signal != signal) { 17057c478bd9Sstevel@tonic-gate preserve_error(gettext("signal name or number " 17067c478bd9Sstevel@tonic-gate "does not match existing action")); 17077c478bd9Sstevel@tonic-gate return (-1); 17087c478bd9Sstevel@tonic-gate } 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate /* remove local action */ 17117c478bd9Sstevel@tonic-gate action = action & (~arg_action); 17127c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0); 17137c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, action, signal); 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate /* enable deny if it must be enabled */ 17167c478bd9Sstevel@tonic-gate if (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS) { 17177c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, RCTL_LOCAL_DENY | action, 17187c478bd9Sstevel@tonic-gate signal); 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate return (0); 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate /* 17247c478bd9Sstevel@tonic-gate * prctl_setrctl 17257c478bd9Sstevel@tonic-gate * 17267c478bd9Sstevel@tonic-gate * Input 17277c478bd9Sstevel@tonic-gate * This function expects that input has been validated. In the 17287c478bd9Sstevel@tonic-gate * case of a replace operation, both old_rblk and new_rblk must 17297c478bd9Sstevel@tonic-gate * be valid resource controls. If a resource control is being 17307c478bd9Sstevel@tonic-gate * created, only new_rblk must be supplied. If a resource control 17317c478bd9Sstevel@tonic-gate * is being deleted, only new_rblk must be supplied. 17327c478bd9Sstevel@tonic-gate * 17337c478bd9Sstevel@tonic-gate * If the privilege is a priviliged type, at this time, the process 17347c478bd9Sstevel@tonic-gate * tries to take on superuser privileges. 17357c478bd9Sstevel@tonic-gate */ 17367c478bd9Sstevel@tonic-gate int 17377c478bd9Sstevel@tonic-gate prctl_setrctl(struct ps_prochandle *Pr, const char *name, 17387c478bd9Sstevel@tonic-gate rctlblk_t *old_rblk, rctlblk_t *new_rblk, uint_t flags) 17397c478bd9Sstevel@tonic-gate { 17407c478bd9Sstevel@tonic-gate int ret = 0; 17417c478bd9Sstevel@tonic-gate rctl_priv_t rblk_priv; 17427c478bd9Sstevel@tonic-gate psinfo_t psinfo; 17437c478bd9Sstevel@tonic-gate zoneid_t oldzoneid = GLOBAL_ZONEID; 17447c478bd9Sstevel@tonic-gate prpriv_t *old_prpriv = NULL, *new_prpriv = NULL; 17457c478bd9Sstevel@tonic-gate priv_set_t *eset, *pset; 17467c478bd9Sstevel@tonic-gate boolean_t relinquish_failed = B_FALSE; 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate rblk_priv = rctlblk_get_privilege(new_rblk); 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate if (rblk_priv == RCPRIV_SYSTEM) { 17517c478bd9Sstevel@tonic-gate preserve_error(gettext("cannot modify system values")); 17527c478bd9Sstevel@tonic-gate return (1); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate if (rblk_priv == RCPRIV_PRIVILEGED) { 17557c478bd9Sstevel@tonic-gate new_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid); 17567c478bd9Sstevel@tonic-gate if (new_prpriv == NULL) { 17577c478bd9Sstevel@tonic-gate preserve_error(gettext("cannot get process privileges " 17587c478bd9Sstevel@tonic-gate "for pid %d: %s"), Pstatus(Pr)->pr_pid, 17597c478bd9Sstevel@tonic-gate strerror(errno)); 17607c478bd9Sstevel@tonic-gate return (1); 17617c478bd9Sstevel@tonic-gate } 17627c478bd9Sstevel@tonic-gate /* 17637c478bd9Sstevel@tonic-gate * We only have to change the process privileges if it doesn't 17647c478bd9Sstevel@tonic-gate * already have PRIV_SYS_RESOURCE. In addition, we want to make 17657c478bd9Sstevel@tonic-gate * sure that we don't leave a process with elevated privileges, 17667c478bd9Sstevel@tonic-gate * so we make sure the process dies if we exit unexpectedly. 17677c478bd9Sstevel@tonic-gate */ 17687c478bd9Sstevel@tonic-gate eset = (priv_set_t *) 17697c478bd9Sstevel@tonic-gate &new_prpriv->pr_sets[new_prpriv->pr_setsize * 17707c478bd9Sstevel@tonic-gate priv_getsetbyname(PRIV_EFFECTIVE)]; 17717c478bd9Sstevel@tonic-gate pset = (priv_set_t *) 17727c478bd9Sstevel@tonic-gate &new_prpriv->pr_sets[new_prpriv->pr_setsize * 17737c478bd9Sstevel@tonic-gate priv_getsetbyname(PRIV_PERMITTED)]; 17747c478bd9Sstevel@tonic-gate if (!priv_ismember(eset, PRIV_SYS_RESOURCE)) { 17757c478bd9Sstevel@tonic-gate /* Keep track of original privileges */ 17767c478bd9Sstevel@tonic-gate old_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid); 17777c478bd9Sstevel@tonic-gate if (old_prpriv == NULL) { 17787c478bd9Sstevel@tonic-gate preserve_error(gettext("cannot get process " 17797c478bd9Sstevel@tonic-gate "privileges for pid %d: %s"), 17807c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid, strerror(errno)); 17817c478bd9Sstevel@tonic-gate free(new_prpriv); 17827c478bd9Sstevel@tonic-gate return (1); 17837c478bd9Sstevel@tonic-gate } 17847c478bd9Sstevel@tonic-gate (void) priv_addset(eset, PRIV_SYS_RESOURCE); 17857c478bd9Sstevel@tonic-gate (void) priv_addset(pset, PRIV_SYS_RESOURCE); 17867c478bd9Sstevel@tonic-gate if (Psetflags(Pr, PR_KLC) != 0 || 17877c478bd9Sstevel@tonic-gate Psetpriv(Pr, new_prpriv) != 0) { 17887c478bd9Sstevel@tonic-gate preserve_error(gettext("cannot set process " 17897c478bd9Sstevel@tonic-gate "privileges for pid %d: %s"), 17907c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid, strerror(errno)); 17917c478bd9Sstevel@tonic-gate (void) Punsetflags(Pr, PR_KLC); 17927c478bd9Sstevel@tonic-gate free(new_prpriv); 17937c478bd9Sstevel@tonic-gate free(old_prpriv); 17947c478bd9Sstevel@tonic-gate return (1); 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate /* 17987c478bd9Sstevel@tonic-gate * If this is a zone.* rctl, it requires more than 17997c478bd9Sstevel@tonic-gate * PRIV_SYS_RESOURCE: it wants the process to have global-zone 18007c478bd9Sstevel@tonic-gate * credentials. We temporarily grant non-global zone processes 18017c478bd9Sstevel@tonic-gate * these credentials, and make sure the process dies if we exit 18027c478bd9Sstevel@tonic-gate * unexpectedly. 18037c478bd9Sstevel@tonic-gate */ 18047c478bd9Sstevel@tonic-gate if (arg_name && 18057c478bd9Sstevel@tonic-gate arg_name_entity == RCENTITY_ZONE && 18067c478bd9Sstevel@tonic-gate getzoneid() == GLOBAL_ZONEID && 18077c478bd9Sstevel@tonic-gate proc_get_psinfo(Pstatus(Pr)->pr_pid, &psinfo) == 0 && 18087c478bd9Sstevel@tonic-gate (oldzoneid = psinfo.pr_zoneid) != GLOBAL_ZONEID) { 18097c478bd9Sstevel@tonic-gate /* 18107c478bd9Sstevel@tonic-gate * We need to give this process superuser 18117c478bd9Sstevel@tonic-gate * ("super-zone") privileges. 18127c478bd9Sstevel@tonic-gate * 18137c478bd9Sstevel@tonic-gate * Must never return without setting this back! 18147c478bd9Sstevel@tonic-gate */ 18157c478bd9Sstevel@tonic-gate if (Psetflags(Pr, PR_KLC) != 0 || 18167c478bd9Sstevel@tonic-gate Psetzoneid(Pr, GLOBAL_ZONEID) < 0) { 18177c478bd9Sstevel@tonic-gate preserve_error(gettext( 18187c478bd9Sstevel@tonic-gate "cannot set global-zone " 18197c478bd9Sstevel@tonic-gate "privileges for pid %d: %s"), 18207c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid, strerror(errno)); 18217c478bd9Sstevel@tonic-gate /* 18227c478bd9Sstevel@tonic-gate * We couldn't set the zoneid to begin with, so 18237c478bd9Sstevel@tonic-gate * there's no point in warning the user about 18247c478bd9Sstevel@tonic-gate * trying to un-set it. 18257c478bd9Sstevel@tonic-gate */ 18267c478bd9Sstevel@tonic-gate oldzoneid = GLOBAL_ZONEID; 18277c478bd9Sstevel@tonic-gate ret = 1; 18287c478bd9Sstevel@tonic-gate goto bail; 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate } 18327c478bd9Sstevel@tonic-gate /* Now, actually populate the rctlblk in the kernel */ 18337c478bd9Sstevel@tonic-gate if (flags == RCTL_REPLACE) { 18347c478bd9Sstevel@tonic-gate /* 18357c478bd9Sstevel@tonic-gate * Replace should be a delete followed by an insert. This 18367c478bd9Sstevel@tonic-gate * allows us to replace rctl value blocks which match in 18377c478bd9Sstevel@tonic-gate * privilege and value, but have updated actions, etc. 18387c478bd9Sstevel@tonic-gate * setrctl() doesn't allow a direct replace, but we 18397c478bd9Sstevel@tonic-gate * should do the right thing for the user in the command. 18407c478bd9Sstevel@tonic-gate */ 18417c478bd9Sstevel@tonic-gate if (pr_setrctl(Pr, name, NULL, 18427c478bd9Sstevel@tonic-gate old_rblk, RCTL_DELETE)) { 18437c478bd9Sstevel@tonic-gate preserve_error(gettext("failed to delete resource " 18447c478bd9Sstevel@tonic-gate "control %s for pid %d: %s"), name, 18457c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid, strerror(errno)); 18467c478bd9Sstevel@tonic-gate ret = 1; 18477c478bd9Sstevel@tonic-gate goto bail; 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate if (pr_setrctl(Pr, name, NULL, 18507c478bd9Sstevel@tonic-gate new_rblk, RCTL_INSERT)) { 18517c478bd9Sstevel@tonic-gate preserve_error(gettext("failed to insert resource " 18527c478bd9Sstevel@tonic-gate "control %s for pid %d: %s"), name, 18537c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid, strerror(errno)); 18547c478bd9Sstevel@tonic-gate ret = 1; 18557c478bd9Sstevel@tonic-gate goto bail; 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate } else if (flags == RCTL_INSERT) { 18587c478bd9Sstevel@tonic-gate if (pr_setrctl(Pr, name, NULL, 18597c478bd9Sstevel@tonic-gate new_rblk, RCTL_INSERT)) { 18607c478bd9Sstevel@tonic-gate preserve_error(gettext("failed to create resource " 18617c478bd9Sstevel@tonic-gate "control %s for pid %d: %s"), name, 18627c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid, strerror(errno)); 18637c478bd9Sstevel@tonic-gate ret = 1; 18647c478bd9Sstevel@tonic-gate goto bail; 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate } else if (flags == RCTL_DELETE) { 18677c478bd9Sstevel@tonic-gate if (pr_setrctl(Pr, name, NULL, 18687c478bd9Sstevel@tonic-gate new_rblk, RCTL_DELETE)) { 18697c478bd9Sstevel@tonic-gate preserve_error(gettext("failed to delete resource " 18707c478bd9Sstevel@tonic-gate "control %s for pid %d: %s"), name, 18717c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid, strerror(errno)); 18727c478bd9Sstevel@tonic-gate ret = 1; 18737c478bd9Sstevel@tonic-gate goto bail; 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate } 18767c478bd9Sstevel@tonic-gate bail: 18777c478bd9Sstevel@tonic-gate if (oldzoneid != GLOBAL_ZONEID) { 18787c478bd9Sstevel@tonic-gate if (Psetzoneid(Pr, oldzoneid) != 0) 18797c478bd9Sstevel@tonic-gate relinquish_failed = B_TRUE; 18807c478bd9Sstevel@tonic-gate } 18817c478bd9Sstevel@tonic-gate if (old_prpriv != NULL) { 18827c478bd9Sstevel@tonic-gate if (Psetpriv(Pr, old_prpriv) != 0) 18837c478bd9Sstevel@tonic-gate relinquish_failed = B_TRUE; 18847c478bd9Sstevel@tonic-gate free(old_prpriv); 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate if (relinquish_failed) { 18877c478bd9Sstevel@tonic-gate /* 18887c478bd9Sstevel@tonic-gate * If this failed, we can't leave a process hanging 18897c478bd9Sstevel@tonic-gate * around with elevated privileges, so we'll have to 18907c478bd9Sstevel@tonic-gate * release the process from libproc, knowing that it 18917c478bd9Sstevel@tonic-gate * will be killed (since we set PR_KLC). 18927c478bd9Sstevel@tonic-gate */ 18937c478bd9Sstevel@tonic-gate Pdestroy_agent(Pr); 18947c478bd9Sstevel@tonic-gate preserve_error(gettext("cannot relinquish privileges " 18957c478bd9Sstevel@tonic-gate "for pid %d. The process was killed."), 18967c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid); 18977c478bd9Sstevel@tonic-gate } else { 18987c478bd9Sstevel@tonic-gate if (Punsetflags(Pr, PR_KLC) != 0) 18997c478bd9Sstevel@tonic-gate preserve_error(gettext("cannot relinquish privileges " 19007c478bd9Sstevel@tonic-gate "for pid %d. The process was killed."), 19017c478bd9Sstevel@tonic-gate Pstatus(Pr)->pr_pid); 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate if (new_prpriv != NULL) 19047c478bd9Sstevel@tonic-gate free(new_prpriv); 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate return (ret); 19077c478bd9Sstevel@tonic-gate } 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate void 19107c478bd9Sstevel@tonic-gate print_priv(rctl_priv_t local_priv, char *format) 19117c478bd9Sstevel@tonic-gate { 19127c478bd9Sstevel@tonic-gate char pstring[11]; 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate switch (local_priv) { 19157c478bd9Sstevel@tonic-gate case RCPRIV_BASIC: 19167c478bd9Sstevel@tonic-gate (void) strcpy(pstring, "basic"); 19177c478bd9Sstevel@tonic-gate break; 19187c478bd9Sstevel@tonic-gate case RCPRIV_PRIVILEGED: 19197c478bd9Sstevel@tonic-gate (void) strcpy(pstring, "privileged"); 19207c478bd9Sstevel@tonic-gate break; 19217c478bd9Sstevel@tonic-gate case RCPRIV_SYSTEM: 19227c478bd9Sstevel@tonic-gate (void) strcpy(pstring, "system"); 19237c478bd9Sstevel@tonic-gate break; 19247c478bd9Sstevel@tonic-gate default: 19257c478bd9Sstevel@tonic-gate (void) sprintf(pstring, "%d", local_priv); 19267c478bd9Sstevel@tonic-gate break; 19277c478bd9Sstevel@tonic-gate } 19287c478bd9Sstevel@tonic-gate /* LINTED */ 19297c478bd9Sstevel@tonic-gate (void) fprintf(stdout, format, pstring); 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate void 19337c478bd9Sstevel@tonic-gate print_local_action(int action, int *signalp, char *format) 19347c478bd9Sstevel@tonic-gate { 19357c478bd9Sstevel@tonic-gate char sig[SIG2STR_MAX]; 19367c478bd9Sstevel@tonic-gate char sigstring[SIG2STR_MAX + 7]; 19377c478bd9Sstevel@tonic-gate char astring[5 + SIG2STR_MAX + 7]; 19387c478bd9Sstevel@tonic-gate int set = 0; 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate astring[0] = '\0'; 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate if (action == RCTL_LOCAL_NOACTION) { 19437c478bd9Sstevel@tonic-gate (void) strcat(astring, "none"); 19447c478bd9Sstevel@tonic-gate set++; 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate if (action & RCTL_LOCAL_DENY) { 19477c478bd9Sstevel@tonic-gate (void) strcat(astring, "deny"); 19487c478bd9Sstevel@tonic-gate set++; 19497c478bd9Sstevel@tonic-gate } 19507c478bd9Sstevel@tonic-gate if ((action & RCTL_LOCAL_DENY) && 19517c478bd9Sstevel@tonic-gate (action & RCTL_LOCAL_SIGNAL)) { 19527c478bd9Sstevel@tonic-gate (void) strcat(astring, ","); 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate if (action & RCTL_LOCAL_SIGNAL) { 19557c478bd9Sstevel@tonic-gate if (sig2str(*signalp, sig)) 19567c478bd9Sstevel@tonic-gate (void) snprintf(sigstring, sizeof (astring), 19577c478bd9Sstevel@tonic-gate "signal=%d", *signalp); 19587c478bd9Sstevel@tonic-gate else 19597c478bd9Sstevel@tonic-gate (void) snprintf(sigstring, sizeof (astring), 19607c478bd9Sstevel@tonic-gate "signal=%s", sig); 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate (void) strcat(astring, sigstring); 19637c478bd9Sstevel@tonic-gate set++; 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate if (set) 19667c478bd9Sstevel@tonic-gate /* LINTED */ 19677c478bd9Sstevel@tonic-gate (void) fprintf(stdout, format, astring); 19687c478bd9Sstevel@tonic-gate else 19697c478bd9Sstevel@tonic-gate /* LINTED */ 19707c478bd9Sstevel@tonic-gate (void) fprintf(stdout, format, action); 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate /* 19747c478bd9Sstevel@tonic-gate * This function is used to grab the process matching the recipient pid 19757c478bd9Sstevel@tonic-gate */ 19767c478bd9Sstevel@tonic-gate pid_t 19777c478bd9Sstevel@tonic-gate regrab_process(pid_t pid, pr_info_handle_t *p, int priv, int *gret) 19787c478bd9Sstevel@tonic-gate { 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate char pidstring[24]; 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate gret = 0; 19837c478bd9Sstevel@tonic-gate if (pid == -1) 19847c478bd9Sstevel@tonic-gate return (p->pid); 19857c478bd9Sstevel@tonic-gate if (p->pid == pid) 19867c478bd9Sstevel@tonic-gate return (p->pid); 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate release_process(p->pr); 19897c478bd9Sstevel@tonic-gate (void) memset(p, 0, sizeof (*p)); 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate (void) snprintf(pidstring, 24, "%d", pid); 19927c478bd9Sstevel@tonic-gate return (grab_process_by_id( 19937c478bd9Sstevel@tonic-gate pidstring, RCENTITY_PROCESS, p, priv, gret)); 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /* 19977c478bd9Sstevel@tonic-gate * int grab_process_by_id(char *, rctl_entity_t, pr_info_handle_t *, int, int *) 19987c478bd9Sstevel@tonic-gate * 19997c478bd9Sstevel@tonic-gate * Input 20007c478bd9Sstevel@tonic-gate * Supply a non-NULL string containing: 20017c478bd9Sstevel@tonic-gate * - logical project/zone name or project/zone number if type is 20027c478bd9Sstevel@tonic-gate * RCENTITY_PROJECT or RCENTITY_ZONE 20037c478bd9Sstevel@tonic-gate * - task number if type is RCENTITY_TYPE 20047c478bd9Sstevel@tonic-gate * - a pid if type is RCENTITY_PID 20057c478bd9Sstevel@tonic-gate * Also supply an un-allocated prochandle, and an allocated info_handle. 20067c478bd9Sstevel@tonic-gate * This function assumes that the type is set. 20077c478bd9Sstevel@tonic-gate * If priv is not RCPRIV_BASIC, the grabbed process is required to have 20087c478bd9Sstevel@tonic-gate * PRIV_SYS_RESOURCE in it's limit set. 20097c478bd9Sstevel@tonic-gate * 20107c478bd9Sstevel@tonic-gate * Return Values 20117c478bd9Sstevel@tonic-gate * Returns 0 on success and 1 on failure. If there is a process 20127c478bd9Sstevel@tonic-gate * running under the specified id, success is returned, and 20137c478bd9Sstevel@tonic-gate * Pr is pointed to the process. Success will be returned and Pr 20147c478bd9Sstevel@tonic-gate * set to NULL if the matching process is our own. 20157c478bd9Sstevel@tonic-gate * If success is returned, psinfo will be valid, and pid will 20167c478bd9Sstevel@tonic-gate * be the process number. The process will also be held at the 20177c478bd9Sstevel@tonic-gate * end, so release_process should be used by the caller. 20187c478bd9Sstevel@tonic-gate * 20197c478bd9Sstevel@tonic-gate * This function assumes that signals are caught already so that libproc 20207c478bd9Sstevel@tonic-gate * can be safely used. 20217c478bd9Sstevel@tonic-gate * 20227c478bd9Sstevel@tonic-gate * Return Values 20237c478bd9Sstevel@tonic-gate * pid - Process found and grabbed 20247c478bd9Sstevel@tonic-gate * -1 - Error 20257c478bd9Sstevel@tonic-gate */ 20267c478bd9Sstevel@tonic-gate pid_t 20277c478bd9Sstevel@tonic-gate grab_process_by_id(char *idname, rctl_entity_t type, pr_info_handle_t *p, 20287c478bd9Sstevel@tonic-gate int priv, int *gret) 20297c478bd9Sstevel@tonic-gate { 20307c478bd9Sstevel@tonic-gate char prbuf[PROJECT_BUFSZ]; 20317c478bd9Sstevel@tonic-gate projid_t projid; 20327c478bd9Sstevel@tonic-gate taskid_t taskid; 20337c478bd9Sstevel@tonic-gate zoneid_t zoneid; 20347c478bd9Sstevel@tonic-gate zoneid_t zone_self; 20357c478bd9Sstevel@tonic-gate struct project proj; 20367c478bd9Sstevel@tonic-gate DIR *dirp; 20377c478bd9Sstevel@tonic-gate struct dirent *dentp; 20387c478bd9Sstevel@tonic-gate int found = 0; 20397c478bd9Sstevel@tonic-gate int pid_self; 20407c478bd9Sstevel@tonic-gate int ret; 20417c478bd9Sstevel@tonic-gate int gret_in; 20427c478bd9Sstevel@tonic-gate int intidname; 20437c478bd9Sstevel@tonic-gate char *end; 20447c478bd9Sstevel@tonic-gate prpriv_t *prpriv; 20457c478bd9Sstevel@tonic-gate priv_set_t *prset; 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate gret_in = *gret; 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate /* get our pid se we do not try to operate on self */ 20507c478bd9Sstevel@tonic-gate pid_self = getpid(); 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate /* Store integer version of id */ 20537c478bd9Sstevel@tonic-gate intidname = strtoul(idname, &end, 10); 20547c478bd9Sstevel@tonic-gate if (errno || *end != '\0' || end == idname) { 20557c478bd9Sstevel@tonic-gate intidname = -1; 20567c478bd9Sstevel@tonic-gate } 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate /* 20597c478bd9Sstevel@tonic-gate * get our zoneid so we don't try to operate on a project in 20607c478bd9Sstevel@tonic-gate * another zone 20617c478bd9Sstevel@tonic-gate */ 20627c478bd9Sstevel@tonic-gate zone_self = getzoneid(); 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate if (idname == NULL || strcmp(idname, "") == 0) { 20657c478bd9Sstevel@tonic-gate warn(gettext("id name cannot be nuint64\n")); 20667c478bd9Sstevel@tonic-gate return (-1); 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate /* 20697c478bd9Sstevel@tonic-gate * Set up zoneid, projid or taskid, as appropriate, so that comparisons 20707c478bd9Sstevel@tonic-gate * can be done later with the input. 20717c478bd9Sstevel@tonic-gate */ 20727c478bd9Sstevel@tonic-gate if (type == RCENTITY_ZONE) { 20737c478bd9Sstevel@tonic-gate if (zone_get_id(idname, &zoneid) != 0) { 20747c478bd9Sstevel@tonic-gate warn(gettext("%s: unknown zone\n"), idname); 20757c478bd9Sstevel@tonic-gate return (-1); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate } else if (type == RCENTITY_PROJECT) { 20787c478bd9Sstevel@tonic-gate if (getprojbyname(idname, &proj, prbuf, PROJECT_BUFSZ) 20797c478bd9Sstevel@tonic-gate == NULL) { 20807c478bd9Sstevel@tonic-gate if (getprojbyid(intidname, &proj, prbuf, 20817c478bd9Sstevel@tonic-gate PROJECT_BUFSZ) == NULL) { 20827c478bd9Sstevel@tonic-gate warn(gettext("%s: cannot find project\n"), 20837c478bd9Sstevel@tonic-gate idname); 20847c478bd9Sstevel@tonic-gate return (-1); 20857c478bd9Sstevel@tonic-gate } 20867c478bd9Sstevel@tonic-gate } 20877c478bd9Sstevel@tonic-gate projid = proj.pj_projid; 20887c478bd9Sstevel@tonic-gate } else if (type == RCENTITY_TASK) { 20897c478bd9Sstevel@tonic-gate taskid = (taskid_t)atol(idname); 20907c478bd9Sstevel@tonic-gate } 20917c478bd9Sstevel@tonic-gate /* 20927c478bd9Sstevel@tonic-gate * Projects and tasks need to search through /proc for 20937c478bd9Sstevel@tonic-gate * a parent process. 20947c478bd9Sstevel@tonic-gate */ 20957c478bd9Sstevel@tonic-gate if (type == RCENTITY_ZONE || type == RCENTITY_PROJECT || 20967c478bd9Sstevel@tonic-gate type == RCENTITY_TASK) { 20977c478bd9Sstevel@tonic-gate if ((dirp = opendir("/proc")) == NULL) { 20987c478bd9Sstevel@tonic-gate warn(gettext("%s: cannot open /proc directory\n"), 20997c478bd9Sstevel@tonic-gate idname); 21007c478bd9Sstevel@tonic-gate return (-1); 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate /* 21037c478bd9Sstevel@tonic-gate * Look through all processes in /proc. For each process, 21047c478bd9Sstevel@tonic-gate * check if the pr_projid in their psinfo matches the 21057c478bd9Sstevel@tonic-gate * specified id. 21067c478bd9Sstevel@tonic-gate */ 21077c478bd9Sstevel@tonic-gate while (dentp = readdir(dirp)) { 21087c478bd9Sstevel@tonic-gate p->pid = atoi(dentp->d_name); 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate /* Skip self */ 21117c478bd9Sstevel@tonic-gate if (p->pid == pid_self) 21127c478bd9Sstevel@tonic-gate continue; 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate if (proc_get_psinfo(p->pid, &(p->psinfo)) != 0) 21157c478bd9Sstevel@tonic-gate continue; 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate /* Skip process if it is not what we are looking for */ 21187c478bd9Sstevel@tonic-gate if (type == RCENTITY_ZONE && 21197c478bd9Sstevel@tonic-gate (p->psinfo).pr_zoneid != zoneid) { 21207c478bd9Sstevel@tonic-gate continue; 2121c3ea2840SMenno Lageman } else if (type == RCENTITY_PROJECT && 21227c478bd9Sstevel@tonic-gate ((p->psinfo).pr_projid != projid || 21237c478bd9Sstevel@tonic-gate (p->psinfo).pr_zoneid != zone_self)) { 21247c478bd9Sstevel@tonic-gate continue; 21257c478bd9Sstevel@tonic-gate } else if (type == RCENTITY_TASK && 21267c478bd9Sstevel@tonic-gate (p->psinfo).pr_taskid != taskid) { 21277c478bd9Sstevel@tonic-gate continue; 21287c478bd9Sstevel@tonic-gate } 21297c478bd9Sstevel@tonic-gate /* attempt to grab process */ 21307c478bd9Sstevel@tonic-gate if (grab_process(p, gret) != 0) 21317c478bd9Sstevel@tonic-gate continue; 21327c478bd9Sstevel@tonic-gate 21337c478bd9Sstevel@tonic-gate /* 21347c478bd9Sstevel@tonic-gate * Re-confirm that this process is still running as 21357c478bd9Sstevel@tonic-gate * part of the specified project or task. If it 21367c478bd9Sstevel@tonic-gate * doesn't match, release the process and return an 21377c478bd9Sstevel@tonic-gate * error. This should only be done if the Pr struct is 21387c478bd9Sstevel@tonic-gate * not NULL. 21397c478bd9Sstevel@tonic-gate */ 21407c478bd9Sstevel@tonic-gate if (type == RCENTITY_PROJECT) { 21417c478bd9Sstevel@tonic-gate if (pr_getprojid(p->pr) != projid || 21427c478bd9Sstevel@tonic-gate pr_getzoneid(p->pr) != zone_self) { 21437c478bd9Sstevel@tonic-gate release_process(p->pr); 21447c478bd9Sstevel@tonic-gate continue; 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate } else if (type == RCENTITY_TASK) { 21477c478bd9Sstevel@tonic-gate if (pr_gettaskid(p->pr) != taskid) { 21487c478bd9Sstevel@tonic-gate release_process(p->pr); 21497c478bd9Sstevel@tonic-gate continue; 21507c478bd9Sstevel@tonic-gate } 21517c478bd9Sstevel@tonic-gate } else if (type == RCENTITY_ZONE) { 21527c478bd9Sstevel@tonic-gate if (pr_getzoneid(p->pr) != zoneid) { 21537c478bd9Sstevel@tonic-gate release_process(p->pr); 21547c478bd9Sstevel@tonic-gate continue; 21557c478bd9Sstevel@tonic-gate } 21567c478bd9Sstevel@tonic-gate } 21577c478bd9Sstevel@tonic-gate 21587c478bd9Sstevel@tonic-gate /* 21597c478bd9Sstevel@tonic-gate * If we are setting a privileged resource control, 21607c478bd9Sstevel@tonic-gate * verify that process has PRIV_SYS_RESOURCE in it's 21617c478bd9Sstevel@tonic-gate * limit set. If it does not, then we will not be 21627c478bd9Sstevel@tonic-gate * able to give this process the privilege it needs 21637c478bd9Sstevel@tonic-gate * to set the resource control. 21647c478bd9Sstevel@tonic-gate */ 21657c478bd9Sstevel@tonic-gate if (priv != RCPRIV_BASIC) { 21667c478bd9Sstevel@tonic-gate prpriv = proc_get_priv(p->pid); 21677c478bd9Sstevel@tonic-gate if (prpriv == NULL) { 21687c478bd9Sstevel@tonic-gate release_process(p->pr); 21697c478bd9Sstevel@tonic-gate continue; 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate prset = (priv_set_t *) 21727c478bd9Sstevel@tonic-gate &prpriv->pr_sets[prpriv->pr_setsize * 21737c478bd9Sstevel@tonic-gate priv_getsetbyname(PRIV_LIMIT)]; 21747c478bd9Sstevel@tonic-gate if (!priv_ismember(prset, PRIV_SYS_RESOURCE)) { 21757c478bd9Sstevel@tonic-gate release_process(p->pr); 21767c478bd9Sstevel@tonic-gate continue; 21777c478bd9Sstevel@tonic-gate } 21787c478bd9Sstevel@tonic-gate } 21797c478bd9Sstevel@tonic-gate found = 1; 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate p->taskid = pr_gettaskid(p->pr); 21827c478bd9Sstevel@tonic-gate p->projid = pr_getprojid(p->pr); 21837c478bd9Sstevel@tonic-gate p->zoneid = pr_getzoneid(p->pr); 21847c478bd9Sstevel@tonic-gate 21857c478bd9Sstevel@tonic-gate break; 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate (void) closedir(dirp); 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate if (found == 0) { 21907c478bd9Sstevel@tonic-gate warn(gettext("%s: No controllable process found in " 21917c478bd9Sstevel@tonic-gate "task, project, or zone.\n"), idname); 21927c478bd9Sstevel@tonic-gate return (-1); 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate return (p->pid); 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate } else if (type == RCENTITY_PROCESS) { 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate /* fail if self */ 21997c478bd9Sstevel@tonic-gate if (p->pid == pid_self) { 22007c478bd9Sstevel@tonic-gate 22017c478bd9Sstevel@tonic-gate warn(gettext("%s: cannot control self"), idname); 22027c478bd9Sstevel@tonic-gate return (-1); 22037c478bd9Sstevel@tonic-gate } 22047c478bd9Sstevel@tonic-gate /* 22057c478bd9Sstevel@tonic-gate * Process types need to be set up with the correct pid 22067c478bd9Sstevel@tonic-gate * and psinfo structure. 22077c478bd9Sstevel@tonic-gate */ 22087c478bd9Sstevel@tonic-gate if ((p->pid = proc_arg_psinfo(idname, PR_ARG_PIDS, 22097c478bd9Sstevel@tonic-gate &(p->psinfo), gret)) == -1) { 22107c478bd9Sstevel@tonic-gate warn(gettext("%s: cannot examine: %s"), idname, 22117c478bd9Sstevel@tonic-gate Pgrab_error(*gret)); 22127c478bd9Sstevel@tonic-gate return (-1); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate /* grab process */ 22157c478bd9Sstevel@tonic-gate ret = grab_process(p, gret); 22167c478bd9Sstevel@tonic-gate if (ret == 1) { 22177c478bd9Sstevel@tonic-gate /* Don't print error if G_SYS is allowed */ 22187c478bd9Sstevel@tonic-gate if (gret_in == G_SYS && *gret == G_SYS) { 22197c478bd9Sstevel@tonic-gate return (-1); 22207c478bd9Sstevel@tonic-gate } else { 22217c478bd9Sstevel@tonic-gate warn(gettext("%s: cannot control: %s"), idname, 22227c478bd9Sstevel@tonic-gate Pgrab_error(*gret)); 22237c478bd9Sstevel@tonic-gate return (-1); 22247c478bd9Sstevel@tonic-gate } 22257c478bd9Sstevel@tonic-gate } else if (ret == 2) { 22267c478bd9Sstevel@tonic-gate ret = errno; 22277c478bd9Sstevel@tonic-gate warn(gettext("%s: cannot control: %s"), idname, 22287c478bd9Sstevel@tonic-gate strerror(ret)); 22297c478bd9Sstevel@tonic-gate return (-1); 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate p->taskid = pr_gettaskid(p->pr); 22327c478bd9Sstevel@tonic-gate p->projid = pr_getprojid(p->pr); 22337c478bd9Sstevel@tonic-gate p->zoneid = pr_getzoneid(p->pr); 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate return (p->pid); 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate } else { 22387c478bd9Sstevel@tonic-gate warn(gettext("%s: unknown resource entity type %d\n"), idname, 22397c478bd9Sstevel@tonic-gate type); 22407c478bd9Sstevel@tonic-gate return (-1); 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate /* 22457c478bd9Sstevel@tonic-gate * Do the work required to manipulate a process through libproc. 22467c478bd9Sstevel@tonic-gate * If grab_process() returns no errors (0), then release_process() 22477c478bd9Sstevel@tonic-gate * must eventually be called. 22487c478bd9Sstevel@tonic-gate * 22497c478bd9Sstevel@tonic-gate * Return values: 22507c478bd9Sstevel@tonic-gate * 0 Successful creation of agent thread 22517c478bd9Sstevel@tonic-gate * 1 Error grabbing 22527c478bd9Sstevel@tonic-gate * 2 Error creating agent 22537c478bd9Sstevel@tonic-gate */ 22547c478bd9Sstevel@tonic-gate int 22557c478bd9Sstevel@tonic-gate grab_process(pr_info_handle_t *p, int *gret) 22567c478bd9Sstevel@tonic-gate { 22577c478bd9Sstevel@tonic-gate 22587c478bd9Sstevel@tonic-gate if ((p->pr = Pgrab(p->pid, arg_force, gret)) != NULL) { 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate if (Psetflags(p->pr, PR_RLC) != 0) { 22617c478bd9Sstevel@tonic-gate Prelease(p->pr, 0); 22627c478bd9Sstevel@tonic-gate return (1); 22637c478bd9Sstevel@tonic-gate } 22647c478bd9Sstevel@tonic-gate if (Pcreate_agent(p->pr) == 0) { 22657c478bd9Sstevel@tonic-gate return (0); 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate } else { 22687c478bd9Sstevel@tonic-gate Prelease(p->pr, 0); 22697c478bd9Sstevel@tonic-gate return (2); 22707c478bd9Sstevel@tonic-gate } 22717c478bd9Sstevel@tonic-gate } else { 22727c478bd9Sstevel@tonic-gate return (1); 22737c478bd9Sstevel@tonic-gate } 22747c478bd9Sstevel@tonic-gate } 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate /* 22777c478bd9Sstevel@tonic-gate * Release the specified process. This destroys the agent 22787c478bd9Sstevel@tonic-gate * and releases the process. If the process is NULL, nothing 22797c478bd9Sstevel@tonic-gate * is done. This function should only be called if grab_process() 22807c478bd9Sstevel@tonic-gate * has previously been called and returned success. 22817c478bd9Sstevel@tonic-gate * 22827c478bd9Sstevel@tonic-gate * This function is Pgrab-safe. 22837c478bd9Sstevel@tonic-gate */ 22847c478bd9Sstevel@tonic-gate void 22857c478bd9Sstevel@tonic-gate release_process(struct ps_prochandle *Pr) 22867c478bd9Sstevel@tonic-gate { 22877c478bd9Sstevel@tonic-gate if (Pr == NULL) 22887c478bd9Sstevel@tonic-gate return; 22897c478bd9Sstevel@tonic-gate 22907c478bd9Sstevel@tonic-gate Pdestroy_agent(Pr); 22917c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 22927c478bd9Sstevel@tonic-gate } 22937c478bd9Sstevel@tonic-gate 22947c478bd9Sstevel@tonic-gate /* 22957c478bd9Sstevel@tonic-gate * preserve_error(char *, ...) 22967c478bd9Sstevel@tonic-gate * 22977c478bd9Sstevel@tonic-gate * preserve_error() should be called rather than warn() by any 22987c478bd9Sstevel@tonic-gate * function that is called while the victim process is held by Pgrab. 22997c478bd9Sstevel@tonic-gate * It will save the error until the process has been un-controlled 23007c478bd9Sstevel@tonic-gate * and output is reasonable again. 23017c478bd9Sstevel@tonic-gate * 23027c478bd9Sstevel@tonic-gate * Note that multiple errors are not stored. Any error in these 23037c478bd9Sstevel@tonic-gate * sections should be critical and return immediately. 23047c478bd9Sstevel@tonic-gate * 23057c478bd9Sstevel@tonic-gate * This function is Pgrab-safe. 23067c478bd9Sstevel@tonic-gate * 23077c478bd9Sstevel@tonic-gate * Since this function may copy untrusted command line arguments to 23087c478bd9Sstevel@tonic-gate * global_error, security practices require that global_error never be 23097c478bd9Sstevel@tonic-gate * printed directly. Use printf("%s\n", global_error) or equivalent. 23107c478bd9Sstevel@tonic-gate */ 23117c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 23127c478bd9Sstevel@tonic-gate void 23137c478bd9Sstevel@tonic-gate preserve_error(char *format, ...) 23147c478bd9Sstevel@tonic-gate { 23157c478bd9Sstevel@tonic-gate va_list alist; 23167c478bd9Sstevel@tonic-gate 23177c478bd9Sstevel@tonic-gate va_start(alist, format); 23187c478bd9Sstevel@tonic-gate 23197c478bd9Sstevel@tonic-gate /* 23207c478bd9Sstevel@tonic-gate * GLOBAL_ERR_SZ is pretty big. If the error is longer 23217c478bd9Sstevel@tonic-gate * than that, just truncate it, rather than chance missing 23227c478bd9Sstevel@tonic-gate * the error altogether. 23237c478bd9Sstevel@tonic-gate */ 23247c478bd9Sstevel@tonic-gate (void) vsnprintf(global_error, GLOBAL_ERR_SZ-1, format, alist); 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate va_end(alist); 23277c478bd9Sstevel@tonic-gate } 2328