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