xref: /onnv-gate/usr/src/cmd/rcm_daemon/common/rcm_event.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <door.h>
30*0Sstevel@tonic-gate #include <assert.h>
31*0Sstevel@tonic-gate #include <sys/acl.h>
32*0Sstevel@tonic-gate #include <sys/stat.h>
33*0Sstevel@tonic-gate #include <librcm_event.h>
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include "rcm_impl.h"
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate  * Event handling routine
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #define	RCM_NOTIFY	0
42*0Sstevel@tonic-gate #define	RCM_GETINFO	1
43*0Sstevel@tonic-gate #define	RCM_REQUEST	2
44*0Sstevel@tonic-gate #define	RCM_EFAULT	3
45*0Sstevel@tonic-gate #define	RCM_EPERM	4
46*0Sstevel@tonic-gate #define	RCM_EINVAL	5
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate static void process_event(int, int, nvlist_t *, nvlist_t **);
49*0Sstevel@tonic-gate static void generate_reply_event(int, rcm_info_t *, nvlist_t **);
50*0Sstevel@tonic-gate static void rcm_print_nvlist(nvlist_t *);
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  * Top level function for event service
54*0Sstevel@tonic-gate  */
55*0Sstevel@tonic-gate void
event_service(void ** data,size_t * datalen)56*0Sstevel@tonic-gate event_service(void **data, size_t *datalen)
57*0Sstevel@tonic-gate {
58*0Sstevel@tonic-gate 	int cmd;
59*0Sstevel@tonic-gate 	int lerrno;
60*0Sstevel@tonic-gate 	int seq_num;
61*0Sstevel@tonic-gate 	nvlist_t *nvl;
62*0Sstevel@tonic-gate 	nvlist_t *ret;
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "received door operation\n");
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate 	/* Decode the data from the door into an unpacked nvlist */
67*0Sstevel@tonic-gate 	if (data == NULL || datalen == NULL) {
68*0Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, "received null door argument\n");
69*0Sstevel@tonic-gate 		return;
70*0Sstevel@tonic-gate 	}
71*0Sstevel@tonic-gate 	if (lerrno = nvlist_unpack(*data, *datalen, &nvl, 0)) {
72*0Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, "received bad door argument, %s\n",
73*0Sstevel@tonic-gate 		    strerror(lerrno));
74*0Sstevel@tonic-gate 		return;
75*0Sstevel@tonic-gate 	}
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	/* Do nothing if the door is just being knocked on */
78*0Sstevel@tonic-gate 	if (errno = nvlist_lookup_int32(nvl, RCM_CMD, &cmd)) {
79*0Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
80*0Sstevel@tonic-gate 		    "bad door argument (nvlist_lookup=%s)\n", strerror(errno));
81*0Sstevel@tonic-gate 		nvlist_free(nvl);
82*0Sstevel@tonic-gate 		return;
83*0Sstevel@tonic-gate 	}
84*0Sstevel@tonic-gate 	if (cmd == CMD_KNOCK) {
85*0Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1, "door event was just a knock\n");
86*0Sstevel@tonic-gate 		nvlist_free(nvl);
87*0Sstevel@tonic-gate 		*data = NULL;
88*0Sstevel@tonic-gate 		*datalen = 0;
89*0Sstevel@tonic-gate 		return;
90*0Sstevel@tonic-gate 	}
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	/*
93*0Sstevel@tonic-gate 	 * Go increment thread count. Before daemon is fully initialized,
94*0Sstevel@tonic-gate 	 * the event processing blocks inside this function.
95*0Sstevel@tonic-gate 	 */
96*0Sstevel@tonic-gate 	seq_num = rcmd_thr_incr(cmd);
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	process_event(cmd, seq_num, nvl, &ret);
99*0Sstevel@tonic-gate 	nvlist_free(nvl);
100*0Sstevel@tonic-gate 	assert(ret != NULL);
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	/*
103*0Sstevel@tonic-gate 	 * Decrement thread count
104*0Sstevel@tonic-gate 	 */
105*0Sstevel@tonic-gate 	rcmd_thr_decr();
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate out:
108*0Sstevel@tonic-gate 	*data = ret;
109*0Sstevel@tonic-gate 	*datalen = 0;
110*0Sstevel@tonic-gate }
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate /*
113*0Sstevel@tonic-gate  * Actually processes events; returns a reply event
114*0Sstevel@tonic-gate  */
115*0Sstevel@tonic-gate static void
process_event(int cmd,int seq_num,nvlist_t * nvl,nvlist_t ** ret)116*0Sstevel@tonic-gate process_event(int cmd, int seq_num, nvlist_t *nvl, nvlist_t **ret)
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate 	int i;
119*0Sstevel@tonic-gate 	int error;
120*0Sstevel@tonic-gate 	uint_t nvl_nrsrcs = 0;
121*0Sstevel@tonic-gate 	pid_t pid;
122*0Sstevel@tonic-gate 	uint32_t flag = (uint32_t)0;
123*0Sstevel@tonic-gate 	uint64_t pid64 = (uint64_t)0;
124*0Sstevel@tonic-gate 	size_t buflen = 0;
125*0Sstevel@tonic-gate 	size_t interval_size = 0;
126*0Sstevel@tonic-gate 	timespec_t *interval = NULL;
127*0Sstevel@tonic-gate 	nvlist_t *change_data = NULL;
128*0Sstevel@tonic-gate 	nvlist_t *event_data = NULL;
129*0Sstevel@tonic-gate 	rcm_info_t *info = NULL;
130*0Sstevel@tonic-gate 	char *modname = NULL;
131*0Sstevel@tonic-gate 	char *buf = NULL;
132*0Sstevel@tonic-gate 	char **rsrcnames = NULL;
133*0Sstevel@tonic-gate 	char **nvl_rsrcs = NULL;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "servicing door command=%d\n", cmd);
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	rcm_print_nvlist(nvl);
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	/*
140*0Sstevel@tonic-gate 	 * Extract data from the door argument nvlist.  Not all arguments
141*0Sstevel@tonic-gate 	 * are needed; sanity checks are performed later.
142*0Sstevel@tonic-gate 	 */
143*0Sstevel@tonic-gate 	(void) nvlist_lookup_string_array(nvl, RCM_RSRCNAMES, &nvl_rsrcs,
144*0Sstevel@tonic-gate 	    &nvl_nrsrcs);
145*0Sstevel@tonic-gate 	(void) nvlist_lookup_string(nvl, RCM_CLIENT_MODNAME, &modname);
146*0Sstevel@tonic-gate 	(void) nvlist_lookup_uint64(nvl, RCM_CLIENT_ID, (uint64_t *)&pid64);
147*0Sstevel@tonic-gate 	pid = (pid_t)pid64;
148*0Sstevel@tonic-gate 	(void) nvlist_lookup_uint32(nvl, RCM_REQUEST_FLAG, (uint32_t *)&flag);
149*0Sstevel@tonic-gate 	(void) nvlist_lookup_byte_array(nvl, RCM_SUSPEND_INTERVAL,
150*0Sstevel@tonic-gate 	    (uchar_t **)&interval, &interval_size);
151*0Sstevel@tonic-gate 	(void) nvlist_lookup_byte_array(nvl, RCM_CHANGE_DATA, (uchar_t **)&buf,
152*0Sstevel@tonic-gate 	    &buflen);
153*0Sstevel@tonic-gate 	if (buf != NULL && buflen > 0) {
154*0Sstevel@tonic-gate 		(void) nvlist_unpack(buf, buflen, &change_data, 0);
155*0Sstevel@tonic-gate 		buf = NULL;
156*0Sstevel@tonic-gate 		buflen = 0;
157*0Sstevel@tonic-gate 	}
158*0Sstevel@tonic-gate 	(void) nvlist_lookup_byte_array(nvl, RCM_EVENT_DATA, (uchar_t **)&buf,
159*0Sstevel@tonic-gate 	    &buflen);
160*0Sstevel@tonic-gate 	if (buf != NULL && buflen > 0)
161*0Sstevel@tonic-gate 		(void) nvlist_unpack(buf, buflen, &event_data, 0);
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	rsrcnames = s_calloc(nvl_nrsrcs + 1, sizeof (char *));
164*0Sstevel@tonic-gate 	for (i = 0; i < nvl_nrsrcs; i++) {
165*0Sstevel@tonic-gate 		rsrcnames[i] = nvl_rsrcs[i];
166*0Sstevel@tonic-gate 	}
167*0Sstevel@tonic-gate 	rsrcnames[nvl_nrsrcs] = NULL;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	/*
170*0Sstevel@tonic-gate 	 * Switch off the command being performed to do the appropriate
171*0Sstevel@tonic-gate 	 * sanity checks and dispatch the arguments to the appropriate
172*0Sstevel@tonic-gate 	 * implementation routine.
173*0Sstevel@tonic-gate 	 */
174*0Sstevel@tonic-gate 	switch (cmd) {
175*0Sstevel@tonic-gate 	case CMD_REGISTER:
176*0Sstevel@tonic-gate 		if ((modname == NULL) || (rsrcnames == NULL) ||
177*0Sstevel@tonic-gate 		    (rsrcnames[0] == NULL))
178*0Sstevel@tonic-gate 			goto faildata;
179*0Sstevel@tonic-gate 		error = add_resource_client(modname, rsrcnames[0], pid, flag,
180*0Sstevel@tonic-gate 		    &info);
181*0Sstevel@tonic-gate 		break;
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	case CMD_UNREGISTER:
184*0Sstevel@tonic-gate 		if ((modname == NULL) || (rsrcnames == NULL) ||
185*0Sstevel@tonic-gate 		    (rsrcnames[0] == NULL))
186*0Sstevel@tonic-gate 			goto faildata;
187*0Sstevel@tonic-gate 		error = remove_resource_client(modname, rsrcnames[0], pid,
188*0Sstevel@tonic-gate 		    flag);
189*0Sstevel@tonic-gate 		break;
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	case CMD_GETINFO:
192*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) &&
193*0Sstevel@tonic-gate 		    ((flag & (RCM_DR_OPERATION | RCM_MOD_INFO)) == 0))
194*0Sstevel@tonic-gate 			goto faildata;
195*0Sstevel@tonic-gate 		if ((error = get_resource_info(rsrcnames, flag, seq_num, &info))
196*0Sstevel@tonic-gate 		    == EINVAL) {
197*0Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
198*0Sstevel@tonic-gate 			    "invalid argument in get info request\n");
199*0Sstevel@tonic-gate 			generate_reply_event(EINVAL, NULL, ret);
200*0Sstevel@tonic-gate 			return;
201*0Sstevel@tonic-gate 		}
202*0Sstevel@tonic-gate 		break;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	case CMD_SUSPEND:
205*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL) ||
206*0Sstevel@tonic-gate 		    (interval == NULL))
207*0Sstevel@tonic-gate 			goto faildata;
208*0Sstevel@tonic-gate 		error = process_resource_suspend(rsrcnames, pid, flag, seq_num,
209*0Sstevel@tonic-gate 		    interval, &info);
210*0Sstevel@tonic-gate 		break;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	case CMD_RESUME:
213*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL))
214*0Sstevel@tonic-gate 			goto faildata;
215*0Sstevel@tonic-gate 		error = notify_resource_resume(rsrcnames, pid, flag, seq_num,
216*0Sstevel@tonic-gate 		    &info);
217*0Sstevel@tonic-gate 		break;
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	case CMD_OFFLINE:
220*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL))
221*0Sstevel@tonic-gate 			goto faildata;
222*0Sstevel@tonic-gate 		error = process_resource_offline(rsrcnames, pid, flag, seq_num,
223*0Sstevel@tonic-gate 		    &info);
224*0Sstevel@tonic-gate 		break;
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	case CMD_ONLINE:
227*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL))
228*0Sstevel@tonic-gate 			goto faildata;
229*0Sstevel@tonic-gate 		error = notify_resource_online(rsrcnames, pid, flag, seq_num,
230*0Sstevel@tonic-gate 		    &info);
231*0Sstevel@tonic-gate 		break;
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	case CMD_REMOVE:
234*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL))
235*0Sstevel@tonic-gate 			goto faildata;
236*0Sstevel@tonic-gate 		error = notify_resource_remove(rsrcnames, pid, flag, seq_num,
237*0Sstevel@tonic-gate 		    &info);
238*0Sstevel@tonic-gate 		break;
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	case CMD_EVENT:
241*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL) ||
242*0Sstevel@tonic-gate 		    (event_data == NULL))
243*0Sstevel@tonic-gate 			goto faildata;
244*0Sstevel@tonic-gate 		error = notify_resource_event(rsrcnames[0], pid, flag, seq_num,
245*0Sstevel@tonic-gate 		    event_data, &info);
246*0Sstevel@tonic-gate 		nvlist_free(event_data);
247*0Sstevel@tonic-gate 		break;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	case CMD_REQUEST_CHANGE:
250*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL) ||
251*0Sstevel@tonic-gate 		    (change_data == NULL))
252*0Sstevel@tonic-gate 			goto faildata;
253*0Sstevel@tonic-gate 		error = request_capacity_change(rsrcnames[0], pid, flag,
254*0Sstevel@tonic-gate 		    seq_num, change_data, &info);
255*0Sstevel@tonic-gate 		nvlist_free(change_data);
256*0Sstevel@tonic-gate 		break;
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	case CMD_NOTIFY_CHANGE:
259*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL) ||
260*0Sstevel@tonic-gate 		    (change_data == NULL))
261*0Sstevel@tonic-gate 			goto faildata;
262*0Sstevel@tonic-gate 		error = notify_capacity_change(rsrcnames[0], pid, flag, seq_num,
263*0Sstevel@tonic-gate 		    change_data, &info);
264*0Sstevel@tonic-gate 		nvlist_free(change_data);
265*0Sstevel@tonic-gate 		break;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	case CMD_GETSTATE:
268*0Sstevel@tonic-gate 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL))
269*0Sstevel@tonic-gate 			goto faildata;
270*0Sstevel@tonic-gate 		error = get_resource_state(rsrcnames[0], pid, &info);
271*0Sstevel@tonic-gate 		break;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	default:
274*0Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
275*0Sstevel@tonic-gate 		    gettext("unknown door command: %d\n"), cmd);
276*0Sstevel@tonic-gate 		generate_reply_event(EFAULT, NULL, ret);
277*0Sstevel@tonic-gate 		(void) free(rsrcnames);
278*0Sstevel@tonic-gate 		return;
279*0Sstevel@tonic-gate 	}
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "finish processing event 0x%x\n", cmd);
282*0Sstevel@tonic-gate 	generate_reply_event(error, info, ret);
283*0Sstevel@tonic-gate 	(void) free(rsrcnames);
284*0Sstevel@tonic-gate 	return;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate faildata:
287*0Sstevel@tonic-gate 	rcm_log_message(RCM_WARNING,
288*0Sstevel@tonic-gate 	    gettext("data error in door arguments for cmd 0x%x\n"), cmd);
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	generate_reply_event(EFAULT, NULL, ret);
291*0Sstevel@tonic-gate 	(void) free(rsrcnames);
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate /*
296*0Sstevel@tonic-gate  * Generate reply event from resource registration information
297*0Sstevel@tonic-gate  */
298*0Sstevel@tonic-gate static void
generate_reply_event(int error,rcm_info_t * info,nvlist_t ** ret)299*0Sstevel@tonic-gate generate_reply_event(int error, rcm_info_t *info, nvlist_t **ret)
300*0Sstevel@tonic-gate {
301*0Sstevel@tonic-gate 	nvlist_t *nvl = NULL;
302*0Sstevel@tonic-gate 	rcm_info_t *tmp;
303*0Sstevel@tonic-gate 	char *buf = NULL;
304*0Sstevel@tonic-gate 	size_t buflen = 0;
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "generating reply event\n");
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	/* Allocate an empty nvlist */
309*0Sstevel@tonic-gate 	if ((errno = nvlist_alloc(&nvl, 0, 0)) > 0) {
310*0Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
311*0Sstevel@tonic-gate 		    gettext("nvlist_alloc failed: %s\n"), strerror(errno));
312*0Sstevel@tonic-gate 		rcmd_exit(errno);
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	/* Encode the result of the operation in the nvlist */
316*0Sstevel@tonic-gate 	if (errno = nvlist_add_int32(nvl, RCM_RESULT, error)) {
317*0Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
318*0Sstevel@tonic-gate 		    gettext("nvlist_add(RESULT) failed: %s\n"),
319*0Sstevel@tonic-gate 		    strerror(errno));
320*0Sstevel@tonic-gate 		rcmd_exit(errno);
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	/* Go through the RCM info tuples, appending them all to the nvlist */
324*0Sstevel@tonic-gate 	tmp = info;
325*0Sstevel@tonic-gate 	while (tmp) {
326*0Sstevel@tonic-gate 		if (tmp->info) {
327*0Sstevel@tonic-gate 			buf = NULL;
328*0Sstevel@tonic-gate 			buflen = 0;
329*0Sstevel@tonic-gate 			if (errno = nvlist_pack(tmp->info, &buf, &buflen,
330*0Sstevel@tonic-gate 			    NV_ENCODE_NATIVE, 0)) {
331*0Sstevel@tonic-gate 				rcm_log_message(RCM_ERROR,
332*0Sstevel@tonic-gate 				    gettext("nvlist_pack(INFO) failed: %s\n"),
333*0Sstevel@tonic-gate 				    strerror(errno));
334*0Sstevel@tonic-gate 				rcmd_exit(errno);
335*0Sstevel@tonic-gate 			}
336*0Sstevel@tonic-gate 			if (errno = nvlist_add_byte_array(nvl, RCM_RESULT_INFO,
337*0Sstevel@tonic-gate 			    (uchar_t *)buf, buflen)) {
338*0Sstevel@tonic-gate 				rcm_log_message(RCM_ERROR,
339*0Sstevel@tonic-gate 				    gettext("nvlist_add(INFO) failed: %s\n"),
340*0Sstevel@tonic-gate 				    strerror(errno));
341*0Sstevel@tonic-gate 				rcmd_exit(errno);
342*0Sstevel@tonic-gate 			}
343*0Sstevel@tonic-gate 			(void) free(buf);
344*0Sstevel@tonic-gate 			nvlist_free(tmp->info);
345*0Sstevel@tonic-gate 		}
346*0Sstevel@tonic-gate 		info = tmp->next;
347*0Sstevel@tonic-gate 		(void) free(tmp);
348*0Sstevel@tonic-gate 		tmp = info;
349*0Sstevel@tonic-gate 	}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	/* Return the nvlist (unpacked) in the return argument */
352*0Sstevel@tonic-gate 	rcm_print_nvlist(nvl);
353*0Sstevel@tonic-gate 	*ret = nvl;
354*0Sstevel@tonic-gate }
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate static void
rcm_print_nvlist(nvlist_t * nvl)357*0Sstevel@tonic-gate rcm_print_nvlist(nvlist_t *nvl)
358*0Sstevel@tonic-gate {
359*0Sstevel@tonic-gate 	uchar_t data_byte;
360*0Sstevel@tonic-gate 	int16_t data_int16;
361*0Sstevel@tonic-gate 	uint16_t data_uint16;
362*0Sstevel@tonic-gate 	int32_t data_int32;
363*0Sstevel@tonic-gate 	uint32_t data_uint32;
364*0Sstevel@tonic-gate 	int64_t data_int64;
365*0Sstevel@tonic-gate 	uint64_t data_uint64;
366*0Sstevel@tonic-gate 	char *data_string;
367*0Sstevel@tonic-gate 	char **data_strings;
368*0Sstevel@tonic-gate 	uint_t data_nstrings;
369*0Sstevel@tonic-gate 	nvpair_t *nvp = NULL;
370*0Sstevel@tonic-gate 	int i;
371*0Sstevel@tonic-gate 	char *name;
372*0Sstevel@tonic-gate 	data_type_t type;
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "event attributes:\n");
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	while (nvp = nvlist_next_nvpair(nvl, nvp)) {
377*0Sstevel@tonic-gate 		type = nvpair_type(nvp);
378*0Sstevel@tonic-gate 		name = nvpair_name(nvp);
379*0Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE3, "\t%s(%d)=", name, type);
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 		switch (type) {
382*0Sstevel@tonic-gate 		case DATA_TYPE_BOOLEAN:
383*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "True (boolean)\n");
384*0Sstevel@tonic-gate 			break;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 		case DATA_TYPE_BYTE:
387*0Sstevel@tonic-gate 			(void) nvpair_value_byte(nvp, &data_byte);
388*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "0x%x (byte)\n",
389*0Sstevel@tonic-gate 			    data_byte);
390*0Sstevel@tonic-gate 			break;
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 		case DATA_TYPE_INT16:
393*0Sstevel@tonic-gate 			(void) nvpair_value_int16(nvp, &data_int16);
394*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "0x%x (int16)\n",
395*0Sstevel@tonic-gate 			    data_int16);
396*0Sstevel@tonic-gate 			break;
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 		case DATA_TYPE_UINT16:
399*0Sstevel@tonic-gate 			(void) nvpair_value_uint16(nvp, &data_uint16);
400*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "0x%x (uint16)\n",
401*0Sstevel@tonic-gate 			    data_uint16);
402*0Sstevel@tonic-gate 			break;
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 		case DATA_TYPE_INT32:
405*0Sstevel@tonic-gate 			(void) nvpair_value_int32(nvp, &data_int32);
406*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "0x%x (int32)\n",
407*0Sstevel@tonic-gate 			    data_int32);
408*0Sstevel@tonic-gate 			break;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 		case DATA_TYPE_UINT32:
411*0Sstevel@tonic-gate 			(void) nvpair_value_uint32(nvp, &data_uint32);
412*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "0x%x (uint32)\n",
413*0Sstevel@tonic-gate 			    data_uint32);
414*0Sstevel@tonic-gate 			break;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 		case DATA_TYPE_INT64:
417*0Sstevel@tonic-gate 			(void) nvpair_value_int64(nvp, &data_int64);
418*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "0x%lx (int64)\n",
419*0Sstevel@tonic-gate 			    data_int64);
420*0Sstevel@tonic-gate 			break;
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 		case DATA_TYPE_UINT64:
423*0Sstevel@tonic-gate 			(void) nvpair_value_uint64(nvp, &data_uint64);
424*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "0x%lx (uint64)\n",
425*0Sstevel@tonic-gate 			    data_uint64);
426*0Sstevel@tonic-gate 			break;
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 		case DATA_TYPE_STRING:
429*0Sstevel@tonic-gate 			(void) nvpair_value_string(nvp, &data_string);
430*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "\"%s\" (string)\n",
431*0Sstevel@tonic-gate 			    data_string);
432*0Sstevel@tonic-gate 			break;
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 		case DATA_TYPE_STRING_ARRAY:
435*0Sstevel@tonic-gate 			(void) nvpair_value_string_array(nvp, &data_strings,
436*0Sstevel@tonic-gate 			    &data_nstrings);
437*0Sstevel@tonic-gate 			for (i = 0; i < data_nstrings; i++) {
438*0Sstevel@tonic-gate 				rcm_log_message(RCM_TRACE3,
439*0Sstevel@tonic-gate 				    "\t\"%s\" (string)\n", data_strings[i]);
440*0Sstevel@tonic-gate 				if (i < (data_nstrings - 1))
441*0Sstevel@tonic-gate 					rcm_log_message(RCM_TRACE3, "\t\t\t");
442*0Sstevel@tonic-gate 			}
443*0Sstevel@tonic-gate 			break;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 		default:
446*0Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE3, "<not dumped>\n");
447*0Sstevel@tonic-gate 			break;
448*0Sstevel@tonic-gate 		}
449*0Sstevel@tonic-gate 	}
450*0Sstevel@tonic-gate }
451