xref: /onnv-gate/usr/src/lib/librcm/librcm.c (revision 3509:6db73ba0cde8)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3509Svikram  * Common Development and Distribution License (the "License").
6*3509Svikram  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3509Svikram  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include "librcm_impl.h"
290Sstevel@tonic-gate #include "librcm_event.h"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #ifdef	DEBUG
320Sstevel@tonic-gate static int rcm_debug = 1;
330Sstevel@tonic-gate #define	dprintf(args) if (rcm_debug) (void) fprintf args
340Sstevel@tonic-gate #else
350Sstevel@tonic-gate #define	dprintf(args) /* nothing */
360Sstevel@tonic-gate #endif	/* DEBUG */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate static int extract_info(nvlist_t *, rcm_info_t **);
390Sstevel@tonic-gate static int rcm_daemon_is_alive();
400Sstevel@tonic-gate static int rcm_common(int, rcm_handle_t *, char **, uint_t, void *,
410Sstevel@tonic-gate     rcm_info_t **);
420Sstevel@tonic-gate static int rcm_direct_call(int, rcm_handle_t *, char **, uint_t, void *,
430Sstevel@tonic-gate     rcm_info_t **);
440Sstevel@tonic-gate static int rcm_daemon_call(int, rcm_handle_t *, char **, uint_t, void *,
450Sstevel@tonic-gate     rcm_info_t **);
460Sstevel@tonic-gate static int rcm_generate_nvlist(int, rcm_handle_t *, char **, uint_t, void *,
470Sstevel@tonic-gate     char **, size_t *);
480Sstevel@tonic-gate static int rcm_check_permission(void);
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * Allocate a handle structure
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate /*ARGSUSED2*/
540Sstevel@tonic-gate int
rcm_alloc_handle(char * modname,uint_t flag,void * arg,rcm_handle_t ** hdp)550Sstevel@tonic-gate rcm_alloc_handle(char *modname, uint_t flag, void *arg, rcm_handle_t **hdp)
560Sstevel@tonic-gate {
570Sstevel@tonic-gate 	rcm_handle_t *hd;
580Sstevel@tonic-gate 	void *temp;
590Sstevel@tonic-gate 	char namebuf[MAXPATHLEN];
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	if ((hdp == NULL) || (flag & ~RCM_ALLOC_HDL_MASK)) {
620Sstevel@tonic-gate 		errno = EINVAL;
630Sstevel@tonic-gate 		return (RCM_FAILURE);
640Sstevel@tonic-gate 	}
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	if (rcm_check_permission() == 0) {
670Sstevel@tonic-gate 		errno = EPERM;
680Sstevel@tonic-gate 		return (RCM_FAILURE);
690Sstevel@tonic-gate 	}
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	if ((hd = calloc(1, sizeof (*hd))) == NULL) {
720Sstevel@tonic-gate 		return (RCM_FAILURE);
730Sstevel@tonic-gate 	}
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	if (modname) {
760Sstevel@tonic-gate 		(void) snprintf(namebuf, MAXPATHLEN, "%s%s", modname,
770Sstevel@tonic-gate 			RCM_MODULE_SUFFIX);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 		if ((hd->modname = strdup(namebuf)) == NULL) {
800Sstevel@tonic-gate 			free(hd);
810Sstevel@tonic-gate 			return (RCM_FAILURE);
820Sstevel@tonic-gate 		}
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 		if ((temp = rcm_module_open(namebuf)) == NULL) {
850Sstevel@tonic-gate 			free(hd->modname);
860Sstevel@tonic-gate 			free(hd);
870Sstevel@tonic-gate 			errno = EINVAL;
880Sstevel@tonic-gate 			return (RCM_FAILURE);
890Sstevel@tonic-gate 		}
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 		rcm_module_close(temp);
920Sstevel@tonic-gate 	}
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	if (flag & RCM_NOPID) {
950Sstevel@tonic-gate 		hd->pid = (pid_t)0;
960Sstevel@tonic-gate 	} else {
970Sstevel@tonic-gate 		hd->pid = (pid_t)getpid();
980Sstevel@tonic-gate 	}
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	*hdp = hd;
1010Sstevel@tonic-gate 	return (RCM_SUCCESS);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /* free handle structure */
1050Sstevel@tonic-gate int
rcm_free_handle(rcm_handle_t * hd)1060Sstevel@tonic-gate rcm_free_handle(rcm_handle_t *hd)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate 	if (hd == NULL) {
1090Sstevel@tonic-gate 		errno = EINVAL;
1100Sstevel@tonic-gate 		return (RCM_FAILURE);
1110Sstevel@tonic-gate 	}
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	if (hd->modname) {
1140Sstevel@tonic-gate 		free(hd->modname);
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	free(hd);
1180Sstevel@tonic-gate 	return (RCM_SUCCESS);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /*
1230Sstevel@tonic-gate  * Operations which require daemon processing
1240Sstevel@tonic-gate  */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /* get registration and DR information from rcm_daemon */
1270Sstevel@tonic-gate int
rcm_get_info(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)1280Sstevel@tonic-gate rcm_get_info(rcm_handle_t *hd, char *rsrcname, uint_t flag, rcm_info_t **infop)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	char *rsrcnames[2];
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	if ((flag & ~RCM_GET_INFO_MASK) || (infop == NULL)) {
1330Sstevel@tonic-gate 		errno = EINVAL;
1340Sstevel@tonic-gate 		return (RCM_FAILURE);
1350Sstevel@tonic-gate 	}
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	/*
1380Sstevel@tonic-gate 	 * rsrcname may be NULL if requesting dr operations or modinfo
1390Sstevel@tonic-gate 	 */
1400Sstevel@tonic-gate 	if ((rsrcname == NULL) &&
1410Sstevel@tonic-gate 	    ((flag & RCM_DR_OPERATION|RCM_MOD_INFO) == 0)) {
1420Sstevel@tonic-gate 		errno = EINVAL;
1430Sstevel@tonic-gate 		return (RCM_FAILURE);
1440Sstevel@tonic-gate 	}
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
1470Sstevel@tonic-gate 	rsrcnames[1] = NULL;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	return (rcm_common(CMD_GETINFO, hd, rsrcnames, flag, NULL, infop));
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate /* get registration and DR information from rcm_daemon (list version) */
1530Sstevel@tonic-gate int
rcm_get_info_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)1540Sstevel@tonic-gate rcm_get_info_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
1550Sstevel@tonic-gate     rcm_info_t **infop)
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate 	/* Requesting the current DR operations with a *list() is invalid */
1580Sstevel@tonic-gate 	if ((flag & RCM_DR_OPERATION) || (flag & RCM_MOD_INFO)) {
1590Sstevel@tonic-gate 		errno = EINVAL;
1600Sstevel@tonic-gate 		return (RCM_FAILURE);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	return (rcm_common(CMD_GETINFO, hd, rsrcnames, flag, NULL, infop));
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /* request to offline a resource before DR removal */
1670Sstevel@tonic-gate int
rcm_request_offline(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)1680Sstevel@tonic-gate rcm_request_offline(rcm_handle_t *hd, char *rsrcname, uint_t flag,
1690Sstevel@tonic-gate     rcm_info_t **infop)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	char *rsrcnames[2];
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
1740Sstevel@tonic-gate 	rsrcnames[1] = NULL;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return (rcm_request_offline_list(hd, rsrcnames, flag, infop));
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /* request to offline a resource before DR removal (list version) */
1800Sstevel@tonic-gate int
rcm_request_offline_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)1810Sstevel@tonic-gate rcm_request_offline_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
1820Sstevel@tonic-gate     rcm_info_t **infop)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	if (flag & ~RCM_REQUEST_MASK) {
1850Sstevel@tonic-gate 		errno = EINVAL;
1860Sstevel@tonic-gate 		return (RCM_FAILURE);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	return (rcm_common(CMD_OFFLINE, hd, rsrcnames, flag, NULL, infop));
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /* cancel offline request and allow apps to use rsrcname */
1930Sstevel@tonic-gate int
rcm_notify_online(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)1940Sstevel@tonic-gate rcm_notify_online(rcm_handle_t *hd, char *rsrcname, uint_t flag,
1950Sstevel@tonic-gate     rcm_info_t **infop)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	char *rsrcnames[2];
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
2000Sstevel@tonic-gate 	rsrcnames[1] = NULL;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	return (rcm_notify_online_list(hd, rsrcnames, flag, infop));
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate /* cancel offline and allow apps to use resources (list version) */
2060Sstevel@tonic-gate int
rcm_notify_online_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)2070Sstevel@tonic-gate rcm_notify_online_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
2080Sstevel@tonic-gate     rcm_info_t **infop)
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate 	if (flag & ~RCM_NOTIFY_MASK) {
2110Sstevel@tonic-gate 		errno = EINVAL;
2120Sstevel@tonic-gate 		return (RCM_FAILURE);
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	return (rcm_common(CMD_ONLINE, hd, rsrcnames, flag, NULL, infop));
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /* notify that rsrcname has been removed */
2190Sstevel@tonic-gate int
rcm_notify_remove(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)2200Sstevel@tonic-gate rcm_notify_remove(rcm_handle_t *hd, char *rsrcname, uint_t flag,
2210Sstevel@tonic-gate     rcm_info_t **infop)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	char *rsrcnames[2];
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
2260Sstevel@tonic-gate 	rsrcnames[1] = NULL;
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	return (rcm_notify_remove_list(hd, rsrcnames, flag, infop));
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /* notify that resrouces have been removed (list form) */
2320Sstevel@tonic-gate int
rcm_notify_remove_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)2330Sstevel@tonic-gate rcm_notify_remove_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
2340Sstevel@tonic-gate     rcm_info_t **infop)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	if (flag & ~RCM_NOTIFY_MASK) {
2370Sstevel@tonic-gate 		errno = EINVAL;
2380Sstevel@tonic-gate 		return (RCM_FAILURE);
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	return (rcm_common(CMD_REMOVE, hd, rsrcnames, flag, NULL, infop));
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate /* request for permission to suspend resource of interval time */
2450Sstevel@tonic-gate int
rcm_request_suspend(rcm_handle_t * hd,char * rsrcname,uint_t flag,timespec_t * interval,rcm_info_t ** infop)2460Sstevel@tonic-gate rcm_request_suspend(rcm_handle_t *hd, char *rsrcname, uint_t flag,
2470Sstevel@tonic-gate     timespec_t *interval, rcm_info_t **infop)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 	char *rsrcnames[2];
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
2520Sstevel@tonic-gate 	rsrcnames[1] = NULL;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	return (rcm_request_suspend_list(hd, rsrcnames, flag, interval, infop));
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /* request for permission to suspend resource of interval time (list form) */
2580Sstevel@tonic-gate int
rcm_request_suspend_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,timespec_t * interval,rcm_info_t ** infop)2590Sstevel@tonic-gate rcm_request_suspend_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
2600Sstevel@tonic-gate     timespec_t *interval, rcm_info_t **infop)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	if ((flag & ~RCM_REQUEST_MASK) || (interval == NULL) ||
2630Sstevel@tonic-gate 	    (interval->tv_sec < 0) || (interval->tv_nsec < 0)) {
2640Sstevel@tonic-gate 		errno = EINVAL;
2650Sstevel@tonic-gate 		return (RCM_FAILURE);
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	return (rcm_common(CMD_SUSPEND, hd, rsrcnames, flag, (void *)interval,
2690Sstevel@tonic-gate 	    infop));
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate /* notify apps of the completion of resource suspension */
2730Sstevel@tonic-gate int
rcm_notify_resume(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)2740Sstevel@tonic-gate rcm_notify_resume(rcm_handle_t *hd, char *rsrcname, uint_t flag,
2750Sstevel@tonic-gate     rcm_info_t **infop)
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	char *rsrcnames[2];
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
2800Sstevel@tonic-gate 	rsrcnames[1] = NULL;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	return (rcm_notify_resume_list(hd, rsrcnames, flag, infop));
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate /* notify apps of the completion of resource suspension (list form) */
2860Sstevel@tonic-gate int
rcm_notify_resume_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)2870Sstevel@tonic-gate rcm_notify_resume_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
2880Sstevel@tonic-gate     rcm_info_t **infop)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 	if (flag & ~(RCM_NOTIFY_MASK | RCM_SUSPENDED)) {
2910Sstevel@tonic-gate 		errno = EINVAL;
2920Sstevel@tonic-gate 		return (RCM_FAILURE);
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	return (rcm_common(CMD_RESUME, hd, rsrcnames, flag, NULL, infop));
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate /* request a capacity change from apps */
2990Sstevel@tonic-gate int
rcm_request_capacity_change(rcm_handle_t * hd,char * rsrcname,uint_t flag,nvlist_t * nvl,rcm_info_t ** infop)3000Sstevel@tonic-gate rcm_request_capacity_change(rcm_handle_t *hd, char *rsrcname, uint_t flag,
3010Sstevel@tonic-gate     nvlist_t *nvl, rcm_info_t **infop)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate 	int rv;
3040Sstevel@tonic-gate 	char *rsrcnames[2];
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	if ((nvl == NULL) || (flag & ~RCM_REQUEST_MASK)) {
3070Sstevel@tonic-gate 		errno = EINVAL;
3080Sstevel@tonic-gate 		return (RCM_FAILURE);
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
3120Sstevel@tonic-gate 	rsrcnames[1] = NULL;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	rv = rcm_common(CMD_REQUEST_CHANGE, hd, rsrcnames, flag, (void *)nvl,
3150Sstevel@tonic-gate 	    infop);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	return (rv);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate /* notify apps of a capacity change */
3210Sstevel@tonic-gate int
rcm_notify_capacity_change(rcm_handle_t * hd,char * rsrcname,uint_t flag,nvlist_t * nvl,rcm_info_t ** infop)3220Sstevel@tonic-gate rcm_notify_capacity_change(rcm_handle_t *hd, char *rsrcname, uint_t flag,
3230Sstevel@tonic-gate     nvlist_t *nvl, rcm_info_t **infop)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	int rv;
3260Sstevel@tonic-gate 	char *rsrcnames[2];
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if ((nvl == NULL) || (flag & ~RCM_REQUEST_MASK)) {
3290Sstevel@tonic-gate 		errno = EINVAL;
3300Sstevel@tonic-gate 		return (RCM_FAILURE);
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
3340Sstevel@tonic-gate 	rsrcnames[1] = NULL;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	rv = rcm_common(CMD_NOTIFY_CHANGE, hd, rsrcnames, flag, (void *)nvl,
3370Sstevel@tonic-gate 	    infop);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	return (rv);
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate /* notify apps of an event */
3430Sstevel@tonic-gate int
rcm_notify_event(rcm_handle_t * hd,char * rsrcname,uint_t flag,nvlist_t * nvl,rcm_info_t ** infop)3440Sstevel@tonic-gate rcm_notify_event(rcm_handle_t *hd, char *rsrcname, uint_t flag, nvlist_t *nvl,
3450Sstevel@tonic-gate     rcm_info_t **infop)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 	int rv;
3480Sstevel@tonic-gate 	char *rsrcnames[2];
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	/* No flags are defined yet for rcm_notify_event() */
3510Sstevel@tonic-gate 	if ((nvl == NULL) || (flag != 0)) {
3520Sstevel@tonic-gate 		errno = EINVAL;
3530Sstevel@tonic-gate 		return (RCM_FAILURE);
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
3570Sstevel@tonic-gate 	rsrcnames[1] = NULL;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	rv = rcm_common(CMD_EVENT, hd, rsrcnames, 0, (void *)nvl, infop);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	return (rv);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate /*
3650Sstevel@tonic-gate  * Register to receive capacity changes. This requires a module to exist in
3660Sstevel@tonic-gate  * module directory. It should be called prior to using a new resource.
3670Sstevel@tonic-gate  */
3680Sstevel@tonic-gate /* ARGSUSED */
3690Sstevel@tonic-gate int
rcm_register_capacity(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)3700Sstevel@tonic-gate rcm_register_capacity(rcm_handle_t *hd, char *rsrcname, uint_t flag,
3710Sstevel@tonic-gate     rcm_info_t **infop)
3720Sstevel@tonic-gate {
3730Sstevel@tonic-gate 	char *rsrcnames[2];
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
3760Sstevel@tonic-gate 		errno = EINVAL;
3770Sstevel@tonic-gate 		return (RCM_FAILURE);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	flag |= RCM_REGISTER_CAPACITY;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
3830Sstevel@tonic-gate 	rsrcnames[1] = NULL;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate /* unregister interest in capacity changes */
3890Sstevel@tonic-gate int
rcm_unregister_capacity(rcm_handle_t * hd,char * rsrcname,uint_t flag)3900Sstevel@tonic-gate rcm_unregister_capacity(rcm_handle_t *hd, char *rsrcname, uint_t flag)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	char *rsrcnames[2];
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
3950Sstevel@tonic-gate 		errno = EINVAL;
3960Sstevel@tonic-gate 		return (RCM_FAILURE);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	flag |= RCM_REGISTER_CAPACITY;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
4020Sstevel@tonic-gate 	rsrcnames[1] = NULL;
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate /*
4080Sstevel@tonic-gate  * Register to receive events. This requires a module to exist in module
4090Sstevel@tonic-gate  * directory. It should be called prior to using a new resource.
4100Sstevel@tonic-gate  */
4110Sstevel@tonic-gate /* ARGSUSED */
4120Sstevel@tonic-gate int
rcm_register_event(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)4130Sstevel@tonic-gate rcm_register_event(rcm_handle_t *hd, char *rsrcname, uint_t flag,
4140Sstevel@tonic-gate     rcm_info_t **infop)
4150Sstevel@tonic-gate {
4160Sstevel@tonic-gate 	char *rsrcnames[2];
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
4190Sstevel@tonic-gate 		errno = EINVAL;
4200Sstevel@tonic-gate 		return (RCM_FAILURE);
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	flag |= RCM_REGISTER_EVENT;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
4260Sstevel@tonic-gate 	rsrcnames[1] = NULL;
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate /* unregister interest in events */
4320Sstevel@tonic-gate int
rcm_unregister_event(rcm_handle_t * hd,char * rsrcname,uint_t flag)4330Sstevel@tonic-gate rcm_unregister_event(rcm_handle_t *hd, char *rsrcname, uint_t flag)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate 	char *rsrcnames[2];
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
4380Sstevel@tonic-gate 		errno = EINVAL;
4390Sstevel@tonic-gate 		return (RCM_FAILURE);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	flag |= RCM_REGISTER_EVENT;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
4450Sstevel@tonic-gate 	rsrcnames[1] = NULL;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate  * Register interest in a resource. This requires a module to exist in module
4520Sstevel@tonic-gate  * directory. It should be called prior to using a new resource.
4530Sstevel@tonic-gate  *
4540Sstevel@tonic-gate  * Registration may be denied if it is presently locked by a DR operation.
4550Sstevel@tonic-gate  */
4560Sstevel@tonic-gate /* ARGSUSED */
4570Sstevel@tonic-gate int
rcm_register_interest(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)4580Sstevel@tonic-gate rcm_register_interest(rcm_handle_t *hd, char *rsrcname, uint_t flag,
4590Sstevel@tonic-gate     rcm_info_t **infop)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate 	char *rsrcnames[2];
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
4640Sstevel@tonic-gate 		errno = EINVAL;
4650Sstevel@tonic-gate 		return (RCM_FAILURE);
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	flag |= RCM_REGISTER_DR;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
4710Sstevel@tonic-gate 	rsrcnames[1] = NULL;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate /* unregister interest in rsrcname */
4770Sstevel@tonic-gate int
rcm_unregister_interest(rcm_handle_t * hd,char * rsrcname,uint_t flag)4780Sstevel@tonic-gate rcm_unregister_interest(rcm_handle_t *hd, char *rsrcname, uint_t flag)
4790Sstevel@tonic-gate {
4800Sstevel@tonic-gate 	char *rsrcnames[2];
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
4830Sstevel@tonic-gate 		errno = EINVAL;
4840Sstevel@tonic-gate 		return (RCM_FAILURE);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	flag |= RCM_REGISTER_DR;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
4900Sstevel@tonic-gate 	rsrcnames[1] = NULL;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate /* get the current state of a resource */
4960Sstevel@tonic-gate int
rcm_get_rsrcstate(rcm_handle_t * hd,char * rsrcname,int * statep)4970Sstevel@tonic-gate rcm_get_rsrcstate(rcm_handle_t *hd, char *rsrcname, int *statep)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	int result;
5000Sstevel@tonic-gate 	int flag = 0;
5010Sstevel@tonic-gate 	rcm_info_t *infop = NULL;
5020Sstevel@tonic-gate 	rcm_info_tuple_t *tuple = NULL;
5030Sstevel@tonic-gate 	char *rsrcnames[2];
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	if (statep == NULL) {
5060Sstevel@tonic-gate 		errno = EINVAL;
5070Sstevel@tonic-gate 		return (RCM_FAILURE);
5080Sstevel@tonic-gate 	}
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
5110Sstevel@tonic-gate 	rsrcnames[1] = NULL;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	result = rcm_common(CMD_GETSTATE, hd, rsrcnames, flag, NULL, &infop);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/*
5160Sstevel@tonic-gate 	 * A successful result implies the presence of exactly one RCM info
5170Sstevel@tonic-gate 	 * tuple containing the state of this resource (a combination of each
5180Sstevel@tonic-gate 	 * client's resources).  If that's not true, change the result to
5190Sstevel@tonic-gate 	 * RCM_FAILURE.
5200Sstevel@tonic-gate 	 */
5210Sstevel@tonic-gate 	if (result == RCM_SUCCESS) {
5220Sstevel@tonic-gate 		if ((infop == NULL) ||
5230Sstevel@tonic-gate 		    ((tuple = rcm_info_next(infop, NULL)) == NULL) ||
5240Sstevel@tonic-gate 		    (rcm_info_next(infop, tuple) != NULL)) {
5250Sstevel@tonic-gate 			result = RCM_FAILURE;
5260Sstevel@tonic-gate 		} else if (infop && tuple) {
5270Sstevel@tonic-gate 			*statep = rcm_info_state(tuple);
5280Sstevel@tonic-gate 		}
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if (infop)
5320Sstevel@tonic-gate 		rcm_free_info(infop);
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	return (result);
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate /*
5380Sstevel@tonic-gate  * RCM helper functions exposed to librcm callers.
5390Sstevel@tonic-gate  */
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate /* Free linked list of registration info */
5420Sstevel@tonic-gate void
rcm_free_info(rcm_info_t * info)5430Sstevel@tonic-gate rcm_free_info(rcm_info_t *info)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate 	while (info) {
5460Sstevel@tonic-gate 		rcm_info_t *tmp = info->next;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 		if (info->info)
5490Sstevel@tonic-gate 			nvlist_free(info->info);
5500Sstevel@tonic-gate 		free(info);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		info = tmp;
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate /* return the next tuple in the info structure */
5570Sstevel@tonic-gate rcm_info_tuple_t *
rcm_info_next(rcm_info_t * info,rcm_info_tuple_t * tuple)5580Sstevel@tonic-gate rcm_info_next(rcm_info_t *info, rcm_info_tuple_t *tuple)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate 	if (info == NULL) {
5610Sstevel@tonic-gate 		errno = EINVAL;
5620Sstevel@tonic-gate 		return (NULL);
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	if (tuple == NULL) {
5660Sstevel@tonic-gate 		return ((rcm_info_tuple_t *)info);
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 	return ((rcm_info_tuple_t *)tuple->next);
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate /* return resource name */
5720Sstevel@tonic-gate const char *
rcm_info_rsrc(rcm_info_tuple_t * tuple)5730Sstevel@tonic-gate rcm_info_rsrc(rcm_info_tuple_t *tuple)
5740Sstevel@tonic-gate {
5750Sstevel@tonic-gate 	char *rsrcname = NULL;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
5780Sstevel@tonic-gate 		errno = EINVAL;
5790Sstevel@tonic-gate 		return (NULL);
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	if (errno = nvlist_lookup_string(tuple->info, RCM_RSRCNAME, &rsrcname))
5830Sstevel@tonic-gate 		return (NULL);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	return (rsrcname);
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate const char *
rcm_info_info(rcm_info_tuple_t * tuple)5890Sstevel@tonic-gate rcm_info_info(rcm_info_tuple_t *tuple)
5900Sstevel@tonic-gate {
5910Sstevel@tonic-gate 	char *info = NULL;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
5940Sstevel@tonic-gate 		errno = EINVAL;
5950Sstevel@tonic-gate 		return (NULL);
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_INFO, &info))
5990Sstevel@tonic-gate 		return (NULL);
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	return (info);
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate const char *
rcm_info_error(rcm_info_tuple_t * tuple)6050Sstevel@tonic-gate rcm_info_error(rcm_info_tuple_t *tuple)
6060Sstevel@tonic-gate {
6070Sstevel@tonic-gate 	char *errstr = NULL;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
6100Sstevel@tonic-gate 		errno = EINVAL;
6110Sstevel@tonic-gate 		return (NULL);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_ERROR,
6150Sstevel@tonic-gate 	    &errstr))
6160Sstevel@tonic-gate 		return (NULL);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	return (errstr);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate /* return info string in the tuple */
6220Sstevel@tonic-gate const char *
rcm_info_modname(rcm_info_tuple_t * tuple)6230Sstevel@tonic-gate rcm_info_modname(rcm_info_tuple_t *tuple)
6240Sstevel@tonic-gate {
6250Sstevel@tonic-gate 	char *modname = NULL;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
6280Sstevel@tonic-gate 		errno = EINVAL;
6290Sstevel@tonic-gate 		return (NULL);
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_MODNAME,
6330Sstevel@tonic-gate 	    &modname))
6340Sstevel@tonic-gate 		return (NULL);
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	return (modname);
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate /* return client pid in the tuple */
6400Sstevel@tonic-gate pid_t
rcm_info_pid(rcm_info_tuple_t * tuple)6410Sstevel@tonic-gate rcm_info_pid(rcm_info_tuple_t *tuple)
6420Sstevel@tonic-gate {
6430Sstevel@tonic-gate 	uint64_t pid64 = (uint64_t)0;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
6460Sstevel@tonic-gate 		errno = EINVAL;
6470Sstevel@tonic-gate 		return ((pid_t)0);
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	if (errno = nvlist_lookup_uint64(tuple->info, RCM_CLIENT_ID, &pid64))
6510Sstevel@tonic-gate 		return ((pid_t)0);
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	return ((pid_t)pid64);
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate /* return client state in the tuple */
6570Sstevel@tonic-gate int
rcm_info_state(rcm_info_tuple_t * tuple)6580Sstevel@tonic-gate rcm_info_state(rcm_info_tuple_t *tuple)
6590Sstevel@tonic-gate {
6600Sstevel@tonic-gate 	int state;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
6630Sstevel@tonic-gate 		errno = EINVAL;
6640Sstevel@tonic-gate 		return (RCM_STATE_UNKNOWN);
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	if (errno = nvlist_lookup_int32(tuple->info, RCM_RSRCSTATE, &state))
6680Sstevel@tonic-gate 		return (RCM_STATE_UNKNOWN);
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	return (state);
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate /* return the generic properties in the tuple */
6740Sstevel@tonic-gate nvlist_t *
rcm_info_properties(rcm_info_tuple_t * tuple)6750Sstevel@tonic-gate rcm_info_properties(rcm_info_tuple_t *tuple)
6760Sstevel@tonic-gate {
6770Sstevel@tonic-gate 	char *buf;
6780Sstevel@tonic-gate 	uint_t buflen;
6790Sstevel@tonic-gate 	nvlist_t *nvl;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
6820Sstevel@tonic-gate 		errno = EINVAL;
6830Sstevel@tonic-gate 		return (NULL);
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	if (errno = nvlist_lookup_byte_array(tuple->info, RCM_CLIENT_PROPERTIES,
6870Sstevel@tonic-gate 	    (uchar_t **)&buf, &buflen))
6880Sstevel@tonic-gate 		return (NULL);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	if (errno = nvlist_unpack(buf, buflen, &nvl, 0)) {
6910Sstevel@tonic-gate 		free(buf);
6920Sstevel@tonic-gate 		return (NULL);
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	return (nvl);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate /*
6990Sstevel@tonic-gate  * return operation sequence number
7000Sstevel@tonic-gate  *
7010Sstevel@tonic-gate  * This is private. Called by rcmctl only for testing purposes.
7020Sstevel@tonic-gate  */
7030Sstevel@tonic-gate int
rcm_info_seqnum(rcm_info_tuple_t * tuple)7040Sstevel@tonic-gate rcm_info_seqnum(rcm_info_tuple_t *tuple)
7050Sstevel@tonic-gate {
7060Sstevel@tonic-gate 	int seqnum;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
7090Sstevel@tonic-gate 		errno = EINVAL;
7100Sstevel@tonic-gate 		return (-1);
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	if (errno = nvlist_lookup_int32(tuple->info, RCM_SEQ_NUM, &seqnum))
7140Sstevel@tonic-gate 		return (-1);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	return (seqnum);
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate /*
7210Sstevel@tonic-gate  * The following interfaces are PRIVATE to the RCM framework. They are not
7220Sstevel@tonic-gate  * declared static because they are called by rcm_daemon.
7230Sstevel@tonic-gate  */
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate /*
7260Sstevel@tonic-gate  * Invoke shell to execute command in MT safe manner.
7270Sstevel@tonic-gate  * Returns wait status or -1 on error.
7280Sstevel@tonic-gate  */
7290Sstevel@tonic-gate int
rcm_exec_cmd(char * cmd)7300Sstevel@tonic-gate rcm_exec_cmd(char *cmd)
7310Sstevel@tonic-gate {
7320Sstevel@tonic-gate 	pid_t pid;
7330Sstevel@tonic-gate 	int status, w;
7340Sstevel@tonic-gate 	char *argvec[] = {"sh", "-c", NULL, NULL};
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	argvec[2] = cmd;
7370Sstevel@tonic-gate 	if ((pid = fork1()) == 0) {
7380Sstevel@tonic-gate 		(void) execv("/bin/sh", argvec);
7390Sstevel@tonic-gate 		_exit(127);
7400Sstevel@tonic-gate 	} else if (pid == -1) {
7410Sstevel@tonic-gate 		return (-1);
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	do {
7450Sstevel@tonic-gate 		w = waitpid(pid, &status, 0);
7460Sstevel@tonic-gate 	} while (w == -1 && errno == EINTR);
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	return ((w == -1) ? w : status);
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate /* Append info at the very end */
7520Sstevel@tonic-gate int
rcm_append_info(rcm_info_t ** head,rcm_info_t * info)7530Sstevel@tonic-gate rcm_append_info(rcm_info_t **head, rcm_info_t *info)
7540Sstevel@tonic-gate {
7550Sstevel@tonic-gate 	rcm_info_t *tuple;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	if (head == NULL) {
7580Sstevel@tonic-gate 		errno = EINVAL;
7590Sstevel@tonic-gate 		return (RCM_FAILURE);
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	if ((tuple = *head) == NULL) {
7630Sstevel@tonic-gate 		*head = info;
7640Sstevel@tonic-gate 		return (RCM_SUCCESS);
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	while (tuple->next) {
7680Sstevel@tonic-gate 		tuple = tuple->next;
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 	tuple->next = info;
7710Sstevel@tonic-gate 	return (RCM_SUCCESS);
7720Sstevel@tonic-gate }
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate /* get rcm module and rcm script directory names */
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate #define	N_MODULE_DIR	3	/* search 3 directories for modules */
7770Sstevel@tonic-gate #define	MODULE_DIR_HW	"/usr/platform/%s/lib/rcm/modules/"
7780Sstevel@tonic-gate #define	MODULE_DIR_GEN	"/usr/lib/rcm/modules/"
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate #define	N_SCRIPT_DIR	4	/* search 4 directories for scripts */
7810Sstevel@tonic-gate #define	SCRIPT_DIR_HW	"/usr/platform/%s/lib/rcm/scripts/"
7820Sstevel@tonic-gate #define	SCRIPT_DIR_GEN	"/usr/lib/rcm/scripts/"
7830Sstevel@tonic-gate #define	SCRIPT_DIR_ETC	"/etc/rcm/scripts/"
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate char *
rcm_module_dir(uint_t dirnum)7870Sstevel@tonic-gate rcm_module_dir(uint_t dirnum)
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate 	if (dirnum < N_MODULE_DIR)
7900Sstevel@tonic-gate 		return (rcm_dir(dirnum, NULL));
7910Sstevel@tonic-gate 	else
7920Sstevel@tonic-gate 		return (NULL);
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate char *
rcm_script_dir(uint_t dirnum)7960Sstevel@tonic-gate rcm_script_dir(uint_t dirnum)
7970Sstevel@tonic-gate {
7980Sstevel@tonic-gate 	if (dirnum < N_SCRIPT_DIR)
7990Sstevel@tonic-gate 		return (rcm_dir(dirnum + N_MODULE_DIR, NULL));
8000Sstevel@tonic-gate 	else
8010Sstevel@tonic-gate 		return (NULL);
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate char *
rcm_dir(uint_t dirnum,int * rcm_script)8050Sstevel@tonic-gate rcm_dir(uint_t dirnum, int *rcm_script)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	static char dir_name[N_MODULE_DIR + N_SCRIPT_DIR][MAXPATHLEN];
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	char infobuf[MAXPATHLEN];
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	if (dirnum >= (N_MODULE_DIR + N_SCRIPT_DIR))
8120Sstevel@tonic-gate 		return (NULL);
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (dir_name[0][0] == '\0') {
8150Sstevel@tonic-gate 		/*
8160Sstevel@tonic-gate 		 * construct the module directory names
8170Sstevel@tonic-gate 		 */
8180Sstevel@tonic-gate 		if (sysinfo(SI_PLATFORM, infobuf, MAXPATHLEN) == -1) {
8190Sstevel@tonic-gate 			dprintf((stderr, "sysinfo %s\n", strerror(errno)));
8200Sstevel@tonic-gate 			return (NULL);
8210Sstevel@tonic-gate 		} else {
8220Sstevel@tonic-gate 			if (snprintf(dir_name[0], MAXPATHLEN, MODULE_DIR_HW,
8230Sstevel@tonic-gate 			    infobuf) >= MAXPATHLEN ||
8240Sstevel@tonic-gate 			    snprintf(dir_name[N_MODULE_DIR + 1], MAXPATHLEN,
8250Sstevel@tonic-gate 			    SCRIPT_DIR_HW, infobuf) >= MAXPATHLEN) {
8260Sstevel@tonic-gate 				dprintf((stderr,
8270Sstevel@tonic-gate 				    "invalid module or script directory for "
8280Sstevel@tonic-gate 				    "platform %s\n", infobuf));
8290Sstevel@tonic-gate 				return (NULL);
8300Sstevel@tonic-gate 			}
8310Sstevel@tonic-gate 		}
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		if (sysinfo(SI_MACHINE, infobuf, MAXPATHLEN) == -1) {
8340Sstevel@tonic-gate 			dprintf((stderr, "sysinfo %s\n", strerror(errno)));
8350Sstevel@tonic-gate 			return (NULL);
8360Sstevel@tonic-gate 		} else {
8370Sstevel@tonic-gate 			if (snprintf(dir_name[1], MAXPATHLEN, MODULE_DIR_HW,
8380Sstevel@tonic-gate 			    infobuf) >= MAXPATHLEN ||
8390Sstevel@tonic-gate 			    snprintf(dir_name[N_MODULE_DIR + 2], MAXPATHLEN,
8400Sstevel@tonic-gate 			    SCRIPT_DIR_HW, infobuf) >= MAXPATHLEN) {
8410Sstevel@tonic-gate 				dprintf((stderr,
8420Sstevel@tonic-gate 				    "invalid module or script directory for "
8430Sstevel@tonic-gate 				    "machine type %s\n", infobuf));
8440Sstevel@tonic-gate 				return (NULL);
8450Sstevel@tonic-gate 			}
8460Sstevel@tonic-gate 		}
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 		if (strlcpy(dir_name[2], MODULE_DIR_GEN, MAXPATHLEN) >=
8490Sstevel@tonic-gate 		    MAXPATHLEN ||
8500Sstevel@tonic-gate 		    strlcpy(dir_name[N_MODULE_DIR + 3], SCRIPT_DIR_GEN,
8510Sstevel@tonic-gate 		    MAXPATHLEN) >= MAXPATHLEN ||
8520Sstevel@tonic-gate 		    strlcpy(dir_name[N_MODULE_DIR + 0], SCRIPT_DIR_ETC,
8530Sstevel@tonic-gate 		    MAXPATHLEN) >= MAXPATHLEN) {
8540Sstevel@tonic-gate 			dprintf((stderr,
8550Sstevel@tonic-gate 			    "invalid module or script generic directory\n"));
8560Sstevel@tonic-gate 			return (NULL);
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	if (rcm_script)
8610Sstevel@tonic-gate 		*rcm_script = (dirnum < N_MODULE_DIR) ? 0 : 1;
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	return (dir_name[dirnum]);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate /*
8670Sstevel@tonic-gate  * Find the directory where the script is located.
8680Sstevel@tonic-gate  * If the script is found return a pointer to the directory where the
8690Sstevel@tonic-gate  * script was found otherwise return NULL.
8700Sstevel@tonic-gate  */
8710Sstevel@tonic-gate char *
rcm_get_script_dir(char * script_name)8720Sstevel@tonic-gate rcm_get_script_dir(char *script_name)
8730Sstevel@tonic-gate {
8740Sstevel@tonic-gate 	uint_t i;
8750Sstevel@tonic-gate 	char *dir_name;
8760Sstevel@tonic-gate 	char path[MAXPATHLEN];
8770Sstevel@tonic-gate 	struct stat stats;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	for (i = 0; (dir_name = rcm_script_dir(i)) != NULL; i++) {
8800Sstevel@tonic-gate 		if (snprintf(path, MAXPATHLEN, "%s%s", dir_name, script_name)
8810Sstevel@tonic-gate 		    >= MAXPATHLEN) {
8820Sstevel@tonic-gate 			dprintf((stderr, "invalid script %s skipped\n",
8830Sstevel@tonic-gate 			    script_name));
8840Sstevel@tonic-gate 			continue;
8850Sstevel@tonic-gate 		}
8860Sstevel@tonic-gate 		if (stat(path, &stats) == 0)
8870Sstevel@tonic-gate 			return (dir_name);
8880Sstevel@tonic-gate 	}
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	return (NULL);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate /*
8940Sstevel@tonic-gate  * Returns 1 if the filename is an rcm script.
8950Sstevel@tonic-gate  * Returns 0 if the filename is an rcm module.
8960Sstevel@tonic-gate  */
8970Sstevel@tonic-gate int
rcm_is_script(char * filename)8980Sstevel@tonic-gate rcm_is_script(char *filename)
8990Sstevel@tonic-gate {
9000Sstevel@tonic-gate 	char *tmp;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	if (((tmp = strstr(filename, RCM_MODULE_SUFFIX)) != NULL) &&
9030Sstevel@tonic-gate 		(tmp[strlen(RCM_MODULE_SUFFIX)] == '\0'))
9040Sstevel@tonic-gate 		return (0);
9050Sstevel@tonic-gate 	else
9060Sstevel@tonic-gate 		return (1);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate /* Locate the module and call dlopen */
9100Sstevel@tonic-gate void *
rcm_module_open(char * modname)9110Sstevel@tonic-gate rcm_module_open(char *modname)
9120Sstevel@tonic-gate {
9130Sstevel@tonic-gate 	unsigned i;
9140Sstevel@tonic-gate 	char *dir_name;
9150Sstevel@tonic-gate 	void *dlhandle = NULL;
9160Sstevel@tonic-gate 	char modpath[MAXPATHLEN];
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate #ifdef DEBUG
9190Sstevel@tonic-gate 	struct stat sbuf;
9200Sstevel@tonic-gate #endif
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	/*
9230Sstevel@tonic-gate 	 * dlopen the module
9240Sstevel@tonic-gate 	 */
9250Sstevel@tonic-gate 	for (i = 0; (dir_name = rcm_module_dir(i)) != NULL; i++) {
9260Sstevel@tonic-gate 		if (snprintf(modpath, MAXPATHLEN, "%s%s", dir_name, modname)
9270Sstevel@tonic-gate 		    >= MAXPATHLEN) {
9280Sstevel@tonic-gate 			dprintf((stderr, "invalid module %s skipped\n",
9290Sstevel@tonic-gate 			    modname));
9300Sstevel@tonic-gate 			continue;
9310Sstevel@tonic-gate 		}
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 		if ((dlhandle = dlopen(modpath, RTLD_LAZY)) != NULL) {
9340Sstevel@tonic-gate 			return (dlhandle);
9350Sstevel@tonic-gate 		}
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 		dprintf((stderr, "failure (dlopen=%s)\n", dlerror()));
9380Sstevel@tonic-gate #ifdef DEBUG
9390Sstevel@tonic-gate 		if (stat(modpath, &sbuf) == 0) {
9400Sstevel@tonic-gate 			(void) fprintf(stderr, "%s is not a valid module\n",
9410Sstevel@tonic-gate 			    modpath);
9420Sstevel@tonic-gate 		}
9430Sstevel@tonic-gate #endif
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	dprintf((stderr, "module %s not found\n", modname));
9470Sstevel@tonic-gate 	return (NULL);
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate /* dlclose module */
9510Sstevel@tonic-gate void
rcm_module_close(void * dlhandle)9520Sstevel@tonic-gate rcm_module_close(void *dlhandle)
9530Sstevel@tonic-gate {
9540Sstevel@tonic-gate 	if (dlclose(dlhandle) == 0)
9550Sstevel@tonic-gate 		return;
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	dprintf((stderr, "dlclose: %s\n", dlerror()));
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate /*
9620Sstevel@tonic-gate  * stub implementation of rcm_log_message allows dlopen of rcm modules
9630Sstevel@tonic-gate  * to proceed in absence of rcm_daemon.
9640Sstevel@tonic-gate  *
9650Sstevel@tonic-gate  * This definition is interposed by the definition in rcm_daemon because of the
9660Sstevel@tonic-gate  * default search order implemented by the linker and dlsym(). All RCM modules
9670Sstevel@tonic-gate  * will see the daemon version when loaded by the rcm_daemon.
9680Sstevel@tonic-gate  */
9690Sstevel@tonic-gate /* ARGSUSED */
9700Sstevel@tonic-gate void
rcm_log_message(int level,char * message,...)9710Sstevel@tonic-gate rcm_log_message(int level, char *message, ...)
9720Sstevel@tonic-gate {
9730Sstevel@tonic-gate 	dprintf((stderr, "rcm_log_message stub\n"));
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate /*
9770Sstevel@tonic-gate  * Helper functions
9780Sstevel@tonic-gate  */
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate /*
9810Sstevel@tonic-gate  * Common routine for all rcm calls which require daemon processing
9820Sstevel@tonic-gate  */
9830Sstevel@tonic-gate static int
rcm_common(int cmd,rcm_handle_t * hd,char ** rsrcnames,uint_t flag,void * arg,rcm_info_t ** infop)9840Sstevel@tonic-gate rcm_common(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag, void *arg,
9850Sstevel@tonic-gate     rcm_info_t **infop)
9860Sstevel@tonic-gate {
9870Sstevel@tonic-gate 	int i;
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	if (hd == NULL) {
9900Sstevel@tonic-gate 		errno = EINVAL;
9910Sstevel@tonic-gate 		return (RCM_FAILURE);
9920Sstevel@tonic-gate 	}
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	if (getuid() != 0) {
9950Sstevel@tonic-gate 		errno = EPERM;
9960Sstevel@tonic-gate 		return (RCM_FAILURE);
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	if ((flag & (RCM_DR_OPERATION | RCM_MOD_INFO)) == 0) {
10000Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL)) {
10010Sstevel@tonic-gate 			errno = EINVAL;
10020Sstevel@tonic-gate 			return (RCM_FAILURE);
10030Sstevel@tonic-gate 		}
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 		for (i = 0; rsrcnames[i] != NULL; i++) {
10060Sstevel@tonic-gate 			if (*rsrcnames[i] == '\0') {
10070Sstevel@tonic-gate 				errno = EINVAL;
10080Sstevel@tonic-gate 				return (RCM_FAILURE);
10090Sstevel@tonic-gate 			}
10100Sstevel@tonic-gate 		}
10110Sstevel@tonic-gate 	}
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	/*
10140Sstevel@tonic-gate 	 * Check if handle is allocated by rcm_daemon. If so, this call came
10150Sstevel@tonic-gate 	 * from an RCM module, so we make a direct call into rcm_daemon.
10160Sstevel@tonic-gate 	 */
10170Sstevel@tonic-gate 	if (hd->lrcm_ops != NULL) {
10180Sstevel@tonic-gate 		return (rcm_direct_call(cmd, hd, rsrcnames, flag, arg, infop));
10190Sstevel@tonic-gate 	}
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	/*
10220Sstevel@tonic-gate 	 * When not called from a RCM module (i.e. no recursion), zero the
10230Sstevel@tonic-gate 	 * pointer just in case caller did not do so. For recursive calls,
10240Sstevel@tonic-gate 	 * we want to append rcm_info_t after infop; zero it may cause
10250Sstevel@tonic-gate 	 * memory leaks.
10260Sstevel@tonic-gate 	 */
10270Sstevel@tonic-gate 	if (infop) {
10280Sstevel@tonic-gate 		*infop = NULL;
10290Sstevel@tonic-gate 	}
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	/*
10320Sstevel@tonic-gate 	 * Now call into the daemon.
10330Sstevel@tonic-gate 	 */
10340Sstevel@tonic-gate 	return (rcm_daemon_call(cmd, hd, rsrcnames, flag, arg, infop));
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate /*
10380Sstevel@tonic-gate  * Caller is an RCM module, call directly into rcm_daemon.
10390Sstevel@tonic-gate  */
10400Sstevel@tonic-gate static int
rcm_direct_call(int cmd,rcm_handle_t * hd,char ** rsrcnames,uint_t flag,void * arg,rcm_info_t ** infop)10410Sstevel@tonic-gate rcm_direct_call(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
10420Sstevel@tonic-gate     void *arg, rcm_info_t **infop)
10430Sstevel@tonic-gate {
10440Sstevel@tonic-gate 	int error;
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	librcm_ops_t *ops = (librcm_ops_t *)hd->lrcm_ops;
10470Sstevel@tonic-gate 	switch (cmd) {
10480Sstevel@tonic-gate 	case CMD_GETINFO:
10490Sstevel@tonic-gate 		error = ops->librcm_getinfo(rsrcnames, flag, hd->seq_num,
10500Sstevel@tonic-gate 		    infop);
10510Sstevel@tonic-gate 		break;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	case CMD_OFFLINE:
10540Sstevel@tonic-gate 		error = ops->librcm_offline(rsrcnames, hd->pid, flag,
10550Sstevel@tonic-gate 		    hd->seq_num, infop);
10560Sstevel@tonic-gate 		break;
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	case CMD_ONLINE:
10590Sstevel@tonic-gate 		error = ops->librcm_online(rsrcnames, hd->pid, flag,
10600Sstevel@tonic-gate 		    hd->seq_num, infop);
10610Sstevel@tonic-gate 		break;
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	case CMD_REMOVE:
10640Sstevel@tonic-gate 		error = ops->librcm_remove(rsrcnames, hd->pid, flag,
10650Sstevel@tonic-gate 		    hd->seq_num, infop);
10660Sstevel@tonic-gate 		break;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	case CMD_SUSPEND:
10690Sstevel@tonic-gate 		error = ops->librcm_suspend(rsrcnames, hd->pid, flag,
10700Sstevel@tonic-gate 		    hd->seq_num, (timespec_t *)arg, infop);
10710Sstevel@tonic-gate 		break;
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	case CMD_RESUME:
10740Sstevel@tonic-gate 		error = ops->librcm_resume(rsrcnames, hd->pid, flag,
10750Sstevel@tonic-gate 		    hd->seq_num, infop);
10760Sstevel@tonic-gate 		break;
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	case CMD_REGISTER:
10790Sstevel@tonic-gate 		error = ops->librcm_regis(hd->modname, rsrcnames[0], hd->pid,
10800Sstevel@tonic-gate 		    flag, infop);
10810Sstevel@tonic-gate 		break;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	case CMD_UNREGISTER:
10840Sstevel@tonic-gate 		error = ops->librcm_unregis(hd->modname, rsrcnames[0], hd->pid,
10850Sstevel@tonic-gate 		    flag);
10860Sstevel@tonic-gate 		break;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	case CMD_REQUEST_CHANGE:
10890Sstevel@tonic-gate 		error = ops->librcm_request_change(rsrcnames[0], hd->pid, flag,
10900Sstevel@tonic-gate 		    hd->seq_num, (nvlist_t *)arg, infop);
10910Sstevel@tonic-gate 		break;
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	case CMD_NOTIFY_CHANGE:
10940Sstevel@tonic-gate 		error = ops->librcm_notify_change(rsrcnames[0], hd->pid, flag,
10950Sstevel@tonic-gate 		    hd->seq_num, (nvlist_t *)arg, infop);
10960Sstevel@tonic-gate 		break;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	case CMD_EVENT:
10990Sstevel@tonic-gate 		error = ops->librcm_notify_event(rsrcnames[0], hd->pid, flag,
11000Sstevel@tonic-gate 		    hd->seq_num, (nvlist_t *)arg, infop);
11010Sstevel@tonic-gate 		break;
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	case CMD_GETSTATE:
11040Sstevel@tonic-gate 		error = ops->librcm_getstate(rsrcnames[0], hd->pid, infop);
11050Sstevel@tonic-gate 		break;
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	default:
11080Sstevel@tonic-gate 		dprintf((stderr, "invalid command: %d\n", cmd));
11090Sstevel@tonic-gate 		error = EFAULT;
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	if (error > 0) {
11130Sstevel@tonic-gate 		errno = error;
11140Sstevel@tonic-gate 		error = RCM_FAILURE;
11150Sstevel@tonic-gate 	}
11160Sstevel@tonic-gate 	return (error);
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate /*
11200Sstevel@tonic-gate  * Call into rcm_daemon door to process the request
11210Sstevel@tonic-gate  */
11220Sstevel@tonic-gate static int
rcm_daemon_call(int cmd,rcm_handle_t * hd,char ** rsrcnames,uint_t flag,void * arg,rcm_info_t ** infop)11230Sstevel@tonic-gate rcm_daemon_call(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
11240Sstevel@tonic-gate     void *arg, rcm_info_t **infop)
11250Sstevel@tonic-gate {
11260Sstevel@tonic-gate 	int errno_found;
1127*3509Svikram 	int daemon_errno = 0;
11280Sstevel@tonic-gate 	int error = RCM_SUCCESS;
11290Sstevel@tonic-gate 	int delay = 300;
11300Sstevel@tonic-gate 	int maxdelay = 10000;	/* 10 seconds */
11310Sstevel@tonic-gate 	char *nvl_packed = NULL;
11320Sstevel@tonic-gate 	size_t nvl_size = 0;
11330Sstevel@tonic-gate 	nvlist_t *ret = NULL;
11340Sstevel@tonic-gate 	nvpair_t *nvp;
11350Sstevel@tonic-gate 	size_t rsize = 0;
11360Sstevel@tonic-gate 	rcm_info_t *info = NULL;
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	errno = 0;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	/*
11410Sstevel@tonic-gate 	 * Decide whether to start the daemon
11420Sstevel@tonic-gate 	 */
11430Sstevel@tonic-gate 	switch (cmd) {
11440Sstevel@tonic-gate 	case CMD_GETINFO:
11450Sstevel@tonic-gate 	case CMD_OFFLINE:
11460Sstevel@tonic-gate 	case CMD_ONLINE:
11470Sstevel@tonic-gate 	case CMD_REMOVE:
11480Sstevel@tonic-gate 	case CMD_SUSPEND:
11490Sstevel@tonic-gate 	case CMD_RESUME:
11500Sstevel@tonic-gate 	case CMD_REGISTER:
11510Sstevel@tonic-gate 	case CMD_UNREGISTER:
11520Sstevel@tonic-gate 	case CMD_EVENT:
11530Sstevel@tonic-gate 	case CMD_REQUEST_CHANGE:
11540Sstevel@tonic-gate 	case CMD_NOTIFY_CHANGE:
11550Sstevel@tonic-gate 	case CMD_GETSTATE:
11560Sstevel@tonic-gate 		break;
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	default:
11590Sstevel@tonic-gate 		errno = EFAULT;
11600Sstevel@tonic-gate 		return (RCM_FAILURE);
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	if (rcm_daemon_is_alive() != 1) {
11640Sstevel@tonic-gate 		dprintf((stderr, "failed to start rcm_daemon\n"));
11650Sstevel@tonic-gate 		errno = EFAULT;
11660Sstevel@tonic-gate 		return (RCM_FAILURE);
11670Sstevel@tonic-gate 	}
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	/*
11700Sstevel@tonic-gate 	 * Generate a packed nvlist for the request
11710Sstevel@tonic-gate 	 */
11720Sstevel@tonic-gate 	if (rcm_generate_nvlist(cmd, hd, rsrcnames, flag, arg, &nvl_packed,
11730Sstevel@tonic-gate 	    &nvl_size) < 0) {
11740Sstevel@tonic-gate 		dprintf((stderr, "error in nvlist generation\n"));
11750Sstevel@tonic-gate 		errno = EFAULT;
11760Sstevel@tonic-gate 		return (RCM_FAILURE);
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	/*
11800Sstevel@tonic-gate 	 * Make the door call and get a return event. We go into a retry loop
11810Sstevel@tonic-gate 	 * when RCM_ET_EAGAIN is returned.
11820Sstevel@tonic-gate 	 */
11830Sstevel@tonic-gate retry:
11840Sstevel@tonic-gate 	if (get_event_service(RCM_SERVICE_DOOR, (void *)nvl_packed, nvl_size,
11850Sstevel@tonic-gate 	    (void **)&ret, &rsize) < 0) {
11860Sstevel@tonic-gate 		dprintf((stderr, "rcm_daemon call failed: %s\n",
11870Sstevel@tonic-gate 		    strerror(errno)));
11880Sstevel@tonic-gate 		free(nvl_packed);
11890Sstevel@tonic-gate 		return (RCM_FAILURE);
11900Sstevel@tonic-gate 	}
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	assert(ret != NULL);
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	/*
11950Sstevel@tonic-gate 	 * nvlist_lookup_* routines don't work because the returned nvlist
11960Sstevel@tonic-gate 	 * was nvlist_alloc'ed without the NV_UNIQUE_NAME flag.  Implement
11970Sstevel@tonic-gate 	 * a sequential search manually, which is fine since there is only
11980Sstevel@tonic-gate 	 * one RCM_RESULT value in the nvlist.
11990Sstevel@tonic-gate 	 */
12000Sstevel@tonic-gate 	errno_found = 0;
12010Sstevel@tonic-gate 	nvp = NULL;
12020Sstevel@tonic-gate 	while (nvp = nvlist_next_nvpair(ret, nvp)) {
12030Sstevel@tonic-gate 		if (strcmp(nvpair_name(nvp), RCM_RESULT) == 0) {
12040Sstevel@tonic-gate 			if (errno = nvpair_value_int32(nvp, &daemon_errno)) {
12050Sstevel@tonic-gate 				error = RCM_FAILURE;
12060Sstevel@tonic-gate 				goto out;
12070Sstevel@tonic-gate 			}
12080Sstevel@tonic-gate 			errno_found++;
12090Sstevel@tonic-gate 			break;
12100Sstevel@tonic-gate 		}
12110Sstevel@tonic-gate 	}
12120Sstevel@tonic-gate 	if (errno_found == 0) {
12130Sstevel@tonic-gate 		errno = EFAULT;
12140Sstevel@tonic-gate 		error = RCM_FAILURE;
12150Sstevel@tonic-gate 		goto out;
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	if (daemon_errno == EAGAIN) {
12190Sstevel@tonic-gate 		/*
12200Sstevel@tonic-gate 		 * Wait and retry
12210Sstevel@tonic-gate 		 */
12220Sstevel@tonic-gate 		dprintf((stderr, "retry door_call\n"));
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 		if (delay > maxdelay) {
12250Sstevel@tonic-gate 			errno = EAGAIN;
12260Sstevel@tonic-gate 			error = RCM_FAILURE;
12270Sstevel@tonic-gate 			goto out;
12280Sstevel@tonic-gate 		}
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 		(void) poll(NULL, 0, delay);
12310Sstevel@tonic-gate 		delay *= 2;		/* exponential back off */
12320Sstevel@tonic-gate 		nvlist_free(ret);
12330Sstevel@tonic-gate 		goto retry;
12340Sstevel@tonic-gate 	}
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	/*
12370Sstevel@tonic-gate 	 * The door call succeeded. Now extract info from returned event.
12380Sstevel@tonic-gate 	 */
12390Sstevel@tonic-gate 	if (extract_info(ret, &info) != 0) {
12400Sstevel@tonic-gate 		dprintf((stderr, "error in extracting event data\n"));
12410Sstevel@tonic-gate 		errno = EFAULT;
12420Sstevel@tonic-gate 		error = RCM_FAILURE;
12430Sstevel@tonic-gate 		goto out;
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	if (infop)
12470Sstevel@tonic-gate 		*infop = info;
12480Sstevel@tonic-gate 	else
12490Sstevel@tonic-gate 		rcm_free_info(info);
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	if (daemon_errno) {
12520Sstevel@tonic-gate 		if (daemon_errno > 0) {
12530Sstevel@tonic-gate 			errno = daemon_errno;
12540Sstevel@tonic-gate 			error = RCM_FAILURE;
12550Sstevel@tonic-gate 		} else {
12560Sstevel@tonic-gate 			error = daemon_errno;
12570Sstevel@tonic-gate 		}
12580Sstevel@tonic-gate 	}
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate out:
12610Sstevel@tonic-gate 	if (nvl_packed)
12620Sstevel@tonic-gate 		free(nvl_packed);
12630Sstevel@tonic-gate 	if (ret)
12640Sstevel@tonic-gate 		nvlist_free(ret);
12650Sstevel@tonic-gate 	dprintf((stderr, "daemon call is done. error = %d, errno = %s\n", error,
12660Sstevel@tonic-gate 	    strerror(errno)));
12670Sstevel@tonic-gate 	return (error);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate /*
12710Sstevel@tonic-gate  * Extract registration info from event data.
12720Sstevel@tonic-gate  * Return 0 on success and -1 on failure.
12730Sstevel@tonic-gate  */
12740Sstevel@tonic-gate static int
extract_info(nvlist_t * nvl,rcm_info_t ** infop)12750Sstevel@tonic-gate extract_info(nvlist_t *nvl, rcm_info_t **infop)
12760Sstevel@tonic-gate {
12770Sstevel@tonic-gate 	rcm_info_t *info = NULL;
12780Sstevel@tonic-gate 	rcm_info_t *prev = NULL;
12790Sstevel@tonic-gate 	rcm_info_t *tmp = NULL;
12800Sstevel@tonic-gate 	char *buf;
12810Sstevel@tonic-gate 	uint_t buflen;
12820Sstevel@tonic-gate 	nvpair_t *nvp = NULL;
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	while (nvp = nvlist_next_nvpair(nvl, nvp)) {
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 		buf = NULL;
12870Sstevel@tonic-gate 		buflen = 0;
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 		if (strcmp(nvpair_name(nvp), RCM_RESULT_INFO) != 0)
12900Sstevel@tonic-gate 			continue;
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 		if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
12930Sstevel@tonic-gate 			dprintf((stderr, "out of memory\n"));
12940Sstevel@tonic-gate 			goto fail;
12950Sstevel@tonic-gate 		}
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 		if (errno = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
12980Sstevel@tonic-gate 		    &buflen)) {
12990Sstevel@tonic-gate 			free(tmp);
13000Sstevel@tonic-gate 			dprintf((stderr, "failed (nvpair_value=%s)\n",
13010Sstevel@tonic-gate 			    strerror(errno)));
13020Sstevel@tonic-gate 			goto fail;
13030Sstevel@tonic-gate 		}
13040Sstevel@tonic-gate 		if (errno = nvlist_unpack(buf, buflen, &(tmp->info), 0)) {
13050Sstevel@tonic-gate 			free(tmp);
13060Sstevel@tonic-gate 			dprintf((stderr, "failed (nvlist_unpack=%s)\n",
13070Sstevel@tonic-gate 			    strerror(errno)));
13080Sstevel@tonic-gate 			goto fail;
13090Sstevel@tonic-gate 		}
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 		if (info == NULL) {
13120Sstevel@tonic-gate 			prev = info = tmp;
13130Sstevel@tonic-gate 		} else {
13140Sstevel@tonic-gate 			prev->next = tmp;
13150Sstevel@tonic-gate 			prev = tmp;
13160Sstevel@tonic-gate 		}
13170Sstevel@tonic-gate 	}
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	*infop = info;
13200Sstevel@tonic-gate 	return (0);
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate fail:
13230Sstevel@tonic-gate 	rcm_free_info(info);
13240Sstevel@tonic-gate 	*infop = NULL;
13250Sstevel@tonic-gate 	return (-1);
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate /* Generate a packed nvlist for communicating with RCM daemon */
13290Sstevel@tonic-gate static int
rcm_generate_nvlist(int cmd,rcm_handle_t * hd,char ** rsrcnames,uint_t flag,void * arg,char ** nvl_packed,size_t * nvl_size)13300Sstevel@tonic-gate rcm_generate_nvlist(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
13310Sstevel@tonic-gate     void *arg, char **nvl_packed, size_t *nvl_size)
13320Sstevel@tonic-gate {
13330Sstevel@tonic-gate 	int nrsrcnames;
13340Sstevel@tonic-gate 	char *buf = NULL;
13350Sstevel@tonic-gate 	size_t buflen = 0;
13360Sstevel@tonic-gate 	nvlist_t *nvl = NULL;
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 	assert((nvl_packed != NULL) && (nvl_size != NULL));
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	*nvl_size = 0;
13410Sstevel@tonic-gate 	*nvl_packed = NULL;
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	/* Allocate an empty nvlist */
13440Sstevel@tonic-gate 	if ((errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) > 0) {
13450Sstevel@tonic-gate 		dprintf((stderr, "failed (nvlist_alloc=%s).\n",
13460Sstevel@tonic-gate 		    strerror(errno)));
13470Sstevel@tonic-gate 		return (-1);
13480Sstevel@tonic-gate 	}
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	/* Stuff in all the arguments for the daemon call */
13510Sstevel@tonic-gate 	if (nvlist_add_int32(nvl, RCM_CMD, cmd) != 0) {
13520Sstevel@tonic-gate 		dprintf((stderr, "failed (nvlist_add(CMD)=%s).\n",
13530Sstevel@tonic-gate 		    strerror(errno)));
13540Sstevel@tonic-gate 		goto fail;
13550Sstevel@tonic-gate 	}
13560Sstevel@tonic-gate 	if (rsrcnames) {
13570Sstevel@tonic-gate 		nrsrcnames = 0;
13580Sstevel@tonic-gate 		while (rsrcnames[nrsrcnames] != NULL)
13590Sstevel@tonic-gate 			nrsrcnames++;
13600Sstevel@tonic-gate 		if (nvlist_add_string_array(nvl, RCM_RSRCNAMES, rsrcnames,
13610Sstevel@tonic-gate 		    nrsrcnames) != 0) {
13620Sstevel@tonic-gate 			dprintf((stderr, "failed (nvlist_add(RSRCNAMES)=%s).\n",
13630Sstevel@tonic-gate 			    strerror(errno)));
13640Sstevel@tonic-gate 			goto fail;
13650Sstevel@tonic-gate 		}
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 	if (hd->modname) {
13680Sstevel@tonic-gate 		if (nvlist_add_string(nvl, RCM_CLIENT_MODNAME, hd->modname)
13690Sstevel@tonic-gate 		    != 0) {
13700Sstevel@tonic-gate 			dprintf((stderr,
13710Sstevel@tonic-gate 			    "failed (nvlist_add(CLIENT_MODNAME)=%s).\n",
13720Sstevel@tonic-gate 			    strerror(errno)));
13730Sstevel@tonic-gate 			goto fail;
13740Sstevel@tonic-gate 		}
13750Sstevel@tonic-gate 	}
13760Sstevel@tonic-gate 	if (hd->pid) {
13770Sstevel@tonic-gate 		if (nvlist_add_uint64(nvl, RCM_CLIENT_ID, hd->pid) != 0) {
13780Sstevel@tonic-gate 			dprintf((stderr, "failed (nvlist_add(CLIENT_ID)=%s).\n",
13790Sstevel@tonic-gate 			    strerror(errno)));
13800Sstevel@tonic-gate 			goto fail;
13810Sstevel@tonic-gate 		}
13820Sstevel@tonic-gate 	}
13830Sstevel@tonic-gate 	if (flag) {
13840Sstevel@tonic-gate 		if (nvlist_add_uint32(nvl, RCM_REQUEST_FLAG, flag) != 0) {
13850Sstevel@tonic-gate 			dprintf((stderr,
13860Sstevel@tonic-gate 			    "failed (nvlist_add(REQUEST_FLAG)=%s).\n",
13870Sstevel@tonic-gate 			    strerror(errno)));
13880Sstevel@tonic-gate 			goto fail;
13890Sstevel@tonic-gate 		}
13900Sstevel@tonic-gate 	}
13910Sstevel@tonic-gate 	if (arg && cmd == CMD_SUSPEND) {
13920Sstevel@tonic-gate 		if (nvlist_add_byte_array(nvl, RCM_SUSPEND_INTERVAL,
13930Sstevel@tonic-gate 		    (uchar_t *)arg, sizeof (timespec_t)) != 0) {
13940Sstevel@tonic-gate 			dprintf((stderr,
13950Sstevel@tonic-gate 			    "failed (nvlist_add(SUSPEND_INTERVAL)=%s).\n",
13960Sstevel@tonic-gate 			    strerror(errno)));
13970Sstevel@tonic-gate 			goto fail;
13980Sstevel@tonic-gate 		}
13990Sstevel@tonic-gate 	}
14000Sstevel@tonic-gate 	if (arg &&
14010Sstevel@tonic-gate 	    ((cmd == CMD_REQUEST_CHANGE) || (cmd == CMD_NOTIFY_CHANGE))) {
14020Sstevel@tonic-gate 		if (errno = nvlist_pack(arg, &buf, &buflen, NV_ENCODE_NATIVE,
14030Sstevel@tonic-gate 		    0)) {
14040Sstevel@tonic-gate 			dprintf((stderr,
14050Sstevel@tonic-gate 			    "failed (nvlist_pack(CHANGE_DATA)=%s).\n",
14060Sstevel@tonic-gate 			    strerror(errno)));
14070Sstevel@tonic-gate 			goto fail;
14080Sstevel@tonic-gate 		}
14090Sstevel@tonic-gate 		if (nvlist_add_byte_array(nvl, RCM_CHANGE_DATA, (uchar_t *)buf,
14100Sstevel@tonic-gate 		    buflen) != 0) {
14110Sstevel@tonic-gate 			dprintf((stderr,
14120Sstevel@tonic-gate 			    "failed (nvlist_add(CHANGE_DATA)=%s).\n",
14130Sstevel@tonic-gate 			    strerror(errno)));
14140Sstevel@tonic-gate 			goto fail;
14150Sstevel@tonic-gate 		}
14160Sstevel@tonic-gate 	}
14170Sstevel@tonic-gate 	if (arg && cmd == CMD_EVENT) {
14180Sstevel@tonic-gate 		if (errno = nvlist_pack(arg, &buf, &buflen, NV_ENCODE_NATIVE,
14190Sstevel@tonic-gate 		    0)) {
14200Sstevel@tonic-gate 			dprintf((stderr,
14210Sstevel@tonic-gate 			    "failed (nvlist_pack(CHANGE_DATA)=%s).\n",
14220Sstevel@tonic-gate 			    strerror(errno)));
14230Sstevel@tonic-gate 			goto fail;
14240Sstevel@tonic-gate 		}
14250Sstevel@tonic-gate 		if (nvlist_add_byte_array(nvl, RCM_EVENT_DATA, (uchar_t *)buf,
14260Sstevel@tonic-gate 		    buflen) != 0) {
14270Sstevel@tonic-gate 			dprintf((stderr,
14280Sstevel@tonic-gate 			    "failed (nvlist_add(EVENT_DATA)=%s).\n",
14290Sstevel@tonic-gate 			    strerror(errno)));
14300Sstevel@tonic-gate 			goto fail;
14310Sstevel@tonic-gate 		}
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	/* Pack the nvlist */
14350Sstevel@tonic-gate 	if (errno = nvlist_pack(nvl, nvl_packed, nvl_size, NV_ENCODE_NATIVE,
14360Sstevel@tonic-gate 	    0)) {
14370Sstevel@tonic-gate 		dprintf((stderr, "failed (nvlist_pack=%s).\n",
14380Sstevel@tonic-gate 		    strerror(errno)));
14390Sstevel@tonic-gate 		goto fail;
14400Sstevel@tonic-gate 	}
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	/* If an argument was packed intermediately, free the buffer */
14430Sstevel@tonic-gate 	if (buf)
14440Sstevel@tonic-gate 		free(buf);
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	/* Free the unpacked version of the nvlist and return the packed list */
14470Sstevel@tonic-gate 	nvlist_free(nvl);
14480Sstevel@tonic-gate 	return (0);
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate fail:
14510Sstevel@tonic-gate 	if (buf)
14520Sstevel@tonic-gate 		free(buf);
14530Sstevel@tonic-gate 	if (nvl)
14540Sstevel@tonic-gate 		nvlist_free(nvl);
14550Sstevel@tonic-gate 	if (*nvl_packed)
14560Sstevel@tonic-gate 		free(*nvl_packed);
14570Sstevel@tonic-gate 	*nvl_packed = NULL;
14580Sstevel@tonic-gate 	*nvl_size = 0;
14590Sstevel@tonic-gate 	return (-1);
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate /* check if rcm_daemon is up and running */
14630Sstevel@tonic-gate static int
rcm_daemon_is_alive()14640Sstevel@tonic-gate rcm_daemon_is_alive()
14650Sstevel@tonic-gate {
14660Sstevel@tonic-gate 	int lasttry;
14670Sstevel@tonic-gate 	struct stat st;
14680Sstevel@tonic-gate 	nvlist_t *nvl;
14690Sstevel@tonic-gate 	char *buf = NULL;
14700Sstevel@tonic-gate 	size_t buflen = 0;
14710Sstevel@tonic-gate 	int delay = 300;
14720Sstevel@tonic-gate 	const int maxdelay = 10000;	/* 10 sec */
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	/* generate a packed nvlist for the door knocking */
14750Sstevel@tonic-gate 	if (errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) {
14760Sstevel@tonic-gate 		dprintf((stderr, "nvlist_alloc failed: %s\n", strerror(errno)));
14770Sstevel@tonic-gate 		return (0);
14780Sstevel@tonic-gate 	}
14790Sstevel@tonic-gate 	if (errno = nvlist_add_int32(nvl, RCM_CMD, CMD_KNOCK)) {
14800Sstevel@tonic-gate 		dprintf((stderr, "nvlist_add failed: %s\n", strerror(errno)));
14810Sstevel@tonic-gate 		nvlist_free(nvl);
14820Sstevel@tonic-gate 		return (0);
14830Sstevel@tonic-gate 	}
14840Sstevel@tonic-gate 	if (errno = nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0)) {
14850Sstevel@tonic-gate 		dprintf((stderr, "nvlist_pack failed: %s\n", strerror(errno)));
14860Sstevel@tonic-gate 		nvlist_free(nvl);
14870Sstevel@tonic-gate 		return (0);
14880Sstevel@tonic-gate 	}
14890Sstevel@tonic-gate 	nvlist_free(nvl);
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	/*
14920Sstevel@tonic-gate 	 * check the door and knock on it
14930Sstevel@tonic-gate 	 */
14940Sstevel@tonic-gate 	if ((stat(RCM_SERVICE_DOOR, &st) == 0) &&
14950Sstevel@tonic-gate 	    (get_event_service(RCM_SERVICE_DOOR, (void *)buf, buflen, NULL,
14960Sstevel@tonic-gate 	    NULL) == 0)) {
14970Sstevel@tonic-gate 		free(buf);
14980Sstevel@tonic-gate 		return (1);	/* daemon is alive */
14990Sstevel@tonic-gate 	}
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	/*
15020Sstevel@tonic-gate 	 * Attempt to start the daemon.
15030Sstevel@tonic-gate 	 * If caller has SIGCHLD set to SIG_IGN or its SA_NOCLDWAIT
15040Sstevel@tonic-gate 	 * flag set, waitpid(2) (hence rcm_exec_cmd) will fail.
15050Sstevel@tonic-gate 	 * get_event_service will determine if the rcm_daemon started.
15060Sstevel@tonic-gate 	 */
15070Sstevel@tonic-gate 	dprintf((stderr, "exec: %s\n", RCM_DAEMON_START));
15080Sstevel@tonic-gate 	(void) rcm_exec_cmd(RCM_DAEMON_START);
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	/*
15110Sstevel@tonic-gate 	 * Wait for daemon to respond, timeout at 10 sec
15120Sstevel@tonic-gate 	 */
15130Sstevel@tonic-gate 	while (((lasttry = get_event_service(RCM_SERVICE_DOOR, (void *)buf,
15140Sstevel@tonic-gate 	    buflen, NULL, NULL)) != 0) &&
15150Sstevel@tonic-gate 	    ((errno == EBADF) || (errno == ESRCH))) {
15160Sstevel@tonic-gate 		if (delay > maxdelay) {
15170Sstevel@tonic-gate 			break;
15180Sstevel@tonic-gate 		}
15190Sstevel@tonic-gate 		(void) poll(NULL, 0, delay);
15200Sstevel@tonic-gate 		delay *= 2;
15210Sstevel@tonic-gate 	}
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	free(buf);
15240Sstevel@tonic-gate 	if (lasttry == 0)
15250Sstevel@tonic-gate 		return (1);
15260Sstevel@tonic-gate 	return (0);
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate /*
15300Sstevel@tonic-gate  * Check permission.
15310Sstevel@tonic-gate  *
15320Sstevel@tonic-gate  * The policy is root only for now. Need to relax this when interface level
15330Sstevel@tonic-gate  * is raised.
15340Sstevel@tonic-gate  */
15350Sstevel@tonic-gate static int
rcm_check_permission(void)15360Sstevel@tonic-gate rcm_check_permission(void)
15370Sstevel@tonic-gate {
15380Sstevel@tonic-gate 	return (getuid() == 0);
15390Sstevel@tonic-gate }
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate /*
15420Sstevel@tonic-gate  * Project private function - for use by RCM MSTC tests
15430Sstevel@tonic-gate  *
15440Sstevel@tonic-gate  * Get the client name (rcm module name or script name) corresponding to
15450Sstevel@tonic-gate  * the given rcm handle.
15460Sstevel@tonic-gate  */
15470Sstevel@tonic-gate const char *
rcm_get_client_name(rcm_handle_t * hd)15480Sstevel@tonic-gate rcm_get_client_name(rcm_handle_t *hd)
15490Sstevel@tonic-gate {
15500Sstevel@tonic-gate 	return (hd->modname);
15510Sstevel@tonic-gate }
1552