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