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 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 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 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 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