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