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