1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * rcm scripting module: 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * This module implements rcm scripting interfaces. 33*0Sstevel@tonic-gate * It translates rcm module based interfaces to rcm script based 34*0Sstevel@tonic-gate * interfaces. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * Entry points: 37*0Sstevel@tonic-gate * 38*0Sstevel@tonic-gate * int script_main_init() 39*0Sstevel@tonic-gate * Initialize the rcm scripting framework. 40*0Sstevel@tonic-gate * Called during the rcm daemon initialization 41*0Sstevel@tonic-gate * 42*0Sstevel@tonic-gate * int script_main_fini() 43*0Sstevel@tonic-gate * Called at the time of the rcm daemon exit. 44*0Sstevel@tonic-gate * 45*0Sstevel@tonic-gate * struct rcm_mod_ops *script_init(module_t *module) 46*0Sstevel@tonic-gate * Initialize the given script. 47*0Sstevel@tonic-gate * module->name contains the name of the script. 48*0Sstevel@tonic-gate * Called at the time of loading scripts. 49*0Sstevel@tonic-gate * Semantics are similar to module init. 50*0Sstevel@tonic-gate * 51*0Sstevel@tonic-gate * char *script_info(module_t *module) 52*0Sstevel@tonic-gate * Called when the rcm daemon wishes to get the script information. 53*0Sstevel@tonic-gate * module->name contains the name of the script. 54*0Sstevel@tonic-gate * Semantics are similar to module info. 55*0Sstevel@tonic-gate * 56*0Sstevel@tonic-gate * int script_fini(module_t *module) 57*0Sstevel@tonic-gate * Called before removing the script. 58*0Sstevel@tonic-gate * module->name contains the name of the script. 59*0Sstevel@tonic-gate * Semantics are similar to module fini. 60*0Sstevel@tonic-gate * 61*0Sstevel@tonic-gate * In addition to the above entry points rcm_mod_ops structure contains 62*0Sstevel@tonic-gate * the other entry points. A pointer to this structure is returned when 63*0Sstevel@tonic-gate * script_init() is called. 64*0Sstevel@tonic-gate */ 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate #include "rcm_impl.h" 67*0Sstevel@tonic-gate #include "rcm_script_impl.h" 68*0Sstevel@tonic-gate #include <sys/resource.h> 69*0Sstevel@tonic-gate #include <procfs.h> 70*0Sstevel@tonic-gate #include <sys/proc.h> 71*0Sstevel@tonic-gate #include <ctype.h> 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate /* 74*0Sstevel@tonic-gate * All rcm scripting commands are enumerated here. 75*0Sstevel@tonic-gate * NOTE: command positions in script_cmd_id_t and script_cmd_name must match. 76*0Sstevel@tonic-gate */ 77*0Sstevel@tonic-gate typedef enum { 78*0Sstevel@tonic-gate C_SCRIPTINFO, 79*0Sstevel@tonic-gate C_RESOURCEINFO, 80*0Sstevel@tonic-gate C_REGISTER, 81*0Sstevel@tonic-gate C_QUERYREMOVE, 82*0Sstevel@tonic-gate C_PREREMOVE, 83*0Sstevel@tonic-gate C_POSTREMOVE, 84*0Sstevel@tonic-gate C_UNDOREMOVE, 85*0Sstevel@tonic-gate C_QUERYCAPACITY, 86*0Sstevel@tonic-gate C_PRECAPACITY, 87*0Sstevel@tonic-gate C_POSTCAPACITY, 88*0Sstevel@tonic-gate C_QUERYSUSPEND, 89*0Sstevel@tonic-gate C_PRESUSPEND, 90*0Sstevel@tonic-gate C_POSTRESUME, 91*0Sstevel@tonic-gate C_CANCELSUSPEND 92*0Sstevel@tonic-gate } script_cmd_id_t; 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* NOTE: command positions in script_cmd_id_t and script_cmd_name must match */ 95*0Sstevel@tonic-gate static char *script_cmd_name[] = { 96*0Sstevel@tonic-gate "scriptinfo", 97*0Sstevel@tonic-gate "resourceinfo", 98*0Sstevel@tonic-gate "register", 99*0Sstevel@tonic-gate "queryremove", 100*0Sstevel@tonic-gate "preremove", 101*0Sstevel@tonic-gate "postremove", 102*0Sstevel@tonic-gate "undoremove", 103*0Sstevel@tonic-gate "querycapacity", 104*0Sstevel@tonic-gate "precapacity", 105*0Sstevel@tonic-gate "postcapacity", 106*0Sstevel@tonic-gate "querysuspend", 107*0Sstevel@tonic-gate "presuspend", 108*0Sstevel@tonic-gate "postresume", 109*0Sstevel@tonic-gate "cancelsuspend", 110*0Sstevel@tonic-gate NULL 111*0Sstevel@tonic-gate }; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* 114*0Sstevel@tonic-gate * All rcm scripting data items are enumerated here. 115*0Sstevel@tonic-gate * NOTE: data item positions in script_data_item_id_t and 116*0Sstevel@tonic-gate * script_data_item_name must match. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate typedef enum { 119*0Sstevel@tonic-gate D_SCRIPT_VERSION, 120*0Sstevel@tonic-gate D_SCRIPT_FUNC_INFO, 121*0Sstevel@tonic-gate D_CMD_TIMEOUT, 122*0Sstevel@tonic-gate D_RESOURCE_NAME, 123*0Sstevel@tonic-gate D_RESOURCE_USAGE_INFO, 124*0Sstevel@tonic-gate D_FAILURE_REASON, 125*0Sstevel@tonic-gate D_LOG_ERR, 126*0Sstevel@tonic-gate D_LOG_WARN, 127*0Sstevel@tonic-gate D_LOG_INFO, 128*0Sstevel@tonic-gate D_LOG_DEBUG 129*0Sstevel@tonic-gate } script_data_item_id_t; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate /* 132*0Sstevel@tonic-gate * NOTE: data item positions in script_data_item_id_t and 133*0Sstevel@tonic-gate * script_data_item_name must match. 134*0Sstevel@tonic-gate */ 135*0Sstevel@tonic-gate static const char *script_data_item_name[] = { 136*0Sstevel@tonic-gate "rcm_script_version", 137*0Sstevel@tonic-gate "rcm_script_func_info", 138*0Sstevel@tonic-gate "rcm_cmd_timeout", 139*0Sstevel@tonic-gate "rcm_resource_name", 140*0Sstevel@tonic-gate "rcm_resource_usage_info", 141*0Sstevel@tonic-gate "rcm_failure_reason", 142*0Sstevel@tonic-gate "rcm_log_err", 143*0Sstevel@tonic-gate "rcm_log_warn", 144*0Sstevel@tonic-gate "rcm_log_info", 145*0Sstevel@tonic-gate "rcm_log_debug", 146*0Sstevel@tonic-gate NULL 147*0Sstevel@tonic-gate }; 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * Maximum number of rcm scripts that can run in parallel. 151*0Sstevel@tonic-gate * RCM daemon has no limit on the number of scripts supported. But 152*0Sstevel@tonic-gate * at most it runs script_max_parallelism number of scripts in parallel. 153*0Sstevel@tonic-gate * For each running script rcm daemon consumes two file descriptors 154*0Sstevel@tonic-gate * in order to communicate with the script via pipes. 155*0Sstevel@tonic-gate * So maximum number of file descriptor entries consumed by rcm daemon 156*0Sstevel@tonic-gate * on behalf of rcm scripts is "script_max_parallelism * 2" 157*0Sstevel@tonic-gate */ 158*0Sstevel@tonic-gate static const int script_max_parallelism = 64; 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate /* 161*0Sstevel@tonic-gate * semaphore to limit the number of rcm script processes running in 162*0Sstevel@tonic-gate * parallel to script_max_parallelism. 163*0Sstevel@tonic-gate */ 164*0Sstevel@tonic-gate static sema_t script_process_sema; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* mutex to protect the any global data */ 167*0Sstevel@tonic-gate static mutex_t script_lock; 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* contains head to a queue of script_info structures */ 170*0Sstevel@tonic-gate static rcm_queue_t script_info_q; 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate /* 173*0Sstevel@tonic-gate * This mmapped state file is used to store the process id and 174*0Sstevel@tonic-gate * rcm script name of all currently running rcm scripts. 175*0Sstevel@tonic-gate */ 176*0Sstevel@tonic-gate static const char *script_ps_state_file = "/var/run/rcm_script_state"; 177*0Sstevel@tonic-gate static state_file_descr_t script_ps_statefd; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate static char *script_env_noforce = "RCM_ENV_FORCE=FALSE"; 180*0Sstevel@tonic-gate static char *script_env_force = "RCM_ENV_FORCE=TRUE"; 181*0Sstevel@tonic-gate static char *script_env_interval = "RCM_ENV_INTERVAL=%ld"; 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate #define RSCR_TRACE RCM_TRACE1 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* rcm script base environment */ 186*0Sstevel@tonic-gate static char *script_env[MAX_ENV_PARAMS]; 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate struct rlimit file_limit; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate /* function prototypes */ 191*0Sstevel@tonic-gate static void build_env(void); 192*0Sstevel@tonic-gate static void copy_env(char *[], char *[]); 193*0Sstevel@tonic-gate static void open_state_file(const char *, state_file_descr_t *, size_t, int, 194*0Sstevel@tonic-gate uint32_t); 195*0Sstevel@tonic-gate static void truncate_state_file(state_file_descr_t *); 196*0Sstevel@tonic-gate static void close_state_file(const char *, state_file_descr_t *); 197*0Sstevel@tonic-gate static void grow_state_file(state_file_descr_t *); 198*0Sstevel@tonic-gate static void *get_state_element(state_file_descr_t *, int, int *); 199*0Sstevel@tonic-gate static void *allocate_state_element(state_file_descr_t *, int *); 200*0Sstevel@tonic-gate static void free_state_element(void *); 201*0Sstevel@tonic-gate static void script_ps_state_file_kill_pids(void); 202*0Sstevel@tonic-gate static void script_ps_state_file_add_entry(pid_t, char *); 203*0Sstevel@tonic-gate static void script_ps_state_file_remove_entry(pid_t); 204*0Sstevel@tonic-gate static int dname_to_id(char *); 205*0Sstevel@tonic-gate static void script_process_sema_wait(void); 206*0Sstevel@tonic-gate static int run_script(script_info_t *, char *[], char *[], char **); 207*0Sstevel@tonic-gate static int get_line(int fd, char *, char *, int, size_t *, time_t, int *); 208*0Sstevel@tonic-gate static void script_exited(script_info_t *); 209*0Sstevel@tonic-gate static int kill_pid(pid_t); 210*0Sstevel@tonic-gate static void kill_script(script_info_t *); 211*0Sstevel@tonic-gate static char *flags_to_name(int, char *, int); 212*0Sstevel@tonic-gate static void fill_argv(script_info_t *, char *[], char *); 213*0Sstevel@tonic-gate static void *read_stderr(script_info_t *); 214*0Sstevel@tonic-gate static int process_dataitem(script_info_t *, int, char *, char **); 215*0Sstevel@tonic-gate static int do_cmd(script_info_t *, char *[], char *[], char **); 216*0Sstevel@tonic-gate static int do_script_info(script_info_t *); 217*0Sstevel@tonic-gate static int do_dr(script_info_t *, char *[], char *[], char **); 218*0Sstevel@tonic-gate static int script_get_info(rcm_handle_t *, char *, pid_t, uint_t, char **, 219*0Sstevel@tonic-gate char **, nvlist_t *, rcm_info_t **); 220*0Sstevel@tonic-gate static void add_for_unregister(script_info_t *); 221*0Sstevel@tonic-gate static void remove_from_unregister(script_info_t *, char *); 222*0Sstevel@tonic-gate static void complete_unregister(script_info_t *); 223*0Sstevel@tonic-gate static int script_register_interest(rcm_handle_t *); 224*0Sstevel@tonic-gate static void add_drreq(script_info_t *, char *); 225*0Sstevel@tonic-gate static void remove_drreq(script_info_t *, char *); 226*0Sstevel@tonic-gate static void remove_drreq_all(script_info_t *); 227*0Sstevel@tonic-gate static int script_request_offline(rcm_handle_t *, char *, pid_t, uint_t, 228*0Sstevel@tonic-gate char **, rcm_info_t **); 229*0Sstevel@tonic-gate static int script_notify_online(rcm_handle_t *, char *, pid_t, uint_t, 230*0Sstevel@tonic-gate char **, rcm_info_t **); 231*0Sstevel@tonic-gate static int script_notify_remove(rcm_handle_t *, char *, pid_t, uint_t, 232*0Sstevel@tonic-gate char **, rcm_info_t **); 233*0Sstevel@tonic-gate static int script_request_suspend(rcm_handle_t *, char *, pid_t, timespec_t *, 234*0Sstevel@tonic-gate uint_t, char **, rcm_info_t **); 235*0Sstevel@tonic-gate static int script_notify_resume(rcm_handle_t *, char *, pid_t, uint_t, 236*0Sstevel@tonic-gate char **, rcm_info_t **); 237*0Sstevel@tonic-gate static capacity_descr_t *get_capacity_descr(char *); 238*0Sstevel@tonic-gate static int build_env_for_capacity(script_info_t *, char *, uint_t, nvlist_t *, 239*0Sstevel@tonic-gate char *[], int *, char **); 240*0Sstevel@tonic-gate static int script_request_capacity_change(rcm_handle_t *, char *, pid_t, 241*0Sstevel@tonic-gate uint_t, nvlist_t *, char **, rcm_info_t **); 242*0Sstevel@tonic-gate static int script_notify_capacity_change(rcm_handle_t *, char *, pid_t, 243*0Sstevel@tonic-gate uint_t, nvlist_t *, char **, rcm_info_t **); 244*0Sstevel@tonic-gate static void log_msg(script_info_t *, int, char *); 245*0Sstevel@tonic-gate static char *dup_err(int, char *, ...); 246*0Sstevel@tonic-gate static void rcmscript_snprintf(char **, int *, char **, char *, ...); 247*0Sstevel@tonic-gate static char *rcmscript_strdup(char *); 248*0Sstevel@tonic-gate static void *rcmscript_malloc(size_t); 249*0Sstevel@tonic-gate static void *rcmscript_calloc(size_t, size_t); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate static struct rcm_mod_ops script_ops = 253*0Sstevel@tonic-gate { 254*0Sstevel@tonic-gate RCM_MOD_OPS_VERSION, 255*0Sstevel@tonic-gate script_register_interest, /* register */ 256*0Sstevel@tonic-gate script_register_interest, /* unregister */ 257*0Sstevel@tonic-gate script_get_info, 258*0Sstevel@tonic-gate script_request_suspend, 259*0Sstevel@tonic-gate script_notify_resume, 260*0Sstevel@tonic-gate script_request_offline, 261*0Sstevel@tonic-gate script_notify_online, 262*0Sstevel@tonic-gate script_notify_remove, 263*0Sstevel@tonic-gate script_request_capacity_change, 264*0Sstevel@tonic-gate script_notify_capacity_change, 265*0Sstevel@tonic-gate NULL 266*0Sstevel@tonic-gate }; 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate /* 269*0Sstevel@tonic-gate * Messages fall into two categories: 270*0Sstevel@tonic-gate * framework messages (MF_..) 271*0Sstevel@tonic-gate * errors directly attributable to scripts (MS_..) 272*0Sstevel@tonic-gate */ 273*0Sstevel@tonic-gate #define MF_MEMORY_ALLOCATION_ERR \ 274*0Sstevel@tonic-gate gettext("rcm: failed to allocate memory: %1$s\n") 275*0Sstevel@tonic-gate #define MF_STATE_FILE_ERR \ 276*0Sstevel@tonic-gate gettext("rcm: state file error: %1$s: %2$s\n") 277*0Sstevel@tonic-gate #define MF_FUNC_CALL_ERR \ 278*0Sstevel@tonic-gate gettext("rcm: %1$s: %2$s\n") 279*0Sstevel@tonic-gate #define MF_NV_ERR \ 280*0Sstevel@tonic-gate gettext("rcm: required name-value parameters missing (%1$s)\n") 281*0Sstevel@tonic-gate #define MF_UNKNOWN_RSRC_ERR \ 282*0Sstevel@tonic-gate gettext("rcm: unknown resource name %1$s (%2$s)\n") 283*0Sstevel@tonic-gate #define MS_REGISTER_RSRC_ERR \ 284*0Sstevel@tonic-gate gettext("rcm script %1$s: failed to register %2$s\n") 285*0Sstevel@tonic-gate #define MS_REGISTER_ERR \ 286*0Sstevel@tonic-gate gettext("rcm script %1$s: register: %2$s\n") 287*0Sstevel@tonic-gate #define MS_SCRIPTINFO_ERR \ 288*0Sstevel@tonic-gate gettext("rcm script %1$s: scriptinfo: %2$s\n") 289*0Sstevel@tonic-gate #define MS_PROTOCOL_ERR \ 290*0Sstevel@tonic-gate gettext("rcm script %1$s: scripting protocol error\n") 291*0Sstevel@tonic-gate #define MS_TIMEOUT_ERR \ 292*0Sstevel@tonic-gate gettext("rcm script %1$s: timeout error\n") 293*0Sstevel@tonic-gate #define MS_UNSUPPORTED_VER \ 294*0Sstevel@tonic-gate gettext("rcm script %1$s: unsupported version %2$d\n") 295*0Sstevel@tonic-gate #define MS_SCRIPT_ERR \ 296*0Sstevel@tonic-gate gettext("rcm script %1$s: error: %2$s\n") 297*0Sstevel@tonic-gate #define MS_UNKNOWN_ERR \ 298*0Sstevel@tonic-gate gettext("rcm script %1$s: unknown error\n") 299*0Sstevel@tonic-gate #define MS_LOG_MSG \ 300*0Sstevel@tonic-gate gettext("rcm script %1$s: %2$s\n") 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate /* 304*0Sstevel@tonic-gate * Initialize rcm scripting framework. 305*0Sstevel@tonic-gate * Called during initialization of rcm daemon. 306*0Sstevel@tonic-gate */ 307*0Sstevel@tonic-gate int 308*0Sstevel@tonic-gate script_main_init(void) 309*0Sstevel@tonic-gate { 310*0Sstevel@tonic-gate #define PS_STATE_FILE_CHUNK_SIZE 32 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* set base script environment */ 313*0Sstevel@tonic-gate build_env(); 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate rcm_init_queue(&script_info_q); 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate /* 318*0Sstevel@tonic-gate * Initialize the semaphore to limit the number of rcm script 319*0Sstevel@tonic-gate * process running in parallel to script_max_parallelism. 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate (void) sema_init(&script_process_sema, script_max_parallelism, 322*0Sstevel@tonic-gate USYNC_THREAD, NULL); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate (void) mutex_init(&script_lock, USYNC_THREAD, NULL); 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* save original file limit */ 327*0Sstevel@tonic-gate (void) getrlimit(RLIMIT_NOFILE, &file_limit); 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate open_state_file(script_ps_state_file, &script_ps_statefd, 330*0Sstevel@tonic-gate sizeof (ps_state_element_t), 331*0Sstevel@tonic-gate PS_STATE_FILE_CHUNK_SIZE, 332*0Sstevel@tonic-gate PS_STATE_FILE_VER); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate /* 335*0Sstevel@tonic-gate * If any pids exist in the ps state file since the last incarnation of 336*0Sstevel@tonic-gate * the rcm daemon, kill the pids. 337*0Sstevel@tonic-gate * On a normal daemon exit no pids should exist in the ps state file. 338*0Sstevel@tonic-gate * But on an abnormal daemon exit pids may exist in the ps state file. 339*0Sstevel@tonic-gate */ 340*0Sstevel@tonic-gate if (script_ps_statefd.state_file) { 341*0Sstevel@tonic-gate script_ps_state_file_kill_pids(); 342*0Sstevel@tonic-gate truncate_state_file(&script_ps_statefd); 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate return (0); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * Do any cleanup. 350*0Sstevel@tonic-gate * Called at the time of normal rcm daemon exit. 351*0Sstevel@tonic-gate */ 352*0Sstevel@tonic-gate int 353*0Sstevel@tonic-gate script_main_fini(void) 354*0Sstevel@tonic-gate { 355*0Sstevel@tonic-gate script_ps_state_file_kill_pids(); 356*0Sstevel@tonic-gate close_state_file(script_ps_state_file, &script_ps_statefd); 357*0Sstevel@tonic-gate return (0); 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate /* 361*0Sstevel@tonic-gate * Initialize the given rcm script. 362*0Sstevel@tonic-gate * module->name contains the name of the rcm script. 363*0Sstevel@tonic-gate */ 364*0Sstevel@tonic-gate struct rcm_mod_ops * 365*0Sstevel@tonic-gate script_init(module_t *module) 366*0Sstevel@tonic-gate { 367*0Sstevel@tonic-gate script_info_t *rsi; 368*0Sstevel@tonic-gate size_t len; 369*0Sstevel@tonic-gate char *script_path; 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "script_init: script name = %s\n", 372*0Sstevel@tonic-gate module->name); 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate module->rsi = NULL; 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate if ((script_path = rcm_get_script_dir(module->name)) == NULL) 377*0Sstevel@tonic-gate return (NULL); 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate len = strlen(script_path) + strlen(module->name) + 2; 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate /* calloc also zeros the contents */ 382*0Sstevel@tonic-gate rsi = (script_info_t *)rcmscript_calloc(1, sizeof (script_info_t)); 383*0Sstevel@tonic-gate rsi->script_full_name = (char *)rcmscript_calloc(1, len); 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate rsi->module = module; 386*0Sstevel@tonic-gate rcm_init_queue(&rsi->drreq_q); 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate (void) mutex_init(&rsi->channel_lock, USYNC_THREAD, NULL); 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate (void) snprintf(rsi->script_full_name, len, "%s%s", script_path, 391*0Sstevel@tonic-gate module->name); 392*0Sstevel@tonic-gate rsi->script_name = strrchr(rsi->script_full_name, '/') + 1; 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate rsi->cmd_timeout = -1; /* don't time scriptinfo command */ 397*0Sstevel@tonic-gate if (do_script_info(rsi) == RCM_SUCCESS) { 398*0Sstevel@tonic-gate /* 399*0Sstevel@tonic-gate * if the script hasn't specified a timeout value set it to 400*0Sstevel@tonic-gate * default 401*0Sstevel@tonic-gate */ 402*0Sstevel@tonic-gate if (rsi->cmd_timeout == -1) 403*0Sstevel@tonic-gate rsi->cmd_timeout = SCRIPT_CMD_TIMEOUT; 404*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate /* put rsi on script_info_q */ 407*0Sstevel@tonic-gate (void) mutex_lock(&script_lock); 408*0Sstevel@tonic-gate rcm_enqueue_tail(&script_info_q, &rsi->queue); 409*0Sstevel@tonic-gate (void) mutex_unlock(&script_lock); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate module->rsi = rsi; 412*0Sstevel@tonic-gate return (&script_ops); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate free(rsi->script_full_name); 418*0Sstevel@tonic-gate free(rsi); 419*0Sstevel@tonic-gate return (NULL); 420*0Sstevel@tonic-gate } 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * Returns a string describing the script's functionality. 424*0Sstevel@tonic-gate * module->name contains the name of the rcm script for which information 425*0Sstevel@tonic-gate * is requested. 426*0Sstevel@tonic-gate */ 427*0Sstevel@tonic-gate char * 428*0Sstevel@tonic-gate script_info(module_t *module) 429*0Sstevel@tonic-gate { 430*0Sstevel@tonic-gate script_info_t *rsi = module->rsi; 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "script_info: script name = %s\n", 433*0Sstevel@tonic-gate rsi->script_name); 434*0Sstevel@tonic-gate return (rsi->func_info_buf); 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* 438*0Sstevel@tonic-gate * Called before unloading the script. 439*0Sstevel@tonic-gate * module->name contains the name of the rcm script which is being unloaded. 440*0Sstevel@tonic-gate * Do any cleanup. 441*0Sstevel@tonic-gate */ 442*0Sstevel@tonic-gate int 443*0Sstevel@tonic-gate script_fini(module_t *module) 444*0Sstevel@tonic-gate { 445*0Sstevel@tonic-gate script_info_t *rsi = module->rsi; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "script_fini: script name = %s\n", 448*0Sstevel@tonic-gate rsi->script_name); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate /* remove rsi from script_info_q */ 451*0Sstevel@tonic-gate (void) mutex_lock(&script_lock); 452*0Sstevel@tonic-gate rcm_dequeue(&rsi->queue); 453*0Sstevel@tonic-gate (void) mutex_unlock(&script_lock); 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate remove_drreq_all(rsi); 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate if (rsi->func_info_buf) 458*0Sstevel@tonic-gate free(rsi->func_info_buf); 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate free(rsi->script_full_name); 461*0Sstevel@tonic-gate free(rsi); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate module->rsi = NULL; 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate return (RCM_SUCCESS); 466*0Sstevel@tonic-gate } 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate /* build base environment for scripts */ 469*0Sstevel@tonic-gate static void 470*0Sstevel@tonic-gate build_env(void) 471*0Sstevel@tonic-gate { 472*0Sstevel@tonic-gate const char *env_list[] = { "LANG", "LC_COLLATE", "LC_CTYPE", 473*0Sstevel@tonic-gate "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", 474*0Sstevel@tonic-gate "LC_ALL", "TZ", NULL }; 475*0Sstevel@tonic-gate char *x; 476*0Sstevel@tonic-gate int len; 477*0Sstevel@tonic-gate int i, j = 0; 478*0Sstevel@tonic-gate int d; 479*0Sstevel@tonic-gate extern int debug_level; 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate script_env[j++] = rcmscript_strdup("PATH=/usr/sbin:/usr/bin"); 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate for (i = 0; env_list[i] != NULL; i++) { 484*0Sstevel@tonic-gate x = getenv(env_list[i]); 485*0Sstevel@tonic-gate if (x) { 486*0Sstevel@tonic-gate len = strlen(env_list[i]) + strlen(x) + 2; 487*0Sstevel@tonic-gate script_env[j] = (char *)rcmscript_malloc(len); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate (void) snprintf(script_env[j++], len, "%s=%s", 490*0Sstevel@tonic-gate env_list[i], x); 491*0Sstevel@tonic-gate } 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate len = strlen("RCM_ENV_DEBUG_LEVEL") + 3; 495*0Sstevel@tonic-gate script_env[j] = (char *)rcmscript_malloc(len); 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate if (debug_level < 0) 498*0Sstevel@tonic-gate d = 0; 499*0Sstevel@tonic-gate else if (debug_level > 9) 500*0Sstevel@tonic-gate d = 9; 501*0Sstevel@tonic-gate else 502*0Sstevel@tonic-gate d = debug_level; 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate (void) snprintf(script_env[j++], len, "RCM_ENV_DEBUG_LEVEL=%d", d); 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate script_env[j] = NULL; 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate static void 510*0Sstevel@tonic-gate copy_env(char *src[], char *dst[]) 511*0Sstevel@tonic-gate { 512*0Sstevel@tonic-gate int i; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate for (i = 0; src[i] != NULL; i++) 515*0Sstevel@tonic-gate dst[i] = src[i]; 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate dst[i] = NULL; 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate /* 521*0Sstevel@tonic-gate * Open (or create if the file does not exist) the given state file 522*0Sstevel@tonic-gate * and mmap it. 523*0Sstevel@tonic-gate */ 524*0Sstevel@tonic-gate static void 525*0Sstevel@tonic-gate open_state_file(const char *filename, 526*0Sstevel@tonic-gate state_file_descr_t *statefd, 527*0Sstevel@tonic-gate size_t element_size, 528*0Sstevel@tonic-gate int chunk_size, 529*0Sstevel@tonic-gate uint32_t version) 530*0Sstevel@tonic-gate { 531*0Sstevel@tonic-gate struct stat stats; 532*0Sstevel@tonic-gate int error_num; 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate if ((statefd->fd = open(filename, O_CREAT|O_RDWR, 0600)) == 535*0Sstevel@tonic-gate -1) { 536*0Sstevel@tonic-gate error_num = errno; 537*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_STATE_FILE_ERR, 538*0Sstevel@tonic-gate "open", strerror(error_num)); 539*0Sstevel@tonic-gate rcmd_exit(error_num); 540*0Sstevel@tonic-gate /*NOTREACHED*/ 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate if (fstat(statefd->fd, &stats) != 0) { 544*0Sstevel@tonic-gate error_num = errno; 545*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_STATE_FILE_ERR, 546*0Sstevel@tonic-gate "fstat", strerror(error_num)); 547*0Sstevel@tonic-gate rcmd_exit(error_num); 548*0Sstevel@tonic-gate /*NOTREACHED*/ 549*0Sstevel@tonic-gate } 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate if (stats.st_size != 0) { 552*0Sstevel@tonic-gate /* LINTED */ 553*0Sstevel@tonic-gate statefd->state_file = (state_file_t *)mmap(NULL, 554*0Sstevel@tonic-gate stats.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, 555*0Sstevel@tonic-gate statefd->fd, 0); 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate if (statefd->state_file == MAP_FAILED) { 558*0Sstevel@tonic-gate error_num = errno; 559*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_STATE_FILE_ERR, 560*0Sstevel@tonic-gate "mmap", strerror(error_num)); 561*0Sstevel@tonic-gate rcmd_exit(error_num); 562*0Sstevel@tonic-gate /*NOTREACHED*/ 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate if (statefd->state_file->version != version) { 566*0Sstevel@tonic-gate (void) munmap((void *)statefd->state_file, 567*0Sstevel@tonic-gate stats.st_size); 568*0Sstevel@tonic-gate statefd->state_file = NULL; 569*0Sstevel@tonic-gate (void) ftruncate(statefd->fd, 0); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate } else { 572*0Sstevel@tonic-gate statefd->state_file = NULL; 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate statefd->version = version; 576*0Sstevel@tonic-gate statefd->element_size = sizeof (state_element_t) + 577*0Sstevel@tonic-gate RSCR_ROUNDUP(element_size, 8); 578*0Sstevel@tonic-gate statefd->chunk_size = chunk_size; 579*0Sstevel@tonic-gate statefd->index = 0; 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate static void 583*0Sstevel@tonic-gate truncate_state_file(state_file_descr_t *statefd) 584*0Sstevel@tonic-gate { 585*0Sstevel@tonic-gate size_t size; 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate if (statefd->state_file) { 588*0Sstevel@tonic-gate size = sizeof (state_file_t) + statefd->element_size * 589*0Sstevel@tonic-gate statefd->state_file->max_elements; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate (void) munmap((void *)statefd->state_file, size); 592*0Sstevel@tonic-gate statefd->state_file = NULL; 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate (void) ftruncate(statefd->fd, 0); 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate static void 598*0Sstevel@tonic-gate close_state_file(const char *filename, state_file_descr_t *statefd) 599*0Sstevel@tonic-gate { 600*0Sstevel@tonic-gate truncate_state_file(statefd); 601*0Sstevel@tonic-gate (void) close(statefd->fd); 602*0Sstevel@tonic-gate (void) unlink(filename); 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate /* 606*0Sstevel@tonic-gate * Grow the state file by the chunk size specified in statefd 607*0Sstevel@tonic-gate * and mmap it. 608*0Sstevel@tonic-gate */ 609*0Sstevel@tonic-gate static void 610*0Sstevel@tonic-gate grow_state_file(state_file_descr_t *statefd) 611*0Sstevel@tonic-gate { 612*0Sstevel@tonic-gate size_t size; 613*0Sstevel@tonic-gate int max_elements; 614*0Sstevel@tonic-gate int error_num; 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate max_elements = statefd->chunk_size; 617*0Sstevel@tonic-gate if (statefd->state_file) 618*0Sstevel@tonic-gate max_elements += statefd->state_file->max_elements; 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate size = sizeof (state_file_t) + 621*0Sstevel@tonic-gate statefd->element_size * max_elements; 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate if (ftruncate(statefd->fd, size) != 0) { 624*0Sstevel@tonic-gate error_num = errno; 625*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_STATE_FILE_ERR, 626*0Sstevel@tonic-gate "ftruncate", strerror(error_num)); 627*0Sstevel@tonic-gate rcmd_exit(error_num); 628*0Sstevel@tonic-gate /*NOTREACHED*/ 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate /* LINTED */ 632*0Sstevel@tonic-gate statefd->state_file = (state_file_t *)mmap(NULL, size, 633*0Sstevel@tonic-gate PROT_READ|PROT_WRITE, MAP_SHARED, statefd->fd, 0); 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate if (statefd->state_file == MAP_FAILED) { 636*0Sstevel@tonic-gate error_num = errno; 637*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_STATE_FILE_ERR, 638*0Sstevel@tonic-gate "mmap", strerror(error_num)); 639*0Sstevel@tonic-gate rcmd_exit(error_num); 640*0Sstevel@tonic-gate /*NOTREACHED*/ 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate statefd->index = statefd->state_file->max_elements; 644*0Sstevel@tonic-gate statefd->state_file->max_elements = max_elements; 645*0Sstevel@tonic-gate statefd->state_file->version = statefd->version; 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* 649*0Sstevel@tonic-gate * Given index into state element array, get the pointer to the actual 650*0Sstevel@tonic-gate * state element. 651*0Sstevel@tonic-gate * If flag is non-null set *flag to 652*0Sstevel@tonic-gate * TRUE if the state element is currently is use. 653*0Sstevel@tonic-gate * FALSE if the state element is free. 654*0Sstevel@tonic-gate */ 655*0Sstevel@tonic-gate static void * 656*0Sstevel@tonic-gate get_state_element(state_file_descr_t *statefd, int index, int *flag) 657*0Sstevel@tonic-gate { 658*0Sstevel@tonic-gate char *ptr; 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate if (statefd->state_file && 661*0Sstevel@tonic-gate (index < statefd->state_file->max_elements)) { 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate ptr = (char *)(statefd->state_file); 664*0Sstevel@tonic-gate ptr += sizeof (state_file_t) + 665*0Sstevel@tonic-gate index * statefd->element_size; 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate if (flag) { 668*0Sstevel@tonic-gate *flag = (((state_element_t *)((void *)ptr))->flags & 669*0Sstevel@tonic-gate STATE_ELEMENT_IN_USE) ? 1 : 0; 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate ptr += sizeof (state_element_t); 673*0Sstevel@tonic-gate } else 674*0Sstevel@tonic-gate ptr = NULL; 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate return ((void *)ptr); 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate /* 680*0Sstevel@tonic-gate * Allocate a state element entry in the state file and return a pointer 681*0Sstevel@tonic-gate * to the allocated entry. 682*0Sstevel@tonic-gate * If index is non-null set *index to index into the state element array 683*0Sstevel@tonic-gate * of the allocated entry. 684*0Sstevel@tonic-gate */ 685*0Sstevel@tonic-gate static void * 686*0Sstevel@tonic-gate allocate_state_element(state_file_descr_t *statefd, int *index) 687*0Sstevel@tonic-gate { 688*0Sstevel@tonic-gate void *x; 689*0Sstevel@tonic-gate int i; 690*0Sstevel@tonic-gate int flag; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate if (statefd->state_file) { 693*0Sstevel@tonic-gate /* find an empty slot */ 694*0Sstevel@tonic-gate for (i = 0; i < statefd->state_file->max_elements; i++) { 695*0Sstevel@tonic-gate x = get_state_element(statefd, statefd->index, 696*0Sstevel@tonic-gate &flag); 697*0Sstevel@tonic-gate assert(x != NULL); 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate if (flag == 0) 700*0Sstevel@tonic-gate /* entry is free */ 701*0Sstevel@tonic-gate break; 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate statefd->index++; 704*0Sstevel@tonic-gate if (statefd->index >= statefd->state_file->max_elements) 705*0Sstevel@tonic-gate statefd->index = 0; 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate if (statefd->state_file == NULL || 710*0Sstevel@tonic-gate i == statefd->state_file->max_elements) { 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate /* All entries are in use. Grow the list */ 713*0Sstevel@tonic-gate grow_state_file(statefd); 714*0Sstevel@tonic-gate x = get_state_element(statefd, statefd->index, &flag); 715*0Sstevel@tonic-gate assert(flag == 0); 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate if (index != NULL) 719*0Sstevel@tonic-gate *index = statefd->index; 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate statefd->index++; 722*0Sstevel@tonic-gate if (statefd->index >= statefd->state_file->max_elements) 723*0Sstevel@tonic-gate statefd->index = 0; 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate ((state_element_t *)x - 1)->flags |= STATE_ELEMENT_IN_USE; 726*0Sstevel@tonic-gate return (x); 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate static void 730*0Sstevel@tonic-gate free_state_element(void *x) 731*0Sstevel@tonic-gate { 732*0Sstevel@tonic-gate ((state_element_t *)x - 1)->flags &= ~STATE_ELEMENT_IN_USE; 733*0Sstevel@tonic-gate } 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate /* 736*0Sstevel@tonic-gate * Kill the pids contained in ps state file. 737*0Sstevel@tonic-gate */ 738*0Sstevel@tonic-gate static void 739*0Sstevel@tonic-gate script_ps_state_file_kill_pids(void) 740*0Sstevel@tonic-gate { 741*0Sstevel@tonic-gate ps_state_element_t *x; 742*0Sstevel@tonic-gate char procfile[80]; 743*0Sstevel@tonic-gate psinfo_t psi; 744*0Sstevel@tonic-gate int fd, i, flag; 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate /* LINTED */ 747*0Sstevel@tonic-gate for (i = 0; 1; i++) { 748*0Sstevel@tonic-gate if ((x = (ps_state_element_t *)get_state_element( 749*0Sstevel@tonic-gate &script_ps_statefd, i, &flag)) == NULL) 750*0Sstevel@tonic-gate break; 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate if (flag == 1) { /* the entry is in use */ 753*0Sstevel@tonic-gate (void) snprintf(procfile, 80, "/proc/%ld/psinfo", 754*0Sstevel@tonic-gate (long)x->pid); 755*0Sstevel@tonic-gate if ((fd = open(procfile, O_RDONLY)) != -1 && 756*0Sstevel@tonic-gate read(fd, &psi, sizeof (psi)) == sizeof (psi) && 757*0Sstevel@tonic-gate strcmp(psi.pr_fname, 758*0Sstevel@tonic-gate x->script_name) == 0) { 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate (void) close(fd); 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate /* 763*0Sstevel@tonic-gate * just a safety check to not to blow up 764*0Sstevel@tonic-gate * system processes if the file is ever corrupt 765*0Sstevel@tonic-gate */ 766*0Sstevel@tonic-gate if (x->pid > 1) { 767*0Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 768*0Sstevel@tonic-gate "script_ps_state_file_kill_pids: " 769*0Sstevel@tonic-gate "killing script_name = %s pid = %ld\n", 770*0Sstevel@tonic-gate x->script_name, x->pid); 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate /* kill the process group */ 773*0Sstevel@tonic-gate (void) kill(-(x->pid), SIGKILL); 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate } else { 776*0Sstevel@tonic-gate if (fd != -1) 777*0Sstevel@tonic-gate (void) close(fd); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate free_state_element((void *)x); 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate } 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate /* 785*0Sstevel@tonic-gate * Add a state element entry to ps state file. 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate static void 788*0Sstevel@tonic-gate script_ps_state_file_add_entry(pid_t pid, char *script_name) 789*0Sstevel@tonic-gate { 790*0Sstevel@tonic-gate ps_state_element_t *x; 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate (void) mutex_lock(&script_lock); 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate x = (ps_state_element_t *)allocate_state_element( 795*0Sstevel@tonic-gate &script_ps_statefd, NULL); 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate x->pid = pid; 798*0Sstevel@tonic-gate (void) strlcpy(x->script_name, script_name, MAXNAMELEN); 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate (void) fsync(script_ps_statefd.fd); 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate (void) mutex_unlock(&script_lock); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate /* 806*0Sstevel@tonic-gate * Remove the state element entry corresponding to pid from the 807*0Sstevel@tonic-gate * ps state file. 808*0Sstevel@tonic-gate */ 809*0Sstevel@tonic-gate static void 810*0Sstevel@tonic-gate script_ps_state_file_remove_entry(pid_t pid) 811*0Sstevel@tonic-gate { 812*0Sstevel@tonic-gate ps_state_element_t *x; 813*0Sstevel@tonic-gate int flag, i; 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate (void) mutex_lock(&script_lock); 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate /* LINTED */ 818*0Sstevel@tonic-gate for (i = 0; 1; i++) { 819*0Sstevel@tonic-gate if ((x = (ps_state_element_t *)get_state_element( 820*0Sstevel@tonic-gate &script_ps_statefd, i, &flag)) == NULL) 821*0Sstevel@tonic-gate break; 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate /* if the state element entry is in use and pid matches */ 824*0Sstevel@tonic-gate if (flag == 1 && x->pid == pid) { 825*0Sstevel@tonic-gate free_state_element((void *)x); 826*0Sstevel@tonic-gate break; 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate (void) mutex_unlock(&script_lock); 831*0Sstevel@tonic-gate } 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate /* 834*0Sstevel@tonic-gate * Get data item id given data item name 835*0Sstevel@tonic-gate */ 836*0Sstevel@tonic-gate static int 837*0Sstevel@tonic-gate dname_to_id(char *dname) 838*0Sstevel@tonic-gate { 839*0Sstevel@tonic-gate int i; 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate for (i = 0; script_data_item_name[i] != NULL; i++) { 842*0Sstevel@tonic-gate if (strcmp(dname, script_data_item_name[i]) == 0) 843*0Sstevel@tonic-gate return (i); 844*0Sstevel@tonic-gate } 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate return (-1); 847*0Sstevel@tonic-gate } 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate /* 850*0Sstevel@tonic-gate * Called before running any script. 851*0Sstevel@tonic-gate * This routine waits until the number of script processes running in 852*0Sstevel@tonic-gate * parallel drops down below to script_max_parallelism. 853*0Sstevel@tonic-gate */ 854*0Sstevel@tonic-gate static void 855*0Sstevel@tonic-gate script_process_sema_wait(void) 856*0Sstevel@tonic-gate { 857*0Sstevel@tonic-gate int error_num; 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate /* LINTED */ 860*0Sstevel@tonic-gate while (1) { 861*0Sstevel@tonic-gate if (sema_wait(&script_process_sema) == 0) 862*0Sstevel@tonic-gate return; 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate if (errno != EINTR && errno != EAGAIN) { 865*0Sstevel@tonic-gate error_num = errno; 866*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_FUNC_CALL_ERR, 867*0Sstevel@tonic-gate "sema_wait", strerror(error_num)); 868*0Sstevel@tonic-gate rcmd_exit(error_num); 869*0Sstevel@tonic-gate /*NOTREACHED*/ 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate } 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate /*NOTREACHED*/ 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate /* 877*0Sstevel@tonic-gate * Fork and execute the script. 878*0Sstevel@tonic-gate */ 879*0Sstevel@tonic-gate static int 880*0Sstevel@tonic-gate run_script(script_info_t *rsi, char *argv[], char *envp[], char **errmsg) 881*0Sstevel@tonic-gate { 882*0Sstevel@tonic-gate int i, p1 = -1, p2 = -1; 883*0Sstevel@tonic-gate struct rlimit rlp; 884*0Sstevel@tonic-gate struct stat stats; 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "run_script: script name = %s\n", 887*0Sstevel@tonic-gate rsi->script_full_name); 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate for (i = 0; argv[i] != NULL; i++) 890*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "run_script: argv[%d] = %s\n", 891*0Sstevel@tonic-gate i, argv[i]); 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate *errmsg = NULL; 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate /* check that the script exists */ 896*0Sstevel@tonic-gate if (stat(rsi->script_full_name, &stats) != 0) 897*0Sstevel@tonic-gate goto error; 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate /* 900*0Sstevel@tonic-gate * If the syscall pipe fails because of reaching the max open file 901*0Sstevel@tonic-gate * count per process then dynamically increase the limit on the max 902*0Sstevel@tonic-gate * open file count. 903*0Sstevel@tonic-gate * 904*0Sstevel@tonic-gate * At present the rcm_daemon consumes file descriptor 905*0Sstevel@tonic-gate * entries for the following files. 906*0Sstevel@tonic-gate * RCM_STATE_FILE - /var/run/rcm_daemon_state 907*0Sstevel@tonic-gate * DAEMON_LOCK_FILE - /var/run/rcm_daemon_lock 908*0Sstevel@tonic-gate * RCM_SERVICE_DOOR - /var/run/rcm_daemon_door 909*0Sstevel@tonic-gate * proc files in the format "/proc/pid/as" for each pid 910*0Sstevel@tonic-gate * communicating with the rcm_daemon via doors 911*0Sstevel@tonic-gate * dlopen for each rcm module 912*0Sstevel@tonic-gate * When in daemon mode stdin, stdout and stderr are closed; 913*0Sstevel@tonic-gate * /dev/null opened and duped to stdout, and stderr 914*0Sstevel@tonic-gate * openlog 915*0Sstevel@tonic-gate * Some files which are opened briefly and closed such as 916*0Sstevel@tonic-gate * directory files. 917*0Sstevel@tonic-gate * Two file descriptors for each script in running state. 918*0Sstevel@tonic-gate * Note that the constant script_max_parallelism sets an 919*0Sstevel@tonic-gate * upper cap on how many rcm scripts can run in 920*0Sstevel@tonic-gate * parallel. 921*0Sstevel@tonic-gate */ 922*0Sstevel@tonic-gate if ((p1 = pipe(rsi->pipe1)) == -1 || (p2 = pipe(rsi->pipe2)) == -1) { 923*0Sstevel@tonic-gate if ((errno == EMFILE) && 924*0Sstevel@tonic-gate (getrlimit(RLIMIT_NOFILE, &rlp) == 0)) { 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate rlp.rlim_cur += 16; 927*0Sstevel@tonic-gate if (rlp.rlim_max < rlp.rlim_cur) 928*0Sstevel@tonic-gate rlp.rlim_max = rlp.rlim_cur; 929*0Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlp); 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate if (p1 == -1) { 932*0Sstevel@tonic-gate if ((p1 = pipe(rsi->pipe1)) == -1) 933*0Sstevel@tonic-gate goto error; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate if ((p2 = pipe(rsi->pipe2)) == -1) 936*0Sstevel@tonic-gate goto error; 937*0Sstevel@tonic-gate } else 938*0Sstevel@tonic-gate goto error; 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate forkagain: 942*0Sstevel@tonic-gate if ((rsi->pid = fork1()) == (pid_t)-1) { 943*0Sstevel@tonic-gate if (errno == EINTR || errno == EAGAIN) 944*0Sstevel@tonic-gate goto forkagain; 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate goto error; 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate if (rsi->pid == 0) { 950*0Sstevel@tonic-gate /* child process */ 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate (void) setsid(); 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate /* close stdin, stdout and stderr */ 955*0Sstevel@tonic-gate (void) close(0); 956*0Sstevel@tonic-gate (void) close(1); 957*0Sstevel@tonic-gate (void) close(2); 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate /* set stdin to /dev/null */ 960*0Sstevel@tonic-gate (void) open("/dev/null", O_RDWR, 0); 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate /* redirect stdout and stderr to pipe */ 963*0Sstevel@tonic-gate (void) dup2(rsi->pipe1[CHILD_END_OF_PIPE], 1); 964*0Sstevel@tonic-gate (void) dup2(rsi->pipe2[CHILD_END_OF_PIPE], 2); 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate /* close all other file descriptors */ 967*0Sstevel@tonic-gate closefrom(3); 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate /* restore original file limit */ 970*0Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &file_limit); 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate /* set current working dir */ 973*0Sstevel@tonic-gate if (stats.st_uid == 0) { 974*0Sstevel@tonic-gate /* root */ 975*0Sstevel@tonic-gate if (chdir("/var/run") == -1) 976*0Sstevel@tonic-gate _exit(127); 977*0Sstevel@tonic-gate } else { 978*0Sstevel@tonic-gate if (chdir("/tmp") == -1) 979*0Sstevel@tonic-gate _exit(127); 980*0Sstevel@tonic-gate } 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate /* 983*0Sstevel@tonic-gate * setuid sets real, effective and saved user ids to the 984*0Sstevel@tonic-gate * given id. 985*0Sstevel@tonic-gate * setgid sets real, effective and saved group ids to the 986*0Sstevel@tonic-gate * given id. 987*0Sstevel@tonic-gate */ 988*0Sstevel@tonic-gate (void) setgid(stats.st_gid); 989*0Sstevel@tonic-gate (void) setuid(stats.st_uid); 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate (void) execve(rsi->script_full_name, argv, envp); 992*0Sstevel@tonic-gate _exit(127); 993*0Sstevel@tonic-gate /*NOTREACHED*/ 994*0Sstevel@tonic-gate } 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate (void) close(rsi->pipe1[CHILD_END_OF_PIPE]); 997*0Sstevel@tonic-gate (void) close(rsi->pipe2[CHILD_END_OF_PIPE]); 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate script_ps_state_file_add_entry(rsi->pid, rsi->script_name); 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate return (0); 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate error: 1004*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MS_SCRIPT_ERR, 1005*0Sstevel@tonic-gate rsi->script_name, strerror(errno)); 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate if (p1 != -1) { 1008*0Sstevel@tonic-gate (void) close(rsi->pipe1[PARENT_END_OF_PIPE]); 1009*0Sstevel@tonic-gate (void) close(rsi->pipe1[CHILD_END_OF_PIPE]); 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate if (p2 != -1) { 1013*0Sstevel@tonic-gate (void) close(rsi->pipe2[PARENT_END_OF_PIPE]); 1014*0Sstevel@tonic-gate (void) close(rsi->pipe2[CHILD_END_OF_PIPE]); 1015*0Sstevel@tonic-gate } 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate return (-1); 1018*0Sstevel@tonic-gate } 1019*0Sstevel@tonic-gate 1020*0Sstevel@tonic-gate /* 1021*0Sstevel@tonic-gate * Reads one line of input (including the newline character) from the 1022*0Sstevel@tonic-gate * given file descriptor "fd" to buf. 1023*0Sstevel@tonic-gate * maxbuflen specifies the size of memory allocated for buf. 1024*0Sstevel@tonic-gate * Timeoutval is the max timeout value in seconds for the script to supply 1025*0Sstevel@tonic-gate * input. A timeoutval of 0 implies no timeout. 1026*0Sstevel@tonic-gate * 1027*0Sstevel@tonic-gate * Upon return *buflen contains the number of bytes read. 1028*0Sstevel@tonic-gate * 1029*0Sstevel@tonic-gate * Return values: 1030*0Sstevel@tonic-gate * 0 success 1031*0Sstevel@tonic-gate * -1 an error occured 1032*0Sstevel@tonic-gate * -2 timeout occurred 1033*0Sstevel@tonic-gate * -3 script exited 1034*0Sstevel@tonic-gate */ 1035*0Sstevel@tonic-gate static int 1036*0Sstevel@tonic-gate get_line(int fd, 1037*0Sstevel@tonic-gate char *fdname, 1038*0Sstevel@tonic-gate char *buf, 1039*0Sstevel@tonic-gate int maxbuflen, 1040*0Sstevel@tonic-gate size_t *buflen, 1041*0Sstevel@tonic-gate time_t timeoutval, 1042*0Sstevel@tonic-gate int *error_num) 1043*0Sstevel@tonic-gate { 1044*0Sstevel@tonic-gate char c = '\0'; 1045*0Sstevel@tonic-gate struct pollfd fds[1]; 1046*0Sstevel@tonic-gate int x; 1047*0Sstevel@tonic-gate size_t len = 0; 1048*0Sstevel@tonic-gate char *ptr; 1049*0Sstevel@tonic-gate int timeit; 1050*0Sstevel@tonic-gate time_t deadline; 1051*0Sstevel@tonic-gate int rval = 0; 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate if (timeoutval) { 1054*0Sstevel@tonic-gate timeit = TRUE; 1055*0Sstevel@tonic-gate deadline = time(NULL) + timeoutval; 1056*0Sstevel@tonic-gate fds[0].fd = fd; 1057*0Sstevel@tonic-gate fds[0].events = POLLIN; 1058*0Sstevel@tonic-gate } else 1059*0Sstevel@tonic-gate timeit = FALSE; 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate ptr = buf; 1062*0Sstevel@tonic-gate 1063*0Sstevel@tonic-gate while (c != '\n' && len < (maxbuflen -1)) { 1064*0Sstevel@tonic-gate if (timeit) { 1065*0Sstevel@tonic-gate pollagain: 1066*0Sstevel@tonic-gate fds[0].revents = 0; 1067*0Sstevel@tonic-gate timeoutval = deadline - time(NULL); 1068*0Sstevel@tonic-gate if (timeoutval <= 0) { 1069*0Sstevel@tonic-gate rval = -2; 1070*0Sstevel@tonic-gate break; 1071*0Sstevel@tonic-gate } 1072*0Sstevel@tonic-gate x = poll(fds, 1, timeoutval*1000); 1073*0Sstevel@tonic-gate if (x <= 0) { 1074*0Sstevel@tonic-gate if (x == 0) 1075*0Sstevel@tonic-gate /* poll timedout */ 1076*0Sstevel@tonic-gate rval = -2; 1077*0Sstevel@tonic-gate else { 1078*0Sstevel@tonic-gate if (errno == EINTR || errno == EAGAIN) 1079*0Sstevel@tonic-gate goto pollagain; 1080*0Sstevel@tonic-gate *error_num = errno; 1081*0Sstevel@tonic-gate rval = -1; 1082*0Sstevel@tonic-gate } 1083*0Sstevel@tonic-gate break; 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate } 1086*0Sstevel@tonic-gate readagain: 1087*0Sstevel@tonic-gate if ((x = read(fd, &c, 1)) != 1) { 1088*0Sstevel@tonic-gate if (x == 0) 1089*0Sstevel@tonic-gate /* 1090*0Sstevel@tonic-gate * Script exited. Or more specifically the 1091*0Sstevel@tonic-gate * script has closed its end of the pipe. 1092*0Sstevel@tonic-gate */ 1093*0Sstevel@tonic-gate rval = -3; 1094*0Sstevel@tonic-gate else { 1095*0Sstevel@tonic-gate if (errno == EINTR || errno == EAGAIN) 1096*0Sstevel@tonic-gate goto readagain; 1097*0Sstevel@tonic-gate *error_num = errno; 1098*0Sstevel@tonic-gate rval = -1; 1099*0Sstevel@tonic-gate } 1100*0Sstevel@tonic-gate break; 1101*0Sstevel@tonic-gate } 1102*0Sstevel@tonic-gate 1103*0Sstevel@tonic-gate *ptr++ = c; 1104*0Sstevel@tonic-gate len++; 1105*0Sstevel@tonic-gate } 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate *ptr = '\0'; 1108*0Sstevel@tonic-gate *buflen = len; 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, 1111*0Sstevel@tonic-gate "get_line(%s): rval = %d buflen = %d line = %s\n", 1112*0Sstevel@tonic-gate fdname, rval, *buflen, buf); 1113*0Sstevel@tonic-gate return (rval); 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate static void 1117*0Sstevel@tonic-gate script_exited(script_info_t *rsi) 1118*0Sstevel@tonic-gate { 1119*0Sstevel@tonic-gate if (rsi->flags & STDERR_THREAD_CREATED) { 1120*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, 1121*0Sstevel@tonic-gate "script_exited: doing thr_join (%s)\n", rsi->script_name); 1122*0Sstevel@tonic-gate (void) thr_join(rsi->tid, NULL, NULL); 1123*0Sstevel@tonic-gate rsi->flags &= ~STDERR_THREAD_CREATED; 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate (void) close(rsi->pipe1[PARENT_END_OF_PIPE]); 1127*0Sstevel@tonic-gate (void) close(rsi->pipe2[PARENT_END_OF_PIPE]); 1128*0Sstevel@tonic-gate rsi->pipe1[PARENT_END_OF_PIPE] = -1; 1129*0Sstevel@tonic-gate rsi->pipe2[PARENT_END_OF_PIPE] = -1; 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate script_ps_state_file_remove_entry(rsi->pid); 1132*0Sstevel@tonic-gate rsi->pid = 0; 1133*0Sstevel@tonic-gate (void) sema_post(&script_process_sema); 1134*0Sstevel@tonic-gate } 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate /* 1137*0Sstevel@tonic-gate * Kill the specified process group 1138*0Sstevel@tonic-gate */ 1139*0Sstevel@tonic-gate static int 1140*0Sstevel@tonic-gate kill_pid(pid_t pid) 1141*0Sstevel@tonic-gate { 1142*0Sstevel@tonic-gate time_t deadline, timeleft; 1143*0Sstevel@tonic-gate int child_status; 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate /* kill the entire process group */ 1146*0Sstevel@tonic-gate (void) kill(-(pid), SIGKILL); 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate /* give some time for the script to be killed */ 1149*0Sstevel@tonic-gate deadline = time(NULL) + SCRIPT_KILL_TIMEOUT; 1150*0Sstevel@tonic-gate do { 1151*0Sstevel@tonic-gate if (waitpid(pid, &child_status, WNOHANG) == pid) 1152*0Sstevel@tonic-gate return (0); 1153*0Sstevel@tonic-gate 1154*0Sstevel@tonic-gate /* wait for 100 ms */ 1155*0Sstevel@tonic-gate (void) poll(NULL, 0, 100); 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate timeleft = deadline - time(NULL); 1158*0Sstevel@tonic-gate } while (timeleft > 0); 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate /* script process was not killed successfully */ 1161*0Sstevel@tonic-gate return (-1); 1162*0Sstevel@tonic-gate } 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate /* 1165*0Sstevel@tonic-gate * Kill the specified script. 1166*0Sstevel@tonic-gate */ 1167*0Sstevel@tonic-gate static void 1168*0Sstevel@tonic-gate kill_script(script_info_t *rsi) 1169*0Sstevel@tonic-gate { 1170*0Sstevel@tonic-gate if (rsi->pid > 1) { 1171*0Sstevel@tonic-gate (void) kill_pid(rsi->pid); 1172*0Sstevel@tonic-gate script_exited(rsi); 1173*0Sstevel@tonic-gate remove_drreq_all(rsi); 1174*0Sstevel@tonic-gate } 1175*0Sstevel@tonic-gate } 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate /* 1178*0Sstevel@tonic-gate * Convert rcm flags parameter to a string. 1179*0Sstevel@tonic-gate * Used for debug prints. 1180*0Sstevel@tonic-gate */ 1181*0Sstevel@tonic-gate static char * 1182*0Sstevel@tonic-gate flags_to_name(int flags, char *buf, int maxbuflen) 1183*0Sstevel@tonic-gate { 1184*0Sstevel@tonic-gate (void) snprintf(buf, maxbuflen, "%s%s", 1185*0Sstevel@tonic-gate (flags & RCM_QUERY) ? "RCM_QUERY " : "", 1186*0Sstevel@tonic-gate (flags & RCM_FORCE) ? "RCM_FORCE" : ""); 1187*0Sstevel@tonic-gate 1188*0Sstevel@tonic-gate return (buf); 1189*0Sstevel@tonic-gate } 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate static void 1192*0Sstevel@tonic-gate fill_argv(script_info_t *rsi, char *argv[], char *resource_name) 1193*0Sstevel@tonic-gate { 1194*0Sstevel@tonic-gate argv[0] = rsi->script_full_name; 1195*0Sstevel@tonic-gate argv[1] = script_cmd_name[rsi->cmd]; 1196*0Sstevel@tonic-gate if (resource_name) { 1197*0Sstevel@tonic-gate argv[2] = resource_name; 1198*0Sstevel@tonic-gate argv[3] = NULL; 1199*0Sstevel@tonic-gate } else 1200*0Sstevel@tonic-gate argv[2] = NULL; 1201*0Sstevel@tonic-gate } 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate /* 1204*0Sstevel@tonic-gate * stderr thread: 1205*0Sstevel@tonic-gate * Reads stderr and logs to syslog. 1206*0Sstevel@tonic-gate * Runs as a separate thread. 1207*0Sstevel@tonic-gate */ 1208*0Sstevel@tonic-gate static void * 1209*0Sstevel@tonic-gate read_stderr(script_info_t *rsi) 1210*0Sstevel@tonic-gate { 1211*0Sstevel@tonic-gate char buf[MAX_LINE_LEN]; 1212*0Sstevel@tonic-gate size_t buflen; 1213*0Sstevel@tonic-gate int error_num; 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate while ((get_line(rsi->pipe2[PARENT_END_OF_PIPE], "stderr", 1216*0Sstevel@tonic-gate buf, MAX_LINE_LEN, &buflen, 0, &error_num)) == 0) { 1217*0Sstevel@tonic-gate log_msg(rsi, RCM_ERROR, buf); 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate if (buflen) 1221*0Sstevel@tonic-gate log_msg(rsi, RCM_ERROR, buf); 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate return (NULL); 1224*0Sstevel@tonic-gate } 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate /* process return data items passed by scripts to the framework */ 1227*0Sstevel@tonic-gate static int 1228*0Sstevel@tonic-gate process_dataitem(script_info_t *rsi, int token, char *value, char **errmsg) 1229*0Sstevel@tonic-gate { 1230*0Sstevel@tonic-gate char *ptr; 1231*0Sstevel@tonic-gate int status; 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate *errmsg = NULL; 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate if (*value == '\0') 1236*0Sstevel@tonic-gate goto error; 1237*0Sstevel@tonic-gate 1238*0Sstevel@tonic-gate switch (token) { 1239*0Sstevel@tonic-gate case D_SCRIPT_VERSION: 1240*0Sstevel@tonic-gate if (rsi->cmd != C_SCRIPTINFO) 1241*0Sstevel@tonic-gate goto error; 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate /* check that value contains only digits */ 1244*0Sstevel@tonic-gate for (ptr = value; *ptr != '\0'; ptr++) 1245*0Sstevel@tonic-gate if (isdigit((int)(*ptr)) == 0) 1246*0Sstevel@tonic-gate break; 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate if (*ptr == '\0') 1249*0Sstevel@tonic-gate rsi->ver = atoi(value); 1250*0Sstevel@tonic-gate else 1251*0Sstevel@tonic-gate goto error; 1252*0Sstevel@tonic-gate 1253*0Sstevel@tonic-gate break; 1254*0Sstevel@tonic-gate 1255*0Sstevel@tonic-gate case D_SCRIPT_FUNC_INFO: 1256*0Sstevel@tonic-gate if (rsi->cmd != C_SCRIPTINFO) 1257*0Sstevel@tonic-gate goto error; 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate rcmscript_snprintf(&rsi->func_info_buf, 1260*0Sstevel@tonic-gate &rsi->func_info_buf_len, 1261*0Sstevel@tonic-gate &rsi->func_info_buf_curptr, 1262*0Sstevel@tonic-gate "%s", value); 1263*0Sstevel@tonic-gate break; 1264*0Sstevel@tonic-gate 1265*0Sstevel@tonic-gate case D_CMD_TIMEOUT: 1266*0Sstevel@tonic-gate if (rsi->cmd != C_SCRIPTINFO) 1267*0Sstevel@tonic-gate goto error; 1268*0Sstevel@tonic-gate 1269*0Sstevel@tonic-gate /* check that value contains only digits */ 1270*0Sstevel@tonic-gate for (ptr = value; *ptr != '\0'; ptr++) 1271*0Sstevel@tonic-gate if (isdigit((int)(*ptr)) == 0) 1272*0Sstevel@tonic-gate break; 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate if (*ptr == '\0') 1275*0Sstevel@tonic-gate rsi->cmd_timeout = atoi(value); 1276*0Sstevel@tonic-gate else 1277*0Sstevel@tonic-gate goto error; 1278*0Sstevel@tonic-gate break; 1279*0Sstevel@tonic-gate 1280*0Sstevel@tonic-gate case D_RESOURCE_NAME: 1281*0Sstevel@tonic-gate if (rsi->cmd != C_REGISTER) 1282*0Sstevel@tonic-gate goto error; 1283*0Sstevel@tonic-gate 1284*0Sstevel@tonic-gate if (get_capacity_descr(value) != NULL) 1285*0Sstevel@tonic-gate status = rcm_register_capacity(rsi->hdl, value, 1286*0Sstevel@tonic-gate 0, NULL); 1287*0Sstevel@tonic-gate else 1288*0Sstevel@tonic-gate status = rcm_register_interest(rsi->hdl, value, 0, 1289*0Sstevel@tonic-gate NULL); 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate if (status == RCM_FAILURE && errno == EALREADY) 1292*0Sstevel@tonic-gate status = RCM_SUCCESS; 1293*0Sstevel@tonic-gate 1294*0Sstevel@tonic-gate if (status != RCM_SUCCESS) { 1295*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MS_REGISTER_RSRC_ERR, 1296*0Sstevel@tonic-gate rsi->script_name, value); 1297*0Sstevel@tonic-gate } 1298*0Sstevel@tonic-gate 1299*0Sstevel@tonic-gate remove_from_unregister(rsi, value); 1300*0Sstevel@tonic-gate break; 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gate case D_RESOURCE_USAGE_INFO: 1303*0Sstevel@tonic-gate if (rsi->cmd != C_RESOURCEINFO) 1304*0Sstevel@tonic-gate goto error; 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate rcmscript_snprintf(&rsi->resource_usage_info_buf, 1307*0Sstevel@tonic-gate &rsi->resource_usage_info_buf_len, 1308*0Sstevel@tonic-gate &rsi->resource_usage_info_buf_curptr, 1309*0Sstevel@tonic-gate "%s", value); 1310*0Sstevel@tonic-gate break; 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gate case D_FAILURE_REASON: 1313*0Sstevel@tonic-gate rcmscript_snprintf(&rsi->failure_reason_buf, 1314*0Sstevel@tonic-gate &rsi->failure_reason_buf_len, 1315*0Sstevel@tonic-gate &rsi->failure_reason_buf_curptr, 1316*0Sstevel@tonic-gate "%s", value); 1317*0Sstevel@tonic-gate break; 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate default: 1320*0Sstevel@tonic-gate goto error; 1321*0Sstevel@tonic-gate } 1322*0Sstevel@tonic-gate 1323*0Sstevel@tonic-gate return (0); 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate error: 1326*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MS_PROTOCOL_ERR, rsi->script_name); 1327*0Sstevel@tonic-gate return (-1); 1328*0Sstevel@tonic-gate } 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate /* Send the given command to the script and process return data */ 1331*0Sstevel@tonic-gate static int 1332*0Sstevel@tonic-gate do_cmd(script_info_t *rsi, char *argv[], char *envp[], char **errmsg) 1333*0Sstevel@tonic-gate { 1334*0Sstevel@tonic-gate char buf[MAX_LINE_LEN]; 1335*0Sstevel@tonic-gate size_t buflen; 1336*0Sstevel@tonic-gate int loglevel = -1, continuelog = 0; 1337*0Sstevel@tonic-gate char *ptr, *dname, *value; 1338*0Sstevel@tonic-gate time_t maxsecs; 1339*0Sstevel@tonic-gate time_t deadline; 1340*0Sstevel@tonic-gate int sigaborted = 0; 1341*0Sstevel@tonic-gate int rval, child_status, token; 1342*0Sstevel@tonic-gate int error_num; 1343*0Sstevel@tonic-gate int cmd_timeout = rsi->cmd_timeout; 1344*0Sstevel@tonic-gate 1345*0Sstevel@tonic-gate *errmsg = NULL; 1346*0Sstevel@tonic-gate 1347*0Sstevel@tonic-gate script_process_sema_wait(); 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate if (run_script(rsi, argv, envp, errmsg) == -1) { 1350*0Sstevel@tonic-gate (void) sema_post(&script_process_sema); 1351*0Sstevel@tonic-gate goto error2; 1352*0Sstevel@tonic-gate } 1353*0Sstevel@tonic-gate 1354*0Sstevel@tonic-gate (void) time(&rsi->lastrun); 1355*0Sstevel@tonic-gate deadline = rsi->lastrun + cmd_timeout; 1356*0Sstevel@tonic-gate 1357*0Sstevel@tonic-gate if (thr_create(NULL, 0, (void *(*)(void *))read_stderr, rsi, 1358*0Sstevel@tonic-gate 0, &rsi->tid) != 0) { 1359*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MF_FUNC_CALL_ERR, 1360*0Sstevel@tonic-gate "thr_create", strerror(errno)); 1361*0Sstevel@tonic-gate goto error1; 1362*0Sstevel@tonic-gate } 1363*0Sstevel@tonic-gate rsi->flags |= STDERR_THREAD_CREATED; 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate /* LINTED */ 1366*0Sstevel@tonic-gate while (1) { 1367*0Sstevel@tonic-gate if (cmd_timeout > 0) { 1368*0Sstevel@tonic-gate maxsecs = deadline - time(NULL); 1369*0Sstevel@tonic-gate if (maxsecs <= 0) 1370*0Sstevel@tonic-gate goto timedout; 1371*0Sstevel@tonic-gate } else 1372*0Sstevel@tonic-gate maxsecs = 0; 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate rval = get_line(rsi->pipe1[PARENT_END_OF_PIPE], 1375*0Sstevel@tonic-gate "stdout", buf, MAX_LINE_LEN, &buflen, 1376*0Sstevel@tonic-gate maxsecs, &error_num); 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate if (buflen) { 1379*0Sstevel@tonic-gate if (continuelog) 1380*0Sstevel@tonic-gate log_msg(rsi, loglevel, buf); 1381*0Sstevel@tonic-gate else { 1382*0Sstevel@tonic-gate if ((ptr = strchr(buf, '=')) == NULL) 1383*0Sstevel@tonic-gate goto error; 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gate *ptr = '\0'; 1386*0Sstevel@tonic-gate dname = buf; 1387*0Sstevel@tonic-gate value = ptr + 1; 1388*0Sstevel@tonic-gate if ((token = dname_to_id(dname)) == -1) 1389*0Sstevel@tonic-gate goto error; 1390*0Sstevel@tonic-gate 1391*0Sstevel@tonic-gate switch (token) { 1392*0Sstevel@tonic-gate case D_LOG_ERR: 1393*0Sstevel@tonic-gate loglevel = RCM_ERROR; 1394*0Sstevel@tonic-gate break; 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate case D_LOG_WARN: 1397*0Sstevel@tonic-gate loglevel = RCM_WARNING; 1398*0Sstevel@tonic-gate break; 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate case D_LOG_INFO: 1401*0Sstevel@tonic-gate loglevel = RCM_INFO; 1402*0Sstevel@tonic-gate break; 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate case D_LOG_DEBUG: 1405*0Sstevel@tonic-gate loglevel = RCM_DEBUG; 1406*0Sstevel@tonic-gate break; 1407*0Sstevel@tonic-gate 1408*0Sstevel@tonic-gate default: 1409*0Sstevel@tonic-gate loglevel = -1; 1410*0Sstevel@tonic-gate break; 1411*0Sstevel@tonic-gate } 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate if (loglevel != -1) { 1414*0Sstevel@tonic-gate log_msg(rsi, loglevel, value); 1415*0Sstevel@tonic-gate if (buf[buflen - 1] == '\n') 1416*0Sstevel@tonic-gate continuelog = 0; 1417*0Sstevel@tonic-gate else 1418*0Sstevel@tonic-gate continuelog = 1; 1419*0Sstevel@tonic-gate } else { 1420*0Sstevel@tonic-gate if (buf[buflen - 1] != '\n') 1421*0Sstevel@tonic-gate goto error; 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gate buf[buflen - 1] = '\0'; 1424*0Sstevel@tonic-gate if (process_dataitem(rsi, token, 1425*0Sstevel@tonic-gate value, errmsg) != 0) 1426*0Sstevel@tonic-gate goto error1; 1427*0Sstevel@tonic-gate } 1428*0Sstevel@tonic-gate } 1429*0Sstevel@tonic-gate } 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate if (rval == -3) { 1432*0Sstevel@tonic-gate /* script exited */ 1433*0Sstevel@tonic-gate waitagain: 1434*0Sstevel@tonic-gate if (waitpid(rsi->pid, &child_status, 0) 1435*0Sstevel@tonic-gate != rsi->pid) { 1436*0Sstevel@tonic-gate if (errno == EINTR || errno == EAGAIN) 1437*0Sstevel@tonic-gate goto waitagain; 1438*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MS_SCRIPT_ERR, 1439*0Sstevel@tonic-gate rsi->script_name, strerror(errno)); 1440*0Sstevel@tonic-gate goto error1; 1441*0Sstevel@tonic-gate } 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate if (WIFEXITED(child_status)) { 1444*0Sstevel@tonic-gate script_exited(rsi); 1445*0Sstevel@tonic-gate rsi->exit_status = WEXITSTATUS(child_status); 1446*0Sstevel@tonic-gate } else { 1447*0Sstevel@tonic-gate if (sigaborted) 1448*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, 1449*0Sstevel@tonic-gate MS_TIMEOUT_ERR, rsi->script_name); 1450*0Sstevel@tonic-gate else 1451*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, 1452*0Sstevel@tonic-gate MS_UNKNOWN_ERR, rsi->script_name); 1453*0Sstevel@tonic-gate 1454*0Sstevel@tonic-gate /* kill any remaining processes in the pgrp */ 1455*0Sstevel@tonic-gate (void) kill(-(rsi->pid), SIGKILL); 1456*0Sstevel@tonic-gate script_exited(rsi); 1457*0Sstevel@tonic-gate goto error2; 1458*0Sstevel@tonic-gate } 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate break; 1461*0Sstevel@tonic-gate } 1462*0Sstevel@tonic-gate 1463*0Sstevel@tonic-gate if (rval == -1) { 1464*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MS_SCRIPT_ERR, 1465*0Sstevel@tonic-gate rsi->script_name, strerror(errno)); 1466*0Sstevel@tonic-gate goto error1; 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate if (rval == -2) { 1470*0Sstevel@tonic-gate timedout: 1471*0Sstevel@tonic-gate /* timeout occurred */ 1472*0Sstevel@tonic-gate if (sigaborted == 0) { 1473*0Sstevel@tonic-gate (void) kill(rsi->pid, SIGABRT); 1474*0Sstevel@tonic-gate sigaborted = 1; 1475*0Sstevel@tonic-gate /* extend deadline */ 1476*0Sstevel@tonic-gate deadline += SCRIPT_ABORT_TIMEOUT; 1477*0Sstevel@tonic-gate } else { 1478*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, 1479*0Sstevel@tonic-gate MS_TIMEOUT_ERR, rsi->script_name); 1480*0Sstevel@tonic-gate goto error1; 1481*0Sstevel@tonic-gate } 1482*0Sstevel@tonic-gate } 1483*0Sstevel@tonic-gate } 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate return (0); 1486*0Sstevel@tonic-gate 1487*0Sstevel@tonic-gate error: 1488*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MS_PROTOCOL_ERR, rsi->script_name); 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate error1: 1491*0Sstevel@tonic-gate kill_script(rsi); 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate error2: 1494*0Sstevel@tonic-gate return (-1); 1495*0Sstevel@tonic-gate } 1496*0Sstevel@tonic-gate 1497*0Sstevel@tonic-gate static int 1498*0Sstevel@tonic-gate do_script_info(script_info_t *rsi) 1499*0Sstevel@tonic-gate { 1500*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 1501*0Sstevel@tonic-gate int status = RCM_FAILURE; 1502*0Sstevel@tonic-gate int err = 0; 1503*0Sstevel@tonic-gate char *errmsg = NULL; 1504*0Sstevel@tonic-gate 1505*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "do_script_info: script name = %s\n", 1506*0Sstevel@tonic-gate rsi->script_name); 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate rsi->cmd = C_SCRIPTINFO; 1509*0Sstevel@tonic-gate rsi->func_info_buf = NULL; 1510*0Sstevel@tonic-gate rsi->failure_reason_buf = NULL; 1511*0Sstevel@tonic-gate fill_argv(rsi, argv, NULL); 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate if (do_cmd(rsi, argv, script_env, &errmsg) == 0) { 1514*0Sstevel@tonic-gate switch (rsi->exit_status) { 1515*0Sstevel@tonic-gate case E_SUCCESS: 1516*0Sstevel@tonic-gate if (rsi->func_info_buf != NULL && 1517*0Sstevel@tonic-gate rsi->failure_reason_buf == NULL) { 1518*0Sstevel@tonic-gate 1519*0Sstevel@tonic-gate if (rsi->ver >= SCRIPT_API_MIN_VER && 1520*0Sstevel@tonic-gate rsi->ver <= SCRIPT_API_MAX_VER) 1521*0Sstevel@tonic-gate status = RCM_SUCCESS; 1522*0Sstevel@tonic-gate else 1523*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 1524*0Sstevel@tonic-gate MS_UNSUPPORTED_VER, rsi->script_name, 1525*0Sstevel@tonic-gate rsi->ver); 1526*0Sstevel@tonic-gate } else 1527*0Sstevel@tonic-gate err = 1; 1528*0Sstevel@tonic-gate break; 1529*0Sstevel@tonic-gate 1530*0Sstevel@tonic-gate case E_FAILURE: 1531*0Sstevel@tonic-gate if (rsi->failure_reason_buf != NULL) { 1532*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MS_SCRIPTINFO_ERR, 1533*0Sstevel@tonic-gate rsi->script_name, 1534*0Sstevel@tonic-gate rsi->failure_reason_buf); 1535*0Sstevel@tonic-gate } else 1536*0Sstevel@tonic-gate err = 1; 1537*0Sstevel@tonic-gate break; 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate default: 1540*0Sstevel@tonic-gate err = 1; 1541*0Sstevel@tonic-gate break; 1542*0Sstevel@tonic-gate } 1543*0Sstevel@tonic-gate if (err) 1544*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MS_PROTOCOL_ERR, 1545*0Sstevel@tonic-gate rsi->script_name); 1546*0Sstevel@tonic-gate } else if (errmsg) 1547*0Sstevel@tonic-gate (void) free(errmsg); 1548*0Sstevel@tonic-gate 1549*0Sstevel@tonic-gate if (status != RCM_SUCCESS && rsi->func_info_buf != NULL) 1550*0Sstevel@tonic-gate free(rsi->func_info_buf); 1551*0Sstevel@tonic-gate 1552*0Sstevel@tonic-gate if (rsi->failure_reason_buf) 1553*0Sstevel@tonic-gate free(rsi->failure_reason_buf); 1554*0Sstevel@tonic-gate 1555*0Sstevel@tonic-gate return (status); 1556*0Sstevel@tonic-gate } 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate static int 1559*0Sstevel@tonic-gate do_dr(script_info_t *rsi, char *argv[], char *envp[], char **info) 1560*0Sstevel@tonic-gate { 1561*0Sstevel@tonic-gate int status = RCM_FAILURE; 1562*0Sstevel@tonic-gate int err = 0; 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate rsi->failure_reason_buf = NULL; 1565*0Sstevel@tonic-gate 1566*0Sstevel@tonic-gate if (do_cmd(rsi, argv, envp, info) == 0) { 1567*0Sstevel@tonic-gate switch (rsi->exit_status) { 1568*0Sstevel@tonic-gate case E_SUCCESS: 1569*0Sstevel@tonic-gate case E_UNSUPPORTED_CMD: 1570*0Sstevel@tonic-gate if (rsi->failure_reason_buf == NULL) 1571*0Sstevel@tonic-gate status = RCM_SUCCESS; 1572*0Sstevel@tonic-gate else 1573*0Sstevel@tonic-gate err = 1; 1574*0Sstevel@tonic-gate break; 1575*0Sstevel@tonic-gate 1576*0Sstevel@tonic-gate case E_FAILURE: 1577*0Sstevel@tonic-gate case E_REFUSE: 1578*0Sstevel@tonic-gate if (rsi->failure_reason_buf != NULL) { 1579*0Sstevel@tonic-gate *info = rsi->failure_reason_buf; 1580*0Sstevel@tonic-gate rsi->failure_reason_buf = NULL; 1581*0Sstevel@tonic-gate } else 1582*0Sstevel@tonic-gate err = 1; 1583*0Sstevel@tonic-gate break; 1584*0Sstevel@tonic-gate 1585*0Sstevel@tonic-gate default: 1586*0Sstevel@tonic-gate err = 1; 1587*0Sstevel@tonic-gate break; 1588*0Sstevel@tonic-gate } 1589*0Sstevel@tonic-gate 1590*0Sstevel@tonic-gate if (err) 1591*0Sstevel@tonic-gate *info = dup_err(RCM_ERROR, MS_PROTOCOL_ERR, 1592*0Sstevel@tonic-gate rsi->script_name); 1593*0Sstevel@tonic-gate } 1594*0Sstevel@tonic-gate 1595*0Sstevel@tonic-gate if (rsi->failure_reason_buf) 1596*0Sstevel@tonic-gate free(rsi->failure_reason_buf); 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gate return (status); 1599*0Sstevel@tonic-gate } 1600*0Sstevel@tonic-gate 1601*0Sstevel@tonic-gate /* 1602*0Sstevel@tonic-gate * get_info entry point 1603*0Sstevel@tonic-gate */ 1604*0Sstevel@tonic-gate /* ARGSUSED */ 1605*0Sstevel@tonic-gate static int 1606*0Sstevel@tonic-gate script_get_info(rcm_handle_t *hdl, 1607*0Sstevel@tonic-gate char *resource_name, 1608*0Sstevel@tonic-gate pid_t pid, 1609*0Sstevel@tonic-gate uint_t flag, 1610*0Sstevel@tonic-gate char **info, 1611*0Sstevel@tonic-gate char **error, 1612*0Sstevel@tonic-gate nvlist_t *props, 1613*0Sstevel@tonic-gate rcm_info_t **dependent_info) 1614*0Sstevel@tonic-gate { 1615*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 1616*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 1617*0Sstevel@tonic-gate int status = RCM_FAILURE; 1618*0Sstevel@tonic-gate int err = 0; 1619*0Sstevel@tonic-gate 1620*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "script_get_info: resource = %s\n", 1621*0Sstevel@tonic-gate resource_name); 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate *info = NULL; 1624*0Sstevel@tonic-gate *error = NULL; 1625*0Sstevel@tonic-gate 1626*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 1627*0Sstevel@tonic-gate 1628*0Sstevel@tonic-gate rsi->hdl = hdl; 1629*0Sstevel@tonic-gate rsi->cmd = C_RESOURCEINFO; 1630*0Sstevel@tonic-gate rsi->resource_usage_info_buf = NULL; 1631*0Sstevel@tonic-gate rsi->failure_reason_buf = NULL; 1632*0Sstevel@tonic-gate fill_argv(rsi, argv, resource_name); 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate if (do_cmd(rsi, argv, script_env, error) == 0) { 1635*0Sstevel@tonic-gate switch (rsi->exit_status) { 1636*0Sstevel@tonic-gate case E_SUCCESS: 1637*0Sstevel@tonic-gate if (rsi->resource_usage_info_buf != NULL && 1638*0Sstevel@tonic-gate rsi->failure_reason_buf == NULL) { 1639*0Sstevel@tonic-gate 1640*0Sstevel@tonic-gate *info = rsi->resource_usage_info_buf; 1641*0Sstevel@tonic-gate rsi->resource_usage_info_buf = NULL; 1642*0Sstevel@tonic-gate status = RCM_SUCCESS; 1643*0Sstevel@tonic-gate } else 1644*0Sstevel@tonic-gate err = 1; 1645*0Sstevel@tonic-gate break; 1646*0Sstevel@tonic-gate 1647*0Sstevel@tonic-gate case E_FAILURE: 1648*0Sstevel@tonic-gate if (rsi->failure_reason_buf != NULL) { 1649*0Sstevel@tonic-gate *error = rsi->failure_reason_buf; 1650*0Sstevel@tonic-gate rsi->failure_reason_buf = NULL; 1651*0Sstevel@tonic-gate } else 1652*0Sstevel@tonic-gate err = 1; 1653*0Sstevel@tonic-gate break; 1654*0Sstevel@tonic-gate 1655*0Sstevel@tonic-gate default: 1656*0Sstevel@tonic-gate err = 1; 1657*0Sstevel@tonic-gate break; 1658*0Sstevel@tonic-gate } 1659*0Sstevel@tonic-gate if (err) 1660*0Sstevel@tonic-gate *error = dup_err(RCM_ERROR, MS_PROTOCOL_ERR, 1661*0Sstevel@tonic-gate rsi->script_name); 1662*0Sstevel@tonic-gate } 1663*0Sstevel@tonic-gate 1664*0Sstevel@tonic-gate if (rsi->resource_usage_info_buf) 1665*0Sstevel@tonic-gate free(rsi->resource_usage_info_buf); 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate if (rsi->failure_reason_buf) 1668*0Sstevel@tonic-gate free(rsi->failure_reason_buf); 1669*0Sstevel@tonic-gate 1670*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 1671*0Sstevel@tonic-gate 1672*0Sstevel@tonic-gate return (status); 1673*0Sstevel@tonic-gate } 1674*0Sstevel@tonic-gate 1675*0Sstevel@tonic-gate static void 1676*0Sstevel@tonic-gate add_for_unregister(script_info_t *rsi) 1677*0Sstevel@tonic-gate { 1678*0Sstevel@tonic-gate module_t *module = rsi->module; 1679*0Sstevel@tonic-gate client_t *client; 1680*0Sstevel@tonic-gate rcm_queue_t *head; 1681*0Sstevel@tonic-gate rcm_queue_t *q; 1682*0Sstevel@tonic-gate 1683*0Sstevel@tonic-gate (void) mutex_lock(&rcm_req_lock); 1684*0Sstevel@tonic-gate 1685*0Sstevel@tonic-gate head = &module->client_q; 1686*0Sstevel@tonic-gate 1687*0Sstevel@tonic-gate for (q = head->next; q != head; q = q->next) { 1688*0Sstevel@tonic-gate client = RCM_STRUCT_BASE_ADDR(client_t, q, queue); 1689*0Sstevel@tonic-gate client->prv_flags |= RCM_NEED_TO_UNREGISTER; 1690*0Sstevel@tonic-gate } 1691*0Sstevel@tonic-gate 1692*0Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock); 1693*0Sstevel@tonic-gate } 1694*0Sstevel@tonic-gate 1695*0Sstevel@tonic-gate static void 1696*0Sstevel@tonic-gate remove_from_unregister(script_info_t *rsi, char *resource_name) 1697*0Sstevel@tonic-gate { 1698*0Sstevel@tonic-gate module_t *module = rsi->module; 1699*0Sstevel@tonic-gate client_t *client; 1700*0Sstevel@tonic-gate rcm_queue_t *head; 1701*0Sstevel@tonic-gate rcm_queue_t *q; 1702*0Sstevel@tonic-gate 1703*0Sstevel@tonic-gate (void) mutex_lock(&rcm_req_lock); 1704*0Sstevel@tonic-gate 1705*0Sstevel@tonic-gate head = &module->client_q; 1706*0Sstevel@tonic-gate 1707*0Sstevel@tonic-gate for (q = head->next; q != head; q = q->next) { 1708*0Sstevel@tonic-gate client = RCM_STRUCT_BASE_ADDR(client_t, q, queue); 1709*0Sstevel@tonic-gate if (strcmp(client->alias, resource_name) == 0) { 1710*0Sstevel@tonic-gate client->prv_flags &= ~RCM_NEED_TO_UNREGISTER; 1711*0Sstevel@tonic-gate break; 1712*0Sstevel@tonic-gate } 1713*0Sstevel@tonic-gate } 1714*0Sstevel@tonic-gate 1715*0Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock); 1716*0Sstevel@tonic-gate } 1717*0Sstevel@tonic-gate 1718*0Sstevel@tonic-gate static void 1719*0Sstevel@tonic-gate complete_unregister(script_info_t *rsi) 1720*0Sstevel@tonic-gate { 1721*0Sstevel@tonic-gate module_t *module = rsi->module; 1722*0Sstevel@tonic-gate client_t *client; 1723*0Sstevel@tonic-gate rcm_queue_t *head; 1724*0Sstevel@tonic-gate rcm_queue_t *q; 1725*0Sstevel@tonic-gate 1726*0Sstevel@tonic-gate (void) mutex_lock(&rcm_req_lock); 1727*0Sstevel@tonic-gate 1728*0Sstevel@tonic-gate head = &module->client_q; 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate for (q = head->next; q != head; q = q->next) { 1731*0Sstevel@tonic-gate client = RCM_STRUCT_BASE_ADDR(client_t, q, queue); 1732*0Sstevel@tonic-gate if (client->prv_flags & RCM_NEED_TO_UNREGISTER) { 1733*0Sstevel@tonic-gate client->prv_flags &= ~RCM_NEED_TO_UNREGISTER; 1734*0Sstevel@tonic-gate client->state = RCM_STATE_REMOVE; 1735*0Sstevel@tonic-gate } 1736*0Sstevel@tonic-gate } 1737*0Sstevel@tonic-gate 1738*0Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock); 1739*0Sstevel@tonic-gate } 1740*0Sstevel@tonic-gate 1741*0Sstevel@tonic-gate /* 1742*0Sstevel@tonic-gate * register_interest entry point 1743*0Sstevel@tonic-gate */ 1744*0Sstevel@tonic-gate static int 1745*0Sstevel@tonic-gate script_register_interest(rcm_handle_t *hdl) 1746*0Sstevel@tonic-gate { 1747*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 1748*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 1749*0Sstevel@tonic-gate int status = RCM_FAILURE; 1750*0Sstevel@tonic-gate int err = 0; 1751*0Sstevel@tonic-gate char *errmsg = NULL; 1752*0Sstevel@tonic-gate 1753*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, 1754*0Sstevel@tonic-gate "script_register_interest: script name = %s\n", 1755*0Sstevel@tonic-gate rsi->script_name); 1756*0Sstevel@tonic-gate 1757*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 1758*0Sstevel@tonic-gate 1759*0Sstevel@tonic-gate if (rsi->drreq_q.next != &rsi->drreq_q) { 1760*0Sstevel@tonic-gate /* if DR is already in progress no need to register again */ 1761*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 1762*0Sstevel@tonic-gate return (RCM_SUCCESS); 1763*0Sstevel@tonic-gate } 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate rsi->hdl = hdl; 1766*0Sstevel@tonic-gate rsi->cmd = C_REGISTER; 1767*0Sstevel@tonic-gate rsi->failure_reason_buf = NULL; 1768*0Sstevel@tonic-gate fill_argv(rsi, argv, NULL); 1769*0Sstevel@tonic-gate 1770*0Sstevel@tonic-gate add_for_unregister(rsi); 1771*0Sstevel@tonic-gate 1772*0Sstevel@tonic-gate if (do_cmd(rsi, argv, script_env, &errmsg) == 0) { 1773*0Sstevel@tonic-gate switch (rsi->exit_status) { 1774*0Sstevel@tonic-gate case E_SUCCESS: 1775*0Sstevel@tonic-gate status = RCM_SUCCESS; 1776*0Sstevel@tonic-gate break; 1777*0Sstevel@tonic-gate 1778*0Sstevel@tonic-gate case E_FAILURE: 1779*0Sstevel@tonic-gate if (rsi->failure_reason_buf != NULL) { 1780*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MS_REGISTER_ERR, 1781*0Sstevel@tonic-gate rsi->script_name, 1782*0Sstevel@tonic-gate rsi->failure_reason_buf); 1783*0Sstevel@tonic-gate } else 1784*0Sstevel@tonic-gate err = 1; 1785*0Sstevel@tonic-gate break; 1786*0Sstevel@tonic-gate 1787*0Sstevel@tonic-gate default: 1788*0Sstevel@tonic-gate err = 1; 1789*0Sstevel@tonic-gate break; 1790*0Sstevel@tonic-gate } 1791*0Sstevel@tonic-gate if (err) 1792*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MS_PROTOCOL_ERR, 1793*0Sstevel@tonic-gate rsi->script_name); 1794*0Sstevel@tonic-gate } else if (errmsg) 1795*0Sstevel@tonic-gate (void) free(errmsg); 1796*0Sstevel@tonic-gate 1797*0Sstevel@tonic-gate complete_unregister(rsi); 1798*0Sstevel@tonic-gate 1799*0Sstevel@tonic-gate if (rsi->failure_reason_buf) 1800*0Sstevel@tonic-gate free(rsi->failure_reason_buf); 1801*0Sstevel@tonic-gate 1802*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 1803*0Sstevel@tonic-gate 1804*0Sstevel@tonic-gate return (status); 1805*0Sstevel@tonic-gate } 1806*0Sstevel@tonic-gate 1807*0Sstevel@tonic-gate /* 1808*0Sstevel@tonic-gate * Add the specified resource name to the drreq_q. 1809*0Sstevel@tonic-gate */ 1810*0Sstevel@tonic-gate static void 1811*0Sstevel@tonic-gate add_drreq(script_info_t *rsi, char *resource_name) 1812*0Sstevel@tonic-gate { 1813*0Sstevel@tonic-gate rcm_queue_t *head = &rsi->drreq_q; 1814*0Sstevel@tonic-gate rcm_queue_t *q; 1815*0Sstevel@tonic-gate drreq_t *drreq; 1816*0Sstevel@tonic-gate 1817*0Sstevel@tonic-gate /* check if the dr req is already in the list */ 1818*0Sstevel@tonic-gate for (q = head->next; q != head; q = q->next) { 1819*0Sstevel@tonic-gate drreq = RCM_STRUCT_BASE_ADDR(drreq_t, q, queue); 1820*0Sstevel@tonic-gate if (strcmp(drreq->resource_name, resource_name) == 0) 1821*0Sstevel@tonic-gate /* dr req is already present in the queue */ 1822*0Sstevel@tonic-gate return; 1823*0Sstevel@tonic-gate } 1824*0Sstevel@tonic-gate 1825*0Sstevel@tonic-gate drreq = (drreq_t *)rcmscript_calloc(1, sizeof (drreq_t)); 1826*0Sstevel@tonic-gate drreq->resource_name = rcmscript_strdup(resource_name); 1827*0Sstevel@tonic-gate 1828*0Sstevel@tonic-gate rcm_enqueue_tail(&rsi->drreq_q, &drreq->queue); 1829*0Sstevel@tonic-gate } 1830*0Sstevel@tonic-gate 1831*0Sstevel@tonic-gate /* 1832*0Sstevel@tonic-gate * Remove the dr req for the specified resource name from the drreq_q. 1833*0Sstevel@tonic-gate */ 1834*0Sstevel@tonic-gate static void 1835*0Sstevel@tonic-gate remove_drreq(script_info_t *rsi, char *resource_name) 1836*0Sstevel@tonic-gate { 1837*0Sstevel@tonic-gate rcm_queue_t *head = &rsi->drreq_q; 1838*0Sstevel@tonic-gate rcm_queue_t *q; 1839*0Sstevel@tonic-gate drreq_t *drreq; 1840*0Sstevel@tonic-gate 1841*0Sstevel@tonic-gate /* search for dr req and remove from the list */ 1842*0Sstevel@tonic-gate for (q = head->next; q != head; q = q->next) { 1843*0Sstevel@tonic-gate drreq = RCM_STRUCT_BASE_ADDR(drreq_t, q, queue); 1844*0Sstevel@tonic-gate if (strcmp(drreq->resource_name, resource_name) == 0) 1845*0Sstevel@tonic-gate break; 1846*0Sstevel@tonic-gate } 1847*0Sstevel@tonic-gate 1848*0Sstevel@tonic-gate if (q != head) { 1849*0Sstevel@tonic-gate /* found drreq on the queue */ 1850*0Sstevel@tonic-gate rcm_dequeue(&drreq->queue); 1851*0Sstevel@tonic-gate free(drreq->resource_name); 1852*0Sstevel@tonic-gate free(drreq); 1853*0Sstevel@tonic-gate } 1854*0Sstevel@tonic-gate } 1855*0Sstevel@tonic-gate 1856*0Sstevel@tonic-gate /* 1857*0Sstevel@tonic-gate * Remove all dr req's. 1858*0Sstevel@tonic-gate */ 1859*0Sstevel@tonic-gate static void 1860*0Sstevel@tonic-gate remove_drreq_all(script_info_t *rsi) 1861*0Sstevel@tonic-gate { 1862*0Sstevel@tonic-gate drreq_t *drreq; 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate while (rsi->drreq_q.next != &rsi->drreq_q) { 1865*0Sstevel@tonic-gate drreq = RCM_STRUCT_BASE_ADDR(drreq_t, 1866*0Sstevel@tonic-gate rsi->drreq_q.next, queue); 1867*0Sstevel@tonic-gate remove_drreq(rsi, drreq->resource_name); 1868*0Sstevel@tonic-gate } 1869*0Sstevel@tonic-gate } 1870*0Sstevel@tonic-gate 1871*0Sstevel@tonic-gate /* 1872*0Sstevel@tonic-gate * request_offline entry point 1873*0Sstevel@tonic-gate */ 1874*0Sstevel@tonic-gate /* ARGSUSED */ 1875*0Sstevel@tonic-gate static int 1876*0Sstevel@tonic-gate script_request_offline(rcm_handle_t *hdl, 1877*0Sstevel@tonic-gate char *resource_name, 1878*0Sstevel@tonic-gate pid_t pid, 1879*0Sstevel@tonic-gate uint_t flag, 1880*0Sstevel@tonic-gate char **info, 1881*0Sstevel@tonic-gate rcm_info_t **dependent_info) 1882*0Sstevel@tonic-gate { 1883*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 1884*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 1885*0Sstevel@tonic-gate char *envp[MAX_ENV_PARAMS]; 1886*0Sstevel@tonic-gate char flags_name[MAX_FLAGS_NAME_LEN]; 1887*0Sstevel@tonic-gate int status; 1888*0Sstevel@tonic-gate int i; 1889*0Sstevel@tonic-gate 1890*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, 1891*0Sstevel@tonic-gate "script_request_offline: resource = %s flags = %s\n", 1892*0Sstevel@tonic-gate resource_name, 1893*0Sstevel@tonic-gate flags_to_name(flag, flags_name, MAX_FLAGS_NAME_LEN)); 1894*0Sstevel@tonic-gate 1895*0Sstevel@tonic-gate *info = NULL; 1896*0Sstevel@tonic-gate 1897*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 1898*0Sstevel@tonic-gate 1899*0Sstevel@tonic-gate rsi->hdl = hdl; 1900*0Sstevel@tonic-gate rsi->cmd = (flag & RCM_QUERY) ? C_QUERYREMOVE : C_PREREMOVE; 1901*0Sstevel@tonic-gate 1902*0Sstevel@tonic-gate if (rsi->cmd == C_PREREMOVE) 1903*0Sstevel@tonic-gate add_drreq(rsi, resource_name); 1904*0Sstevel@tonic-gate 1905*0Sstevel@tonic-gate fill_argv(rsi, argv, resource_name); 1906*0Sstevel@tonic-gate copy_env(script_env, envp); 1907*0Sstevel@tonic-gate for (i = 0; envp[i] != NULL; i++) 1908*0Sstevel@tonic-gate ; 1909*0Sstevel@tonic-gate envp[i++] = (flag & RCM_FORCE) ? script_env_force : script_env_noforce; 1910*0Sstevel@tonic-gate envp[i] = NULL; 1911*0Sstevel@tonic-gate 1912*0Sstevel@tonic-gate status = do_dr(rsi, argv, envp, info); 1913*0Sstevel@tonic-gate 1914*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 1915*0Sstevel@tonic-gate return (status); 1916*0Sstevel@tonic-gate } 1917*0Sstevel@tonic-gate 1918*0Sstevel@tonic-gate /* 1919*0Sstevel@tonic-gate * notify_online entry point 1920*0Sstevel@tonic-gate */ 1921*0Sstevel@tonic-gate /* ARGSUSED */ 1922*0Sstevel@tonic-gate static int 1923*0Sstevel@tonic-gate script_notify_online(rcm_handle_t *hdl, 1924*0Sstevel@tonic-gate char *resource_name, 1925*0Sstevel@tonic-gate pid_t pid, 1926*0Sstevel@tonic-gate uint_t flag, 1927*0Sstevel@tonic-gate char **info, 1928*0Sstevel@tonic-gate rcm_info_t **dependent_info) 1929*0Sstevel@tonic-gate { 1930*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 1931*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 1932*0Sstevel@tonic-gate int status; 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "script_notify_online: resource = %s\n", 1935*0Sstevel@tonic-gate resource_name); 1936*0Sstevel@tonic-gate 1937*0Sstevel@tonic-gate *info = NULL; 1938*0Sstevel@tonic-gate 1939*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 1940*0Sstevel@tonic-gate 1941*0Sstevel@tonic-gate rsi->hdl = hdl; 1942*0Sstevel@tonic-gate rsi->cmd = C_UNDOREMOVE; 1943*0Sstevel@tonic-gate fill_argv(rsi, argv, resource_name); 1944*0Sstevel@tonic-gate 1945*0Sstevel@tonic-gate status = do_dr(rsi, argv, script_env, info); 1946*0Sstevel@tonic-gate 1947*0Sstevel@tonic-gate remove_drreq(rsi, resource_name); 1948*0Sstevel@tonic-gate 1949*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 1950*0Sstevel@tonic-gate return (status); 1951*0Sstevel@tonic-gate } 1952*0Sstevel@tonic-gate 1953*0Sstevel@tonic-gate /* 1954*0Sstevel@tonic-gate * notify_remove entry point 1955*0Sstevel@tonic-gate */ 1956*0Sstevel@tonic-gate /* ARGSUSED */ 1957*0Sstevel@tonic-gate static int 1958*0Sstevel@tonic-gate script_notify_remove(rcm_handle_t *hdl, 1959*0Sstevel@tonic-gate char *resource_name, 1960*0Sstevel@tonic-gate pid_t pid, 1961*0Sstevel@tonic-gate uint_t flag, 1962*0Sstevel@tonic-gate char **info, 1963*0Sstevel@tonic-gate rcm_info_t **dependent_info) 1964*0Sstevel@tonic-gate { 1965*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 1966*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 1967*0Sstevel@tonic-gate int status; 1968*0Sstevel@tonic-gate 1969*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "script_notify_remove: resource = %s\n", 1970*0Sstevel@tonic-gate resource_name); 1971*0Sstevel@tonic-gate 1972*0Sstevel@tonic-gate *info = NULL; 1973*0Sstevel@tonic-gate 1974*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 1975*0Sstevel@tonic-gate 1976*0Sstevel@tonic-gate rsi->hdl = hdl; 1977*0Sstevel@tonic-gate rsi->cmd = C_POSTREMOVE; 1978*0Sstevel@tonic-gate fill_argv(rsi, argv, resource_name); 1979*0Sstevel@tonic-gate 1980*0Sstevel@tonic-gate status = do_dr(rsi, argv, script_env, info); 1981*0Sstevel@tonic-gate 1982*0Sstevel@tonic-gate remove_drreq(rsi, resource_name); 1983*0Sstevel@tonic-gate 1984*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 1985*0Sstevel@tonic-gate return (status); 1986*0Sstevel@tonic-gate } 1987*0Sstevel@tonic-gate 1988*0Sstevel@tonic-gate /* 1989*0Sstevel@tonic-gate * request_suspend entry point 1990*0Sstevel@tonic-gate */ 1991*0Sstevel@tonic-gate /* ARGSUSED */ 1992*0Sstevel@tonic-gate static int 1993*0Sstevel@tonic-gate script_request_suspend(rcm_handle_t *hdl, 1994*0Sstevel@tonic-gate char *resource_name, 1995*0Sstevel@tonic-gate pid_t pid, 1996*0Sstevel@tonic-gate timespec_t *interval, 1997*0Sstevel@tonic-gate uint_t flag, 1998*0Sstevel@tonic-gate char **info, 1999*0Sstevel@tonic-gate rcm_info_t **dependent_info) 2000*0Sstevel@tonic-gate { 2001*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 2002*0Sstevel@tonic-gate char *buf = NULL; 2003*0Sstevel@tonic-gate char *curptr = NULL; 2004*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 2005*0Sstevel@tonic-gate char *envp[MAX_ENV_PARAMS]; 2006*0Sstevel@tonic-gate char flags_name[MAX_FLAGS_NAME_LEN]; 2007*0Sstevel@tonic-gate int buflen = 0; 2008*0Sstevel@tonic-gate long seconds; 2009*0Sstevel@tonic-gate int status; 2010*0Sstevel@tonic-gate int i; 2011*0Sstevel@tonic-gate 2012*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, 2013*0Sstevel@tonic-gate "script_request_suspend: resource = %s flags = %s\n", resource_name, 2014*0Sstevel@tonic-gate flags_to_name(flag, flags_name, MAX_FLAGS_NAME_LEN)); 2015*0Sstevel@tonic-gate 2016*0Sstevel@tonic-gate *info = NULL; 2017*0Sstevel@tonic-gate 2018*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 2019*0Sstevel@tonic-gate 2020*0Sstevel@tonic-gate rsi->hdl = hdl; 2021*0Sstevel@tonic-gate rsi->cmd = (flag & RCM_QUERY) ? C_QUERYSUSPEND : C_PRESUSPEND; 2022*0Sstevel@tonic-gate 2023*0Sstevel@tonic-gate if (rsi->cmd == C_PRESUSPEND) 2024*0Sstevel@tonic-gate add_drreq(rsi, resource_name); 2025*0Sstevel@tonic-gate 2026*0Sstevel@tonic-gate fill_argv(rsi, argv, resource_name); 2027*0Sstevel@tonic-gate 2028*0Sstevel@tonic-gate copy_env(script_env, envp); 2029*0Sstevel@tonic-gate for (i = 0; envp[i] != NULL; i++); 2030*0Sstevel@tonic-gate 2031*0Sstevel@tonic-gate envp[i++] = (flag & RCM_FORCE) ? script_env_force : script_env_noforce; 2032*0Sstevel@tonic-gate 2033*0Sstevel@tonic-gate if (interval) { 2034*0Sstevel@tonic-gate /* 2035*0Sstevel@tonic-gate * Merge the seconds and nanoseconds, rounding up if there 2036*0Sstevel@tonic-gate * are any remainder nanoseconds. 2037*0Sstevel@tonic-gate */ 2038*0Sstevel@tonic-gate seconds = interval->tv_sec + (interval->tv_nsec / 1000000000L); 2039*0Sstevel@tonic-gate if (interval->tv_nsec % 1000000000L) 2040*0Sstevel@tonic-gate seconds += (interval->tv_sec > 0) ? 1L : -1L; 2041*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, script_env_interval, 2042*0Sstevel@tonic-gate seconds); 2043*0Sstevel@tonic-gate envp[i++] = buf; 2044*0Sstevel@tonic-gate } 2045*0Sstevel@tonic-gate 2046*0Sstevel@tonic-gate envp[i] = NULL; 2047*0Sstevel@tonic-gate 2048*0Sstevel@tonic-gate status = do_dr(rsi, argv, envp, info); 2049*0Sstevel@tonic-gate 2050*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 2051*0Sstevel@tonic-gate if (buf) 2052*0Sstevel@tonic-gate free(buf); 2053*0Sstevel@tonic-gate return (status); 2054*0Sstevel@tonic-gate } 2055*0Sstevel@tonic-gate 2056*0Sstevel@tonic-gate /* 2057*0Sstevel@tonic-gate * notify_resume entry point 2058*0Sstevel@tonic-gate */ 2059*0Sstevel@tonic-gate /* ARGSUSED */ 2060*0Sstevel@tonic-gate static int 2061*0Sstevel@tonic-gate script_notify_resume(rcm_handle_t *hdl, 2062*0Sstevel@tonic-gate char *resource_name, 2063*0Sstevel@tonic-gate pid_t pid, 2064*0Sstevel@tonic-gate uint_t flag, 2065*0Sstevel@tonic-gate char **info, 2066*0Sstevel@tonic-gate rcm_info_t **dependent_info) 2067*0Sstevel@tonic-gate { 2068*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 2069*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 2070*0Sstevel@tonic-gate int status; 2071*0Sstevel@tonic-gate 2072*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, "script_notify_resume: resource = %s\n", 2073*0Sstevel@tonic-gate resource_name); 2074*0Sstevel@tonic-gate 2075*0Sstevel@tonic-gate *info = NULL; 2076*0Sstevel@tonic-gate 2077*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 2078*0Sstevel@tonic-gate 2079*0Sstevel@tonic-gate rsi->hdl = hdl; 2080*0Sstevel@tonic-gate rsi->cmd = (flag & RCM_SUSPENDED) ? C_POSTRESUME : C_CANCELSUSPEND; 2081*0Sstevel@tonic-gate fill_argv(rsi, argv, resource_name); 2082*0Sstevel@tonic-gate 2083*0Sstevel@tonic-gate status = do_dr(rsi, argv, script_env, info); 2084*0Sstevel@tonic-gate 2085*0Sstevel@tonic-gate remove_drreq(rsi, resource_name); 2086*0Sstevel@tonic-gate 2087*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 2088*0Sstevel@tonic-gate return (status); 2089*0Sstevel@tonic-gate } 2090*0Sstevel@tonic-gate 2091*0Sstevel@tonic-gate static capacity_descr_t capacity_type[] = { 2092*0Sstevel@tonic-gate { "SUNW_memory", MATCH_EXACT, 2093*0Sstevel@tonic-gate "new_pages", "RCM_ENV_CAPACITY", 2094*0Sstevel@tonic-gate "page_size", "RCM_ENV_UNIT_SIZE", 2095*0Sstevel@tonic-gate "", ""}, 2096*0Sstevel@tonic-gate { "SUNW_cpu", MATCH_EXACT, 2097*0Sstevel@tonic-gate "new_total", "RCM_ENV_CAPACITY", 2098*0Sstevel@tonic-gate "new_cpu_list", "RCM_ENV_CPU_IDS", 2099*0Sstevel@tonic-gate "", ""}, 2100*0Sstevel@tonic-gate { "SUNW_cpu/set", MATCH_PREFIX, 2101*0Sstevel@tonic-gate "new_total", "RCM_ENV_CAPACITY", 2102*0Sstevel@tonic-gate "new_cpu_list", "RCM_ENV_CPU_IDS", 2103*0Sstevel@tonic-gate "", ""}, 2104*0Sstevel@tonic-gate { "", MATCH_INVALID, "", "" } 2105*0Sstevel@tonic-gate }; 2106*0Sstevel@tonic-gate 2107*0Sstevel@tonic-gate static capacity_descr_t * 2108*0Sstevel@tonic-gate get_capacity_descr(char *resource_name) 2109*0Sstevel@tonic-gate { 2110*0Sstevel@tonic-gate int i; 2111*0Sstevel@tonic-gate 2112*0Sstevel@tonic-gate for (i = 0; *capacity_type[i].resource_name != '\0'; i++) { 2113*0Sstevel@tonic-gate if ((capacity_type[i].match_type == MATCH_EXACT && 2114*0Sstevel@tonic-gate strcmp(capacity_type[i].resource_name, 2115*0Sstevel@tonic-gate resource_name) == 0) || 2116*0Sstevel@tonic-gate (capacity_type[i].match_type == MATCH_PREFIX && 2117*0Sstevel@tonic-gate strncmp(capacity_type[i].resource_name, 2118*0Sstevel@tonic-gate resource_name, 2119*0Sstevel@tonic-gate strlen(capacity_type[i].resource_name)) == 0)) 2120*0Sstevel@tonic-gate 2121*0Sstevel@tonic-gate return (&capacity_type[i]); 2122*0Sstevel@tonic-gate } 2123*0Sstevel@tonic-gate 2124*0Sstevel@tonic-gate return (NULL); 2125*0Sstevel@tonic-gate } 2126*0Sstevel@tonic-gate 2127*0Sstevel@tonic-gate static int 2128*0Sstevel@tonic-gate build_env_for_capacity(script_info_t *rsi, 2129*0Sstevel@tonic-gate char *resource_name, 2130*0Sstevel@tonic-gate uint_t flag, 2131*0Sstevel@tonic-gate nvlist_t *capacity_info, 2132*0Sstevel@tonic-gate char *envp[], 2133*0Sstevel@tonic-gate int *dynamic_env_index, 2134*0Sstevel@tonic-gate char **errmsg) 2135*0Sstevel@tonic-gate { 2136*0Sstevel@tonic-gate int p, i; 2137*0Sstevel@tonic-gate capacity_descr_t *capa = NULL; 2138*0Sstevel@tonic-gate nvpair_t *nvpair; 2139*0Sstevel@tonic-gate char *buf; 2140*0Sstevel@tonic-gate char *curptr; 2141*0Sstevel@tonic-gate int buflen; 2142*0Sstevel@tonic-gate int error; 2143*0Sstevel@tonic-gate uint_t n; 2144*0Sstevel@tonic-gate 2145*0Sstevel@tonic-gate copy_env(script_env, envp); 2146*0Sstevel@tonic-gate for (p = 0; envp[p] != NULL; p++) 2147*0Sstevel@tonic-gate ; 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate if (rsi->cmd == C_QUERYCAPACITY || rsi->cmd == C_PRECAPACITY) 2150*0Sstevel@tonic-gate envp[p++] = (flag & RCM_FORCE) ? script_env_force : 2151*0Sstevel@tonic-gate script_env_noforce; 2152*0Sstevel@tonic-gate 2153*0Sstevel@tonic-gate envp[p] = NULL; 2154*0Sstevel@tonic-gate *dynamic_env_index = p; 2155*0Sstevel@tonic-gate 2156*0Sstevel@tonic-gate if ((capa = get_capacity_descr(resource_name)) == NULL) { 2157*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MF_UNKNOWN_RSRC_ERR, 2158*0Sstevel@tonic-gate resource_name, rsi->script_name); 2159*0Sstevel@tonic-gate return (-1); 2160*0Sstevel@tonic-gate } 2161*0Sstevel@tonic-gate 2162*0Sstevel@tonic-gate for (i = 0; *capa->param[i].nvname != '\0'; i++) { 2163*0Sstevel@tonic-gate nvpair = NULL; 2164*0Sstevel@tonic-gate while ((nvpair = nvlist_next_nvpair(capacity_info, nvpair)) 2165*0Sstevel@tonic-gate != NULL) { 2166*0Sstevel@tonic-gate if (strcmp(nvpair_name(nvpair), 2167*0Sstevel@tonic-gate capa->param[i].nvname) == 0) 2168*0Sstevel@tonic-gate break; 2169*0Sstevel@tonic-gate } 2170*0Sstevel@tonic-gate 2171*0Sstevel@tonic-gate if (nvpair == NULL) { 2172*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MF_NV_ERR, 2173*0Sstevel@tonic-gate rsi->script_name); 2174*0Sstevel@tonic-gate return (-1); 2175*0Sstevel@tonic-gate } 2176*0Sstevel@tonic-gate 2177*0Sstevel@tonic-gate error = 0; 2178*0Sstevel@tonic-gate buf = NULL; 2179*0Sstevel@tonic-gate 2180*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, "%s=", 2181*0Sstevel@tonic-gate capa->param[i].envname); 2182*0Sstevel@tonic-gate 2183*0Sstevel@tonic-gate switch (nvpair_type(nvpair)) { 2184*0Sstevel@tonic-gate case DATA_TYPE_INT16: 2185*0Sstevel@tonic-gate { 2186*0Sstevel@tonic-gate int16_t x; 2187*0Sstevel@tonic-gate 2188*0Sstevel@tonic-gate if (nvpair_value_int16(nvpair, &x) == 0) { 2189*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, 2190*0Sstevel@tonic-gate "%hd", (short)x); 2191*0Sstevel@tonic-gate } else 2192*0Sstevel@tonic-gate error = 1; 2193*0Sstevel@tonic-gate break; 2194*0Sstevel@tonic-gate } 2195*0Sstevel@tonic-gate 2196*0Sstevel@tonic-gate case DATA_TYPE_UINT16: 2197*0Sstevel@tonic-gate { 2198*0Sstevel@tonic-gate uint16_t x; 2199*0Sstevel@tonic-gate 2200*0Sstevel@tonic-gate if (nvpair_value_uint16(nvpair, &x) == 0) { 2201*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, 2202*0Sstevel@tonic-gate "%hu", (unsigned short)x); 2203*0Sstevel@tonic-gate } else 2204*0Sstevel@tonic-gate error = 1; 2205*0Sstevel@tonic-gate break; 2206*0Sstevel@tonic-gate } 2207*0Sstevel@tonic-gate 2208*0Sstevel@tonic-gate case DATA_TYPE_INT32: 2209*0Sstevel@tonic-gate { 2210*0Sstevel@tonic-gate int32_t x; 2211*0Sstevel@tonic-gate 2212*0Sstevel@tonic-gate if (nvpair_value_int32(nvpair, &x) == 0) { 2213*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, 2214*0Sstevel@tonic-gate "%d", (int)x); 2215*0Sstevel@tonic-gate } else 2216*0Sstevel@tonic-gate error = 1; 2217*0Sstevel@tonic-gate break; 2218*0Sstevel@tonic-gate } 2219*0Sstevel@tonic-gate 2220*0Sstevel@tonic-gate case DATA_TYPE_UINT32: 2221*0Sstevel@tonic-gate { 2222*0Sstevel@tonic-gate uint32_t x; 2223*0Sstevel@tonic-gate 2224*0Sstevel@tonic-gate if (nvpair_value_uint32(nvpair, &x) == 0) { 2225*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, 2226*0Sstevel@tonic-gate "%u", (uint_t)x); 2227*0Sstevel@tonic-gate } else 2228*0Sstevel@tonic-gate error = 1; 2229*0Sstevel@tonic-gate break; 2230*0Sstevel@tonic-gate } 2231*0Sstevel@tonic-gate 2232*0Sstevel@tonic-gate case DATA_TYPE_INT64: 2233*0Sstevel@tonic-gate { 2234*0Sstevel@tonic-gate int64_t x; 2235*0Sstevel@tonic-gate 2236*0Sstevel@tonic-gate if (nvpair_value_int64(nvpair, &x) == 0) { 2237*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, 2238*0Sstevel@tonic-gate "%lld", (long long)x); 2239*0Sstevel@tonic-gate } else 2240*0Sstevel@tonic-gate error = 1; 2241*0Sstevel@tonic-gate break; 2242*0Sstevel@tonic-gate } 2243*0Sstevel@tonic-gate 2244*0Sstevel@tonic-gate case DATA_TYPE_UINT64: 2245*0Sstevel@tonic-gate { 2246*0Sstevel@tonic-gate uint64_t x; 2247*0Sstevel@tonic-gate 2248*0Sstevel@tonic-gate if (nvpair_value_uint64(nvpair, &x) == 0) { 2249*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, 2250*0Sstevel@tonic-gate "%llu", (unsigned long long)x); 2251*0Sstevel@tonic-gate } else 2252*0Sstevel@tonic-gate error = 1; 2253*0Sstevel@tonic-gate break; 2254*0Sstevel@tonic-gate } 2255*0Sstevel@tonic-gate 2256*0Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 2257*0Sstevel@tonic-gate { 2258*0Sstevel@tonic-gate int16_t *x; 2259*0Sstevel@tonic-gate 2260*0Sstevel@tonic-gate if (nvpair_value_int16_array(nvpair, &x, &n) == 0) { 2261*0Sstevel@tonic-gate while (n--) { 2262*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, 2263*0Sstevel@tonic-gate &curptr, "%hd%s", 2264*0Sstevel@tonic-gate (short)(*x), 2265*0Sstevel@tonic-gate (n == 0) ? "" : " "); 2266*0Sstevel@tonic-gate x++; 2267*0Sstevel@tonic-gate } 2268*0Sstevel@tonic-gate } else 2269*0Sstevel@tonic-gate error = 1; 2270*0Sstevel@tonic-gate break; 2271*0Sstevel@tonic-gate } 2272*0Sstevel@tonic-gate 2273*0Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 2274*0Sstevel@tonic-gate { 2275*0Sstevel@tonic-gate uint16_t *x; 2276*0Sstevel@tonic-gate 2277*0Sstevel@tonic-gate if (nvpair_value_uint16_array(nvpair, &x, &n) == 0) { 2278*0Sstevel@tonic-gate while (n--) { 2279*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, 2280*0Sstevel@tonic-gate &curptr, "%hu%s", 2281*0Sstevel@tonic-gate (unsigned short)(*x), 2282*0Sstevel@tonic-gate (n == 0) ? "" : " "); 2283*0Sstevel@tonic-gate x++; 2284*0Sstevel@tonic-gate } 2285*0Sstevel@tonic-gate } else 2286*0Sstevel@tonic-gate error = 1; 2287*0Sstevel@tonic-gate break; 2288*0Sstevel@tonic-gate } 2289*0Sstevel@tonic-gate 2290*0Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 2291*0Sstevel@tonic-gate { 2292*0Sstevel@tonic-gate int32_t *x; 2293*0Sstevel@tonic-gate 2294*0Sstevel@tonic-gate if (nvpair_value_int32_array(nvpair, &x, &n) == 0) { 2295*0Sstevel@tonic-gate while (n--) { 2296*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, 2297*0Sstevel@tonic-gate &curptr, "%d%s", 2298*0Sstevel@tonic-gate (int)(*x), 2299*0Sstevel@tonic-gate (n == 0) ? "" : " "); 2300*0Sstevel@tonic-gate x++; 2301*0Sstevel@tonic-gate } 2302*0Sstevel@tonic-gate } else 2303*0Sstevel@tonic-gate error = 1; 2304*0Sstevel@tonic-gate break; 2305*0Sstevel@tonic-gate } 2306*0Sstevel@tonic-gate 2307*0Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 2308*0Sstevel@tonic-gate { 2309*0Sstevel@tonic-gate uint32_t *x; 2310*0Sstevel@tonic-gate 2311*0Sstevel@tonic-gate if (nvpair_value_uint32_array(nvpair, &x, &n) == 0) { 2312*0Sstevel@tonic-gate while (n--) { 2313*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, 2314*0Sstevel@tonic-gate &curptr, "%u%s", 2315*0Sstevel@tonic-gate (uint_t)(*x), 2316*0Sstevel@tonic-gate (n == 0) ? "" : " "); 2317*0Sstevel@tonic-gate x++; 2318*0Sstevel@tonic-gate } 2319*0Sstevel@tonic-gate } else 2320*0Sstevel@tonic-gate error = 1; 2321*0Sstevel@tonic-gate break; 2322*0Sstevel@tonic-gate } 2323*0Sstevel@tonic-gate 2324*0Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 2325*0Sstevel@tonic-gate { 2326*0Sstevel@tonic-gate int64_t *x; 2327*0Sstevel@tonic-gate 2328*0Sstevel@tonic-gate if (nvpair_value_int64_array(nvpair, &x, &n) == 0) { 2329*0Sstevel@tonic-gate while (n--) { 2330*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, 2331*0Sstevel@tonic-gate &curptr, "%lld%s", 2332*0Sstevel@tonic-gate (long long)(*x), 2333*0Sstevel@tonic-gate (n == 0) ? "" : " "); 2334*0Sstevel@tonic-gate x++; 2335*0Sstevel@tonic-gate } 2336*0Sstevel@tonic-gate } else 2337*0Sstevel@tonic-gate error = 1; 2338*0Sstevel@tonic-gate break; 2339*0Sstevel@tonic-gate } 2340*0Sstevel@tonic-gate 2341*0Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 2342*0Sstevel@tonic-gate { 2343*0Sstevel@tonic-gate uint64_t *x; 2344*0Sstevel@tonic-gate 2345*0Sstevel@tonic-gate if (nvpair_value_uint64_array(nvpair, &x, &n) == 0) { 2346*0Sstevel@tonic-gate while (n--) { 2347*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, 2348*0Sstevel@tonic-gate &curptr, "%llu%s", 2349*0Sstevel@tonic-gate (unsigned long long)(*x), 2350*0Sstevel@tonic-gate (n == 0) ? "" : " "); 2351*0Sstevel@tonic-gate x++; 2352*0Sstevel@tonic-gate } 2353*0Sstevel@tonic-gate } else 2354*0Sstevel@tonic-gate error = 1; 2355*0Sstevel@tonic-gate break; 2356*0Sstevel@tonic-gate } 2357*0Sstevel@tonic-gate 2358*0Sstevel@tonic-gate case DATA_TYPE_STRING: 2359*0Sstevel@tonic-gate { 2360*0Sstevel@tonic-gate char *x; 2361*0Sstevel@tonic-gate 2362*0Sstevel@tonic-gate if (nvpair_value_string(nvpair, &x) == 0) { 2363*0Sstevel@tonic-gate rcmscript_snprintf(&buf, &buflen, &curptr, 2364*0Sstevel@tonic-gate "%s", x); 2365*0Sstevel@tonic-gate } else 2366*0Sstevel@tonic-gate error = 1; 2367*0Sstevel@tonic-gate break; 2368*0Sstevel@tonic-gate } 2369*0Sstevel@tonic-gate 2370*0Sstevel@tonic-gate 2371*0Sstevel@tonic-gate default: 2372*0Sstevel@tonic-gate error = 1; 2373*0Sstevel@tonic-gate break; 2374*0Sstevel@tonic-gate } 2375*0Sstevel@tonic-gate 2376*0Sstevel@tonic-gate envp[p++] = buf; 2377*0Sstevel@tonic-gate 2378*0Sstevel@tonic-gate if (error) { 2379*0Sstevel@tonic-gate envp[p] = NULL; 2380*0Sstevel@tonic-gate for (p = *dynamic_env_index; envp[p] != NULL; p++) 2381*0Sstevel@tonic-gate free(envp[p]); 2382*0Sstevel@tonic-gate *errmsg = dup_err(RCM_ERROR, MF_NV_ERR, 2383*0Sstevel@tonic-gate rsi->script_name); 2384*0Sstevel@tonic-gate return (-1); 2385*0Sstevel@tonic-gate } 2386*0Sstevel@tonic-gate } 2387*0Sstevel@tonic-gate 2388*0Sstevel@tonic-gate envp[p] = NULL; 2389*0Sstevel@tonic-gate 2390*0Sstevel@tonic-gate return (0); 2391*0Sstevel@tonic-gate } 2392*0Sstevel@tonic-gate 2393*0Sstevel@tonic-gate /* 2394*0Sstevel@tonic-gate * request_capacity_change entry point 2395*0Sstevel@tonic-gate */ 2396*0Sstevel@tonic-gate /* ARGSUSED */ 2397*0Sstevel@tonic-gate static int 2398*0Sstevel@tonic-gate script_request_capacity_change(rcm_handle_t *hdl, 2399*0Sstevel@tonic-gate char *resource_name, 2400*0Sstevel@tonic-gate pid_t pid, 2401*0Sstevel@tonic-gate uint_t flag, 2402*0Sstevel@tonic-gate nvlist_t *capacity_info, 2403*0Sstevel@tonic-gate char **info, 2404*0Sstevel@tonic-gate rcm_info_t **dependent_info) 2405*0Sstevel@tonic-gate { 2406*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 2407*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 2408*0Sstevel@tonic-gate char *envp[MAX_ENV_PARAMS]; 2409*0Sstevel@tonic-gate char flags_name[MAX_FLAGS_NAME_LEN]; 2410*0Sstevel@tonic-gate int status; 2411*0Sstevel@tonic-gate int dynamic_env_index; 2412*0Sstevel@tonic-gate 2413*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, 2414*0Sstevel@tonic-gate "script_request_capacity_change: resource = %s flags = %s\n", 2415*0Sstevel@tonic-gate resource_name, 2416*0Sstevel@tonic-gate flags_to_name(flag, flags_name, MAX_FLAGS_NAME_LEN)); 2417*0Sstevel@tonic-gate 2418*0Sstevel@tonic-gate *info = NULL; 2419*0Sstevel@tonic-gate 2420*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 2421*0Sstevel@tonic-gate 2422*0Sstevel@tonic-gate rsi->hdl = hdl; 2423*0Sstevel@tonic-gate rsi->cmd = (flag & RCM_QUERY) ? C_QUERYCAPACITY : C_PRECAPACITY; 2424*0Sstevel@tonic-gate fill_argv(rsi, argv, resource_name); 2425*0Sstevel@tonic-gate 2426*0Sstevel@tonic-gate if (build_env_for_capacity(rsi, resource_name, flag, 2427*0Sstevel@tonic-gate capacity_info, envp, &dynamic_env_index, info) == 0) { 2428*0Sstevel@tonic-gate 2429*0Sstevel@tonic-gate status = do_dr(rsi, argv, envp, info); 2430*0Sstevel@tonic-gate 2431*0Sstevel@tonic-gate while (envp[dynamic_env_index] != NULL) { 2432*0Sstevel@tonic-gate free(envp[dynamic_env_index]); 2433*0Sstevel@tonic-gate dynamic_env_index++; 2434*0Sstevel@tonic-gate } 2435*0Sstevel@tonic-gate } else 2436*0Sstevel@tonic-gate status = RCM_FAILURE; 2437*0Sstevel@tonic-gate 2438*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 2439*0Sstevel@tonic-gate return (status); 2440*0Sstevel@tonic-gate } 2441*0Sstevel@tonic-gate 2442*0Sstevel@tonic-gate /* 2443*0Sstevel@tonic-gate * notify_capacity_change entry point 2444*0Sstevel@tonic-gate */ 2445*0Sstevel@tonic-gate /* ARGSUSED */ 2446*0Sstevel@tonic-gate static int 2447*0Sstevel@tonic-gate script_notify_capacity_change(rcm_handle_t *hdl, 2448*0Sstevel@tonic-gate char *resource_name, 2449*0Sstevel@tonic-gate pid_t pid, 2450*0Sstevel@tonic-gate uint_t flag, 2451*0Sstevel@tonic-gate nvlist_t *capacity_info, 2452*0Sstevel@tonic-gate char **info, 2453*0Sstevel@tonic-gate rcm_info_t **dependent_info) 2454*0Sstevel@tonic-gate { 2455*0Sstevel@tonic-gate script_info_t *rsi = hdl->module->rsi; 2456*0Sstevel@tonic-gate char *argv[MAX_ARGS]; 2457*0Sstevel@tonic-gate char *envp[MAX_ENV_PARAMS]; 2458*0Sstevel@tonic-gate int status; 2459*0Sstevel@tonic-gate int dynamic_env_index; 2460*0Sstevel@tonic-gate 2461*0Sstevel@tonic-gate rcm_log_message(RSCR_TRACE, 2462*0Sstevel@tonic-gate "script_notify_capacity_change: resource = %s\n", resource_name); 2463*0Sstevel@tonic-gate 2464*0Sstevel@tonic-gate *info = NULL; 2465*0Sstevel@tonic-gate 2466*0Sstevel@tonic-gate (void) mutex_lock(&rsi->channel_lock); 2467*0Sstevel@tonic-gate 2468*0Sstevel@tonic-gate rsi->hdl = hdl; 2469*0Sstevel@tonic-gate rsi->cmd = C_POSTCAPACITY; 2470*0Sstevel@tonic-gate fill_argv(rsi, argv, resource_name); 2471*0Sstevel@tonic-gate 2472*0Sstevel@tonic-gate if (build_env_for_capacity(rsi, resource_name, flag, 2473*0Sstevel@tonic-gate capacity_info, envp, &dynamic_env_index, info) == 0) { 2474*0Sstevel@tonic-gate 2475*0Sstevel@tonic-gate status = do_dr(rsi, argv, envp, info); 2476*0Sstevel@tonic-gate 2477*0Sstevel@tonic-gate while (envp[dynamic_env_index] != NULL) { 2478*0Sstevel@tonic-gate free(envp[dynamic_env_index]); 2479*0Sstevel@tonic-gate dynamic_env_index++; 2480*0Sstevel@tonic-gate } 2481*0Sstevel@tonic-gate } else 2482*0Sstevel@tonic-gate status = RCM_FAILURE; 2483*0Sstevel@tonic-gate 2484*0Sstevel@tonic-gate (void) mutex_unlock(&rsi->channel_lock); 2485*0Sstevel@tonic-gate return (status); 2486*0Sstevel@tonic-gate } 2487*0Sstevel@tonic-gate 2488*0Sstevel@tonic-gate /* Log the message to syslog */ 2489*0Sstevel@tonic-gate static void 2490*0Sstevel@tonic-gate log_msg(script_info_t *rsi, int level, char *msg) 2491*0Sstevel@tonic-gate { 2492*0Sstevel@tonic-gate rcm_log_msg(level, MS_LOG_MSG, rsi->script_name, msg); 2493*0Sstevel@tonic-gate } 2494*0Sstevel@tonic-gate 2495*0Sstevel@tonic-gate /*PRINTFLIKE2*/ 2496*0Sstevel@tonic-gate static char * 2497*0Sstevel@tonic-gate dup_err(int level, char *format, ...) 2498*0Sstevel@tonic-gate { 2499*0Sstevel@tonic-gate va_list ap; 2500*0Sstevel@tonic-gate char buf1[1]; 2501*0Sstevel@tonic-gate char *buf2; 2502*0Sstevel@tonic-gate int n; 2503*0Sstevel@tonic-gate 2504*0Sstevel@tonic-gate va_start(ap, format); 2505*0Sstevel@tonic-gate n = vsnprintf(buf1, 1, format, ap); 2506*0Sstevel@tonic-gate va_end(ap); 2507*0Sstevel@tonic-gate 2508*0Sstevel@tonic-gate if (n > 0) { 2509*0Sstevel@tonic-gate n++; 2510*0Sstevel@tonic-gate if (buf2 = (char *)malloc(n)) { 2511*0Sstevel@tonic-gate va_start(ap, format); 2512*0Sstevel@tonic-gate n = vsnprintf(buf2, n, format, ap); 2513*0Sstevel@tonic-gate va_end(ap); 2514*0Sstevel@tonic-gate if (n > 0) { 2515*0Sstevel@tonic-gate if (level != -1) 2516*0Sstevel@tonic-gate rcm_log_message(level, buf2); 2517*0Sstevel@tonic-gate return (buf2); 2518*0Sstevel@tonic-gate } 2519*0Sstevel@tonic-gate free(buf2); 2520*0Sstevel@tonic-gate } 2521*0Sstevel@tonic-gate } 2522*0Sstevel@tonic-gate 2523*0Sstevel@tonic-gate return (NULL); 2524*0Sstevel@tonic-gate } 2525*0Sstevel@tonic-gate 2526*0Sstevel@tonic-gate /*PRINTFLIKE4*/ 2527*0Sstevel@tonic-gate static void 2528*0Sstevel@tonic-gate rcmscript_snprintf(char **buf, int *buflen, char **curptr, char *format, ...) 2529*0Sstevel@tonic-gate { 2530*0Sstevel@tonic-gate /* must be power of 2 otherwise RSCR_ROUNDUP would break */ 2531*0Sstevel@tonic-gate #define SPRINTF_CHUNK_LEN 512 2532*0Sstevel@tonic-gate #define SPRINTF_MIN_CHUNK_LEN 64 2533*0Sstevel@tonic-gate 2534*0Sstevel@tonic-gate va_list ap; 2535*0Sstevel@tonic-gate int offset, bytesneeded, bytesleft, error_num; 2536*0Sstevel@tonic-gate 2537*0Sstevel@tonic-gate if (*buf == NULL) { 2538*0Sstevel@tonic-gate *buflen = 0; 2539*0Sstevel@tonic-gate *curptr = NULL; 2540*0Sstevel@tonic-gate } 2541*0Sstevel@tonic-gate 2542*0Sstevel@tonic-gate offset = *curptr - *buf; 2543*0Sstevel@tonic-gate bytesneeded = SPRINTF_MIN_CHUNK_LEN; 2544*0Sstevel@tonic-gate bytesleft = *buflen - offset; 2545*0Sstevel@tonic-gate 2546*0Sstevel@tonic-gate /* LINTED */ 2547*0Sstevel@tonic-gate while (1) { 2548*0Sstevel@tonic-gate if (bytesneeded > bytesleft) { 2549*0Sstevel@tonic-gate *buflen += RSCR_ROUNDUP(bytesneeded - bytesleft, 2550*0Sstevel@tonic-gate SPRINTF_CHUNK_LEN); 2551*0Sstevel@tonic-gate if ((*buf = (char *)realloc(*buf, *buflen)) == NULL) { 2552*0Sstevel@tonic-gate error_num = errno; 2553*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 2554*0Sstevel@tonic-gate MF_MEMORY_ALLOCATION_ERR, 2555*0Sstevel@tonic-gate strerror(error_num)); 2556*0Sstevel@tonic-gate rcmd_exit(error_num); 2557*0Sstevel@tonic-gate /*NOTREACHED*/ 2558*0Sstevel@tonic-gate } 2559*0Sstevel@tonic-gate *curptr = *buf + offset; 2560*0Sstevel@tonic-gate bytesleft = *buflen - offset; 2561*0Sstevel@tonic-gate } 2562*0Sstevel@tonic-gate 2563*0Sstevel@tonic-gate va_start(ap, format); 2564*0Sstevel@tonic-gate bytesneeded = vsnprintf(*curptr, bytesleft, format, ap); 2565*0Sstevel@tonic-gate va_end(ap); 2566*0Sstevel@tonic-gate 2567*0Sstevel@tonic-gate if (bytesneeded < 0) { 2568*0Sstevel@tonic-gate /* vsnprintf encountered an error */ 2569*0Sstevel@tonic-gate error_num = errno; 2570*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_FUNC_CALL_ERR, 2571*0Sstevel@tonic-gate "vsnprintf", strerror(error_num)); 2572*0Sstevel@tonic-gate rcmd_exit(error_num); 2573*0Sstevel@tonic-gate /*NOTREACHED*/ 2574*0Sstevel@tonic-gate 2575*0Sstevel@tonic-gate } else if (bytesneeded < bytesleft) { 2576*0Sstevel@tonic-gate /* vsnprintf succeeded */ 2577*0Sstevel@tonic-gate *curptr += bytesneeded; 2578*0Sstevel@tonic-gate return; 2579*0Sstevel@tonic-gate 2580*0Sstevel@tonic-gate } else { 2581*0Sstevel@tonic-gate bytesneeded++; /* to account for storage for '\0' */ 2582*0Sstevel@tonic-gate } 2583*0Sstevel@tonic-gate } 2584*0Sstevel@tonic-gate } 2585*0Sstevel@tonic-gate 2586*0Sstevel@tonic-gate static char * 2587*0Sstevel@tonic-gate rcmscript_strdup(char *str) 2588*0Sstevel@tonic-gate { 2589*0Sstevel@tonic-gate char *dupstr; 2590*0Sstevel@tonic-gate 2591*0Sstevel@tonic-gate if ((dupstr = strdup(str)) == NULL) { 2592*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_MEMORY_ALLOCATION_ERR, 2593*0Sstevel@tonic-gate strerror(errno)); 2594*0Sstevel@tonic-gate rcmd_exit(errno); 2595*0Sstevel@tonic-gate /*NOTREACHED*/ 2596*0Sstevel@tonic-gate } 2597*0Sstevel@tonic-gate 2598*0Sstevel@tonic-gate return (dupstr); 2599*0Sstevel@tonic-gate } 2600*0Sstevel@tonic-gate 2601*0Sstevel@tonic-gate static void * 2602*0Sstevel@tonic-gate rcmscript_malloc(size_t len) 2603*0Sstevel@tonic-gate { 2604*0Sstevel@tonic-gate void *ptr; 2605*0Sstevel@tonic-gate 2606*0Sstevel@tonic-gate if ((ptr = malloc(len)) == NULL) { 2607*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_MEMORY_ALLOCATION_ERR, 2608*0Sstevel@tonic-gate strerror(errno)); 2609*0Sstevel@tonic-gate rcmd_exit(errno); 2610*0Sstevel@tonic-gate /*NOTREACHED*/ 2611*0Sstevel@tonic-gate } 2612*0Sstevel@tonic-gate 2613*0Sstevel@tonic-gate return (ptr); 2614*0Sstevel@tonic-gate } 2615*0Sstevel@tonic-gate 2616*0Sstevel@tonic-gate static void * 2617*0Sstevel@tonic-gate rcmscript_calloc(size_t nelem, size_t elsize) 2618*0Sstevel@tonic-gate { 2619*0Sstevel@tonic-gate void *ptr; 2620*0Sstevel@tonic-gate 2621*0Sstevel@tonic-gate if ((ptr = calloc(nelem, elsize)) == NULL) { 2622*0Sstevel@tonic-gate rcm_log_message(RCM_ERROR, MF_MEMORY_ALLOCATION_ERR, 2623*0Sstevel@tonic-gate strerror(errno)); 2624*0Sstevel@tonic-gate rcmd_exit(errno); 2625*0Sstevel@tonic-gate /*NOTREACHED*/ 2626*0Sstevel@tonic-gate } 2627*0Sstevel@tonic-gate 2628*0Sstevel@tonic-gate return (ptr); 2629*0Sstevel@tonic-gate } 2630