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