/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "librcm_impl.h"
#include "librcm_event.h"
#ifdef DEBUG
#else
#endif /* DEBUG */
static int rcm_daemon_is_alive();
rcm_info_t **);
rcm_info_t **);
rcm_info_t **);
char **, size_t *);
static int rcm_check_permission(void);
/*
* Allocate a handle structure
*/
/*ARGSUSED2*/
int
{
void *temp;
return (RCM_FAILURE);
}
if (rcm_check_permission() == 0) {
return (RCM_FAILURE);
}
return (RCM_FAILURE);
}
if (modname) {
return (RCM_FAILURE);
}
return (RCM_FAILURE);
}
}
} else {
}
return (RCM_SUCCESS);
}
/* free handle structure */
int
{
return (RCM_FAILURE);
}
}
return (RCM_SUCCESS);
}
/*
* Operations which require daemon processing
*/
/* get registration and DR information from rcm_daemon */
int
{
return (RCM_FAILURE);
}
/*
* rsrcname may be NULL if requesting dr operations or modinfo
*/
return (RCM_FAILURE);
}
}
/* get registration and DR information from rcm_daemon (list version) */
int
rcm_info_t **infop)
{
/* Requesting the current DR operations with a *list() is invalid */
return (RCM_FAILURE);
}
}
/* request to offline a resource before DR removal */
int
rcm_info_t **infop)
{
}
/* request to offline a resource before DR removal (list version) */
int
rcm_info_t **infop)
{
if (flag & ~RCM_REQUEST_MASK) {
return (RCM_FAILURE);
}
}
/* cancel offline request and allow apps to use rsrcname */
int
rcm_info_t **infop)
{
}
/* cancel offline and allow apps to use resources (list version) */
int
rcm_info_t **infop)
{
if (flag & ~RCM_NOTIFY_MASK) {
return (RCM_FAILURE);
}
}
/* notify that rsrcname has been removed */
int
rcm_info_t **infop)
{
}
/* notify that resrouces have been removed (list form) */
int
rcm_info_t **infop)
{
if (flag & ~RCM_NOTIFY_MASK) {
return (RCM_FAILURE);
}
}
/* request for permission to suspend resource of interval time */
int
{
}
/* request for permission to suspend resource of interval time (list form) */
int
{
return (RCM_FAILURE);
}
infop));
}
/* notify apps of the completion of resource suspension */
int
rcm_info_t **infop)
{
}
/* notify apps of the completion of resource suspension (list form) */
int
rcm_info_t **infop)
{
return (RCM_FAILURE);
}
}
/* request a capacity change from apps */
int
{
int rv;
return (RCM_FAILURE);
}
infop);
return (rv);
}
/* notify apps of a capacity change */
int
{
int rv;
return (RCM_FAILURE);
}
infop);
return (rv);
}
/* notify apps of an event */
int
rcm_info_t **infop)
{
int rv;
/* No flags are defined yet for rcm_notify_event() */
return (RCM_FAILURE);
}
return (rv);
}
/*
* Register to receive capacity changes. This requires a module to exist in
* module directory. It should be called prior to using a new resource.
*/
/* ARGSUSED */
int
rcm_info_t **infop)
{
if (flag & ~RCM_REGISTER_MASK) {
return (RCM_FAILURE);
}
}
/* unregister interest in capacity changes */
int
{
if (flag & ~RCM_REGISTER_MASK) {
return (RCM_FAILURE);
}
}
/*
* Register to receive events. This requires a module to exist in module
* directory. It should be called prior to using a new resource.
*/
/* ARGSUSED */
int
rcm_info_t **infop)
{
if (flag & ~RCM_REGISTER_MASK) {
return (RCM_FAILURE);
}
}
/* unregister interest in events */
int
{
if (flag & ~RCM_REGISTER_MASK) {
return (RCM_FAILURE);
}
}
/*
* Register interest in a resource. This requires a module to exist in module
* directory. It should be called prior to using a new resource.
*
* Registration may be denied if it is presently locked by a DR operation.
*/
/* ARGSUSED */
int
rcm_info_t **infop)
{
if (flag & ~RCM_REGISTER_MASK) {
return (RCM_FAILURE);
}
flag |= RCM_REGISTER_DR;
}
/* unregister interest in rsrcname */
int
{
if (flag & ~RCM_REGISTER_MASK) {
return (RCM_FAILURE);
}
flag |= RCM_REGISTER_DR;
}
/* get the current state of a resource */
int
{
int result;
int flag = 0;
return (RCM_FAILURE);
}
/*
* A successful result implies the presence of exactly one RCM info
* tuple containing the state of this resource (a combination of each
* client's resources). If that's not true, change the result to
* RCM_FAILURE.
*/
if (result == RCM_SUCCESS) {
}
}
if (infop)
return (result);
}
/*
* RCM helper functions exposed to librcm callers.
*/
/* Free linked list of registration info */
void
{
while (info) {
}
}
/* return the next tuple in the info structure */
{
return (NULL);
}
return ((rcm_info_tuple_t *)info);
}
}
/* return resource name */
const char *
{
return (NULL);
}
return (NULL);
return (rsrcname);
}
const char *
{
return (NULL);
}
return (NULL);
return (info);
}
const char *
{
return (NULL);
}
&errstr))
return (NULL);
return (errstr);
}
/* return info string in the tuple */
const char *
{
return (NULL);
}
&modname))
return (NULL);
return (modname);
}
/* return client pid in the tuple */
{
return ((pid_t)0);
}
return ((pid_t)0);
}
/* return client state in the tuple */
int
{
int state;
return (RCM_STATE_UNKNOWN);
}
return (RCM_STATE_UNKNOWN);
return (state);
}
/* return the generic properties in the tuple */
nvlist_t *
{
char *buf;
return (NULL);
}
return (NULL);
return (NULL);
}
return (nvl);
}
/*
* return operation sequence number
*
* This is private. Called by rcmctl only for testing purposes.
*/
int
{
int seqnum;
return (-1);
}
return (-1);
return (seqnum);
}
/*
* The following interfaces are PRIVATE to the RCM framework. They are not
* declared static because they are called by rcm_daemon.
*/
/*
* Invoke shell to execute command in MT safe manner.
* Returns wait status or -1 on error.
*/
int
{
int status, w;
_exit(127);
} else if (pid == -1) {
return (-1);
}
do {
return ((w == -1) ? w : status);
}
/* Append info at the very end */
int
{
return (RCM_FAILURE);
}
return (RCM_SUCCESS);
}
}
return (RCM_SUCCESS);
}
/* get rcm module and rcm script directory names */
char *
{
if (dirnum < N_MODULE_DIR)
else
return (NULL);
}
char *
{
if (dirnum < N_SCRIPT_DIR)
else
return (NULL);
}
char *
{
return (NULL);
if (dir_name[0][0] == '\0') {
/*
* construct the module directory names
*/
return (NULL);
} else {
infobuf) >= MAXPATHLEN ||
"invalid module or script directory for "
"platform %s\n", infobuf));
return (NULL);
}
}
return (NULL);
} else {
infobuf) >= MAXPATHLEN ||
"invalid module or script directory for "
"machine type %s\n", infobuf));
return (NULL);
}
}
MAXPATHLEN ||
MAXPATHLEN) >= MAXPATHLEN ||
MAXPATHLEN) >= MAXPATHLEN) {
"invalid module or script generic directory\n"));
return (NULL);
}
}
if (rcm_script)
}
/*
* Find the directory where the script is located.
* If the script is found return a pointer to the directory where the
* script was found otherwise return NULL.
*/
char *
{
uint_t i;
char *dir_name;
>= MAXPATHLEN) {
script_name));
continue;
}
return (dir_name);
}
return (NULL);
}
/*
* Returns 1 if the filename is an rcm script.
* Returns 0 if the filename is an rcm module.
*/
int
{
char *tmp;
return (0);
else
return (1);
}
/* Locate the module and call dlopen */
void *
{
unsigned i;
char *dir_name;
#ifdef DEBUG
#endif
/*
* dlopen the module
*/
>= MAXPATHLEN) {
modname));
continue;
}
return (dlhandle);
}
#ifdef DEBUG
modpath);
}
#endif
}
return (NULL);
}
/* dlclose module */
void
{
return;
}
/*
* stub implementation of rcm_log_message allows dlopen of rcm modules
* to proceed in absence of rcm_daemon.
*
* This definition is interposed by the definition in rcm_daemon because of the
* default search order implemented by the linker and dlsym(). All RCM modules
* will see the daemon version when loaded by the rcm_daemon.
*/
/* ARGSUSED */
void
{
}
/*
* Helper functions
*/
/*
* Common routine for all rcm calls which require daemon processing
*/
static int
rcm_info_t **infop)
{
int i;
return (RCM_FAILURE);
}
if (getuid() != 0) {
return (RCM_FAILURE);
}
return (RCM_FAILURE);
}
if (*rsrcnames[i] == '\0') {
return (RCM_FAILURE);
}
}
}
/*
* Check if handle is allocated by rcm_daemon. If so, this call came
* from an RCM module, so we make a direct call into rcm_daemon.
*/
}
/*
* When not called from a RCM module (i.e. no recursion), zero the
* pointer just in case caller did not do so. For recursive calls,
* we want to append rcm_info_t after infop; zero it may cause
* memory leaks.
*/
if (infop) {
}
/*
* Now call into the daemon.
*/
}
/*
* Caller is an RCM module, call directly into rcm_daemon.
*/
static int
{
int error;
switch (cmd) {
case CMD_GETINFO:
infop);
break;
case CMD_OFFLINE:
break;
case CMD_ONLINE:
break;
case CMD_REMOVE:
break;
case CMD_SUSPEND:
break;
case CMD_RESUME:
break;
case CMD_REGISTER:
break;
case CMD_UNREGISTER:
flag);
break;
case CMD_REQUEST_CHANGE:
break;
case CMD_NOTIFY_CHANGE:
break;
case CMD_EVENT:
break;
case CMD_GETSTATE:
break;
default:
}
if (error > 0) {
error = RCM_FAILURE;
}
return (error);
}
/*
* Call into rcm_daemon door to process the request
*/
static int
{
int errno_found;
int daemon_errno = 0;
errno = 0;
/*
* Decide whether to start the daemon
*/
switch (cmd) {
case CMD_GETINFO:
case CMD_OFFLINE:
case CMD_ONLINE:
case CMD_REMOVE:
case CMD_SUSPEND:
case CMD_RESUME:
case CMD_REGISTER:
case CMD_UNREGISTER:
case CMD_EVENT:
case CMD_REQUEST_CHANGE:
case CMD_NOTIFY_CHANGE:
case CMD_GETSTATE:
break;
default:
return (RCM_FAILURE);
}
if (rcm_daemon_is_alive() != 1) {
return (RCM_FAILURE);
}
/*
* Generate a packed nvlist for the request
*/
&nvl_size) < 0) {
return (RCM_FAILURE);
}
/*
* Make the door call and get a return event. We go into a retry loop
* when RCM_ET_EAGAIN is returned.
*/
return (RCM_FAILURE);
}
/*
* nvlist_lookup_* routines don't work because the returned nvlist
* was nvlist_alloc'ed without the NV_UNIQUE_NAME flag. Implement
* a sequential search manually, which is fine since there is only
* one RCM_RESULT value in the nvlist.
*/
errno_found = 0;
error = RCM_FAILURE;
goto out;
}
errno_found++;
break;
}
}
if (errno_found == 0) {
error = RCM_FAILURE;
goto out;
}
if (daemon_errno == EAGAIN) {
/*
* Wait and retry
*/
error = RCM_FAILURE;
goto out;
}
goto retry;
}
/*
* The door call succeeded. Now extract info from returned event.
*/
error = RCM_FAILURE;
goto out;
}
if (infop)
else
if (daemon_errno) {
if (daemon_errno > 0) {
error = RCM_FAILURE;
} else {
}
}
out:
if (nvl_packed)
return (error);
}
/*
* Extract registration info from event data.
* Return 0 on success and -1 on failure.
*/
static int
{
char *buf;
buflen = 0;
continue;
goto fail;
}
&buflen)) {
goto fail;
}
goto fail;
}
} else {
}
}
return (0);
fail:
return (-1);
}
/* Generate a packed nvlist for communicating with RCM daemon */
static int
{
int nrsrcnames;
*nvl_size = 0;
*nvl_packed = NULL;
/* Allocate an empty nvlist */
return (-1);
}
/* Stuff in all the arguments for the daemon call */
goto fail;
}
if (rsrcnames) {
nrsrcnames = 0;
nrsrcnames++;
nrsrcnames) != 0) {
goto fail;
}
}
!= 0) {
"failed (nvlist_add(CLIENT_MODNAME)=%s).\n",
goto fail;
}
}
goto fail;
}
}
if (flag) {
"failed (nvlist_add(REQUEST_FLAG)=%s).\n",
goto fail;
}
}
"failed (nvlist_add(SUSPEND_INTERVAL)=%s).\n",
goto fail;
}
}
if (arg &&
0)) {
"failed (nvlist_pack(CHANGE_DATA)=%s).\n",
goto fail;
}
buflen) != 0) {
"failed (nvlist_add(CHANGE_DATA)=%s).\n",
goto fail;
}
}
0)) {
"failed (nvlist_pack(CHANGE_DATA)=%s).\n",
goto fail;
}
buflen) != 0) {
"failed (nvlist_add(EVENT_DATA)=%s).\n",
goto fail;
}
}
/* Pack the nvlist */
0)) {
goto fail;
}
/* If an argument was packed intermediately, free the buffer */
if (buf)
/* Free the unpacked version of the nvlist and return the packed list */
return (0);
fail:
if (buf)
if (*nvl_packed)
free(*nvl_packed);
*nvl_packed = NULL;
*nvl_size = 0;
return (-1);
}
/* check if rcm_daemon is up and running */
static int
{
int lasttry;
/* generate a packed nvlist for the door knocking */
return (0);
}
return (0);
}
return (0);
}
/*
* check the door and knock on it
*/
NULL) == 0)) {
return (1); /* daemon is alive */
}
/*
* Attempt to start the daemon.
* If caller has SIGCHLD set to SIG_IGN or its SA_NOCLDWAIT
* flag set, waitpid(2) (hence rcm_exec_cmd) will fail.
* get_event_service will determine if the rcm_daemon started.
*/
(void) rcm_exec_cmd(RCM_DAEMON_START);
/*
* Wait for daemon to respond, timeout at 10 sec
*/
break;
}
delay *= 2;
}
if (lasttry == 0)
return (1);
return (0);
}
/*
* Check permission.
*
* The policy is root only for now. Need to relax this when interface level
* is raised.
*/
static int
rcm_check_permission(void)
{
return (getuid() == 0);
}
/*
* Project private function - for use by RCM MSTC tests
*
* Get the client name (rcm module name or script name) corresponding to
* the given rcm handle.
*/
const char *
{
}