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