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
event_service(void ** data,size_t * datalen)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
process_event(int cmd,int seq_num,nvlist_t * nvl,nvlist_t ** ret)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
generate_reply_event(int error,rcm_info_t * info,nvlist_t ** ret)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
rcm_print_nvlist(nvlist_t * nvl)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