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 *data = ret; 106 *datalen = 0; 107 } 108 109 /* 110 * Actually processes events; returns a reply event 111 */ 112 static void 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 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 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