xref: /titanic_54/usr/src/lib/librcm/librcm.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include "librcm_impl.h"
30*7c478bd9Sstevel@tonic-gate #include "librcm_event.h"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
33*7c478bd9Sstevel@tonic-gate static int rcm_debug = 1;
34*7c478bd9Sstevel@tonic-gate #define	dprintf(args) if (rcm_debug) (void) fprintf args
35*7c478bd9Sstevel@tonic-gate #else
36*7c478bd9Sstevel@tonic-gate #define	dprintf(args) /* nothing */
37*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate static int extract_info(nvlist_t *, rcm_info_t **);
40*7c478bd9Sstevel@tonic-gate static int rcm_daemon_is_alive();
41*7c478bd9Sstevel@tonic-gate static int rcm_common(int, rcm_handle_t *, char **, uint_t, void *,
42*7c478bd9Sstevel@tonic-gate     rcm_info_t **);
43*7c478bd9Sstevel@tonic-gate static int rcm_direct_call(int, rcm_handle_t *, char **, uint_t, void *,
44*7c478bd9Sstevel@tonic-gate     rcm_info_t **);
45*7c478bd9Sstevel@tonic-gate static int rcm_daemon_call(int, rcm_handle_t *, char **, uint_t, void *,
46*7c478bd9Sstevel@tonic-gate     rcm_info_t **);
47*7c478bd9Sstevel@tonic-gate static int rcm_generate_nvlist(int, rcm_handle_t *, char **, uint_t, void *,
48*7c478bd9Sstevel@tonic-gate     char **, size_t *);
49*7c478bd9Sstevel@tonic-gate static int rcm_check_permission(void);
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * Allocate a handle structure
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
55*7c478bd9Sstevel@tonic-gate int
56*7c478bd9Sstevel@tonic-gate rcm_alloc_handle(char *modname, uint_t flag, void *arg, rcm_handle_t **hdp)
57*7c478bd9Sstevel@tonic-gate {
58*7c478bd9Sstevel@tonic-gate 	rcm_handle_t *hd;
59*7c478bd9Sstevel@tonic-gate 	void *temp;
60*7c478bd9Sstevel@tonic-gate 	char namebuf[MAXPATHLEN];
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 	if ((hdp == NULL) || (flag & ~RCM_ALLOC_HDL_MASK)) {
63*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
64*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
65*7c478bd9Sstevel@tonic-gate 	}
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	if (rcm_check_permission() == 0) {
68*7c478bd9Sstevel@tonic-gate 		errno = EPERM;
69*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
70*7c478bd9Sstevel@tonic-gate 	}
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 	if ((hd = calloc(1, sizeof (*hd))) == NULL) {
73*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
74*7c478bd9Sstevel@tonic-gate 	}
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	if (modname) {
77*7c478bd9Sstevel@tonic-gate 		(void) snprintf(namebuf, MAXPATHLEN, "%s%s", modname,
78*7c478bd9Sstevel@tonic-gate 			RCM_MODULE_SUFFIX);
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 		if ((hd->modname = strdup(namebuf)) == NULL) {
81*7c478bd9Sstevel@tonic-gate 			free(hd);
82*7c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
83*7c478bd9Sstevel@tonic-gate 		}
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 		if ((temp = rcm_module_open(namebuf)) == NULL) {
86*7c478bd9Sstevel@tonic-gate 			free(hd->modname);
87*7c478bd9Sstevel@tonic-gate 			free(hd);
88*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
89*7c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
90*7c478bd9Sstevel@tonic-gate 		}
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate 		rcm_module_close(temp);
93*7c478bd9Sstevel@tonic-gate 	}
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	if (flag & RCM_NOPID) {
96*7c478bd9Sstevel@tonic-gate 		hd->pid = (pid_t)0;
97*7c478bd9Sstevel@tonic-gate 	} else {
98*7c478bd9Sstevel@tonic-gate 		hd->pid = (pid_t)getpid();
99*7c478bd9Sstevel@tonic-gate 	}
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	*hdp = hd;
102*7c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
103*7c478bd9Sstevel@tonic-gate }
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /* free handle structure */
106*7c478bd9Sstevel@tonic-gate int
107*7c478bd9Sstevel@tonic-gate rcm_free_handle(rcm_handle_t *hd)
108*7c478bd9Sstevel@tonic-gate {
109*7c478bd9Sstevel@tonic-gate 	if (hd == NULL) {
110*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
111*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
112*7c478bd9Sstevel@tonic-gate 	}
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	if (hd->modname) {
115*7c478bd9Sstevel@tonic-gate 		free(hd->modname);
116*7c478bd9Sstevel@tonic-gate 	}
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	free(hd);
119*7c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate /*
124*7c478bd9Sstevel@tonic-gate  * Operations which require daemon processing
125*7c478bd9Sstevel@tonic-gate  */
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /* get registration and DR information from rcm_daemon */
128*7c478bd9Sstevel@tonic-gate int
129*7c478bd9Sstevel@tonic-gate rcm_get_info(rcm_handle_t *hd, char *rsrcname, uint_t flag, rcm_info_t **infop)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	if ((flag & ~RCM_GET_INFO_MASK) || (infop == NULL)) {
134*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
135*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
136*7c478bd9Sstevel@tonic-gate 	}
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	/*
139*7c478bd9Sstevel@tonic-gate 	 * rsrcname may be NULL if requesting dr operations or modinfo
140*7c478bd9Sstevel@tonic-gate 	 */
141*7c478bd9Sstevel@tonic-gate 	if ((rsrcname == NULL) &&
142*7c478bd9Sstevel@tonic-gate 	    ((flag & RCM_DR_OPERATION|RCM_MOD_INFO) == 0)) {
143*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
144*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
148*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_GETINFO, hd, rsrcnames, flag, NULL, infop));
151*7c478bd9Sstevel@tonic-gate }
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate /* get registration and DR information from rcm_daemon (list version) */
154*7c478bd9Sstevel@tonic-gate int
155*7c478bd9Sstevel@tonic-gate rcm_get_info_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
156*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
157*7c478bd9Sstevel@tonic-gate {
158*7c478bd9Sstevel@tonic-gate 	/* Requesting the current DR operations with a *list() is invalid */
159*7c478bd9Sstevel@tonic-gate 	if ((flag & RCM_DR_OPERATION) || (flag & RCM_MOD_INFO)) {
160*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
161*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
162*7c478bd9Sstevel@tonic-gate 	}
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_GETINFO, hd, rsrcnames, flag, NULL, infop));
165*7c478bd9Sstevel@tonic-gate }
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate /* request to offline a resource before DR removal */
168*7c478bd9Sstevel@tonic-gate int
169*7c478bd9Sstevel@tonic-gate rcm_request_offline(rcm_handle_t *hd, char *rsrcname, uint_t flag,
170*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
171*7c478bd9Sstevel@tonic-gate {
172*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
175*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	return (rcm_request_offline_list(hd, rsrcnames, flag, infop));
178*7c478bd9Sstevel@tonic-gate }
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /* request to offline a resource before DR removal (list version) */
181*7c478bd9Sstevel@tonic-gate int
182*7c478bd9Sstevel@tonic-gate rcm_request_offline_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
183*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
184*7c478bd9Sstevel@tonic-gate {
185*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_REQUEST_MASK) {
186*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
187*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_OFFLINE, hd, rsrcnames, flag, NULL, infop));
191*7c478bd9Sstevel@tonic-gate }
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate /* cancel offline request and allow apps to use rsrcname */
194*7c478bd9Sstevel@tonic-gate int
195*7c478bd9Sstevel@tonic-gate rcm_notify_online(rcm_handle_t *hd, char *rsrcname, uint_t flag,
196*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
197*7c478bd9Sstevel@tonic-gate {
198*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
201*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	return (rcm_notify_online_list(hd, rsrcnames, flag, infop));
204*7c478bd9Sstevel@tonic-gate }
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate /* cancel offline and allow apps to use resources (list version) */
207*7c478bd9Sstevel@tonic-gate int
208*7c478bd9Sstevel@tonic-gate rcm_notify_online_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
209*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
210*7c478bd9Sstevel@tonic-gate {
211*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_NOTIFY_MASK) {
212*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
213*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
214*7c478bd9Sstevel@tonic-gate 	}
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_ONLINE, hd, rsrcnames, flag, NULL, infop));
217*7c478bd9Sstevel@tonic-gate }
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate /* notify that rsrcname has been removed */
220*7c478bd9Sstevel@tonic-gate int
221*7c478bd9Sstevel@tonic-gate rcm_notify_remove(rcm_handle_t *hd, char *rsrcname, uint_t flag,
222*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
223*7c478bd9Sstevel@tonic-gate {
224*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
227*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	return (rcm_notify_remove_list(hd, rsrcnames, flag, infop));
230*7c478bd9Sstevel@tonic-gate }
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate /* notify that resrouces have been removed (list form) */
233*7c478bd9Sstevel@tonic-gate int
234*7c478bd9Sstevel@tonic-gate rcm_notify_remove_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
235*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
236*7c478bd9Sstevel@tonic-gate {
237*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_NOTIFY_MASK) {
238*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
239*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_REMOVE, hd, rsrcnames, flag, NULL, infop));
243*7c478bd9Sstevel@tonic-gate }
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate /* request for permission to suspend resource of interval time */
246*7c478bd9Sstevel@tonic-gate int
247*7c478bd9Sstevel@tonic-gate rcm_request_suspend(rcm_handle_t *hd, char *rsrcname, uint_t flag,
248*7c478bd9Sstevel@tonic-gate     timespec_t *interval, rcm_info_t **infop)
249*7c478bd9Sstevel@tonic-gate {
250*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
253*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	return (rcm_request_suspend_list(hd, rsrcnames, flag, interval, infop));
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate /* request for permission to suspend resource of interval time (list form) */
259*7c478bd9Sstevel@tonic-gate int
260*7c478bd9Sstevel@tonic-gate rcm_request_suspend_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
261*7c478bd9Sstevel@tonic-gate     timespec_t *interval, rcm_info_t **infop)
262*7c478bd9Sstevel@tonic-gate {
263*7c478bd9Sstevel@tonic-gate 	if ((flag & ~RCM_REQUEST_MASK) || (interval == NULL) ||
264*7c478bd9Sstevel@tonic-gate 	    (interval->tv_sec < 0) || (interval->tv_nsec < 0)) {
265*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
266*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
267*7c478bd9Sstevel@tonic-gate 	}
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_SUSPEND, hd, rsrcnames, flag, (void *)interval,
270*7c478bd9Sstevel@tonic-gate 	    infop));
271*7c478bd9Sstevel@tonic-gate }
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate /* notify apps of the completion of resource suspension */
274*7c478bd9Sstevel@tonic-gate int
275*7c478bd9Sstevel@tonic-gate rcm_notify_resume(rcm_handle_t *hd, char *rsrcname, uint_t flag,
276*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
277*7c478bd9Sstevel@tonic-gate {
278*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
281*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	return (rcm_notify_resume_list(hd, rsrcnames, flag, infop));
284*7c478bd9Sstevel@tonic-gate }
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate /* notify apps of the completion of resource suspension (list form) */
287*7c478bd9Sstevel@tonic-gate int
288*7c478bd9Sstevel@tonic-gate rcm_notify_resume_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
289*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
290*7c478bd9Sstevel@tonic-gate {
291*7c478bd9Sstevel@tonic-gate 	if (flag & ~(RCM_NOTIFY_MASK | RCM_SUSPENDED)) {
292*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
293*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
294*7c478bd9Sstevel@tonic-gate 	}
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_RESUME, hd, rsrcnames, flag, NULL, infop));
297*7c478bd9Sstevel@tonic-gate }
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate /* request a capacity change from apps */
300*7c478bd9Sstevel@tonic-gate int
301*7c478bd9Sstevel@tonic-gate rcm_request_capacity_change(rcm_handle_t *hd, char *rsrcname, uint_t flag,
302*7c478bd9Sstevel@tonic-gate     nvlist_t *nvl, rcm_info_t **infop)
303*7c478bd9Sstevel@tonic-gate {
304*7c478bd9Sstevel@tonic-gate 	int rv;
305*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	if ((nvl == NULL) || (flag & ~RCM_REQUEST_MASK)) {
308*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
309*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
313*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	rv = rcm_common(CMD_REQUEST_CHANGE, hd, rsrcnames, flag, (void *)nvl,
316*7c478bd9Sstevel@tonic-gate 	    infop);
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	return (rv);
319*7c478bd9Sstevel@tonic-gate }
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate /* notify apps of a capacity change */
322*7c478bd9Sstevel@tonic-gate int
323*7c478bd9Sstevel@tonic-gate rcm_notify_capacity_change(rcm_handle_t *hd, char *rsrcname, uint_t flag,
324*7c478bd9Sstevel@tonic-gate     nvlist_t *nvl, rcm_info_t **infop)
325*7c478bd9Sstevel@tonic-gate {
326*7c478bd9Sstevel@tonic-gate 	int rv;
327*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	if ((nvl == NULL) || (flag & ~RCM_REQUEST_MASK)) {
330*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
331*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
332*7c478bd9Sstevel@tonic-gate 	}
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
335*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	rv = rcm_common(CMD_NOTIFY_CHANGE, hd, rsrcnames, flag, (void *)nvl,
338*7c478bd9Sstevel@tonic-gate 	    infop);
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	return (rv);
341*7c478bd9Sstevel@tonic-gate }
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate /* notify apps of an event */
344*7c478bd9Sstevel@tonic-gate int
345*7c478bd9Sstevel@tonic-gate rcm_notify_event(rcm_handle_t *hd, char *rsrcname, uint_t flag, nvlist_t *nvl,
346*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
347*7c478bd9Sstevel@tonic-gate {
348*7c478bd9Sstevel@tonic-gate 	int rv;
349*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	/* No flags are defined yet for rcm_notify_event() */
352*7c478bd9Sstevel@tonic-gate 	if ((nvl == NULL) || (flag != 0)) {
353*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
354*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
358*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	rv = rcm_common(CMD_EVENT, hd, rsrcnames, 0, (void *)nvl, infop);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	return (rv);
363*7c478bd9Sstevel@tonic-gate }
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate /*
366*7c478bd9Sstevel@tonic-gate  * Register to receive capacity changes. This requires a module to exist in
367*7c478bd9Sstevel@tonic-gate  * module directory. It should be called prior to using a new resource.
368*7c478bd9Sstevel@tonic-gate  */
369*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
370*7c478bd9Sstevel@tonic-gate int
371*7c478bd9Sstevel@tonic-gate rcm_register_capacity(rcm_handle_t *hd, char *rsrcname, uint_t flag,
372*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
373*7c478bd9Sstevel@tonic-gate {
374*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
377*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
378*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
379*7c478bd9Sstevel@tonic-gate 	}
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	flag |= RCM_REGISTER_CAPACITY;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
384*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
387*7c478bd9Sstevel@tonic-gate }
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate /* unregister interest in capacity changes */
390*7c478bd9Sstevel@tonic-gate int
391*7c478bd9Sstevel@tonic-gate rcm_unregister_capacity(rcm_handle_t *hd, char *rsrcname, uint_t flag)
392*7c478bd9Sstevel@tonic-gate {
393*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
396*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
397*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
398*7c478bd9Sstevel@tonic-gate 	}
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	flag |= RCM_REGISTER_CAPACITY;
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
403*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
406*7c478bd9Sstevel@tonic-gate }
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate /*
409*7c478bd9Sstevel@tonic-gate  * Register to receive events. This requires a module to exist in module
410*7c478bd9Sstevel@tonic-gate  * directory. It should be called prior to using a new resource.
411*7c478bd9Sstevel@tonic-gate  */
412*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
413*7c478bd9Sstevel@tonic-gate int
414*7c478bd9Sstevel@tonic-gate rcm_register_event(rcm_handle_t *hd, char *rsrcname, uint_t flag,
415*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
416*7c478bd9Sstevel@tonic-gate {
417*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
420*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
421*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
422*7c478bd9Sstevel@tonic-gate 	}
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	flag |= RCM_REGISTER_EVENT;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
427*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
430*7c478bd9Sstevel@tonic-gate }
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate /* unregister interest in events */
433*7c478bd9Sstevel@tonic-gate int
434*7c478bd9Sstevel@tonic-gate rcm_unregister_event(rcm_handle_t *hd, char *rsrcname, uint_t flag)
435*7c478bd9Sstevel@tonic-gate {
436*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
439*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
440*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
441*7c478bd9Sstevel@tonic-gate 	}
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	flag |= RCM_REGISTER_EVENT;
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
446*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
449*7c478bd9Sstevel@tonic-gate }
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate /*
452*7c478bd9Sstevel@tonic-gate  * Register interest in a resource. This requires a module to exist in module
453*7c478bd9Sstevel@tonic-gate  * directory. It should be called prior to using a new resource.
454*7c478bd9Sstevel@tonic-gate  *
455*7c478bd9Sstevel@tonic-gate  * Registration may be denied if it is presently locked by a DR operation.
456*7c478bd9Sstevel@tonic-gate  */
457*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
458*7c478bd9Sstevel@tonic-gate int
459*7c478bd9Sstevel@tonic-gate rcm_register_interest(rcm_handle_t *hd, char *rsrcname, uint_t flag,
460*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
461*7c478bd9Sstevel@tonic-gate {
462*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
465*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
466*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
467*7c478bd9Sstevel@tonic-gate 	}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	flag |= RCM_REGISTER_DR;
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
472*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
475*7c478bd9Sstevel@tonic-gate }
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate /* unregister interest in rsrcname */
478*7c478bd9Sstevel@tonic-gate int
479*7c478bd9Sstevel@tonic-gate rcm_unregister_interest(rcm_handle_t *hd, char *rsrcname, uint_t flag)
480*7c478bd9Sstevel@tonic-gate {
481*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	if (flag & ~RCM_REGISTER_MASK) {
484*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
485*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
486*7c478bd9Sstevel@tonic-gate 	}
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	flag |= RCM_REGISTER_DR;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
491*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
494*7c478bd9Sstevel@tonic-gate }
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate /* get the current state of a resource */
497*7c478bd9Sstevel@tonic-gate int
498*7c478bd9Sstevel@tonic-gate rcm_get_rsrcstate(rcm_handle_t *hd, char *rsrcname, int *statep)
499*7c478bd9Sstevel@tonic-gate {
500*7c478bd9Sstevel@tonic-gate 	int result;
501*7c478bd9Sstevel@tonic-gate 	int flag = 0;
502*7c478bd9Sstevel@tonic-gate 	rcm_info_t *infop = NULL;
503*7c478bd9Sstevel@tonic-gate 	rcm_info_tuple_t *tuple = NULL;
504*7c478bd9Sstevel@tonic-gate 	char *rsrcnames[2];
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	if (statep == NULL) {
507*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
508*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
509*7c478bd9Sstevel@tonic-gate 	}
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	rsrcnames[0] = rsrcname;
512*7c478bd9Sstevel@tonic-gate 	rsrcnames[1] = NULL;
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	result = rcm_common(CMD_GETSTATE, hd, rsrcnames, flag, NULL, &infop);
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	/*
517*7c478bd9Sstevel@tonic-gate 	 * A successful result implies the presence of exactly one RCM info
518*7c478bd9Sstevel@tonic-gate 	 * tuple containing the state of this resource (a combination of each
519*7c478bd9Sstevel@tonic-gate 	 * client's resources).  If that's not true, change the result to
520*7c478bd9Sstevel@tonic-gate 	 * RCM_FAILURE.
521*7c478bd9Sstevel@tonic-gate 	 */
522*7c478bd9Sstevel@tonic-gate 	if (result == RCM_SUCCESS) {
523*7c478bd9Sstevel@tonic-gate 		if ((infop == NULL) ||
524*7c478bd9Sstevel@tonic-gate 		    ((tuple = rcm_info_next(infop, NULL)) == NULL) ||
525*7c478bd9Sstevel@tonic-gate 		    (rcm_info_next(infop, tuple) != NULL)) {
526*7c478bd9Sstevel@tonic-gate 			result = RCM_FAILURE;
527*7c478bd9Sstevel@tonic-gate 		} else if (infop && tuple) {
528*7c478bd9Sstevel@tonic-gate 			*statep = rcm_info_state(tuple);
529*7c478bd9Sstevel@tonic-gate 		}
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	if (infop)
533*7c478bd9Sstevel@tonic-gate 		rcm_free_info(infop);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	return (result);
536*7c478bd9Sstevel@tonic-gate }
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate /*
539*7c478bd9Sstevel@tonic-gate  * RCM helper functions exposed to librcm callers.
540*7c478bd9Sstevel@tonic-gate  */
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate /* Free linked list of registration info */
543*7c478bd9Sstevel@tonic-gate void
544*7c478bd9Sstevel@tonic-gate rcm_free_info(rcm_info_t *info)
545*7c478bd9Sstevel@tonic-gate {
546*7c478bd9Sstevel@tonic-gate 	while (info) {
547*7c478bd9Sstevel@tonic-gate 		rcm_info_t *tmp = info->next;
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 		if (info->info)
550*7c478bd9Sstevel@tonic-gate 			nvlist_free(info->info);
551*7c478bd9Sstevel@tonic-gate 		free(info);
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 		info = tmp;
554*7c478bd9Sstevel@tonic-gate 	}
555*7c478bd9Sstevel@tonic-gate }
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate /* return the next tuple in the info structure */
558*7c478bd9Sstevel@tonic-gate rcm_info_tuple_t *
559*7c478bd9Sstevel@tonic-gate rcm_info_next(rcm_info_t *info, rcm_info_tuple_t *tuple)
560*7c478bd9Sstevel@tonic-gate {
561*7c478bd9Sstevel@tonic-gate 	if (info == NULL) {
562*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
563*7c478bd9Sstevel@tonic-gate 		return (NULL);
564*7c478bd9Sstevel@tonic-gate 	}
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL) {
567*7c478bd9Sstevel@tonic-gate 		return ((rcm_info_tuple_t *)info);
568*7c478bd9Sstevel@tonic-gate 	}
569*7c478bd9Sstevel@tonic-gate 	return ((rcm_info_tuple_t *)tuple->next);
570*7c478bd9Sstevel@tonic-gate }
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate /* return resource name */
573*7c478bd9Sstevel@tonic-gate const char *
574*7c478bd9Sstevel@tonic-gate rcm_info_rsrc(rcm_info_tuple_t *tuple)
575*7c478bd9Sstevel@tonic-gate {
576*7c478bd9Sstevel@tonic-gate 	char *rsrcname = NULL;
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
579*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
580*7c478bd9Sstevel@tonic-gate 		return (NULL);
581*7c478bd9Sstevel@tonic-gate 	}
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_lookup_string(tuple->info, RCM_RSRCNAME, &rsrcname))
584*7c478bd9Sstevel@tonic-gate 		return (NULL);
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	return (rsrcname);
587*7c478bd9Sstevel@tonic-gate }
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate const char *
590*7c478bd9Sstevel@tonic-gate rcm_info_info(rcm_info_tuple_t *tuple)
591*7c478bd9Sstevel@tonic-gate {
592*7c478bd9Sstevel@tonic-gate 	char *info = NULL;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
595*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
596*7c478bd9Sstevel@tonic-gate 		return (NULL);
597*7c478bd9Sstevel@tonic-gate 	}
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_INFO, &info))
600*7c478bd9Sstevel@tonic-gate 		return (NULL);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	return (info);
603*7c478bd9Sstevel@tonic-gate }
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate const char *
606*7c478bd9Sstevel@tonic-gate rcm_info_error(rcm_info_tuple_t *tuple)
607*7c478bd9Sstevel@tonic-gate {
608*7c478bd9Sstevel@tonic-gate 	char *errstr = NULL;
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
611*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
612*7c478bd9Sstevel@tonic-gate 		return (NULL);
613*7c478bd9Sstevel@tonic-gate 	}
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_ERROR,
616*7c478bd9Sstevel@tonic-gate 	    &errstr))
617*7c478bd9Sstevel@tonic-gate 		return (NULL);
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	return (errstr);
620*7c478bd9Sstevel@tonic-gate }
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate /* return info string in the tuple */
623*7c478bd9Sstevel@tonic-gate const char *
624*7c478bd9Sstevel@tonic-gate rcm_info_modname(rcm_info_tuple_t *tuple)
625*7c478bd9Sstevel@tonic-gate {
626*7c478bd9Sstevel@tonic-gate 	char *modname = NULL;
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
629*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
630*7c478bd9Sstevel@tonic-gate 		return (NULL);
631*7c478bd9Sstevel@tonic-gate 	}
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_MODNAME,
634*7c478bd9Sstevel@tonic-gate 	    &modname))
635*7c478bd9Sstevel@tonic-gate 		return (NULL);
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	return (modname);
638*7c478bd9Sstevel@tonic-gate }
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate /* return client pid in the tuple */
641*7c478bd9Sstevel@tonic-gate pid_t
642*7c478bd9Sstevel@tonic-gate rcm_info_pid(rcm_info_tuple_t *tuple)
643*7c478bd9Sstevel@tonic-gate {
644*7c478bd9Sstevel@tonic-gate 	uint64_t pid64 = (uint64_t)0;
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
647*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
648*7c478bd9Sstevel@tonic-gate 		return ((pid_t)0);
649*7c478bd9Sstevel@tonic-gate 	}
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_lookup_uint64(tuple->info, RCM_CLIENT_ID, &pid64))
652*7c478bd9Sstevel@tonic-gate 		return ((pid_t)0);
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	return ((pid_t)pid64);
655*7c478bd9Sstevel@tonic-gate }
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate /* return client state in the tuple */
658*7c478bd9Sstevel@tonic-gate int
659*7c478bd9Sstevel@tonic-gate rcm_info_state(rcm_info_tuple_t *tuple)
660*7c478bd9Sstevel@tonic-gate {
661*7c478bd9Sstevel@tonic-gate 	int state;
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
664*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
665*7c478bd9Sstevel@tonic-gate 		return (RCM_STATE_UNKNOWN);
666*7c478bd9Sstevel@tonic-gate 	}
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_lookup_int32(tuple->info, RCM_RSRCSTATE, &state))
669*7c478bd9Sstevel@tonic-gate 		return (RCM_STATE_UNKNOWN);
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	return (state);
672*7c478bd9Sstevel@tonic-gate }
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate /* return the generic properties in the tuple */
675*7c478bd9Sstevel@tonic-gate nvlist_t *
676*7c478bd9Sstevel@tonic-gate rcm_info_properties(rcm_info_tuple_t *tuple)
677*7c478bd9Sstevel@tonic-gate {
678*7c478bd9Sstevel@tonic-gate 	char *buf;
679*7c478bd9Sstevel@tonic-gate 	uint_t buflen;
680*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
683*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
684*7c478bd9Sstevel@tonic-gate 		return (NULL);
685*7c478bd9Sstevel@tonic-gate 	}
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_lookup_byte_array(tuple->info, RCM_CLIENT_PROPERTIES,
688*7c478bd9Sstevel@tonic-gate 	    (uchar_t **)&buf, &buflen))
689*7c478bd9Sstevel@tonic-gate 		return (NULL);
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_unpack(buf, buflen, &nvl, 0)) {
692*7c478bd9Sstevel@tonic-gate 		free(buf);
693*7c478bd9Sstevel@tonic-gate 		return (NULL);
694*7c478bd9Sstevel@tonic-gate 	}
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	return (nvl);
697*7c478bd9Sstevel@tonic-gate }
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate /*
700*7c478bd9Sstevel@tonic-gate  * return operation sequence number
701*7c478bd9Sstevel@tonic-gate  *
702*7c478bd9Sstevel@tonic-gate  * This is private. Called by rcmctl only for testing purposes.
703*7c478bd9Sstevel@tonic-gate  */
704*7c478bd9Sstevel@tonic-gate int
705*7c478bd9Sstevel@tonic-gate rcm_info_seqnum(rcm_info_tuple_t *tuple)
706*7c478bd9Sstevel@tonic-gate {
707*7c478bd9Sstevel@tonic-gate 	int seqnum;
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	if (tuple == NULL || tuple->info == NULL) {
710*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
711*7c478bd9Sstevel@tonic-gate 		return (-1);
712*7c478bd9Sstevel@tonic-gate 	}
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_lookup_int32(tuple->info, RCM_SEQ_NUM, &seqnum))
715*7c478bd9Sstevel@tonic-gate 		return (-1);
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	return (seqnum);
718*7c478bd9Sstevel@tonic-gate }
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate /*
722*7c478bd9Sstevel@tonic-gate  * The following interfaces are PRIVATE to the RCM framework. They are not
723*7c478bd9Sstevel@tonic-gate  * declared static because they are called by rcm_daemon.
724*7c478bd9Sstevel@tonic-gate  */
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate /*
727*7c478bd9Sstevel@tonic-gate  * Invoke shell to execute command in MT safe manner.
728*7c478bd9Sstevel@tonic-gate  * Returns wait status or -1 on error.
729*7c478bd9Sstevel@tonic-gate  */
730*7c478bd9Sstevel@tonic-gate int
731*7c478bd9Sstevel@tonic-gate rcm_exec_cmd(char *cmd)
732*7c478bd9Sstevel@tonic-gate {
733*7c478bd9Sstevel@tonic-gate 	pid_t pid;
734*7c478bd9Sstevel@tonic-gate 	int status, w;
735*7c478bd9Sstevel@tonic-gate 	char *argvec[] = {"sh", "-c", NULL, NULL};
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	argvec[2] = cmd;
738*7c478bd9Sstevel@tonic-gate 	if ((pid = fork1()) == 0) {
739*7c478bd9Sstevel@tonic-gate 		(void) execv("/bin/sh", argvec);
740*7c478bd9Sstevel@tonic-gate 		_exit(127);
741*7c478bd9Sstevel@tonic-gate 	} else if (pid == -1) {
742*7c478bd9Sstevel@tonic-gate 		return (-1);
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	do {
746*7c478bd9Sstevel@tonic-gate 		w = waitpid(pid, &status, 0);
747*7c478bd9Sstevel@tonic-gate 	} while (w == -1 && errno == EINTR);
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	return ((w == -1) ? w : status);
750*7c478bd9Sstevel@tonic-gate }
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate /* Append info at the very end */
753*7c478bd9Sstevel@tonic-gate int
754*7c478bd9Sstevel@tonic-gate rcm_append_info(rcm_info_t **head, rcm_info_t *info)
755*7c478bd9Sstevel@tonic-gate {
756*7c478bd9Sstevel@tonic-gate 	rcm_info_t *tuple;
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	if (head == NULL) {
759*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
760*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
761*7c478bd9Sstevel@tonic-gate 	}
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 	if ((tuple = *head) == NULL) {
764*7c478bd9Sstevel@tonic-gate 		*head = info;
765*7c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
766*7c478bd9Sstevel@tonic-gate 	}
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	while (tuple->next) {
769*7c478bd9Sstevel@tonic-gate 		tuple = tuple->next;
770*7c478bd9Sstevel@tonic-gate 	}
771*7c478bd9Sstevel@tonic-gate 	tuple->next = info;
772*7c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
773*7c478bd9Sstevel@tonic-gate }
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate /* get rcm module and rcm script directory names */
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate #define	N_MODULE_DIR	3	/* search 3 directories for modules */
778*7c478bd9Sstevel@tonic-gate #define	MODULE_DIR_HW	"/usr/platform/%s/lib/rcm/modules/"
779*7c478bd9Sstevel@tonic-gate #define	MODULE_DIR_GEN	"/usr/lib/rcm/modules/"
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate #define	N_SCRIPT_DIR	4	/* search 4 directories for scripts */
782*7c478bd9Sstevel@tonic-gate #define	SCRIPT_DIR_HW	"/usr/platform/%s/lib/rcm/scripts/"
783*7c478bd9Sstevel@tonic-gate #define	SCRIPT_DIR_GEN	"/usr/lib/rcm/scripts/"
784*7c478bd9Sstevel@tonic-gate #define	SCRIPT_DIR_ETC	"/etc/rcm/scripts/"
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate char *
788*7c478bd9Sstevel@tonic-gate rcm_module_dir(uint_t dirnum)
789*7c478bd9Sstevel@tonic-gate {
790*7c478bd9Sstevel@tonic-gate 	if (dirnum < N_MODULE_DIR)
791*7c478bd9Sstevel@tonic-gate 		return (rcm_dir(dirnum, NULL));
792*7c478bd9Sstevel@tonic-gate 	else
793*7c478bd9Sstevel@tonic-gate 		return (NULL);
794*7c478bd9Sstevel@tonic-gate }
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate char *
797*7c478bd9Sstevel@tonic-gate rcm_script_dir(uint_t dirnum)
798*7c478bd9Sstevel@tonic-gate {
799*7c478bd9Sstevel@tonic-gate 	if (dirnum < N_SCRIPT_DIR)
800*7c478bd9Sstevel@tonic-gate 		return (rcm_dir(dirnum + N_MODULE_DIR, NULL));
801*7c478bd9Sstevel@tonic-gate 	else
802*7c478bd9Sstevel@tonic-gate 		return (NULL);
803*7c478bd9Sstevel@tonic-gate }
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate char *
806*7c478bd9Sstevel@tonic-gate rcm_dir(uint_t dirnum, int *rcm_script)
807*7c478bd9Sstevel@tonic-gate {
808*7c478bd9Sstevel@tonic-gate 	static char dir_name[N_MODULE_DIR + N_SCRIPT_DIR][MAXPATHLEN];
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	char infobuf[MAXPATHLEN];
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	if (dirnum >= (N_MODULE_DIR + N_SCRIPT_DIR))
813*7c478bd9Sstevel@tonic-gate 		return (NULL);
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	if (dir_name[0][0] == '\0') {
816*7c478bd9Sstevel@tonic-gate 		/*
817*7c478bd9Sstevel@tonic-gate 		 * construct the module directory names
818*7c478bd9Sstevel@tonic-gate 		 */
819*7c478bd9Sstevel@tonic-gate 		if (sysinfo(SI_PLATFORM, infobuf, MAXPATHLEN) == -1) {
820*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "sysinfo %s\n", strerror(errno)));
821*7c478bd9Sstevel@tonic-gate 			return (NULL);
822*7c478bd9Sstevel@tonic-gate 		} else {
823*7c478bd9Sstevel@tonic-gate 			if (snprintf(dir_name[0], MAXPATHLEN, MODULE_DIR_HW,
824*7c478bd9Sstevel@tonic-gate 			    infobuf) >= MAXPATHLEN ||
825*7c478bd9Sstevel@tonic-gate 			    snprintf(dir_name[N_MODULE_DIR + 1], MAXPATHLEN,
826*7c478bd9Sstevel@tonic-gate 			    SCRIPT_DIR_HW, infobuf) >= MAXPATHLEN) {
827*7c478bd9Sstevel@tonic-gate 				dprintf((stderr,
828*7c478bd9Sstevel@tonic-gate 				    "invalid module or script directory for "
829*7c478bd9Sstevel@tonic-gate 				    "platform %s\n", infobuf));
830*7c478bd9Sstevel@tonic-gate 				return (NULL);
831*7c478bd9Sstevel@tonic-gate 			}
832*7c478bd9Sstevel@tonic-gate 		}
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 		if (sysinfo(SI_MACHINE, infobuf, MAXPATHLEN) == -1) {
835*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "sysinfo %s\n", strerror(errno)));
836*7c478bd9Sstevel@tonic-gate 			return (NULL);
837*7c478bd9Sstevel@tonic-gate 		} else {
838*7c478bd9Sstevel@tonic-gate 			if (snprintf(dir_name[1], MAXPATHLEN, MODULE_DIR_HW,
839*7c478bd9Sstevel@tonic-gate 			    infobuf) >= MAXPATHLEN ||
840*7c478bd9Sstevel@tonic-gate 			    snprintf(dir_name[N_MODULE_DIR + 2], MAXPATHLEN,
841*7c478bd9Sstevel@tonic-gate 			    SCRIPT_DIR_HW, infobuf) >= MAXPATHLEN) {
842*7c478bd9Sstevel@tonic-gate 				dprintf((stderr,
843*7c478bd9Sstevel@tonic-gate 				    "invalid module or script directory for "
844*7c478bd9Sstevel@tonic-gate 				    "machine type %s\n", infobuf));
845*7c478bd9Sstevel@tonic-gate 				return (NULL);
846*7c478bd9Sstevel@tonic-gate 			}
847*7c478bd9Sstevel@tonic-gate 		}
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 		if (strlcpy(dir_name[2], MODULE_DIR_GEN, MAXPATHLEN) >=
850*7c478bd9Sstevel@tonic-gate 		    MAXPATHLEN ||
851*7c478bd9Sstevel@tonic-gate 		    strlcpy(dir_name[N_MODULE_DIR + 3], SCRIPT_DIR_GEN,
852*7c478bd9Sstevel@tonic-gate 		    MAXPATHLEN) >= MAXPATHLEN ||
853*7c478bd9Sstevel@tonic-gate 		    strlcpy(dir_name[N_MODULE_DIR + 0], SCRIPT_DIR_ETC,
854*7c478bd9Sstevel@tonic-gate 		    MAXPATHLEN) >= MAXPATHLEN) {
855*7c478bd9Sstevel@tonic-gate 			dprintf((stderr,
856*7c478bd9Sstevel@tonic-gate 			    "invalid module or script generic directory\n"));
857*7c478bd9Sstevel@tonic-gate 			return (NULL);
858*7c478bd9Sstevel@tonic-gate 		}
859*7c478bd9Sstevel@tonic-gate 	}
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	if (rcm_script)
862*7c478bd9Sstevel@tonic-gate 		*rcm_script = (dirnum < N_MODULE_DIR) ? 0 : 1;
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	return (dir_name[dirnum]);
865*7c478bd9Sstevel@tonic-gate }
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate /*
868*7c478bd9Sstevel@tonic-gate  * Find the directory where the script is located.
869*7c478bd9Sstevel@tonic-gate  * If the script is found return a pointer to the directory where the
870*7c478bd9Sstevel@tonic-gate  * script was found otherwise return NULL.
871*7c478bd9Sstevel@tonic-gate  */
872*7c478bd9Sstevel@tonic-gate char *
873*7c478bd9Sstevel@tonic-gate rcm_get_script_dir(char *script_name)
874*7c478bd9Sstevel@tonic-gate {
875*7c478bd9Sstevel@tonic-gate 	uint_t i;
876*7c478bd9Sstevel@tonic-gate 	char *dir_name;
877*7c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
878*7c478bd9Sstevel@tonic-gate 	struct stat stats;
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	for (i = 0; (dir_name = rcm_script_dir(i)) != NULL; i++) {
881*7c478bd9Sstevel@tonic-gate 		if (snprintf(path, MAXPATHLEN, "%s%s", dir_name, script_name)
882*7c478bd9Sstevel@tonic-gate 		    >= MAXPATHLEN) {
883*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "invalid script %s skipped\n",
884*7c478bd9Sstevel@tonic-gate 			    script_name));
885*7c478bd9Sstevel@tonic-gate 			continue;
886*7c478bd9Sstevel@tonic-gate 		}
887*7c478bd9Sstevel@tonic-gate 		if (stat(path, &stats) == 0)
888*7c478bd9Sstevel@tonic-gate 			return (dir_name);
889*7c478bd9Sstevel@tonic-gate 	}
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 	return (NULL);
892*7c478bd9Sstevel@tonic-gate }
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate /*
895*7c478bd9Sstevel@tonic-gate  * Returns 1 if the filename is an rcm script.
896*7c478bd9Sstevel@tonic-gate  * Returns 0 if the filename is an rcm module.
897*7c478bd9Sstevel@tonic-gate  */
898*7c478bd9Sstevel@tonic-gate int
899*7c478bd9Sstevel@tonic-gate rcm_is_script(char *filename)
900*7c478bd9Sstevel@tonic-gate {
901*7c478bd9Sstevel@tonic-gate 	char *tmp;
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	if (((tmp = strstr(filename, RCM_MODULE_SUFFIX)) != NULL) &&
904*7c478bd9Sstevel@tonic-gate 		(tmp[strlen(RCM_MODULE_SUFFIX)] == '\0'))
905*7c478bd9Sstevel@tonic-gate 		return (0);
906*7c478bd9Sstevel@tonic-gate 	else
907*7c478bd9Sstevel@tonic-gate 		return (1);
908*7c478bd9Sstevel@tonic-gate }
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate /* Locate the module and call dlopen */
911*7c478bd9Sstevel@tonic-gate void *
912*7c478bd9Sstevel@tonic-gate rcm_module_open(char *modname)
913*7c478bd9Sstevel@tonic-gate {
914*7c478bd9Sstevel@tonic-gate 	unsigned i;
915*7c478bd9Sstevel@tonic-gate 	char *dir_name;
916*7c478bd9Sstevel@tonic-gate 	void *dlhandle = NULL;
917*7c478bd9Sstevel@tonic-gate 	char modpath[MAXPATHLEN];
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
920*7c478bd9Sstevel@tonic-gate 	struct stat sbuf;
921*7c478bd9Sstevel@tonic-gate #endif
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	/*
924*7c478bd9Sstevel@tonic-gate 	 * dlopen the module
925*7c478bd9Sstevel@tonic-gate 	 */
926*7c478bd9Sstevel@tonic-gate 	for (i = 0; (dir_name = rcm_module_dir(i)) != NULL; i++) {
927*7c478bd9Sstevel@tonic-gate 		if (snprintf(modpath, MAXPATHLEN, "%s%s", dir_name, modname)
928*7c478bd9Sstevel@tonic-gate 		    >= MAXPATHLEN) {
929*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "invalid module %s skipped\n",
930*7c478bd9Sstevel@tonic-gate 			    modname));
931*7c478bd9Sstevel@tonic-gate 			continue;
932*7c478bd9Sstevel@tonic-gate 		}
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 		if ((dlhandle = dlopen(modpath, RTLD_LAZY)) != NULL) {
935*7c478bd9Sstevel@tonic-gate 			return (dlhandle);
936*7c478bd9Sstevel@tonic-gate 		}
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "failure (dlopen=%s)\n", dlerror()));
939*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
940*7c478bd9Sstevel@tonic-gate 		if (stat(modpath, &sbuf) == 0) {
941*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s is not a valid module\n",
942*7c478bd9Sstevel@tonic-gate 			    modpath);
943*7c478bd9Sstevel@tonic-gate 		}
944*7c478bd9Sstevel@tonic-gate #endif
945*7c478bd9Sstevel@tonic-gate 	}
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	dprintf((stderr, "module %s not found\n", modname));
948*7c478bd9Sstevel@tonic-gate 	return (NULL);
949*7c478bd9Sstevel@tonic-gate }
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate /* dlclose module */
952*7c478bd9Sstevel@tonic-gate void
953*7c478bd9Sstevel@tonic-gate rcm_module_close(void *dlhandle)
954*7c478bd9Sstevel@tonic-gate {
955*7c478bd9Sstevel@tonic-gate 	if (dlclose(dlhandle) == 0)
956*7c478bd9Sstevel@tonic-gate 		return;
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	dprintf((stderr, "dlclose: %s\n", dlerror()));
959*7c478bd9Sstevel@tonic-gate }
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate /*
963*7c478bd9Sstevel@tonic-gate  * stub implementation of rcm_log_message allows dlopen of rcm modules
964*7c478bd9Sstevel@tonic-gate  * to proceed in absence of rcm_daemon.
965*7c478bd9Sstevel@tonic-gate  *
966*7c478bd9Sstevel@tonic-gate  * This definition is interposed by the definition in rcm_daemon because of the
967*7c478bd9Sstevel@tonic-gate  * default search order implemented by the linker and dlsym(). All RCM modules
968*7c478bd9Sstevel@tonic-gate  * will see the daemon version when loaded by the rcm_daemon.
969*7c478bd9Sstevel@tonic-gate  */
970*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
971*7c478bd9Sstevel@tonic-gate void
972*7c478bd9Sstevel@tonic-gate rcm_log_message(int level, char *message, ...)
973*7c478bd9Sstevel@tonic-gate {
974*7c478bd9Sstevel@tonic-gate 	dprintf((stderr, "rcm_log_message stub\n"));
975*7c478bd9Sstevel@tonic-gate }
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate /*
978*7c478bd9Sstevel@tonic-gate  * Helper functions
979*7c478bd9Sstevel@tonic-gate  */
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate /*
982*7c478bd9Sstevel@tonic-gate  * Common routine for all rcm calls which require daemon processing
983*7c478bd9Sstevel@tonic-gate  */
984*7c478bd9Sstevel@tonic-gate static int
985*7c478bd9Sstevel@tonic-gate rcm_common(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag, void *arg,
986*7c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
987*7c478bd9Sstevel@tonic-gate {
988*7c478bd9Sstevel@tonic-gate 	int i;
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	if (hd == NULL) {
991*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
992*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
993*7c478bd9Sstevel@tonic-gate 	}
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 	if (getuid() != 0) {
996*7c478bd9Sstevel@tonic-gate 		errno = EPERM;
997*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
998*7c478bd9Sstevel@tonic-gate 	}
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	if ((flag & (RCM_DR_OPERATION | RCM_MOD_INFO)) == 0) {
1001*7c478bd9Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL)) {
1002*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
1003*7c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
1004*7c478bd9Sstevel@tonic-gate 		}
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 		for (i = 0; rsrcnames[i] != NULL; i++) {
1007*7c478bd9Sstevel@tonic-gate 			if (*rsrcnames[i] == '\0') {
1008*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
1009*7c478bd9Sstevel@tonic-gate 				return (RCM_FAILURE);
1010*7c478bd9Sstevel@tonic-gate 			}
1011*7c478bd9Sstevel@tonic-gate 		}
1012*7c478bd9Sstevel@tonic-gate 	}
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 	/*
1015*7c478bd9Sstevel@tonic-gate 	 * Check if handle is allocated by rcm_daemon. If so, this call came
1016*7c478bd9Sstevel@tonic-gate 	 * from an RCM module, so we make a direct call into rcm_daemon.
1017*7c478bd9Sstevel@tonic-gate 	 */
1018*7c478bd9Sstevel@tonic-gate 	if (hd->lrcm_ops != NULL) {
1019*7c478bd9Sstevel@tonic-gate 		return (rcm_direct_call(cmd, hd, rsrcnames, flag, arg, infop));
1020*7c478bd9Sstevel@tonic-gate 	}
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	/*
1023*7c478bd9Sstevel@tonic-gate 	 * When not called from a RCM module (i.e. no recursion), zero the
1024*7c478bd9Sstevel@tonic-gate 	 * pointer just in case caller did not do so. For recursive calls,
1025*7c478bd9Sstevel@tonic-gate 	 * we want to append rcm_info_t after infop; zero it may cause
1026*7c478bd9Sstevel@tonic-gate 	 * memory leaks.
1027*7c478bd9Sstevel@tonic-gate 	 */
1028*7c478bd9Sstevel@tonic-gate 	if (infop) {
1029*7c478bd9Sstevel@tonic-gate 		*infop = NULL;
1030*7c478bd9Sstevel@tonic-gate 	}
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 	/*
1033*7c478bd9Sstevel@tonic-gate 	 * Now call into the daemon.
1034*7c478bd9Sstevel@tonic-gate 	 */
1035*7c478bd9Sstevel@tonic-gate 	return (rcm_daemon_call(cmd, hd, rsrcnames, flag, arg, infop));
1036*7c478bd9Sstevel@tonic-gate }
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate /*
1039*7c478bd9Sstevel@tonic-gate  * Caller is an RCM module, call directly into rcm_daemon.
1040*7c478bd9Sstevel@tonic-gate  */
1041*7c478bd9Sstevel@tonic-gate static int
1042*7c478bd9Sstevel@tonic-gate rcm_direct_call(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
1043*7c478bd9Sstevel@tonic-gate     void *arg, rcm_info_t **infop)
1044*7c478bd9Sstevel@tonic-gate {
1045*7c478bd9Sstevel@tonic-gate 	int error;
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 	librcm_ops_t *ops = (librcm_ops_t *)hd->lrcm_ops;
1048*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1049*7c478bd9Sstevel@tonic-gate 	case CMD_GETINFO:
1050*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_getinfo(rsrcnames, flag, hd->seq_num,
1051*7c478bd9Sstevel@tonic-gate 		    infop);
1052*7c478bd9Sstevel@tonic-gate 		break;
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 	case CMD_OFFLINE:
1055*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_offline(rsrcnames, hd->pid, flag,
1056*7c478bd9Sstevel@tonic-gate 		    hd->seq_num, infop);
1057*7c478bd9Sstevel@tonic-gate 		break;
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 	case CMD_ONLINE:
1060*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_online(rsrcnames, hd->pid, flag,
1061*7c478bd9Sstevel@tonic-gate 		    hd->seq_num, infop);
1062*7c478bd9Sstevel@tonic-gate 		break;
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 	case CMD_REMOVE:
1065*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_remove(rsrcnames, hd->pid, flag,
1066*7c478bd9Sstevel@tonic-gate 		    hd->seq_num, infop);
1067*7c478bd9Sstevel@tonic-gate 		break;
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	case CMD_SUSPEND:
1070*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_suspend(rsrcnames, hd->pid, flag,
1071*7c478bd9Sstevel@tonic-gate 		    hd->seq_num, (timespec_t *)arg, infop);
1072*7c478bd9Sstevel@tonic-gate 		break;
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate 	case CMD_RESUME:
1075*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_resume(rsrcnames, hd->pid, flag,
1076*7c478bd9Sstevel@tonic-gate 		    hd->seq_num, infop);
1077*7c478bd9Sstevel@tonic-gate 		break;
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	case CMD_REGISTER:
1080*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_regis(hd->modname, rsrcnames[0], hd->pid,
1081*7c478bd9Sstevel@tonic-gate 		    flag, infop);
1082*7c478bd9Sstevel@tonic-gate 		break;
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 	case CMD_UNREGISTER:
1085*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_unregis(hd->modname, rsrcnames[0], hd->pid,
1086*7c478bd9Sstevel@tonic-gate 		    flag);
1087*7c478bd9Sstevel@tonic-gate 		break;
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 	case CMD_REQUEST_CHANGE:
1090*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_request_change(rsrcnames[0], hd->pid, flag,
1091*7c478bd9Sstevel@tonic-gate 		    hd->seq_num, (nvlist_t *)arg, infop);
1092*7c478bd9Sstevel@tonic-gate 		break;
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	case CMD_NOTIFY_CHANGE:
1095*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_notify_change(rsrcnames[0], hd->pid, flag,
1096*7c478bd9Sstevel@tonic-gate 		    hd->seq_num, (nvlist_t *)arg, infop);
1097*7c478bd9Sstevel@tonic-gate 		break;
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	case CMD_EVENT:
1100*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_notify_event(rsrcnames[0], hd->pid, flag,
1101*7c478bd9Sstevel@tonic-gate 		    hd->seq_num, (nvlist_t *)arg, infop);
1102*7c478bd9Sstevel@tonic-gate 		break;
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 	case CMD_GETSTATE:
1105*7c478bd9Sstevel@tonic-gate 		error = ops->librcm_getstate(rsrcnames[0], hd->pid, infop);
1106*7c478bd9Sstevel@tonic-gate 		break;
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 	default:
1109*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "invalid command: %d\n", cmd));
1110*7c478bd9Sstevel@tonic-gate 		error = EFAULT;
1111*7c478bd9Sstevel@tonic-gate 	}
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate 	if (error > 0) {
1114*7c478bd9Sstevel@tonic-gate 		errno = error;
1115*7c478bd9Sstevel@tonic-gate 		error = RCM_FAILURE;
1116*7c478bd9Sstevel@tonic-gate 	}
1117*7c478bd9Sstevel@tonic-gate 	return (error);
1118*7c478bd9Sstevel@tonic-gate }
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate /*
1121*7c478bd9Sstevel@tonic-gate  * Call into rcm_daemon door to process the request
1122*7c478bd9Sstevel@tonic-gate  */
1123*7c478bd9Sstevel@tonic-gate static int
1124*7c478bd9Sstevel@tonic-gate rcm_daemon_call(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
1125*7c478bd9Sstevel@tonic-gate     void *arg, rcm_info_t **infop)
1126*7c478bd9Sstevel@tonic-gate {
1127*7c478bd9Sstevel@tonic-gate 	int errno_found;
1128*7c478bd9Sstevel@tonic-gate 	int daemon_errno;
1129*7c478bd9Sstevel@tonic-gate 	int error = RCM_SUCCESS;
1130*7c478bd9Sstevel@tonic-gate 	int delay = 300;
1131*7c478bd9Sstevel@tonic-gate 	int maxdelay = 10000;	/* 10 seconds */
1132*7c478bd9Sstevel@tonic-gate 	char *nvl_packed = NULL;
1133*7c478bd9Sstevel@tonic-gate 	size_t nvl_size = 0;
1134*7c478bd9Sstevel@tonic-gate 	nvlist_t *ret = NULL;
1135*7c478bd9Sstevel@tonic-gate 	nvpair_t *nvp;
1136*7c478bd9Sstevel@tonic-gate 	size_t rsize = 0;
1137*7c478bd9Sstevel@tonic-gate 	rcm_info_t *info = NULL;
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 	errno = 0;
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate 	/*
1142*7c478bd9Sstevel@tonic-gate 	 * Decide whether to start the daemon
1143*7c478bd9Sstevel@tonic-gate 	 */
1144*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1145*7c478bd9Sstevel@tonic-gate 	case CMD_GETINFO:
1146*7c478bd9Sstevel@tonic-gate 	case CMD_OFFLINE:
1147*7c478bd9Sstevel@tonic-gate 	case CMD_ONLINE:
1148*7c478bd9Sstevel@tonic-gate 	case CMD_REMOVE:
1149*7c478bd9Sstevel@tonic-gate 	case CMD_SUSPEND:
1150*7c478bd9Sstevel@tonic-gate 	case CMD_RESUME:
1151*7c478bd9Sstevel@tonic-gate 	case CMD_REGISTER:
1152*7c478bd9Sstevel@tonic-gate 	case CMD_UNREGISTER:
1153*7c478bd9Sstevel@tonic-gate 	case CMD_EVENT:
1154*7c478bd9Sstevel@tonic-gate 	case CMD_REQUEST_CHANGE:
1155*7c478bd9Sstevel@tonic-gate 	case CMD_NOTIFY_CHANGE:
1156*7c478bd9Sstevel@tonic-gate 	case CMD_GETSTATE:
1157*7c478bd9Sstevel@tonic-gate 		break;
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 	default:
1160*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1161*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
1162*7c478bd9Sstevel@tonic-gate 	}
1163*7c478bd9Sstevel@tonic-gate 
1164*7c478bd9Sstevel@tonic-gate 	if (rcm_daemon_is_alive() != 1) {
1165*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "failed to start rcm_daemon\n"));
1166*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1167*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
1168*7c478bd9Sstevel@tonic-gate 	}
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate 	/*
1171*7c478bd9Sstevel@tonic-gate 	 * Generate a packed nvlist for the request
1172*7c478bd9Sstevel@tonic-gate 	 */
1173*7c478bd9Sstevel@tonic-gate 	if (rcm_generate_nvlist(cmd, hd, rsrcnames, flag, arg, &nvl_packed,
1174*7c478bd9Sstevel@tonic-gate 	    &nvl_size) < 0) {
1175*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "error in nvlist generation\n"));
1176*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1177*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
1178*7c478bd9Sstevel@tonic-gate 	}
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	/*
1181*7c478bd9Sstevel@tonic-gate 	 * Make the door call and get a return event. We go into a retry loop
1182*7c478bd9Sstevel@tonic-gate 	 * when RCM_ET_EAGAIN is returned.
1183*7c478bd9Sstevel@tonic-gate 	 */
1184*7c478bd9Sstevel@tonic-gate retry:
1185*7c478bd9Sstevel@tonic-gate 	if (get_event_service(RCM_SERVICE_DOOR, (void *)nvl_packed, nvl_size,
1186*7c478bd9Sstevel@tonic-gate 	    (void **)&ret, &rsize) < 0) {
1187*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "rcm_daemon call failed: %s\n",
1188*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1189*7c478bd9Sstevel@tonic-gate 		free(nvl_packed);
1190*7c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
1191*7c478bd9Sstevel@tonic-gate 	}
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 	assert(ret != NULL);
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate 	/*
1196*7c478bd9Sstevel@tonic-gate 	 * nvlist_lookup_* routines don't work because the returned nvlist
1197*7c478bd9Sstevel@tonic-gate 	 * was nvlist_alloc'ed without the NV_UNIQUE_NAME flag.  Implement
1198*7c478bd9Sstevel@tonic-gate 	 * a sequential search manually, which is fine since there is only
1199*7c478bd9Sstevel@tonic-gate 	 * one RCM_RESULT value in the nvlist.
1200*7c478bd9Sstevel@tonic-gate 	 */
1201*7c478bd9Sstevel@tonic-gate 	errno_found = 0;
1202*7c478bd9Sstevel@tonic-gate 	nvp = NULL;
1203*7c478bd9Sstevel@tonic-gate 	while (nvp = nvlist_next_nvpair(ret, nvp)) {
1204*7c478bd9Sstevel@tonic-gate 		if (strcmp(nvpair_name(nvp), RCM_RESULT) == 0) {
1205*7c478bd9Sstevel@tonic-gate 			if (errno = nvpair_value_int32(nvp, &daemon_errno)) {
1206*7c478bd9Sstevel@tonic-gate 				error = RCM_FAILURE;
1207*7c478bd9Sstevel@tonic-gate 				goto out;
1208*7c478bd9Sstevel@tonic-gate 			}
1209*7c478bd9Sstevel@tonic-gate 			errno_found++;
1210*7c478bd9Sstevel@tonic-gate 			break;
1211*7c478bd9Sstevel@tonic-gate 		}
1212*7c478bd9Sstevel@tonic-gate 	}
1213*7c478bd9Sstevel@tonic-gate 	if (errno_found == 0) {
1214*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1215*7c478bd9Sstevel@tonic-gate 		error = RCM_FAILURE;
1216*7c478bd9Sstevel@tonic-gate 		goto out;
1217*7c478bd9Sstevel@tonic-gate 	}
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	if (daemon_errno == EAGAIN) {
1220*7c478bd9Sstevel@tonic-gate 		/*
1221*7c478bd9Sstevel@tonic-gate 		 * Wait and retry
1222*7c478bd9Sstevel@tonic-gate 		 */
1223*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "retry door_call\n"));
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 		if (delay > maxdelay) {
1226*7c478bd9Sstevel@tonic-gate 			errno = EAGAIN;
1227*7c478bd9Sstevel@tonic-gate 			error = RCM_FAILURE;
1228*7c478bd9Sstevel@tonic-gate 			goto out;
1229*7c478bd9Sstevel@tonic-gate 		}
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 		(void) poll(NULL, 0, delay);
1232*7c478bd9Sstevel@tonic-gate 		delay *= 2;		/* exponential back off */
1233*7c478bd9Sstevel@tonic-gate 		nvlist_free(ret);
1234*7c478bd9Sstevel@tonic-gate 		goto retry;
1235*7c478bd9Sstevel@tonic-gate 	}
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 	/*
1238*7c478bd9Sstevel@tonic-gate 	 * The door call succeeded. Now extract info from returned event.
1239*7c478bd9Sstevel@tonic-gate 	 */
1240*7c478bd9Sstevel@tonic-gate 	if (extract_info(ret, &info) != 0) {
1241*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "error in extracting event data\n"));
1242*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1243*7c478bd9Sstevel@tonic-gate 		error = RCM_FAILURE;
1244*7c478bd9Sstevel@tonic-gate 		goto out;
1245*7c478bd9Sstevel@tonic-gate 	}
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate 	if (infop)
1248*7c478bd9Sstevel@tonic-gate 		*infop = info;
1249*7c478bd9Sstevel@tonic-gate 	else
1250*7c478bd9Sstevel@tonic-gate 		rcm_free_info(info);
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	if (daemon_errno) {
1253*7c478bd9Sstevel@tonic-gate 		if (daemon_errno > 0) {
1254*7c478bd9Sstevel@tonic-gate 			errno = daemon_errno;
1255*7c478bd9Sstevel@tonic-gate 			error = RCM_FAILURE;
1256*7c478bd9Sstevel@tonic-gate 		} else {
1257*7c478bd9Sstevel@tonic-gate 			error = daemon_errno;
1258*7c478bd9Sstevel@tonic-gate 		}
1259*7c478bd9Sstevel@tonic-gate 	}
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate out:
1262*7c478bd9Sstevel@tonic-gate 	if (nvl_packed)
1263*7c478bd9Sstevel@tonic-gate 		free(nvl_packed);
1264*7c478bd9Sstevel@tonic-gate 	if (ret)
1265*7c478bd9Sstevel@tonic-gate 		nvlist_free(ret);
1266*7c478bd9Sstevel@tonic-gate 	dprintf((stderr, "daemon call is done. error = %d, errno = %s\n", error,
1267*7c478bd9Sstevel@tonic-gate 	    strerror(errno)));
1268*7c478bd9Sstevel@tonic-gate 	return (error);
1269*7c478bd9Sstevel@tonic-gate }
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate /*
1272*7c478bd9Sstevel@tonic-gate  * Extract registration info from event data.
1273*7c478bd9Sstevel@tonic-gate  * Return 0 on success and -1 on failure.
1274*7c478bd9Sstevel@tonic-gate  */
1275*7c478bd9Sstevel@tonic-gate static int
1276*7c478bd9Sstevel@tonic-gate extract_info(nvlist_t *nvl, rcm_info_t **infop)
1277*7c478bd9Sstevel@tonic-gate {
1278*7c478bd9Sstevel@tonic-gate 	rcm_info_t *info = NULL;
1279*7c478bd9Sstevel@tonic-gate 	rcm_info_t *prev = NULL;
1280*7c478bd9Sstevel@tonic-gate 	rcm_info_t *tmp = NULL;
1281*7c478bd9Sstevel@tonic-gate 	char *buf;
1282*7c478bd9Sstevel@tonic-gate 	uint_t buflen;
1283*7c478bd9Sstevel@tonic-gate 	nvpair_t *nvp = NULL;
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 	while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 		buf = NULL;
1288*7c478bd9Sstevel@tonic-gate 		buflen = 0;
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 		if (strcmp(nvpair_name(nvp), RCM_RESULT_INFO) != 0)
1291*7c478bd9Sstevel@tonic-gate 			continue;
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate 		if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
1294*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "out of memory\n"));
1295*7c478bd9Sstevel@tonic-gate 			goto fail;
1296*7c478bd9Sstevel@tonic-gate 		}
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 		if (errno = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
1299*7c478bd9Sstevel@tonic-gate 		    &buflen)) {
1300*7c478bd9Sstevel@tonic-gate 			free(tmp);
1301*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "failed (nvpair_value=%s)\n",
1302*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1303*7c478bd9Sstevel@tonic-gate 			goto fail;
1304*7c478bd9Sstevel@tonic-gate 		}
1305*7c478bd9Sstevel@tonic-gate 		if (errno = nvlist_unpack(buf, buflen, &(tmp->info), 0)) {
1306*7c478bd9Sstevel@tonic-gate 			free(tmp);
1307*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "failed (nvlist_unpack=%s)\n",
1308*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1309*7c478bd9Sstevel@tonic-gate 			goto fail;
1310*7c478bd9Sstevel@tonic-gate 		}
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 		if (info == NULL) {
1313*7c478bd9Sstevel@tonic-gate 			prev = info = tmp;
1314*7c478bd9Sstevel@tonic-gate 		} else {
1315*7c478bd9Sstevel@tonic-gate 			prev->next = tmp;
1316*7c478bd9Sstevel@tonic-gate 			prev = tmp;
1317*7c478bd9Sstevel@tonic-gate 		}
1318*7c478bd9Sstevel@tonic-gate 	}
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate 	*infop = info;
1321*7c478bd9Sstevel@tonic-gate 	return (0);
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate fail:
1324*7c478bd9Sstevel@tonic-gate 	rcm_free_info(info);
1325*7c478bd9Sstevel@tonic-gate 	*infop = NULL;
1326*7c478bd9Sstevel@tonic-gate 	return (-1);
1327*7c478bd9Sstevel@tonic-gate }
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate /* Generate a packed nvlist for communicating with RCM daemon */
1330*7c478bd9Sstevel@tonic-gate static int
1331*7c478bd9Sstevel@tonic-gate rcm_generate_nvlist(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
1332*7c478bd9Sstevel@tonic-gate     void *arg, char **nvl_packed, size_t *nvl_size)
1333*7c478bd9Sstevel@tonic-gate {
1334*7c478bd9Sstevel@tonic-gate 	int nrsrcnames;
1335*7c478bd9Sstevel@tonic-gate 	char *buf = NULL;
1336*7c478bd9Sstevel@tonic-gate 	size_t buflen = 0;
1337*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl = NULL;
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 	assert((nvl_packed != NULL) && (nvl_size != NULL));
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 	*nvl_size = 0;
1342*7c478bd9Sstevel@tonic-gate 	*nvl_packed = NULL;
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	/* Allocate an empty nvlist */
1345*7c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) > 0) {
1346*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "failed (nvlist_alloc=%s).\n",
1347*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1348*7c478bd9Sstevel@tonic-gate 		return (-1);
1349*7c478bd9Sstevel@tonic-gate 	}
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate 	/* Stuff in all the arguments for the daemon call */
1352*7c478bd9Sstevel@tonic-gate 	if (nvlist_add_int32(nvl, RCM_CMD, cmd) != 0) {
1353*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "failed (nvlist_add(CMD)=%s).\n",
1354*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1355*7c478bd9Sstevel@tonic-gate 		goto fail;
1356*7c478bd9Sstevel@tonic-gate 	}
1357*7c478bd9Sstevel@tonic-gate 	if (rsrcnames) {
1358*7c478bd9Sstevel@tonic-gate 		nrsrcnames = 0;
1359*7c478bd9Sstevel@tonic-gate 		while (rsrcnames[nrsrcnames] != NULL)
1360*7c478bd9Sstevel@tonic-gate 			nrsrcnames++;
1361*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_string_array(nvl, RCM_RSRCNAMES, rsrcnames,
1362*7c478bd9Sstevel@tonic-gate 		    nrsrcnames) != 0) {
1363*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "failed (nvlist_add(RSRCNAMES)=%s).\n",
1364*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1365*7c478bd9Sstevel@tonic-gate 			goto fail;
1366*7c478bd9Sstevel@tonic-gate 		}
1367*7c478bd9Sstevel@tonic-gate 	}
1368*7c478bd9Sstevel@tonic-gate 	if (hd->modname) {
1369*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_string(nvl, RCM_CLIENT_MODNAME, hd->modname)
1370*7c478bd9Sstevel@tonic-gate 		    != 0) {
1371*7c478bd9Sstevel@tonic-gate 			dprintf((stderr,
1372*7c478bd9Sstevel@tonic-gate 			    "failed (nvlist_add(CLIENT_MODNAME)=%s).\n",
1373*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1374*7c478bd9Sstevel@tonic-gate 			goto fail;
1375*7c478bd9Sstevel@tonic-gate 		}
1376*7c478bd9Sstevel@tonic-gate 	}
1377*7c478bd9Sstevel@tonic-gate 	if (hd->pid) {
1378*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_uint64(nvl, RCM_CLIENT_ID, hd->pid) != 0) {
1379*7c478bd9Sstevel@tonic-gate 			dprintf((stderr, "failed (nvlist_add(CLIENT_ID)=%s).\n",
1380*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1381*7c478bd9Sstevel@tonic-gate 			goto fail;
1382*7c478bd9Sstevel@tonic-gate 		}
1383*7c478bd9Sstevel@tonic-gate 	}
1384*7c478bd9Sstevel@tonic-gate 	if (flag) {
1385*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_uint32(nvl, RCM_REQUEST_FLAG, flag) != 0) {
1386*7c478bd9Sstevel@tonic-gate 			dprintf((stderr,
1387*7c478bd9Sstevel@tonic-gate 			    "failed (nvlist_add(REQUEST_FLAG)=%s).\n",
1388*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1389*7c478bd9Sstevel@tonic-gate 			goto fail;
1390*7c478bd9Sstevel@tonic-gate 		}
1391*7c478bd9Sstevel@tonic-gate 	}
1392*7c478bd9Sstevel@tonic-gate 	if (arg && cmd == CMD_SUSPEND) {
1393*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_byte_array(nvl, RCM_SUSPEND_INTERVAL,
1394*7c478bd9Sstevel@tonic-gate 		    (uchar_t *)arg, sizeof (timespec_t)) != 0) {
1395*7c478bd9Sstevel@tonic-gate 			dprintf((stderr,
1396*7c478bd9Sstevel@tonic-gate 			    "failed (nvlist_add(SUSPEND_INTERVAL)=%s).\n",
1397*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1398*7c478bd9Sstevel@tonic-gate 			goto fail;
1399*7c478bd9Sstevel@tonic-gate 		}
1400*7c478bd9Sstevel@tonic-gate 	}
1401*7c478bd9Sstevel@tonic-gate 	if (arg &&
1402*7c478bd9Sstevel@tonic-gate 	    ((cmd == CMD_REQUEST_CHANGE) || (cmd == CMD_NOTIFY_CHANGE))) {
1403*7c478bd9Sstevel@tonic-gate 		if (errno = nvlist_pack(arg, &buf, &buflen, NV_ENCODE_NATIVE,
1404*7c478bd9Sstevel@tonic-gate 		    0)) {
1405*7c478bd9Sstevel@tonic-gate 			dprintf((stderr,
1406*7c478bd9Sstevel@tonic-gate 			    "failed (nvlist_pack(CHANGE_DATA)=%s).\n",
1407*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1408*7c478bd9Sstevel@tonic-gate 			goto fail;
1409*7c478bd9Sstevel@tonic-gate 		}
1410*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_byte_array(nvl, RCM_CHANGE_DATA, (uchar_t *)buf,
1411*7c478bd9Sstevel@tonic-gate 		    buflen) != 0) {
1412*7c478bd9Sstevel@tonic-gate 			dprintf((stderr,
1413*7c478bd9Sstevel@tonic-gate 			    "failed (nvlist_add(CHANGE_DATA)=%s).\n",
1414*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1415*7c478bd9Sstevel@tonic-gate 			goto fail;
1416*7c478bd9Sstevel@tonic-gate 		}
1417*7c478bd9Sstevel@tonic-gate 	}
1418*7c478bd9Sstevel@tonic-gate 	if (arg && cmd == CMD_EVENT) {
1419*7c478bd9Sstevel@tonic-gate 		if (errno = nvlist_pack(arg, &buf, &buflen, NV_ENCODE_NATIVE,
1420*7c478bd9Sstevel@tonic-gate 		    0)) {
1421*7c478bd9Sstevel@tonic-gate 			dprintf((stderr,
1422*7c478bd9Sstevel@tonic-gate 			    "failed (nvlist_pack(CHANGE_DATA)=%s).\n",
1423*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1424*7c478bd9Sstevel@tonic-gate 			goto fail;
1425*7c478bd9Sstevel@tonic-gate 		}
1426*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_byte_array(nvl, RCM_EVENT_DATA, (uchar_t *)buf,
1427*7c478bd9Sstevel@tonic-gate 		    buflen) != 0) {
1428*7c478bd9Sstevel@tonic-gate 			dprintf((stderr,
1429*7c478bd9Sstevel@tonic-gate 			    "failed (nvlist_add(EVENT_DATA)=%s).\n",
1430*7c478bd9Sstevel@tonic-gate 			    strerror(errno)));
1431*7c478bd9Sstevel@tonic-gate 			goto fail;
1432*7c478bd9Sstevel@tonic-gate 		}
1433*7c478bd9Sstevel@tonic-gate 	}
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	/* Pack the nvlist */
1436*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_pack(nvl, nvl_packed, nvl_size, NV_ENCODE_NATIVE,
1437*7c478bd9Sstevel@tonic-gate 	    0)) {
1438*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "failed (nvlist_pack=%s).\n",
1439*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1440*7c478bd9Sstevel@tonic-gate 		goto fail;
1441*7c478bd9Sstevel@tonic-gate 	}
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 	/* If an argument was packed intermediately, free the buffer */
1444*7c478bd9Sstevel@tonic-gate 	if (buf)
1445*7c478bd9Sstevel@tonic-gate 		free(buf);
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	/* Free the unpacked version of the nvlist and return the packed list */
1448*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
1449*7c478bd9Sstevel@tonic-gate 	return (0);
1450*7c478bd9Sstevel@tonic-gate 
1451*7c478bd9Sstevel@tonic-gate fail:
1452*7c478bd9Sstevel@tonic-gate 	if (buf)
1453*7c478bd9Sstevel@tonic-gate 		free(buf);
1454*7c478bd9Sstevel@tonic-gate 	if (nvl)
1455*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1456*7c478bd9Sstevel@tonic-gate 	if (*nvl_packed)
1457*7c478bd9Sstevel@tonic-gate 		free(*nvl_packed);
1458*7c478bd9Sstevel@tonic-gate 	*nvl_packed = NULL;
1459*7c478bd9Sstevel@tonic-gate 	*nvl_size = 0;
1460*7c478bd9Sstevel@tonic-gate 	return (-1);
1461*7c478bd9Sstevel@tonic-gate }
1462*7c478bd9Sstevel@tonic-gate 
1463*7c478bd9Sstevel@tonic-gate /* check if rcm_daemon is up and running */
1464*7c478bd9Sstevel@tonic-gate static int
1465*7c478bd9Sstevel@tonic-gate rcm_daemon_is_alive()
1466*7c478bd9Sstevel@tonic-gate {
1467*7c478bd9Sstevel@tonic-gate 	int lasttry;
1468*7c478bd9Sstevel@tonic-gate 	struct stat st;
1469*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
1470*7c478bd9Sstevel@tonic-gate 	char *buf = NULL;
1471*7c478bd9Sstevel@tonic-gate 	size_t buflen = 0;
1472*7c478bd9Sstevel@tonic-gate 	int delay = 300;
1473*7c478bd9Sstevel@tonic-gate 	const int maxdelay = 10000;	/* 10 sec */
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate 	/* generate a packed nvlist for the door knocking */
1476*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) {
1477*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "nvlist_alloc failed: %s\n", strerror(errno)));
1478*7c478bd9Sstevel@tonic-gate 		return (0);
1479*7c478bd9Sstevel@tonic-gate 	}
1480*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_add_int32(nvl, RCM_CMD, CMD_KNOCK)) {
1481*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "nvlist_add failed: %s\n", strerror(errno)));
1482*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1483*7c478bd9Sstevel@tonic-gate 		return (0);
1484*7c478bd9Sstevel@tonic-gate 	}
1485*7c478bd9Sstevel@tonic-gate 	if (errno = nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0)) {
1486*7c478bd9Sstevel@tonic-gate 		dprintf((stderr, "nvlist_pack failed: %s\n", strerror(errno)));
1487*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1488*7c478bd9Sstevel@tonic-gate 		return (0);
1489*7c478bd9Sstevel@tonic-gate 	}
1490*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 	/*
1493*7c478bd9Sstevel@tonic-gate 	 * check the door and knock on it
1494*7c478bd9Sstevel@tonic-gate 	 */
1495*7c478bd9Sstevel@tonic-gate 	if ((stat(RCM_SERVICE_DOOR, &st) == 0) &&
1496*7c478bd9Sstevel@tonic-gate 	    (get_event_service(RCM_SERVICE_DOOR, (void *)buf, buflen, NULL,
1497*7c478bd9Sstevel@tonic-gate 	    NULL) == 0)) {
1498*7c478bd9Sstevel@tonic-gate 		free(buf);
1499*7c478bd9Sstevel@tonic-gate 		return (1);	/* daemon is alive */
1500*7c478bd9Sstevel@tonic-gate 	}
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate 	/*
1503*7c478bd9Sstevel@tonic-gate 	 * Attempt to start the daemon.
1504*7c478bd9Sstevel@tonic-gate 	 * If caller has SIGCHLD set to SIG_IGN or its SA_NOCLDWAIT
1505*7c478bd9Sstevel@tonic-gate 	 * flag set, waitpid(2) (hence rcm_exec_cmd) will fail.
1506*7c478bd9Sstevel@tonic-gate 	 * get_event_service will determine if the rcm_daemon started.
1507*7c478bd9Sstevel@tonic-gate 	 */
1508*7c478bd9Sstevel@tonic-gate 	dprintf((stderr, "exec: %s\n", RCM_DAEMON_START));
1509*7c478bd9Sstevel@tonic-gate 	(void) rcm_exec_cmd(RCM_DAEMON_START);
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 	/*
1512*7c478bd9Sstevel@tonic-gate 	 * Wait for daemon to respond, timeout at 10 sec
1513*7c478bd9Sstevel@tonic-gate 	 */
1514*7c478bd9Sstevel@tonic-gate 	while (((lasttry = get_event_service(RCM_SERVICE_DOOR, (void *)buf,
1515*7c478bd9Sstevel@tonic-gate 	    buflen, NULL, NULL)) != 0) &&
1516*7c478bd9Sstevel@tonic-gate 	    ((errno == EBADF) || (errno == ESRCH))) {
1517*7c478bd9Sstevel@tonic-gate 		if (delay > maxdelay) {
1518*7c478bd9Sstevel@tonic-gate 			break;
1519*7c478bd9Sstevel@tonic-gate 		}
1520*7c478bd9Sstevel@tonic-gate 		(void) poll(NULL, 0, delay);
1521*7c478bd9Sstevel@tonic-gate 		delay *= 2;
1522*7c478bd9Sstevel@tonic-gate 	}
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate 	free(buf);
1525*7c478bd9Sstevel@tonic-gate 	if (lasttry == 0)
1526*7c478bd9Sstevel@tonic-gate 		return (1);
1527*7c478bd9Sstevel@tonic-gate 	return (0);
1528*7c478bd9Sstevel@tonic-gate }
1529*7c478bd9Sstevel@tonic-gate 
1530*7c478bd9Sstevel@tonic-gate /*
1531*7c478bd9Sstevel@tonic-gate  * Check permission.
1532*7c478bd9Sstevel@tonic-gate  *
1533*7c478bd9Sstevel@tonic-gate  * The policy is root only for now. Need to relax this when interface level
1534*7c478bd9Sstevel@tonic-gate  * is raised.
1535*7c478bd9Sstevel@tonic-gate  */
1536*7c478bd9Sstevel@tonic-gate static int
1537*7c478bd9Sstevel@tonic-gate rcm_check_permission(void)
1538*7c478bd9Sstevel@tonic-gate {
1539*7c478bd9Sstevel@tonic-gate 	return (getuid() == 0);
1540*7c478bd9Sstevel@tonic-gate }
1541*7c478bd9Sstevel@tonic-gate 
1542*7c478bd9Sstevel@tonic-gate /*
1543*7c478bd9Sstevel@tonic-gate  * Project private function - for use by RCM MSTC tests
1544*7c478bd9Sstevel@tonic-gate  *
1545*7c478bd9Sstevel@tonic-gate  * Get the client name (rcm module name or script name) corresponding to
1546*7c478bd9Sstevel@tonic-gate  * the given rcm handle.
1547*7c478bd9Sstevel@tonic-gate  */
1548*7c478bd9Sstevel@tonic-gate const char *
1549*7c478bd9Sstevel@tonic-gate rcm_get_client_name(rcm_handle_t *hd)
1550*7c478bd9Sstevel@tonic-gate {
1551*7c478bd9Sstevel@tonic-gate 	return (hd->modname);
1552*7c478bd9Sstevel@tonic-gate }
1553