/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* rcm scripting module:
*
* This module implements rcm scripting interfaces.
* It translates rcm module based interfaces to rcm script based
* interfaces.
*
* Entry points:
*
* int script_main_init()
* Initialize the rcm scripting framework.
* Called during the rcm daemon initialization
*
* int script_main_fini()
* Called at the time of the rcm daemon exit.
*
* struct rcm_mod_ops *script_init(module_t *module)
* Initialize the given script.
* module->name contains the name of the script.
* Called at the time of loading scripts.
* Semantics are similar to module init.
*
* char *script_info(module_t *module)
* Called when the rcm daemon wishes to get the script information.
* module->name contains the name of the script.
* Semantics are similar to module info.
*
* int script_fini(module_t *module)
* Called before removing the script.
* module->name contains the name of the script.
* Semantics are similar to module fini.
*
* In addition to the above entry points rcm_mod_ops structure contains
* the other entry points. A pointer to this structure is returned when
* script_init() is called.
*/
#include "rcm_impl.h"
#include "rcm_script_impl.h"
#include <sys/resource.h>
#include <procfs.h>
#include <ctype.h>
/*
* All rcm scripting commands are enumerated here.
* NOTE: command positions in script_cmd_id_t and script_cmd_name must match.
*/
typedef enum {
/* NOTE: command positions in script_cmd_id_t and script_cmd_name must match */
static char *script_cmd_name[] = {
"scriptinfo",
"resourceinfo",
"register",
"queryremove",
"preremove",
"postremove",
"undoremove",
"querycapacity",
"precapacity",
"postcapacity",
"querysuspend",
"presuspend",
"postresume",
"cancelsuspend",
};
/*
* All rcm scripting data items are enumerated here.
* NOTE: data item positions in script_data_item_id_t and
* script_data_item_name must match.
*/
typedef enum {
/*
* NOTE: data item positions in script_data_item_id_t and
* script_data_item_name must match.
*/
static const char *script_data_item_name[] = {
"rcm_script_version",
"rcm_script_func_info",
"rcm_cmd_timeout",
"rcm_resource_name",
"rcm_resource_usage_info",
"rcm_failure_reason",
"rcm_log_err",
"rcm_log_warn",
"rcm_log_info",
"rcm_log_debug",
};
/*
* Maximum number of rcm scripts that can run in parallel.
* RCM daemon has no limit on the number of scripts supported. But
* at most it runs script_max_parallelism number of scripts in parallel.
* For each running script rcm daemon consumes two file descriptors
* in order to communicate with the script via pipes.
* So maximum number of file descriptor entries consumed by rcm daemon
* on behalf of rcm scripts is "script_max_parallelism * 2"
*/
/*
* semaphore to limit the number of rcm script processes running in
* parallel to script_max_parallelism.
*/
/* mutex to protect the any global data */
/* contains head to a queue of script_info structures */
/*
* This mmapped state file is used to store the process id and
* rcm script name of all currently running rcm scripts.
*/
/* rcm script base environment */
/* function prototypes */
static void build_env(void);
static void copy_env(char *[], char *[]);
uint32_t);
static void truncate_state_file(state_file_descr_t *);
static void close_state_file(const char *, state_file_descr_t *);
static void grow_state_file(state_file_descr_t *);
static void *get_state_element(state_file_descr_t *, int, int *);
static void *allocate_state_element(state_file_descr_t *, int *);
static void free_state_element(void *);
static void script_ps_state_file_kill_pids(void);
static void script_ps_state_file_add_entry(pid_t, char *);
static void script_ps_state_file_remove_entry(pid_t);
static int dname_to_id(char *);
static void script_process_sema_wait(void);
static int run_script(script_info_t *, char *[], char *[], char **);
static void script_exited(script_info_t *);
static void kill_script(script_info_t *);
static char *flags_to_name(int, char *, int);
static void fill_argv(script_info_t *, char *[], char *);
static void *read_stderr(script_info_t *);
static int process_dataitem(script_info_t *, int, char *, char **);
static int do_cmd(script_info_t *, char *[], char *[], char **);
static int do_script_info(script_info_t *);
static int do_dr(script_info_t *, char *[], char *[], char **);
char **, nvlist_t *, rcm_info_t **);
static void add_for_unregister(script_info_t *);
static void remove_from_unregister(script_info_t *, char *);
static void complete_unregister(script_info_t *);
static int script_register_interest(rcm_handle_t *);
static void add_drreq(script_info_t *, char *);
static void remove_drreq(script_info_t *, char *);
static void remove_drreq_all(script_info_t *);
char **, rcm_info_t **);
char **, rcm_info_t **);
char **, rcm_info_t **);
uint_t, char **, rcm_info_t **);
char **, rcm_info_t **);
static capacity_descr_t *get_capacity_descr(char *);
char *[], int *, char **);
static void log_msg(script_info_t *, int, char *);
static char *dup_err(int, char *, ...);
static void rcmscript_snprintf(char **, int *, char **, char *, ...);
static char *rcmscript_strdup(char *);
static void *rcmscript_malloc(size_t);
{
script_register_interest, /* register */
script_register_interest, /* unregister */
};
/*
* Messages fall into two categories:
* framework messages (MF_..)
* errors directly attributable to scripts (MS_..)
*/
#define MF_MEMORY_ALLOCATION_ERR \
gettext("rcm: failed to allocate memory: %1$s\n")
#define MF_STATE_FILE_ERR \
gettext("rcm: state file error: %1$s: %2$s\n")
#define MF_FUNC_CALL_ERR \
gettext("rcm: %1$s: %2$s\n")
#define MF_NV_ERR \
gettext("rcm: required name-value parameters missing (%1$s)\n")
#define MF_UNKNOWN_RSRC_ERR \
gettext("rcm: unknown resource name %1$s (%2$s)\n")
#define MS_REGISTER_RSRC_ERR \
gettext("rcm script %1$s: failed to register %2$s\n")
#define MS_REGISTER_ERR \
gettext("rcm script %1$s: register: %2$s\n")
#define MS_SCRIPTINFO_ERR \
gettext("rcm script %1$s: scriptinfo: %2$s\n")
#define MS_PROTOCOL_ERR \
gettext("rcm script %1$s: scripting protocol error\n")
#define MS_TIMEOUT_ERR \
gettext("rcm script %1$s: timeout error\n")
#define MS_UNSUPPORTED_VER \
gettext("rcm script %1$s: unsupported version %2$d\n")
#define MS_SCRIPT_ERR \
gettext("rcm script %1$s: error: %2$s\n")
#define MS_UNKNOWN_ERR \
gettext("rcm script %1$s: unknown error\n")
#define MS_LOG_MSG \
gettext("rcm script %1$s: %2$s\n")
/*
* Initialize rcm scripting framework.
* Called during initialization of rcm daemon.
*/
int
script_main_init(void)
{
/* set base script environment */
build_env();
/*
* Initialize the semaphore to limit the number of rcm script
* process running in parallel to script_max_parallelism.
*/
USYNC_THREAD, NULL);
/* save original file limit */
sizeof (ps_state_element_t),
/*
* If any pids exist in the ps state file since the last incarnation of
* the rcm daemon, kill the pids.
* On a normal daemon exit no pids should exist in the ps state file.
* But on an abnormal daemon exit pids may exist in the ps state file.
*/
if (script_ps_statefd.state_file) {
}
return (0);
}
/*
* Do any cleanup.
* Called at the time of normal rcm daemon exit.
*/
int
script_main_fini(void)
{
return (0);
}
/*
* Initialize the given rcm script.
* module->name contains the name of the rcm script.
*/
struct rcm_mod_ops *
{
char *script_path;
return (NULL);
/* calloc also zeros the contents */
/*
* if the script hasn't specified a timeout value set it to
* default
*/
/* put rsi on script_info_q */
(void) mutex_lock(&script_lock);
(void) mutex_unlock(&script_lock);
return (&script_ops);
}
return (NULL);
}
/*
* Returns a string describing the script's functionality.
* module->name contains the name of the rcm script for which information
* is requested.
*/
char *
{
rsi->script_name);
return (rsi->func_info_buf);
}
/*
* Called before unloading the script.
* module->name contains the name of the rcm script which is being unloaded.
* Do any cleanup.
*/
int
{
rsi->script_name);
/* remove rsi from script_info_q */
(void) mutex_lock(&script_lock);
(void) mutex_unlock(&script_lock);
if (rsi->func_info_buf)
return (RCM_SUCCESS);
}
/* build base environment for scripts */
static void
build_env(void)
{
"LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME",
char *x;
int len;
int i, j = 0;
int d;
extern int debug_level;
if (x) {
env_list[i], x);
}
}
if (debug_level < 0)
d = 0;
else if (debug_level > 9)
d = 9;
else
d = debug_level;
script_env[j] = NULL;
}
static void
{
int i;
}
/*
* Open (or create if the file does not exist) the given state file
* and mmap it.
*/
static void
int chunk_size,
{
int error_num;
-1) {
/*NOTREACHED*/
}
/*NOTREACHED*/
}
/* LINTED */
/*NOTREACHED*/
}
}
} else {
}
}
static void
{
if (statefd->state_file) {
}
}
static void
{
}
/*
* Grow the state file by the chunk size specified in statefd
* and mmap it.
*/
static void
{
int max_elements;
int error_num;
if (statefd->state_file)
size = sizeof (state_file_t) +
/*NOTREACHED*/
}
/* LINTED */
/*NOTREACHED*/
}
}
/*
* Given index into state element array, get the pointer to the actual
* state element.
* If flag is non-null set *flag to
* TRUE if the state element is currently is use.
* FALSE if the state element is free.
*/
static void *
{
char *ptr;
if (statefd->state_file &&
ptr += sizeof (state_file_t) +
if (flag) {
STATE_ELEMENT_IN_USE) ? 1 : 0;
}
ptr += sizeof (state_element_t);
} else
return ((void *)ptr);
}
/*
* Allocate a state element entry in the state file and return a pointer
* to the allocated entry.
* If index is non-null set *index to index into the state element array
* of the allocated entry.
*/
static void *
{
void *x;
int i;
int flag;
if (statefd->state_file) {
/* find an empty slot */
&flag);
if (flag == 0)
/* entry is free */
break;
}
}
/* All entries are in use. Grow the list */
}
return (x);
}
static void
free_state_element(void *x)
{
}
/*
* Kill the pids contained in ps state file.
*/
static void
{
/* LINTED */
for (i = 0; 1; i++) {
if ((x = (ps_state_element_t *)get_state_element(
break;
(long)x->pid);
x->script_name) == 0) {
/*
* just a safety check to not to blow up
* system processes if the file is ever corrupt
*/
if (x->pid > 1) {
"script_ps_state_file_kill_pids: "
"killing script_name = %s pid = %ld\n",
x->script_name, x->pid);
/* kill the process group */
}
} else {
if (fd != -1)
}
free_state_element((void *)x);
}
}
}
/*
* Add a state element entry to ps state file.
*/
static void
{
(void) mutex_lock(&script_lock);
(void) mutex_unlock(&script_lock);
}
/*
* Remove the state element entry corresponding to pid from the
* ps state file.
*/
static void
{
int flag, i;
(void) mutex_lock(&script_lock);
/* LINTED */
for (i = 0; 1; i++) {
if ((x = (ps_state_element_t *)get_state_element(
break;
/* if the state element entry is in use and pid matches */
free_state_element((void *)x);
break;
}
}
(void) mutex_unlock(&script_lock);
}
/*
* Get data item id given data item name
*/
static int
{
int i;
for (i = 0; script_data_item_name[i] != NULL; i++) {
return (i);
}
return (-1);
}
/*
* Called before running any script.
* This routine waits until the number of script processes running in
* parallel drops down below to script_max_parallelism.
*/
static void
script_process_sema_wait(void)
{
int error_num;
/* LINTED */
while (1) {
if (sema_wait(&script_process_sema) == 0)
return;
/*NOTREACHED*/
}
}
/*NOTREACHED*/
}
/*
* Fork and execute the script.
*/
static int
{
i, argv[i]);
/* check that the script exists */
goto error;
/*
* If the syscall pipe fails because of reaching the max open file
* count per process then dynamically increase the limit on the max
* open file count.
*
* At present the rcm_daemon consumes file descriptor
* entries for the following files.
* RCM_STATE_FILE - /var/run/rcm_daemon_state
* DAEMON_LOCK_FILE - /var/run/rcm_daemon_lock
* RCM_SERVICE_DOOR - /var/run/rcm_daemon_door
* communicating with the rcm_daemon via doors
* dlopen for each rcm module
* When in daemon mode stdin, stdout and stderr are closed;
* openlog
* Some files which are opened briefly and closed such as
* directory files.
* Two file descriptors for each script in running state.
* Note that the constant script_max_parallelism sets an
* upper cap on how many rcm scripts can run in
* parallel.
*/
if (p1 == -1) {
goto error;
}
goto error;
} else
goto error;
}
goto forkagain;
goto error;
}
/* child process */
(void) setsid();
/* close stdin, stdout and stderr */
(void) close(0);
(void) close(1);
(void) close(2);
/* redirect stdout and stderr to pipe */
/* close all other file descriptors */
closefrom(3);
/* restore original file limit */
/* set current working dir */
/* root */
_exit(127);
} else {
_exit(127);
}
/*
* setuid sets real, effective and saved user ids to the
* given id.
* setgid sets real, effective and saved group ids to the
* given id.
*/
_exit(127);
/*NOTREACHED*/
}
return (0);
if (p1 != -1) {
}
if (p2 != -1) {
}
return (-1);
}
/*
* Reads one line of input (including the newline character) from the
* given file descriptor "fd" to buf.
* maxbuflen specifies the size of memory allocated for buf.
* Timeoutval is the max timeout value in seconds for the script to supply
* input. A timeoutval of 0 implies no timeout.
*
* Upon return *buflen contains the number of bytes read.
*
* Return values:
* 0 success
* -1 an error occured
* -2 timeout occurred
* -3 script exited
*/
static int
char *fdname,
char *buf,
int maxbuflen,
int *error_num)
{
char c = '\0';
int x;
char *ptr;
int timeit;
int rval = 0;
if (timeoutval) {
} else
if (timeit) {
if (timeoutval <= 0) {
rval = -2;
break;
}
if (x <= 0) {
if (x == 0)
/* poll timedout */
rval = -2;
else {
goto pollagain;
rval = -1;
}
break;
}
}
if (x == 0)
/*
* Script exited. Or more specifically the
* script has closed its end of the pipe.
*/
rval = -3;
else {
goto readagain;
rval = -1;
}
break;
}
*ptr++ = c;
len++;
}
*ptr = '\0';
"get_line(%s): rval = %d buflen = %d line = %s\n",
return (rval);
}
static void
{
}
(void) sema_post(&script_process_sema);
}
/*
* Kill the specified process group
*/
static int
{
int child_status;
/* kill the entire process group */
/* give some time for the script to be killed */
do {
return (0);
/* wait for 100 ms */
} while (timeleft > 0);
/* script process was not killed successfully */
return (-1);
}
/*
* Kill the specified script.
*/
static void
{
}
}
/*
* Convert rcm flags parameter to a string.
* Used for debug prints.
*/
static char *
{
return (buf);
}
static void
{
if (resource_name) {
} else
}
/*
* stderr thread:
* Reads stderr and logs to syslog.
* Runs as a separate thread.
*/
static void *
{
int error_num;
}
if (buflen)
return (NULL);
}
/* process return data items passed by scripts to the framework */
static int
{
char *ptr;
int status;
if (*value == '\0')
goto error;
switch (token) {
case D_SCRIPT_VERSION:
goto error;
/* check that value contains only digits */
break;
if (*ptr == '\0')
else
goto error;
break;
case D_SCRIPT_FUNC_INFO:
goto error;
"%s", value);
break;
case D_CMD_TIMEOUT:
goto error;
/* check that value contains only digits */
break;
if (*ptr == '\0')
else
goto error;
break;
case D_RESOURCE_NAME:
goto error;
0, NULL);
else
NULL);
if (status != RCM_SUCCESS) {
}
break;
case D_RESOURCE_USAGE_INFO:
goto error;
"%s", value);
break;
case D_FAILURE_REASON:
"%s", value);
break;
default:
goto error;
}
return (0);
return (-1);
}
/* Send the given command to the script and process return data */
static int
{
int sigaborted = 0;
int error_num;
(void) sema_post(&script_process_sema);
goto error2;
}
goto error1;
}
/* LINTED */
while (1) {
if (cmd_timeout > 0) {
if (maxsecs <= 0)
goto timedout;
} else
maxsecs = 0;
if (buflen) {
if (continuelog)
else {
goto error;
*ptr = '\0';
goto error;
switch (token) {
case D_LOG_ERR:
break;
case D_LOG_WARN:
break;
case D_LOG_INFO:
break;
case D_LOG_DEBUG:
break;
default:
loglevel = -1;
break;
}
if (loglevel != -1) {
continuelog = 0;
else
continuelog = 1;
} else {
goto error;
goto error1;
}
}
}
if (rval == -3) {
/* script exited */
goto waitagain;
goto error1;
}
if (WIFEXITED(child_status)) {
} else {
if (sigaborted)
else
/* kill any remaining processes in the pgrp */
goto error2;
}
break;
}
if (rval == -1) {
goto error1;
}
if (rval == -2) {
/* timeout occurred */
if (sigaborted == 0) {
sigaborted = 1;
/* extend deadline */
} else {
goto error1;
}
}
}
return (0);
return (-1);
}
static int
{
int err = 0;
rsi->script_name);
switch (rsi->exit_status) {
case E_SUCCESS:
else
} else
err = 1;
break;
case E_FAILURE:
} else
err = 1;
break;
default:
err = 1;
break;
}
if (err)
rsi->script_name);
} else if (errmsg)
if (rsi->failure_reason_buf)
return (status);
}
static int
{
int err = 0;
switch (rsi->exit_status) {
case E_SUCCESS:
case E_UNSUPPORTED_CMD:
else
err = 1;
break;
case E_FAILURE:
case E_REFUSE:
} else
err = 1;
break;
default:
err = 1;
break;
}
if (err)
rsi->script_name);
}
if (rsi->failure_reason_buf)
return (status);
}
/*
* get_info entry point
*/
/* ARGSUSED */
static int
char *resource_name,
char **info,
char **error,
{
int err = 0;
switch (rsi->exit_status) {
case E_SUCCESS:
} else
err = 1;
break;
case E_FAILURE:
} else
err = 1;
break;
default:
err = 1;
break;
}
if (err)
rsi->script_name);
}
if (rsi->resource_usage_info_buf)
if (rsi->failure_reason_buf)
return (status);
}
static void
{
rcm_queue_t *q;
(void) mutex_lock(&rcm_req_lock);
}
(void) mutex_unlock(&rcm_req_lock);
}
static void
{
rcm_queue_t *q;
(void) mutex_lock(&rcm_req_lock);
break;
}
}
(void) mutex_unlock(&rcm_req_lock);
}
static void
{
rcm_queue_t *q;
(void) mutex_lock(&rcm_req_lock);
}
}
(void) mutex_unlock(&rcm_req_lock);
}
/*
* register_interest entry point
*/
static int
{
int err = 0;
"script_register_interest: script name = %s\n",
rsi->script_name);
/* if DR is already in progress no need to register again */
return (RCM_SUCCESS);
}
switch (rsi->exit_status) {
case E_SUCCESS:
break;
case E_FAILURE:
} else
err = 1;
break;
default:
err = 1;
break;
}
if (err)
rsi->script_name);
} else if (errmsg)
if (rsi->failure_reason_buf)
return (status);
}
/*
* Add the specified resource name to the drreq_q.
*/
static void
{
rcm_queue_t *q;
/* check if the dr req is already in the list */
/* dr req is already present in the queue */
return;
}
}
/*
* Remove the dr req for the specified resource name from the drreq_q.
*/
static void
{
rcm_queue_t *q;
/* search for dr req and remove from the list */
break;
}
if (q != head) {
/* found drreq on the queue */
}
}
/*
* Remove all dr req's.
*/
static void
{
}
}
/*
* request_offline entry point
*/
/* ARGSUSED */
static int
char *resource_name,
char **info,
{
int status;
int i;
"script_request_offline: resource = %s flags = %s\n",
;
return (status);
}
/*
* notify_online entry point
*/
/* ARGSUSED */
static int
char *resource_name,
char **info,
{
int status;
return (status);
}
/*
* notify_remove entry point
*/
/* ARGSUSED */
static int
char *resource_name,
char **info,
{
int status;
return (status);
}
/*
* request_suspend entry point
*/
/* ARGSUSED */
static int
char *resource_name,
char **info,
{
int buflen = 0;
long seconds;
int status;
int i;
"script_request_suspend: resource = %s flags = %s\n", resource_name,
if (interval) {
/*
* Merge the seconds and nanoseconds, rounding up if there
* are any remainder nanoseconds.
*/
seconds);
}
if (buf)
return (status);
}
/*
* notify_resume entry point
*/
/* ARGSUSED */
static int
char *resource_name,
char **info,
{
int status;
return (status);
}
{ "SUNW_memory", MATCH_EXACT,
"new_pages", "RCM_ENV_CAPACITY",
"page_size", "RCM_ENV_UNIT_SIZE",
"", ""},
{ "SUNW_cpu", MATCH_EXACT,
"new_total", "RCM_ENV_CAPACITY",
"new_cpu_list", "RCM_ENV_CPU_IDS",
"", ""},
{ "SUNW_cpu/set", MATCH_PREFIX,
"new_total", "RCM_ENV_CAPACITY",
"new_cpu_list", "RCM_ENV_CPU_IDS",
"", ""},
};
static capacity_descr_t *
{
int i;
resource_name) == 0) ||
return (&capacity_type[i]);
}
return (NULL);
}
static int
char *resource_name,
char *envp[],
int *dynamic_env_index,
char **errmsg)
{
int p, i;
char *buf;
char *curptr;
int buflen;
int error;
uint_t n;
;
*dynamic_env_index = p;
return (-1);
}
!= NULL) {
break;
}
rsi->script_name);
return (-1);
}
error = 0;
switch (nvpair_type(nvpair)) {
case DATA_TYPE_INT16:
{
int16_t x;
if (nvpair_value_int16(nvpair, &x) == 0) {
"%hd", (short)x);
} else
error = 1;
break;
}
case DATA_TYPE_UINT16:
{
uint16_t x;
if (nvpair_value_uint16(nvpair, &x) == 0) {
"%hu", (unsigned short)x);
} else
error = 1;
break;
}
case DATA_TYPE_INT32:
{
int32_t x;
if (nvpair_value_int32(nvpair, &x) == 0) {
"%d", (int)x);
} else
error = 1;
break;
}
case DATA_TYPE_UINT32:
{
uint32_t x;
if (nvpair_value_uint32(nvpair, &x) == 0) {
"%u", (uint_t)x);
} else
error = 1;
break;
}
case DATA_TYPE_INT64:
{
int64_t x;
if (nvpair_value_int64(nvpair, &x) == 0) {
"%lld", (long long)x);
} else
error = 1;
break;
}
case DATA_TYPE_UINT64:
{
uint64_t x;
if (nvpair_value_uint64(nvpair, &x) == 0) {
"%llu", (unsigned long long)x);
} else
error = 1;
break;
}
case DATA_TYPE_INT16_ARRAY:
{
int16_t *x;
if (nvpair_value_int16_array(nvpair, &x, &n) == 0) {
while (n--) {
&curptr, "%hd%s",
(short)(*x),
(n == 0) ? "" : " ");
x++;
}
} else
error = 1;
break;
}
case DATA_TYPE_UINT16_ARRAY:
{
uint16_t *x;
if (nvpair_value_uint16_array(nvpair, &x, &n) == 0) {
while (n--) {
&curptr, "%hu%s",
(unsigned short)(*x),
(n == 0) ? "" : " ");
x++;
}
} else
error = 1;
break;
}
case DATA_TYPE_INT32_ARRAY:
{
int32_t *x;
if (nvpair_value_int32_array(nvpair, &x, &n) == 0) {
while (n--) {
&curptr, "%d%s",
(int)(*x),
(n == 0) ? "" : " ");
x++;
}
} else
error = 1;
break;
}
case DATA_TYPE_UINT32_ARRAY:
{
uint32_t *x;
if (nvpair_value_uint32_array(nvpair, &x, &n) == 0) {
while (n--) {
&curptr, "%u%s",
(uint_t)(*x),
(n == 0) ? "" : " ");
x++;
}
} else
error = 1;
break;
}
case DATA_TYPE_INT64_ARRAY:
{
int64_t *x;
if (nvpair_value_int64_array(nvpair, &x, &n) == 0) {
while (n--) {
&curptr, "%lld%s",
(long long)(*x),
(n == 0) ? "" : " ");
x++;
}
} else
error = 1;
break;
}
case DATA_TYPE_UINT64_ARRAY:
{
uint64_t *x;
if (nvpair_value_uint64_array(nvpair, &x, &n) == 0) {
while (n--) {
&curptr, "%llu%s",
(unsigned long long)(*x),
(n == 0) ? "" : " ");
x++;
}
} else
error = 1;
break;
}
case DATA_TYPE_STRING:
{
char *x;
if (nvpair_value_string(nvpair, &x) == 0) {
"%s", x);
} else
error = 1;
break;
}
default:
error = 1;
break;
}
if (error) {
rsi->script_name);
return (-1);
}
}
return (0);
}
/*
* request_capacity_change entry point
*/
/* ARGSUSED */
static int
char *resource_name,
char **info,
{
int status;
int dynamic_env_index;
"script_request_capacity_change: resource = %s flags = %s\n",
}
} else
return (status);
}
/*
* notify_capacity_change entry point
*/
/* ARGSUSED */
static int
char *resource_name,
char **info,
{
int status;
int dynamic_env_index;
"script_notify_capacity_change: resource = %s\n", resource_name);
}
} else
return (status);
}
/* Log the message to syslog */
static void
{
}
/*PRINTFLIKE2*/
static char *
{
char *buf2;
int n;
if (n > 0) {
n++;
if (n > 0) {
if (level != -1)
return (buf2);
}
}
}
return (NULL);
}
/*PRINTFLIKE4*/
static void
{
/* must be power of 2 otherwise RSCR_ROUNDUP would break */
*buflen = 0;
}
/* LINTED */
while (1) {
if (bytesneeded > bytesleft) {
/*NOTREACHED*/
}
}
if (bytesneeded < 0) {
/* vsnprintf encountered an error */
/*NOTREACHED*/
} else if (bytesneeded < bytesleft) {
/* vsnprintf succeeded */
*curptr += bytesneeded;
return;
} else {
bytesneeded++; /* to account for storage for '\0' */
}
}
}
static char *
{
char *dupstr;
/*NOTREACHED*/
}
return (dupstr);
}
static void *
{
void *ptr;
/*NOTREACHED*/
}
return (ptr);
}
static void *
{
void *ptr;
/*NOTREACHED*/
}
return (ptr);
}