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