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 }