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