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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include "librcm_impl.h" 27 #include "librcm_event.h" 28 29 #ifdef DEBUG 30 static int rcm_debug = 1; 31 #define dprintf(args) if (rcm_debug) (void) fprintf args 32 #else 33 #define dprintf(args) /* nothing */ 34 #endif /* DEBUG */ 35 36 static int extract_info(nvlist_t *, rcm_info_t **); 37 static int rcm_daemon_is_alive(); 38 static int rcm_common(int, rcm_handle_t *, char **, uint_t, void *, 39 rcm_info_t **); 40 static int rcm_direct_call(int, rcm_handle_t *, char **, uint_t, void *, 41 rcm_info_t **); 42 static int rcm_daemon_call(int, rcm_handle_t *, char **, uint_t, void *, 43 rcm_info_t **); 44 static int rcm_generate_nvlist(int, rcm_handle_t *, char **, uint_t, void *, 45 char **, size_t *); 46 static int rcm_check_permission(void); 47 48 /* 49 * Allocate a handle structure 50 */ 51 /*ARGSUSED2*/ 52 int 53 rcm_alloc_handle(char *modname, uint_t flag, void *arg, rcm_handle_t **hdp) 54 { 55 rcm_handle_t *hd; 56 void *temp; 57 char namebuf[MAXPATHLEN]; 58 59 if ((hdp == NULL) || (flag & ~RCM_ALLOC_HDL_MASK)) { 60 errno = EINVAL; 61 return (RCM_FAILURE); 62 } 63 64 if (rcm_check_permission() == 0) { 65 errno = EPERM; 66 return (RCM_FAILURE); 67 } 68 69 if ((hd = calloc(1, sizeof (*hd))) == NULL) { 70 return (RCM_FAILURE); 71 } 72 73 if (modname) { 74 (void) snprintf(namebuf, MAXPATHLEN, "%s%s", modname, 75 RCM_MODULE_SUFFIX); 76 77 if ((hd->modname = strdup(namebuf)) == NULL) { 78 free(hd); 79 return (RCM_FAILURE); 80 } 81 82 if ((temp = rcm_module_open(namebuf)) == NULL) { 83 free(hd->modname); 84 free(hd); 85 errno = EINVAL; 86 return (RCM_FAILURE); 87 } 88 89 rcm_module_close(temp); 90 } 91 92 if (flag & RCM_NOPID) { 93 hd->pid = (pid_t)0; 94 } else { 95 hd->pid = (pid_t)getpid(); 96 } 97 98 *hdp = hd; 99 return (RCM_SUCCESS); 100 } 101 102 /* free handle structure */ 103 int 104 rcm_free_handle(rcm_handle_t *hd) 105 { 106 if (hd == NULL) { 107 errno = EINVAL; 108 return (RCM_FAILURE); 109 } 110 111 if (hd->modname) { 112 free(hd->modname); 113 } 114 115 free(hd); 116 return (RCM_SUCCESS); 117 } 118 119 120 /* 121 * Operations which require daemon processing 122 */ 123 124 /* get registration and DR information from rcm_daemon */ 125 int 126 rcm_get_info(rcm_handle_t *hd, char *rsrcname, uint_t flag, rcm_info_t **infop) 127 { 128 char *rsrcnames[2]; 129 130 if ((flag & ~RCM_GET_INFO_MASK) || (infop == NULL)) { 131 errno = EINVAL; 132 return (RCM_FAILURE); 133 } 134 135 /* 136 * rsrcname may be NULL if requesting dr operations or modinfo 137 */ 138 if (rsrcname == NULL && 139 (flag & (RCM_DR_OPERATION | RCM_MOD_INFO)) == 0) { 140 errno = EINVAL; 141 return (RCM_FAILURE); 142 } 143 144 rsrcnames[0] = rsrcname; 145 rsrcnames[1] = NULL; 146 147 return (rcm_common(CMD_GETINFO, hd, rsrcnames, flag, NULL, infop)); 148 } 149 150 /* get registration and DR information from rcm_daemon (list version) */ 151 int 152 rcm_get_info_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag, 153 rcm_info_t **infop) 154 { 155 /* Requesting the current DR operations with a *list() is invalid */ 156 if ((flag & RCM_DR_OPERATION) || (flag & RCM_MOD_INFO)) { 157 errno = EINVAL; 158 return (RCM_FAILURE); 159 } 160 161 return (rcm_common(CMD_GETINFO, hd, rsrcnames, flag, NULL, infop)); 162 } 163 164 /* request to offline a resource before DR removal */ 165 int 166 rcm_request_offline(rcm_handle_t *hd, char *rsrcname, uint_t flag, 167 rcm_info_t **infop) 168 { 169 char *rsrcnames[2]; 170 171 rsrcnames[0] = rsrcname; 172 rsrcnames[1] = NULL; 173 174 return (rcm_request_offline_list(hd, rsrcnames, flag, infop)); 175 } 176 177 /* request to offline a resource before DR removal (list version) */ 178 int 179 rcm_request_offline_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag, 180 rcm_info_t **infop) 181 { 182 if (flag & ~RCM_REQUEST_MASK) { 183 errno = EINVAL; 184 return (RCM_FAILURE); 185 } 186 187 return (rcm_common(CMD_OFFLINE, hd, rsrcnames, flag, NULL, infop)); 188 } 189 190 /* cancel offline request and allow apps to use rsrcname */ 191 int 192 rcm_notify_online(rcm_handle_t *hd, char *rsrcname, uint_t flag, 193 rcm_info_t **infop) 194 { 195 char *rsrcnames[2]; 196 197 rsrcnames[0] = rsrcname; 198 rsrcnames[1] = NULL; 199 200 return (rcm_notify_online_list(hd, rsrcnames, flag, infop)); 201 } 202 203 /* cancel offline and allow apps to use resources (list version) */ 204 int 205 rcm_notify_online_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag, 206 rcm_info_t **infop) 207 { 208 if (flag & ~RCM_NOTIFY_MASK) { 209 errno = EINVAL; 210 return (RCM_FAILURE); 211 } 212 213 return (rcm_common(CMD_ONLINE, hd, rsrcnames, flag, NULL, infop)); 214 } 215 216 /* notify that rsrcname has been removed */ 217 int 218 rcm_notify_remove(rcm_handle_t *hd, char *rsrcname, uint_t flag, 219 rcm_info_t **infop) 220 { 221 char *rsrcnames[2]; 222 223 rsrcnames[0] = rsrcname; 224 rsrcnames[1] = NULL; 225 226 return (rcm_notify_remove_list(hd, rsrcnames, flag, infop)); 227 } 228 229 /* notify that resrouces have been removed (list form) */ 230 int 231 rcm_notify_remove_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag, 232 rcm_info_t **infop) 233 { 234 if (flag & ~RCM_NOTIFY_MASK) { 235 errno = EINVAL; 236 return (RCM_FAILURE); 237 } 238 239 return (rcm_common(CMD_REMOVE, hd, rsrcnames, flag, NULL, infop)); 240 } 241 242 /* request for permission to suspend resource of interval time */ 243 int 244 rcm_request_suspend(rcm_handle_t *hd, char *rsrcname, uint_t flag, 245 timespec_t *interval, rcm_info_t **infop) 246 { 247 char *rsrcnames[2]; 248 249 rsrcnames[0] = rsrcname; 250 rsrcnames[1] = NULL; 251 252 return (rcm_request_suspend_list(hd, rsrcnames, flag, interval, infop)); 253 } 254 255 /* request for permission to suspend resource of interval time (list form) */ 256 int 257 rcm_request_suspend_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag, 258 timespec_t *interval, rcm_info_t **infop) 259 { 260 if ((flag & ~RCM_REQUEST_MASK) || (interval == NULL) || 261 (interval->tv_sec < 0) || (interval->tv_nsec < 0)) { 262 errno = EINVAL; 263 return (RCM_FAILURE); 264 } 265 266 return (rcm_common(CMD_SUSPEND, hd, rsrcnames, flag, (void *)interval, 267 infop)); 268 } 269 270 /* notify apps of the completion of resource suspension */ 271 int 272 rcm_notify_resume(rcm_handle_t *hd, char *rsrcname, uint_t flag, 273 rcm_info_t **infop) 274 { 275 char *rsrcnames[2]; 276 277 rsrcnames[0] = rsrcname; 278 rsrcnames[1] = NULL; 279 280 return (rcm_notify_resume_list(hd, rsrcnames, flag, infop)); 281 } 282 283 /* notify apps of the completion of resource suspension (list form) */ 284 int 285 rcm_notify_resume_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag, 286 rcm_info_t **infop) 287 { 288 if (flag & ~(RCM_NOTIFY_MASK | RCM_SUSPENDED)) { 289 errno = EINVAL; 290 return (RCM_FAILURE); 291 } 292 293 return (rcm_common(CMD_RESUME, hd, rsrcnames, flag, NULL, infop)); 294 } 295 296 /* request a capacity change from apps */ 297 int 298 rcm_request_capacity_change(rcm_handle_t *hd, char *rsrcname, uint_t flag, 299 nvlist_t *nvl, rcm_info_t **infop) 300 { 301 int rv; 302 char *rsrcnames[2]; 303 304 if ((nvl == NULL) || (flag & ~RCM_REQUEST_MASK)) { 305 errno = EINVAL; 306 return (RCM_FAILURE); 307 } 308 309 rsrcnames[0] = rsrcname; 310 rsrcnames[1] = NULL; 311 312 rv = rcm_common(CMD_REQUEST_CHANGE, hd, rsrcnames, flag, (void *)nvl, 313 infop); 314 315 return (rv); 316 } 317 318 /* notify apps of a capacity change */ 319 int 320 rcm_notify_capacity_change(rcm_handle_t *hd, char *rsrcname, uint_t flag, 321 nvlist_t *nvl, rcm_info_t **infop) 322 { 323 int rv; 324 char *rsrcnames[2]; 325 326 if ((nvl == NULL) || (flag & ~RCM_REQUEST_MASK)) { 327 errno = EINVAL; 328 return (RCM_FAILURE); 329 } 330 331 rsrcnames[0] = rsrcname; 332 rsrcnames[1] = NULL; 333 334 rv = rcm_common(CMD_NOTIFY_CHANGE, hd, rsrcnames, flag, (void *)nvl, 335 infop); 336 337 return (rv); 338 } 339 340 /* notify apps of an event */ 341 int 342 rcm_notify_event(rcm_handle_t *hd, char *rsrcname, uint_t flag, nvlist_t *nvl, 343 rcm_info_t **infop) 344 { 345 int rv; 346 char *rsrcnames[2]; 347 348 /* No flags are defined yet for rcm_notify_event() */ 349 if ((nvl == NULL) || (flag != 0)) { 350 errno = EINVAL; 351 return (RCM_FAILURE); 352 } 353 354 rsrcnames[0] = rsrcname; 355 rsrcnames[1] = NULL; 356 357 rv = rcm_common(CMD_EVENT, hd, rsrcnames, 0, (void *)nvl, infop); 358 359 return (rv); 360 } 361 362 /* 363 * Register to receive capacity changes. This requires a module to exist in 364 * module directory. It should be called prior to using a new resource. 365 */ 366 /* ARGSUSED */ 367 int 368 rcm_register_capacity(rcm_handle_t *hd, char *rsrcname, uint_t flag, 369 rcm_info_t **infop) 370 { 371 char *rsrcnames[2]; 372 373 if (flag & ~RCM_REGISTER_MASK) { 374 errno = EINVAL; 375 return (RCM_FAILURE); 376 } 377 378 flag |= RCM_REGISTER_CAPACITY; 379 380 rsrcnames[0] = rsrcname; 381 rsrcnames[1] = NULL; 382 383 return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL)); 384 } 385 386 /* unregister interest in capacity changes */ 387 int 388 rcm_unregister_capacity(rcm_handle_t *hd, char *rsrcname, uint_t flag) 389 { 390 char *rsrcnames[2]; 391 392 if (flag & ~RCM_REGISTER_MASK) { 393 errno = EINVAL; 394 return (RCM_FAILURE); 395 } 396 397 flag |= RCM_REGISTER_CAPACITY; 398 399 rsrcnames[0] = rsrcname; 400 rsrcnames[1] = NULL; 401 402 return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL)); 403 } 404 405 /* 406 * Register to receive events. This requires a module to exist in module 407 * directory. It should be called prior to using a new resource. 408 */ 409 /* ARGSUSED */ 410 int 411 rcm_register_event(rcm_handle_t *hd, char *rsrcname, uint_t flag, 412 rcm_info_t **infop) 413 { 414 char *rsrcnames[2]; 415 416 if (flag & ~RCM_REGISTER_MASK) { 417 errno = EINVAL; 418 return (RCM_FAILURE); 419 } 420 421 flag |= RCM_REGISTER_EVENT; 422 423 rsrcnames[0] = rsrcname; 424 rsrcnames[1] = NULL; 425 426 return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL)); 427 } 428 429 /* unregister interest in events */ 430 int 431 rcm_unregister_event(rcm_handle_t *hd, char *rsrcname, uint_t flag) 432 { 433 char *rsrcnames[2]; 434 435 if (flag & ~RCM_REGISTER_MASK) { 436 errno = EINVAL; 437 return (RCM_FAILURE); 438 } 439 440 flag |= RCM_REGISTER_EVENT; 441 442 rsrcnames[0] = rsrcname; 443 rsrcnames[1] = NULL; 444 445 return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL)); 446 } 447 448 /* 449 * Register interest in a resource. This requires a module to exist in module 450 * directory. It should be called prior to using a new resource. 451 * 452 * Registration may be denied if it is presently locked by a DR operation. 453 */ 454 /* ARGSUSED */ 455 int 456 rcm_register_interest(rcm_handle_t *hd, char *rsrcname, uint_t flag, 457 rcm_info_t **infop) 458 { 459 char *rsrcnames[2]; 460 461 if (flag & ~RCM_REGISTER_MASK) { 462 errno = EINVAL; 463 return (RCM_FAILURE); 464 } 465 466 flag |= RCM_REGISTER_DR; 467 468 rsrcnames[0] = rsrcname; 469 rsrcnames[1] = NULL; 470 471 return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL)); 472 } 473 474 /* unregister interest in rsrcname */ 475 int 476 rcm_unregister_interest(rcm_handle_t *hd, char *rsrcname, uint_t flag) 477 { 478 char *rsrcnames[2]; 479 480 if (flag & ~RCM_REGISTER_MASK) { 481 errno = EINVAL; 482 return (RCM_FAILURE); 483 } 484 485 flag |= RCM_REGISTER_DR; 486 487 rsrcnames[0] = rsrcname; 488 rsrcnames[1] = NULL; 489 490 return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL)); 491 } 492 493 /* get the current state of a resource */ 494 int 495 rcm_get_rsrcstate(rcm_handle_t *hd, char *rsrcname, int *statep) 496 { 497 int result; 498 int flag = 0; 499 rcm_info_t *infop = NULL; 500 rcm_info_tuple_t *tuple = NULL; 501 char *rsrcnames[2]; 502 503 if (statep == NULL) { 504 errno = EINVAL; 505 return (RCM_FAILURE); 506 } 507 508 rsrcnames[0] = rsrcname; 509 rsrcnames[1] = NULL; 510 511 result = rcm_common(CMD_GETSTATE, hd, rsrcnames, flag, NULL, &infop); 512 513 /* 514 * A successful result implies the presence of exactly one RCM info 515 * tuple containing the state of this resource (a combination of each 516 * client's resources). If that's not true, change the result to 517 * RCM_FAILURE. 518 */ 519 if (result == RCM_SUCCESS) { 520 if ((infop == NULL) || 521 ((tuple = rcm_info_next(infop, NULL)) == NULL) || 522 (rcm_info_next(infop, tuple) != NULL)) { 523 result = RCM_FAILURE; 524 } else if (infop && tuple) { 525 *statep = rcm_info_state(tuple); 526 } 527 } 528 529 if (infop) 530 rcm_free_info(infop); 531 532 return (result); 533 } 534 535 /* 536 * RCM helper functions exposed to librcm callers. 537 */ 538 539 /* Free linked list of registration info */ 540 void 541 rcm_free_info(rcm_info_t *info) 542 { 543 while (info) { 544 rcm_info_t *tmp = info->next; 545 546 nvlist_free(info->info); 547 free(info); 548 549 info = tmp; 550 } 551 } 552 553 /* return the next tuple in the info structure */ 554 rcm_info_tuple_t * 555 rcm_info_next(rcm_info_t *info, rcm_info_tuple_t *tuple) 556 { 557 if (info == NULL) { 558 errno = EINVAL; 559 return (NULL); 560 } 561 562 if (tuple == NULL) { 563 return ((rcm_info_tuple_t *)info); 564 } 565 return ((rcm_info_tuple_t *)tuple->next); 566 } 567 568 /* return resource name */ 569 const char * 570 rcm_info_rsrc(rcm_info_tuple_t *tuple) 571 { 572 char *rsrcname = NULL; 573 574 if (tuple == NULL || tuple->info == NULL) { 575 errno = EINVAL; 576 return (NULL); 577 } 578 579 if (errno = nvlist_lookup_string(tuple->info, RCM_RSRCNAME, &rsrcname)) 580 return (NULL); 581 582 return (rsrcname); 583 } 584 585 const char * 586 rcm_info_info(rcm_info_tuple_t *tuple) 587 { 588 char *info = NULL; 589 590 if (tuple == NULL || tuple->info == NULL) { 591 errno = EINVAL; 592 return (NULL); 593 } 594 595 if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_INFO, &info)) 596 return (NULL); 597 598 return (info); 599 } 600 601 const char * 602 rcm_info_error(rcm_info_tuple_t *tuple) 603 { 604 char *errstr = NULL; 605 606 if (tuple == NULL || tuple->info == NULL) { 607 errno = EINVAL; 608 return (NULL); 609 } 610 611 if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_ERROR, 612 &errstr)) 613 return (NULL); 614 615 return (errstr); 616 } 617 618 /* return info string in the tuple */ 619 const char * 620 rcm_info_modname(rcm_info_tuple_t *tuple) 621 { 622 char *modname = NULL; 623 624 if (tuple == NULL || tuple->info == NULL) { 625 errno = EINVAL; 626 return (NULL); 627 } 628 629 if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_MODNAME, 630 &modname)) 631 return (NULL); 632 633 return (modname); 634 } 635 636 /* return client pid in the tuple */ 637 pid_t 638 rcm_info_pid(rcm_info_tuple_t *tuple) 639 { 640 uint64_t pid64 = (uint64_t)0; 641 642 if (tuple == NULL || tuple->info == NULL) { 643 errno = EINVAL; 644 return ((pid_t)0); 645 } 646 647 if (errno = nvlist_lookup_uint64(tuple->info, RCM_CLIENT_ID, &pid64)) 648 return ((pid_t)0); 649 650 return ((pid_t)pid64); 651 } 652 653 /* return client state in the tuple */ 654 int 655 rcm_info_state(rcm_info_tuple_t *tuple) 656 { 657 int state; 658 659 if (tuple == NULL || tuple->info == NULL) { 660 errno = EINVAL; 661 return (RCM_STATE_UNKNOWN); 662 } 663 664 if (errno = nvlist_lookup_int32(tuple->info, RCM_RSRCSTATE, &state)) 665 return (RCM_STATE_UNKNOWN); 666 667 return (state); 668 } 669 670 /* return the generic properties in the tuple */ 671 nvlist_t * 672 rcm_info_properties(rcm_info_tuple_t *tuple) 673 { 674 char *buf; 675 uint_t buflen; 676 nvlist_t *nvl; 677 678 if (tuple == NULL || tuple->info == NULL) { 679 errno = EINVAL; 680 return (NULL); 681 } 682 683 if (errno = nvlist_lookup_byte_array(tuple->info, RCM_CLIENT_PROPERTIES, 684 (uchar_t **)&buf, &buflen)) 685 return (NULL); 686 687 if (errno = nvlist_unpack(buf, buflen, &nvl, 0)) { 688 free(buf); 689 return (NULL); 690 } 691 692 return (nvl); 693 } 694 695 /* 696 * return operation sequence number 697 * 698 * This is private. Called by rcmctl only for testing purposes. 699 */ 700 int 701 rcm_info_seqnum(rcm_info_tuple_t *tuple) 702 { 703 int seqnum; 704 705 if (tuple == NULL || tuple->info == NULL) { 706 errno = EINVAL; 707 return (-1); 708 } 709 710 if (errno = nvlist_lookup_int32(tuple->info, RCM_SEQ_NUM, &seqnum)) 711 return (-1); 712 713 return (seqnum); 714 } 715 716 717 /* 718 * The following interfaces are PRIVATE to the RCM framework. They are not 719 * declared static because they are called by rcm_daemon. 720 */ 721 722 /* 723 * Invoke shell to execute command in MT safe manner. 724 * Returns wait status or -1 on error. 725 */ 726 int 727 rcm_exec_cmd(char *cmd) 728 { 729 pid_t pid; 730 int status, w; 731 char *argvec[] = {"sh", "-c", NULL, NULL}; 732 733 argvec[2] = cmd; 734 if ((pid = fork1()) == 0) { 735 (void) execv("/bin/sh", argvec); 736 _exit(127); 737 } else if (pid == -1) { 738 return (-1); 739 } 740 741 do { 742 w = waitpid(pid, &status, 0); 743 } while (w == -1 && errno == EINTR); 744 745 return ((w == -1) ? w : status); 746 } 747 748 /* Append info at the very end */ 749 int 750 rcm_append_info(rcm_info_t **head, rcm_info_t *info) 751 { 752 rcm_info_t *tuple; 753 754 if (head == NULL) { 755 errno = EINVAL; 756 return (RCM_FAILURE); 757 } 758 759 if ((tuple = *head) == NULL) { 760 *head = info; 761 return (RCM_SUCCESS); 762 } 763 764 while (tuple->next) { 765 tuple = tuple->next; 766 } 767 tuple->next = info; 768 return (RCM_SUCCESS); 769 } 770 771 /* get rcm module and rcm script directory names */ 772 773 #define N_MODULE_DIR 3 /* search 3 directories for modules */ 774 #define MODULE_DIR_HW "/usr/platform/%s/lib/rcm/modules/" 775 #define MODULE_DIR_GEN "/usr/lib/rcm/modules/" 776 777 #define N_SCRIPT_DIR 4 /* search 4 directories for scripts */ 778 #define SCRIPT_DIR_HW "/usr/platform/%s/lib/rcm/scripts/" 779 #define SCRIPT_DIR_GEN "/usr/lib/rcm/scripts/" 780 #define SCRIPT_DIR_ETC "/etc/rcm/scripts/" 781 782 783 char * 784 rcm_module_dir(uint_t dirnum) 785 { 786 if (dirnum < N_MODULE_DIR) 787 return (rcm_dir(dirnum, NULL)); 788 else 789 return (NULL); 790 } 791 792 char * 793 rcm_script_dir(uint_t dirnum) 794 { 795 if (dirnum < N_SCRIPT_DIR) 796 return (rcm_dir(dirnum + N_MODULE_DIR, NULL)); 797 else 798 return (NULL); 799 } 800 801 char * 802 rcm_dir(uint_t dirnum, int *rcm_script) 803 { 804 static char dir_name[N_MODULE_DIR + N_SCRIPT_DIR][MAXPATHLEN]; 805 806 char infobuf[MAXPATHLEN]; 807 808 if (dirnum >= (N_MODULE_DIR + N_SCRIPT_DIR)) 809 return (NULL); 810 811 if (dir_name[0][0] == '\0') { 812 /* 813 * construct the module directory names 814 */ 815 if (sysinfo(SI_PLATFORM, infobuf, MAXPATHLEN) == -1) { 816 dprintf((stderr, "sysinfo %s\n", strerror(errno))); 817 return (NULL); 818 } else { 819 if (snprintf(dir_name[0], MAXPATHLEN, MODULE_DIR_HW, 820 infobuf) >= MAXPATHLEN || 821 snprintf(dir_name[N_MODULE_DIR + 1], MAXPATHLEN, 822 SCRIPT_DIR_HW, infobuf) >= MAXPATHLEN) { 823 dprintf((stderr, 824 "invalid module or script directory for " 825 "platform %s\n", infobuf)); 826 return (NULL); 827 } 828 } 829 830 if (sysinfo(SI_MACHINE, infobuf, MAXPATHLEN) == -1) { 831 dprintf((stderr, "sysinfo %s\n", strerror(errno))); 832 return (NULL); 833 } else { 834 if (snprintf(dir_name[1], MAXPATHLEN, MODULE_DIR_HW, 835 infobuf) >= MAXPATHLEN || 836 snprintf(dir_name[N_MODULE_DIR + 2], MAXPATHLEN, 837 SCRIPT_DIR_HW, infobuf) >= MAXPATHLEN) { 838 dprintf((stderr, 839 "invalid module or script directory for " 840 "machine type %s\n", infobuf)); 841 return (NULL); 842 } 843 } 844 845 if (strlcpy(dir_name[2], MODULE_DIR_GEN, MAXPATHLEN) >= 846 MAXPATHLEN || 847 strlcpy(dir_name[N_MODULE_DIR + 3], SCRIPT_DIR_GEN, 848 MAXPATHLEN) >= MAXPATHLEN || 849 strlcpy(dir_name[N_MODULE_DIR + 0], SCRIPT_DIR_ETC, 850 MAXPATHLEN) >= MAXPATHLEN) { 851 dprintf((stderr, 852 "invalid module or script generic directory\n")); 853 return (NULL); 854 } 855 } 856 857 if (rcm_script) 858 *rcm_script = (dirnum < N_MODULE_DIR) ? 0 : 1; 859 860 return (dir_name[dirnum]); 861 } 862 863 /* 864 * Find the directory where the script is located. 865 * If the script is found return a pointer to the directory where the 866 * script was found otherwise return NULL. 867 */ 868 char * 869 rcm_get_script_dir(char *script_name) 870 { 871 uint_t i; 872 char *dir_name; 873 char path[MAXPATHLEN]; 874 struct stat stats; 875 876 for (i = 0; (dir_name = rcm_script_dir(i)) != NULL; i++) { 877 if (snprintf(path, MAXPATHLEN, "%s%s", dir_name, script_name) 878 >= MAXPATHLEN) { 879 dprintf((stderr, "invalid script %s skipped\n", 880 script_name)); 881 continue; 882 } 883 if (stat(path, &stats) == 0) 884 return (dir_name); 885 } 886 887 return (NULL); 888 } 889 890 /* 891 * Returns 1 if the filename is an rcm script. 892 * Returns 0 if the filename is an rcm module. 893 */ 894 int 895 rcm_is_script(char *filename) 896 { 897 char *tmp; 898 899 if (((tmp = strstr(filename, RCM_MODULE_SUFFIX)) != NULL) && 900 (tmp[strlen(RCM_MODULE_SUFFIX)] == '\0')) 901 return (0); 902 else 903 return (1); 904 } 905 906 /* Locate the module and call dlopen */ 907 void * 908 rcm_module_open(char *modname) 909 { 910 unsigned i; 911 char *dir_name; 912 void *dlhandle = NULL; 913 char modpath[MAXPATHLEN]; 914 915 #ifdef DEBUG 916 struct stat sbuf; 917 #endif 918 919 /* 920 * dlopen the module 921 */ 922 for (i = 0; (dir_name = rcm_module_dir(i)) != NULL; i++) { 923 if (snprintf(modpath, MAXPATHLEN, "%s%s", dir_name, modname) 924 >= MAXPATHLEN) { 925 dprintf((stderr, "invalid module %s skipped\n", 926 modname)); 927 continue; 928 } 929 930 if ((dlhandle = dlopen(modpath, RTLD_LAZY)) != NULL) { 931 return (dlhandle); 932 } 933 934 dprintf((stderr, "failure (dlopen=%s)\n", dlerror())); 935 #ifdef DEBUG 936 if (stat(modpath, &sbuf) == 0) { 937 (void) fprintf(stderr, "%s is not a valid module\n", 938 modpath); 939 } 940 #endif 941 } 942 943 dprintf((stderr, "module %s not found\n", modname)); 944 return (NULL); 945 } 946 947 /* dlclose module */ 948 void 949 rcm_module_close(void *dlhandle) 950 { 951 if (dlclose(dlhandle) == 0) 952 return; 953 954 dprintf((stderr, "dlclose: %s\n", dlerror())); 955 } 956 957 958 /* 959 * stub implementation of rcm_log_message allows dlopen of rcm modules 960 * to proceed in absence of rcm_daemon. 961 * 962 * This definition is interposed by the definition in rcm_daemon because of the 963 * default search order implemented by the linker and dlsym(). All RCM modules 964 * will see the daemon version when loaded by the rcm_daemon. 965 */ 966 /* ARGSUSED */ 967 void 968 rcm_log_message(int level, char *message, ...) 969 { 970 dprintf((stderr, "rcm_log_message stub\n")); 971 } 972 973 /* 974 * Helper functions 975 */ 976 977 /* 978 * Common routine for all rcm calls which require daemon processing 979 */ 980 static int 981 rcm_common(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag, void *arg, 982 rcm_info_t **infop) 983 { 984 int i; 985 986 if (hd == NULL) { 987 errno = EINVAL; 988 return (RCM_FAILURE); 989 } 990 991 if (getuid() != 0) { 992 errno = EPERM; 993 return (RCM_FAILURE); 994 } 995 996 if ((flag & (RCM_DR_OPERATION | RCM_MOD_INFO)) == 0) { 997 if ((rsrcnames == NULL) || (rsrcnames[0] == NULL)) { 998 errno = EINVAL; 999 return (RCM_FAILURE); 1000 } 1001 1002 for (i = 0; rsrcnames[i] != NULL; i++) { 1003 if (*rsrcnames[i] == '\0') { 1004 errno = EINVAL; 1005 return (RCM_FAILURE); 1006 } 1007 } 1008 } 1009 1010 /* 1011 * Check if handle is allocated by rcm_daemon. If so, this call came 1012 * from an RCM module, so we make a direct call into rcm_daemon. 1013 */ 1014 if (hd->lrcm_ops != NULL) { 1015 return (rcm_direct_call(cmd, hd, rsrcnames, flag, arg, infop)); 1016 } 1017 1018 /* 1019 * When not called from a RCM module (i.e. no recursion), zero the 1020 * pointer just in case caller did not do so. For recursive calls, 1021 * we want to append rcm_info_t after infop; zero it may cause 1022 * memory leaks. 1023 */ 1024 if (infop) { 1025 *infop = NULL; 1026 } 1027 1028 /* 1029 * Now call into the daemon. 1030 */ 1031 return (rcm_daemon_call(cmd, hd, rsrcnames, flag, arg, infop)); 1032 } 1033 1034 /* 1035 * Caller is an RCM module, call directly into rcm_daemon. 1036 */ 1037 static int 1038 rcm_direct_call(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag, 1039 void *arg, rcm_info_t **infop) 1040 { 1041 int error; 1042 1043 librcm_ops_t *ops = (librcm_ops_t *)hd->lrcm_ops; 1044 switch (cmd) { 1045 case CMD_GETINFO: 1046 error = ops->librcm_getinfo(rsrcnames, flag, hd->seq_num, 1047 infop); 1048 break; 1049 1050 case CMD_OFFLINE: 1051 error = ops->librcm_offline(rsrcnames, hd->pid, flag, 1052 hd->seq_num, infop); 1053 break; 1054 1055 case CMD_ONLINE: 1056 error = ops->librcm_online(rsrcnames, hd->pid, flag, 1057 hd->seq_num, infop); 1058 break; 1059 1060 case CMD_REMOVE: 1061 error = ops->librcm_remove(rsrcnames, hd->pid, flag, 1062 hd->seq_num, infop); 1063 break; 1064 1065 case CMD_SUSPEND: 1066 error = ops->librcm_suspend(rsrcnames, hd->pid, flag, 1067 hd->seq_num, (timespec_t *)arg, infop); 1068 break; 1069 1070 case CMD_RESUME: 1071 error = ops->librcm_resume(rsrcnames, hd->pid, flag, 1072 hd->seq_num, infop); 1073 break; 1074 1075 case CMD_REGISTER: 1076 error = ops->librcm_regis(hd->modname, rsrcnames[0], hd->pid, 1077 flag, infop); 1078 break; 1079 1080 case CMD_UNREGISTER: 1081 error = ops->librcm_unregis(hd->modname, rsrcnames[0], hd->pid, 1082 flag); 1083 break; 1084 1085 case CMD_REQUEST_CHANGE: 1086 error = ops->librcm_request_change(rsrcnames[0], hd->pid, flag, 1087 hd->seq_num, (nvlist_t *)arg, infop); 1088 break; 1089 1090 case CMD_NOTIFY_CHANGE: 1091 error = ops->librcm_notify_change(rsrcnames[0], hd->pid, flag, 1092 hd->seq_num, (nvlist_t *)arg, infop); 1093 break; 1094 1095 case CMD_EVENT: 1096 error = ops->librcm_notify_event(rsrcnames[0], hd->pid, flag, 1097 hd->seq_num, (nvlist_t *)arg, infop); 1098 break; 1099 1100 case CMD_GETSTATE: 1101 error = ops->librcm_getstate(rsrcnames[0], hd->pid, infop); 1102 break; 1103 1104 default: 1105 dprintf((stderr, "invalid command: %d\n", cmd)); 1106 error = EFAULT; 1107 } 1108 1109 if (error > 0) { 1110 errno = error; 1111 error = RCM_FAILURE; 1112 } 1113 return (error); 1114 } 1115 1116 /* 1117 * Call into rcm_daemon door to process the request 1118 */ 1119 static int 1120 rcm_daemon_call(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag, 1121 void *arg, rcm_info_t **infop) 1122 { 1123 int errno_found; 1124 int daemon_errno = 0; 1125 int error = RCM_SUCCESS; 1126 int delay = 300; 1127 int maxdelay = 10000; /* 10 seconds */ 1128 char *nvl_packed = NULL; 1129 size_t nvl_size = 0; 1130 nvlist_t *ret = NULL; 1131 nvpair_t *nvp; 1132 size_t rsize = 0; 1133 rcm_info_t *info = NULL; 1134 1135 errno = 0; 1136 1137 /* 1138 * Decide whether to start the daemon 1139 */ 1140 switch (cmd) { 1141 case CMD_GETINFO: 1142 case CMD_OFFLINE: 1143 case CMD_ONLINE: 1144 case CMD_REMOVE: 1145 case CMD_SUSPEND: 1146 case CMD_RESUME: 1147 case CMD_REGISTER: 1148 case CMD_UNREGISTER: 1149 case CMD_EVENT: 1150 case CMD_REQUEST_CHANGE: 1151 case CMD_NOTIFY_CHANGE: 1152 case CMD_GETSTATE: 1153 break; 1154 1155 default: 1156 errno = EFAULT; 1157 return (RCM_FAILURE); 1158 } 1159 1160 if (rcm_daemon_is_alive() != 1) { 1161 dprintf((stderr, "failed to start rcm_daemon\n")); 1162 errno = EFAULT; 1163 return (RCM_FAILURE); 1164 } 1165 1166 /* 1167 * Generate a packed nvlist for the request 1168 */ 1169 if (rcm_generate_nvlist(cmd, hd, rsrcnames, flag, arg, &nvl_packed, 1170 &nvl_size) < 0) { 1171 dprintf((stderr, "error in nvlist generation\n")); 1172 errno = EFAULT; 1173 return (RCM_FAILURE); 1174 } 1175 1176 /* 1177 * Make the door call and get a return event. We go into a retry loop 1178 * when RCM_ET_EAGAIN is returned. 1179 */ 1180 retry: 1181 if (get_event_service(RCM_SERVICE_DOOR, (void *)nvl_packed, nvl_size, 1182 (void **)&ret, &rsize) < 0) { 1183 dprintf((stderr, "rcm_daemon call failed: %s\n", 1184 strerror(errno))); 1185 free(nvl_packed); 1186 return (RCM_FAILURE); 1187 } 1188 1189 assert(ret != NULL); 1190 1191 /* 1192 * nvlist_lookup_* routines don't work because the returned nvlist 1193 * was nvlist_alloc'ed without the NV_UNIQUE_NAME flag. Implement 1194 * a sequential search manually, which is fine since there is only 1195 * one RCM_RESULT value in the nvlist. 1196 */ 1197 errno_found = 0; 1198 nvp = NULL; 1199 while (nvp = nvlist_next_nvpair(ret, nvp)) { 1200 if (strcmp(nvpair_name(nvp), RCM_RESULT) == 0) { 1201 if (errno = nvpair_value_int32(nvp, &daemon_errno)) { 1202 error = RCM_FAILURE; 1203 goto out; 1204 } 1205 errno_found++; 1206 break; 1207 } 1208 } 1209 if (errno_found == 0) { 1210 errno = EFAULT; 1211 error = RCM_FAILURE; 1212 goto out; 1213 } 1214 1215 if (daemon_errno == EAGAIN) { 1216 /* 1217 * Wait and retry 1218 */ 1219 dprintf((stderr, "retry door_call\n")); 1220 1221 if (delay > maxdelay) { 1222 errno = EAGAIN; 1223 error = RCM_FAILURE; 1224 goto out; 1225 } 1226 1227 (void) poll(NULL, 0, delay); 1228 delay *= 2; /* exponential back off */ 1229 nvlist_free(ret); 1230 goto retry; 1231 } 1232 1233 /* 1234 * The door call succeeded. Now extract info from returned event. 1235 */ 1236 if (extract_info(ret, &info) != 0) { 1237 dprintf((stderr, "error in extracting event data\n")); 1238 errno = EFAULT; 1239 error = RCM_FAILURE; 1240 goto out; 1241 } 1242 1243 if (infop) 1244 *infop = info; 1245 else 1246 rcm_free_info(info); 1247 1248 if (daemon_errno) { 1249 if (daemon_errno > 0) { 1250 errno = daemon_errno; 1251 error = RCM_FAILURE; 1252 } else { 1253 error = daemon_errno; 1254 } 1255 } 1256 1257 out: 1258 if (nvl_packed) 1259 free(nvl_packed); 1260 nvlist_free(ret); 1261 dprintf((stderr, "daemon call is done. error = %d, errno = %s\n", error, 1262 strerror(errno))); 1263 return (error); 1264 } 1265 1266 /* 1267 * Extract registration info from event data. 1268 * Return 0 on success and -1 on failure. 1269 */ 1270 static int 1271 extract_info(nvlist_t *nvl, rcm_info_t **infop) 1272 { 1273 rcm_info_t *info = NULL; 1274 rcm_info_t *prev = NULL; 1275 rcm_info_t *tmp = NULL; 1276 char *buf; 1277 uint_t buflen; 1278 nvpair_t *nvp = NULL; 1279 1280 while (nvp = nvlist_next_nvpair(nvl, nvp)) { 1281 1282 buf = NULL; 1283 buflen = 0; 1284 1285 if (strcmp(nvpair_name(nvp), RCM_RESULT_INFO) != 0) 1286 continue; 1287 1288 if ((tmp = calloc(1, sizeof (*tmp))) == NULL) { 1289 dprintf((stderr, "out of memory\n")); 1290 goto fail; 1291 } 1292 1293 if (errno = nvpair_value_byte_array(nvp, (uchar_t **)&buf, 1294 &buflen)) { 1295 free(tmp); 1296 dprintf((stderr, "failed (nvpair_value=%s)\n", 1297 strerror(errno))); 1298 goto fail; 1299 } 1300 if (errno = nvlist_unpack(buf, buflen, &(tmp->info), 0)) { 1301 free(tmp); 1302 dprintf((stderr, "failed (nvlist_unpack=%s)\n", 1303 strerror(errno))); 1304 goto fail; 1305 } 1306 1307 if (info == NULL) { 1308 prev = info = tmp; 1309 } else { 1310 prev->next = tmp; 1311 prev = tmp; 1312 } 1313 } 1314 1315 *infop = info; 1316 return (0); 1317 1318 fail: 1319 rcm_free_info(info); 1320 *infop = NULL; 1321 return (-1); 1322 } 1323 1324 /* Generate a packed nvlist for communicating with RCM daemon */ 1325 static int 1326 rcm_generate_nvlist(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag, 1327 void *arg, char **nvl_packed, size_t *nvl_size) 1328 { 1329 int nrsrcnames; 1330 char *buf = NULL; 1331 size_t buflen = 0; 1332 nvlist_t *nvl = NULL; 1333 1334 assert((nvl_packed != NULL) && (nvl_size != NULL)); 1335 1336 *nvl_size = 0; 1337 *nvl_packed = NULL; 1338 1339 /* Allocate an empty nvlist */ 1340 if ((errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) > 0) { 1341 dprintf((stderr, "failed (nvlist_alloc=%s).\n", 1342 strerror(errno))); 1343 return (-1); 1344 } 1345 1346 /* Stuff in all the arguments for the daemon call */ 1347 if (nvlist_add_int32(nvl, RCM_CMD, cmd) != 0) { 1348 dprintf((stderr, "failed (nvlist_add(CMD)=%s).\n", 1349 strerror(errno))); 1350 goto fail; 1351 } 1352 if (rsrcnames) { 1353 nrsrcnames = 0; 1354 while (rsrcnames[nrsrcnames] != NULL) 1355 nrsrcnames++; 1356 if (nvlist_add_string_array(nvl, RCM_RSRCNAMES, rsrcnames, 1357 nrsrcnames) != 0) { 1358 dprintf((stderr, "failed (nvlist_add(RSRCNAMES)=%s).\n", 1359 strerror(errno))); 1360 goto fail; 1361 } 1362 } 1363 if (hd->modname) { 1364 if (nvlist_add_string(nvl, RCM_CLIENT_MODNAME, hd->modname) 1365 != 0) { 1366 dprintf((stderr, 1367 "failed (nvlist_add(CLIENT_MODNAME)=%s).\n", 1368 strerror(errno))); 1369 goto fail; 1370 } 1371 } 1372 if (hd->pid) { 1373 if (nvlist_add_uint64(nvl, RCM_CLIENT_ID, hd->pid) != 0) { 1374 dprintf((stderr, "failed (nvlist_add(CLIENT_ID)=%s).\n", 1375 strerror(errno))); 1376 goto fail; 1377 } 1378 } 1379 if (flag) { 1380 if (nvlist_add_uint32(nvl, RCM_REQUEST_FLAG, flag) != 0) { 1381 dprintf((stderr, 1382 "failed (nvlist_add(REQUEST_FLAG)=%s).\n", 1383 strerror(errno))); 1384 goto fail; 1385 } 1386 } 1387 if (arg && cmd == CMD_SUSPEND) { 1388 if (nvlist_add_byte_array(nvl, RCM_SUSPEND_INTERVAL, 1389 (uchar_t *)arg, sizeof (timespec_t)) != 0) { 1390 dprintf((stderr, 1391 "failed (nvlist_add(SUSPEND_INTERVAL)=%s).\n", 1392 strerror(errno))); 1393 goto fail; 1394 } 1395 } 1396 if (arg && 1397 ((cmd == CMD_REQUEST_CHANGE) || (cmd == CMD_NOTIFY_CHANGE))) { 1398 if (errno = nvlist_pack(arg, &buf, &buflen, NV_ENCODE_NATIVE, 1399 0)) { 1400 dprintf((stderr, 1401 "failed (nvlist_pack(CHANGE_DATA)=%s).\n", 1402 strerror(errno))); 1403 goto fail; 1404 } 1405 if (nvlist_add_byte_array(nvl, RCM_CHANGE_DATA, (uchar_t *)buf, 1406 buflen) != 0) { 1407 dprintf((stderr, 1408 "failed (nvlist_add(CHANGE_DATA)=%s).\n", 1409 strerror(errno))); 1410 goto fail; 1411 } 1412 } 1413 if (arg && cmd == CMD_EVENT) { 1414 if (errno = nvlist_pack(arg, &buf, &buflen, NV_ENCODE_NATIVE, 1415 0)) { 1416 dprintf((stderr, 1417 "failed (nvlist_pack(CHANGE_DATA)=%s).\n", 1418 strerror(errno))); 1419 goto fail; 1420 } 1421 if (nvlist_add_byte_array(nvl, RCM_EVENT_DATA, (uchar_t *)buf, 1422 buflen) != 0) { 1423 dprintf((stderr, 1424 "failed (nvlist_add(EVENT_DATA)=%s).\n", 1425 strerror(errno))); 1426 goto fail; 1427 } 1428 } 1429 1430 /* Pack the nvlist */ 1431 if (errno = nvlist_pack(nvl, nvl_packed, nvl_size, NV_ENCODE_NATIVE, 1432 0)) { 1433 dprintf((stderr, "failed (nvlist_pack=%s).\n", 1434 strerror(errno))); 1435 goto fail; 1436 } 1437 1438 /* If an argument was packed intermediately, free the buffer */ 1439 if (buf) 1440 free(buf); 1441 1442 /* Free the unpacked version of the nvlist and return the packed list */ 1443 nvlist_free(nvl); 1444 return (0); 1445 1446 fail: 1447 if (buf) 1448 free(buf); 1449 nvlist_free(nvl); 1450 if (*nvl_packed) 1451 free(*nvl_packed); 1452 *nvl_packed = NULL; 1453 *nvl_size = 0; 1454 return (-1); 1455 } 1456 1457 /* check if rcm_daemon is up and running */ 1458 static int 1459 rcm_daemon_is_alive() 1460 { 1461 int lasttry; 1462 struct stat st; 1463 nvlist_t *nvl; 1464 char *buf = NULL; 1465 size_t buflen = 0; 1466 int delay = 300; 1467 const int maxdelay = 10000; /* 10 sec */ 1468 1469 /* generate a packed nvlist for the door knocking */ 1470 if (errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) { 1471 dprintf((stderr, "nvlist_alloc failed: %s\n", strerror(errno))); 1472 return (0); 1473 } 1474 if (errno = nvlist_add_int32(nvl, RCM_CMD, CMD_KNOCK)) { 1475 dprintf((stderr, "nvlist_add failed: %s\n", strerror(errno))); 1476 nvlist_free(nvl); 1477 return (0); 1478 } 1479 if (errno = nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0)) { 1480 dprintf((stderr, "nvlist_pack failed: %s\n", strerror(errno))); 1481 nvlist_free(nvl); 1482 return (0); 1483 } 1484 nvlist_free(nvl); 1485 1486 /* 1487 * check the door and knock on it 1488 */ 1489 if ((stat(RCM_SERVICE_DOOR, &st) == 0) && 1490 (get_event_service(RCM_SERVICE_DOOR, (void *)buf, buflen, NULL, 1491 NULL) == 0)) { 1492 free(buf); 1493 return (1); /* daemon is alive */ 1494 } 1495 1496 /* 1497 * Attempt to start the daemon. 1498 * If caller has SIGCHLD set to SIG_IGN or its SA_NOCLDWAIT 1499 * flag set, waitpid(2) (hence rcm_exec_cmd) will fail. 1500 * get_event_service will determine if the rcm_daemon started. 1501 */ 1502 dprintf((stderr, "exec: %s\n", RCM_DAEMON_START)); 1503 (void) rcm_exec_cmd(RCM_DAEMON_START); 1504 1505 /* 1506 * Wait for daemon to respond, timeout at 10 sec 1507 */ 1508 while (((lasttry = get_event_service(RCM_SERVICE_DOOR, (void *)buf, 1509 buflen, NULL, NULL)) != 0) && 1510 ((errno == EBADF) || (errno == ESRCH))) { 1511 if (delay > maxdelay) { 1512 break; 1513 } 1514 (void) poll(NULL, 0, delay); 1515 delay *= 2; 1516 } 1517 1518 free(buf); 1519 if (lasttry == 0) 1520 return (1); 1521 return (0); 1522 } 1523 1524 /* 1525 * Check permission. 1526 * 1527 * The policy is root only for now. Need to relax this when interface level 1528 * is raised. 1529 */ 1530 static int 1531 rcm_check_permission(void) 1532 { 1533 return (getuid() == 0); 1534 } 1535 1536 /* 1537 * Project private function - for use by RCM MSTC tests 1538 * 1539 * Get the client name (rcm module name or script name) corresponding to 1540 * the given rcm handle. 1541 */ 1542 const char * 1543 rcm_get_client_name(rcm_handle_t *hd) 1544 { 1545 return (hd->modname); 1546 } 1547