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