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 /*
  23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Disk & Indicator Monitor configuration file support routines
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/stat.h>
  33 #include <fcntl.h>
  34 #include <unistd.h>
  35 #include <string.h>
  36 #include <strings.h>
  37 #include <errno.h>
  38 #include <limits.h>
  39 #include <pthread.h>
  40 
  41 #include "disk_monitor.h"
  42 #include "util.h"
  43 #include "topo_gather.h"
  44 
  45 extern log_class_t g_verbose;
  46 
  47 const char *
  48 hotplug_state_string(hotplug_state_t state)
  49 {
  50         switch (state & ~HPS_FAULTED) {
  51         default:
  52         case HPS_UNKNOWN:
  53                 return ("Unknown");
  54         case HPS_ABSENT:
  55                 return ("Absent");
  56         case HPS_PRESENT:
  57                 return ("Present");
  58         case HPS_CONFIGURED:
  59                 return ("Configured");
  60         case HPS_UNCONFIGURED:
  61                 return ("Unconfigured");
  62         }
  63 }
  64 
  65 void
  66 conf_error_msg(conf_err_t err, char *buf, int buflen, void *arg)
  67 {
  68         switch (err) {
  69         case E_MULTIPLE_IND_LISTS_DEFINED:
  70                 (void) snprintf(buf, buflen, "Multiple Indicator lists "
  71                     "defined");
  72                 break;
  73         case E_MULTIPLE_INDRULE_LISTS_DEFINED:
  74                 (void) snprintf(buf, buflen, "Multiple Indicator rule lists "
  75                     "defined");
  76                 break;
  77         case E_INVALID_STATE_CHANGE:
  78                 (void) snprintf(buf, buflen, "Invalid state change");
  79                 break;
  80         case E_IND_MULTIPLY_DEFINED:
  81                 (void) snprintf(buf, buflen,
  82                     "Multiple Indicator definitions (name & state) detected");
  83                 break;
  84         case E_IND_ACTION_REDUNDANT:
  85                 (void) snprintf(buf, buflen, "Redundant Indicator actions "
  86                     "specified");
  87                 break;
  88         case E_IND_ACTION_CONFLICT:
  89                 (void) snprintf(buf, buflen, "Indicator action conflict (+/- "
  90                     "same Indicator) found");
  91                 break;
  92         case E_IND_MISSING_FAULT_ON:
  93                 (void) snprintf(buf, buflen, "Missing declaration of `+"
  94                     INDICATOR_FAULT_IDENTIFIER "'");
  95                 break;
  96         case E_IND_MISSING_FAULT_OFF:
  97                 (void) snprintf(buf, buflen, "Missing declaration of `-"
  98                     INDICATOR_FAULT_IDENTIFIER "'");
  99                 break;
 100         case E_INDRULE_REFERENCES_NONEXISTENT_IND_ACTION:
 101                 (void) snprintf(buf, buflen, "`%c%s': Undefined Indicator in "
 102                     BAY_IND_ACTION " property",
 103                     (((ind_action_t *)arg)->ind_state == INDICATOR_ON)
 104                     ? '+' : '-',
 105                     ((ind_action_t *)arg)->ind_name);
 106                 break;
 107         case E_DUPLICATE_STATE_TRANSITION:
 108                 (void) snprintf(buf, buflen, "Duplicate state transition "
 109                     "(%s -> %s)",
 110                     hotplug_state_string(((state_transition_t *)arg)->begin),
 111                     hotplug_state_string(((state_transition_t *)arg)->end));
 112                 break;
 113         default:
 114                 (void) snprintf(buf, buflen, "Unknown error");
 115                 break;
 116         }
 117 }
 118 
 119 static int
 120 string_to_integer(const char *prop, int *value)
 121 {
 122         long val;
 123 
 124         errno = 0;
 125 
 126         val = strtol(prop, NULL, 0);
 127 
 128         if (val == 0 && errno != 0)
 129                 return (-1);
 130         else if (val > INT_MAX || val < INT_MIN) {
 131                 errno = ERANGE;
 132                 return (-1);
 133         }
 134 
 135         if (value != NULL)
 136                 *value = (int)val;
 137 
 138         return (0);
 139 }
 140 
 141 const char *
 142 dm_prop_lookup(nvlist_t *props, const char *prop_name)
 143 {
 144         char *str;
 145 
 146         if (nvlist_lookup_string(props, prop_name, &str) == 0)
 147                 return ((const char *)str);
 148         else
 149                 return (NULL);
 150 }
 151 
 152 int
 153 dm_prop_lookup_int(nvlist_t *props, const char *prop_name, int *value)
 154 {
 155         const char *prop = dm_prop_lookup(props, prop_name);
 156 
 157         if (prop == NULL)
 158                 return (-1);
 159 
 160         return (string_to_integer(prop, value));
 161 }
 162 
 163 nvlist_t *
 164 namevalpr_to_nvlist(namevalpr_t *nvprp)
 165 {
 166         nvlist_t *nvlp = NULL;
 167 
 168         if (nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0) != 0) {
 169                 return (NULL);
 170         }
 171 
 172         if (nvlist_add_string(nvlp, nvprp->name, nvprp->value) != 0) {
 173                 nvlist_free(nvlp);
 174                 return (NULL);
 175         }
 176 
 177         return (nvlp);
 178 }
 179 
 180 indicator_t *
 181 new_indicator(ind_state_t lstate, char *namep, char *actionp)
 182 {
 183         indicator_t *newindicator =
 184             (indicator_t *)dmalloc(sizeof (indicator_t));
 185         newindicator->ind_state = lstate;
 186         newindicator->ind_name = namep ? dstrdup(namep) : NULL;
 187         newindicator->ind_instr_spec = actionp ? dstrdup(actionp) : NULL;
 188         newindicator->next = NULL;
 189         return (newindicator);
 190 }
 191 
 192 void
 193 link_indicator(indicator_t **first, indicator_t *to_add)
 194 {
 195         indicator_t *travptr;
 196         dm_assert(first != NULL);
 197 
 198         if (*first == NULL)
 199                 *first = to_add;
 200         else {
 201                 travptr = *first;
 202                 while (travptr->next != NULL) {
 203                         travptr = travptr->next;
 204                 }
 205                 travptr->next = to_add;
 206         }
 207 }
 208 
 209 void
 210 ind_free(indicator_t *indp)
 211 {
 212         indicator_t *nextp;
 213 
 214         while (indp != NULL) {
 215                 nextp = indp->next;
 216                 if (indp->ind_name)
 217                         dstrfree(indp->ind_name);
 218                 if (indp->ind_instr_spec)
 219                         dstrfree(indp->ind_instr_spec);
 220                 dfree(indp, sizeof (indicator_t));
 221                 indp = nextp;
 222         }
 223 }
 224 
 225 ind_action_t *
 226 new_indaction(ind_state_t state, char *namep)
 227 {
 228         ind_action_t *lap = (ind_action_t *)dmalloc(sizeof (ind_action_t));
 229         lap->ind_state = state;
 230         lap->ind_name = namep ? dstrdup(namep) : NULL;
 231         lap->next = NULL;
 232         return (lap);
 233 }
 234 
 235 void
 236 link_indaction(ind_action_t **first, ind_action_t *to_add)
 237 {
 238         ind_action_t *travptr;
 239         dm_assert(first != NULL);
 240 
 241         if (*first == NULL)
 242                 *first = to_add;
 243         else {
 244                 travptr = *first;
 245                 while (travptr->next != NULL) {
 246                         travptr = travptr->next;
 247                 }
 248                 travptr->next = to_add;
 249         }
 250 }
 251 
 252 void
 253 indaction_free(ind_action_t *lap)
 254 {
 255         ind_action_t *nextp;
 256 
 257         /* Free the whole list */
 258         while (lap != NULL) {
 259                 nextp = lap->next;
 260                 if (lap->ind_name)
 261                         dstrfree(lap->ind_name);
 262                 dfree(lap, sizeof (ind_action_t));
 263                 lap = nextp;
 264         }
 265 }
 266 
 267 indrule_t *
 268 new_indrule(state_transition_t *st, ind_action_t *actionp)
 269 {
 270         indrule_t *lrp = (indrule_t *)dmalloc(sizeof (indrule_t));
 271         if (st != NULL)
 272                 lrp->strans = *st;
 273         lrp->action_list = actionp;
 274         lrp->next = NULL;
 275         return (lrp);
 276 }
 277 
 278 void
 279 link_indrule(indrule_t **first, indrule_t *to_add)
 280 {
 281         indrule_t *travptr;
 282         dm_assert(first != NULL);
 283 
 284         if (*first == NULL)
 285                 *first = to_add;
 286         else {
 287                 travptr = *first;
 288                 while (travptr->next != NULL) {
 289                         travptr = travptr->next;
 290                 }
 291                 travptr->next = to_add;
 292         }
 293 }
 294 
 295 void
 296 indrule_free(indrule_t *lrp)
 297 {
 298         indrule_t *nextp;
 299 
 300         /* Free the whole list */
 301         while (lrp != NULL) {
 302                 nextp = lrp->next;
 303                 if (lrp->action_list)
 304                         indaction_free(lrp->action_list);
 305                 dfree(lrp, sizeof (indrule_t));
 306                 lrp = nextp;
 307         }
 308 }
 309 
 310 dm_fru_t *
 311 new_dmfru(char *manu, char *modl, char *firmrev, char *serno, uint64_t capa)
 312 {
 313         dm_fru_t *frup = (dm_fru_t *)dzmalloc(sizeof (dm_fru_t));
 314 
 315         bcopy(manu, frup->manuf, MIN(sizeof (frup->manuf), strlen(manu) + 1));
 316         bcopy(modl, frup->model, MIN(sizeof (frup->model), strlen(modl) + 1));
 317         bcopy(firmrev, frup->rev, MIN(sizeof (frup->rev), strlen(firmrev) + 1));
 318         bcopy(serno, frup->serial,
 319             MIN(sizeof (frup->serial), strlen(serno) + 1));
 320         frup->size_in_bytes = capa;
 321         return (frup);
 322 }
 323 
 324 void
 325 dmfru_free(dm_fru_t *frup)
 326 {
 327         dfree(frup, sizeof (dm_fru_t));
 328 }
 329 
 330 diskmon_t *
 331 new_diskmon(nvlist_t *app_props, indicator_t *indp, indrule_t *indrp,
 332     nvlist_t *nvlp)
 333 {
 334         diskmon_t *dmp = (diskmon_t *)dmalloc(sizeof (diskmon_t));
 335 
 336         if (nvlp != NULL)
 337                 dmp->props = nvlp;
 338         else
 339                 (void) nvlist_alloc(&dmp->props, NV_UNIQUE_NAME, 0);
 340 
 341         if (app_props)
 342                 dmp->app_props = app_props;
 343         else
 344                 (void) nvlist_alloc(&dmp->app_props, NV_UNIQUE_NAME, 0);
 345         dmp->ind_list = indp;
 346         dmp->indrule_list = indrp;
 347 
 348         dm_assert(pthread_mutex_init(&dmp->manager_mutex, NULL) == 0);
 349 
 350         dmp->state = HPS_UNKNOWN;
 351 
 352         dmp->initial_configuration = B_TRUE;
 353 
 354         dm_assert(pthread_mutex_init(&dmp->fault_indicator_mutex, NULL) == 0);
 355         dmp->fault_indicator_state = INDICATOR_UNKNOWN;
 356 
 357         dmp->configured_yet = B_FALSE;
 358         dmp->state_change_count = 0;
 359 
 360         dm_assert(pthread_mutex_init(&dmp->fru_mutex, NULL) == 0);
 361         dmp->frup = NULL;
 362 
 363         dmp->next = NULL;
 364         return (dmp);
 365 }
 366 
 367 void
 368 diskmon_free(diskmon_t *dmp)
 369 {
 370         diskmon_t *nextp;
 371 
 372         /* Free the whole list */
 373         while (dmp != NULL) {
 374                 nextp = dmp->next;
 375 
 376                 nvlist_free(dmp->props);
 377                 if (dmp->location)
 378                         dstrfree(dmp->location);
 379                 if (dmp->ind_list)
 380                         ind_free(dmp->ind_list);
 381                 if (dmp->indrule_list)
 382                         indrule_free(dmp->indrule_list);
 383                 nvlist_free(dmp->app_props);
 384                 if (dmp->frup)
 385                         dmfru_free(dmp->frup);
 386                 dfree(dmp, sizeof (diskmon_t));
 387 
 388                 dmp = nextp;
 389         }
 390 }
 391 
 392 static cfgdata_t *
 393 new_cfgdata(namevalpr_t *nvp, diskmon_t *dmp)
 394 {
 395         cfgdata_t *cdp = (cfgdata_t *)dzmalloc(sizeof (cfgdata_t));
 396 
 397         if (nvp != NULL)
 398                 cdp->props = namevalpr_to_nvlist(nvp);
 399         else if (nvlist_alloc(&cdp->props, NV_UNIQUE_NAME, 0) != 0) {
 400                 return (NULL);
 401         }
 402 
 403         if (dmp != NULL)
 404                 cdp->disk_list = dmp;
 405         return (cdp);
 406 
 407 }
 408 
 409 static void
 410 cfgdata_add_namevalpr(cfgdata_t *cfgp, namevalpr_t *nvp)
 411 {
 412         if (cfgp->props == NULL) {
 413                 (void) nvlist_alloc(&cfgp->props, NV_UNIQUE_NAME, 0);
 414         }
 415         (void) nvlist_add_string(cfgp->props, nvp->name, nvp->value);
 416 }
 417 
 418 void
 419 cfgdata_add_diskmon(cfgdata_t *cfgp, diskmon_t *dmp)
 420 {
 421         if (cfgp->disk_list == NULL) {
 422                 cfgp->disk_list = dmp;
 423         } else {
 424                 diskmon_t *disklist = cfgp->disk_list;
 425 
 426                 while (disklist->next != NULL)
 427                         disklist = disklist->next;
 428 
 429                 disklist->next = dmp;
 430         }
 431 }
 432 
 433 static void
 434 cfgdata_free(cfgdata_t *cdp)
 435 {
 436         nvlist_free(cdp->props);
 437         diskmon_free(cdp->disk_list);
 438         dfree(cdp, sizeof (cfgdata_t));
 439 }
 440 
 441 conf_err_t
 442 check_indactions(ind_action_t *indrp)
 443 {
 444         char *buf;
 445         conf_err_t rv = E_NO_ERROR;
 446         nvlist_t *nvp = NULL;
 447         int len;
 448 
 449         (void) nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0);
 450 
 451         /*
 452          * Check indicator actions for conflicts
 453          */
 454         while (indrp != NULL && rv == E_NO_ERROR) {
 455                 len = strlen(indrp->ind_name) + 2;
 456                 buf = dmalloc(len);
 457                 (void) snprintf(buf, len, "%c%s",
 458                     indrp->ind_state == INDICATOR_ON ? '+' : '-',
 459                     indrp->ind_name);
 460                 switch (nvlist_lookup_boolean(nvp, buf)) {
 461                 case ENOENT:
 462                         (void) nvlist_add_boolean(nvp, buf);
 463                         break;
 464                 case 0:
 465                         rv = E_IND_ACTION_REDUNDANT;
 466                         break;
 467                 default:
 468                         break;
 469                 }
 470 
 471                 /* Look for the opposite action.  If found, that's an error */
 472                 (void) snprintf(buf, len, "%c%s",
 473                     indrp->ind_state == INDICATOR_ON ? '-' : '+',
 474                     indrp->ind_name);
 475                 switch (nvlist_lookup_boolean(nvp, buf)) {
 476                 case ENOENT:
 477                         break;
 478                 case 0:
 479                         rv = E_IND_ACTION_CONFLICT;
 480                         break;
 481                 default:
 482                         break;
 483                 }
 484                 dfree(buf, len);
 485                 indrp = indrp->next;
 486         }
 487 
 488         nvlist_free(nvp);
 489         return (rv);
 490 }
 491 
 492 conf_err_t
 493 check_inds(indicator_t *indp)
 494 {
 495         char *buf;
 496         conf_err_t rv = E_NO_ERROR;
 497         nvlist_t *nvp = NULL;
 498         int len;
 499         boolean_t fault_on = B_FALSE, fault_off = B_FALSE;
 500 
 501         (void) nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0);
 502 
 503         /*
 504          * Check inds for multiple definitions (same identifier or same action)
 505          */
 506         while (indp != NULL && rv == E_NO_ERROR) {
 507                 len = strlen(indp->ind_name) + 2;
 508                 buf = dmalloc(len);
 509                 (void) snprintf(buf, len, "%c%s",
 510                     indp->ind_state == INDICATOR_ON ? '+' : '-',
 511                     indp->ind_name);
 512 
 513                 /* Keep track of the +/-FAULT for checking later */
 514                 if (strcasecmp(buf, "+" INDICATOR_FAULT_IDENTIFIER) == 0)
 515                         fault_on = B_TRUE;
 516                 else if (strcasecmp(buf, "-" INDICATOR_FAULT_IDENTIFIER) == 0)
 517                         fault_off = B_TRUE;
 518 
 519                 switch (nvlist_lookup_boolean(nvp, buf)) {
 520                 case ENOENT:
 521                         (void) nvlist_add_boolean(nvp, buf);
 522                         break;
 523                 case 0:
 524                         rv = E_IND_MULTIPLY_DEFINED;
 525                         break;
 526                 default:
 527                         break;
 528                 }
 529                 dfree(buf, len);
 530                 indp = indp->next;
 531         }
 532 
 533         /*
 534          * Make sure we have a -FAULT and +FAULT
 535          */
 536         if (!fault_on)
 537                 rv = E_IND_MISSING_FAULT_ON;
 538         else if (!fault_off)
 539                 rv = E_IND_MISSING_FAULT_OFF;
 540 
 541         nvlist_free(nvp);
 542         return (rv);
 543 }
 544 
 545 conf_err_t
 546 check_indrules(indrule_t *indrp, state_transition_t **offender)
 547 {
 548         char buf[32];
 549         conf_err_t rv = E_NO_ERROR;
 550         nvlist_t *nvp = NULL;
 551 
 552         /*
 553          * Ensure that no two rules have the same state transitions.
 554          */
 555 
 556         (void) nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0);
 557 
 558         while (indrp != NULL && rv == E_NO_ERROR) {
 559                 (void) snprintf(buf, sizeof (buf), "%d-%d",
 560                     (int)indrp->strans.begin, (int)indrp->strans.end);
 561                 switch (nvlist_lookup_boolean(nvp, buf)) {
 562                 case 0:
 563                         *offender = &indrp->strans;
 564                         rv = E_DUPLICATE_STATE_TRANSITION;
 565                         break;
 566                 case ENOENT:
 567                         (void) nvlist_add_boolean(nvp, buf);
 568                         break;
 569                 default:
 570                         break;
 571                 }
 572                 indrp = indrp->next;
 573         }
 574 
 575         nvlist_free(nvp);
 576         return (rv);
 577 }
 578 
 579 
 580 conf_err_t
 581 check_consistent_ind_indrules(indicator_t *indp, indrule_t *indrp,
 582     ind_action_t **offender)
 583 {
 584         char *buf;
 585         conf_err_t rv = E_NO_ERROR;
 586         nvlist_t *nvp = NULL;
 587         ind_action_t *alp;
 588         int len;
 589 
 590         /*
 591          * Ensure that every indicator action referenced in each ruleset
 592          * exists in the indicator list given.
 593          */
 594 
 595         (void) nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0);
 596 
 597         while (indp != NULL) {
 598                 len = strlen(indp->ind_name) + 2;
 599                 buf = dmalloc(len);
 600                 (void) snprintf(buf, len, "%c%s",
 601                     indp->ind_state == INDICATOR_ON ? '+' : '-',
 602                     indp->ind_name);
 603                 (void) nvlist_add_boolean(nvp, buf);
 604                 dfree(buf, len);
 605                 indp = indp->next;
 606         }
 607 
 608         while (indrp != NULL && rv == E_NO_ERROR) {
 609                 alp = indrp->action_list;
 610                 while (alp != NULL && rv == E_NO_ERROR) {
 611                         len = strlen(alp->ind_name) + 2;
 612                         buf = dmalloc(len);
 613                         (void) snprintf(buf, len, "%c%s",
 614                             alp->ind_state == INDICATOR_ON ? '+' : '-',
 615                             alp->ind_name);
 616 
 617                         switch (nvlist_lookup_boolean(nvp, buf)) {
 618                         case 0:         /* Normal case */
 619                                 break;
 620                         case ENOENT:
 621                                 *offender = alp;
 622                                 rv =
 623                                     E_INDRULE_REFERENCES_NONEXISTENT_IND_ACTION;
 624                                 break;
 625                         default:
 626                                 break;
 627                         }
 628                         dfree(buf, len);
 629                         alp = alp->next;
 630                 }
 631                 indrp = indrp->next;
 632         }
 633 
 634         nvlist_free(nvp);
 635         return (rv);
 636 }
 637 
 638 conf_err_t
 639 check_state_transition(hotplug_state_t s1, hotplug_state_t s2)
 640 {
 641         /*
 642          * The following are valid transitions:
 643          *
 644          * HPS_ABSENT -> HPS_PRESENT
 645          * HPS_ABSENT -> HPS_CONFIGURED
 646          * HPS_PRESENT -> HPS_CONFIGURED
 647          * HPS_PRESENT -> HPS_ABSENT
 648          * HPS_CONFIGURED -> HPS_UNCONFIGURED
 649          * HPS_CONFIGURED -> HPS_ABSENT
 650          * HPS_UNCONFIGURED -> HPS_ABSENT
 651          * HPS_UNCONFIGURED -> HPS_CONFIGURED
 652          *
 653          */
 654         if (s1 == HPS_ABSENT && s2 != HPS_PRESENT && s2 != HPS_CONFIGURED)
 655                 return (E_INVALID_STATE_CHANGE);
 656         else if (s1 == HPS_PRESENT && (s2 != HPS_CONFIGURED &&
 657             s2 != HPS_ABSENT))
 658                 return (E_INVALID_STATE_CHANGE);
 659         else if (s1 == HPS_CONFIGURED && (s2 != HPS_UNCONFIGURED &&
 660             s2 != HPS_ABSENT))
 661                 return (E_INVALID_STATE_CHANGE);
 662         else if (s1 == HPS_UNCONFIGURED && (s2 != HPS_ABSENT &&
 663             s2 != HPS_CONFIGURED))
 664                 return (E_INVALID_STATE_CHANGE);
 665         else
 666                 return (E_NO_ERROR);
 667 }
 668 
 669 static void
 670 print_inds(indicator_t *indp, FILE *fp, char *prefix)
 671 {
 672         char plusminus;
 673 
 674         (void) fprintf(fp, "%sindicators {\n", prefix);
 675         while (indp != NULL) {
 676                 plusminus = (indp->ind_state == INDICATOR_ON) ? '+' : '-';
 677                 (void) fprintf(fp, "%s\t%c%s = \"%s\"\n", prefix, plusminus,
 678                     indp->ind_name, indp->ind_instr_spec);
 679                 indp = indp->next;
 680         }
 681         (void) fprintf(fp, "%s}\n", prefix);
 682 }
 683 
 684 static void
 685 print_indrules(indrule_t *lrp, FILE *fp, char *prefix)
 686 {
 687         char plusminus;
 688         ind_action_t *lap;
 689 
 690         (void) fprintf(fp, "%sindicator_rules {\n", prefix);
 691         while (lrp != NULL) {
 692                 (void) fprintf(fp, "%s\t%12s -> %12s\t{ ", prefix,
 693                     hotplug_state_string(lrp->strans.begin),
 694                     hotplug_state_string(lrp->strans.end));
 695                 lap = lrp->action_list;
 696                 while (lap != NULL) {
 697                         plusminus = (lap->ind_state == INDICATOR_ON)
 698                             ? '+' : '-';
 699                         (void) fprintf(fp, "%c%s", plusminus, lap->ind_name);
 700                         lap = lap->next;
 701                         if (lap != NULL)
 702                                 (void) fprintf(fp, ", ");
 703                 }
 704                 (void) fprintf(fp, " }\n");
 705                 lrp = lrp->next;
 706         }
 707         (void) fprintf(fp, "%s}\n", prefix);
 708 }
 709 
 710 static void
 711 print_props(nvlist_t *nvlp, FILE *fp, char *prefix)
 712 {
 713         nvpair_t *nvp = nvlist_next_nvpair(nvlp, NULL);
 714         char *name, *str;
 715 
 716         while (nvp != NULL) {
 717                 dm_assert(nvpair_type(nvp) == DATA_TYPE_STRING);
 718                 name = nvpair_name(nvp);
 719                 (void) nvlist_lookup_string(nvlp, name, &str);
 720                 (void) fprintf(fp, "%s%s = \"%s\"\n", prefix, name, str);
 721                 nvp = nvlist_next_nvpair(nvlp, nvp);
 722         }
 723 }
 724 
 725 static void
 726 print_ap(nvlist_t *dpp, FILE *fp, char *prefix)
 727 {
 728         int len = strlen(prefix) + 2;
 729         char *buf = dmalloc(len);
 730 
 731         (void) snprintf(buf, len, "%s\t", prefix);
 732 
 733         (void) fprintf(fp, "%sap_props {\n", prefix);
 734         print_props(dpp, fp, buf);
 735         (void) fprintf(fp, "%s}\n", prefix);
 736 
 737         dfree(buf, len);
 738 }
 739 
 740 static void
 741 print_disks(diskmon_t *dmp, FILE *fp, char *prefix)
 742 {
 743         int len = strlen(prefix) + 2;
 744         char *buf = dmalloc(len);
 745 
 746         (void) snprintf(buf, len, "%s\t", prefix);
 747 
 748         while (dmp != NULL) {
 749                 (void) fprintf(fp, "%sdisk \"%s\" {\n", prefix, dmp->location);
 750                 if (dmp->props) {
 751                         print_props(dmp->props, fp, buf);
 752                 }
 753                 if (dmp->app_props) {
 754                         print_ap(dmp->app_props, fp, buf);
 755                 }
 756                 (void) fprintf(fp, "%s\n", prefix);
 757                 print_inds(dmp->ind_list, fp, buf);
 758                 (void) fprintf(fp, "%s\n", prefix);
 759                 print_indrules(dmp->indrule_list, fp, buf);
 760                 (void) fprintf(fp, "%s}\n", prefix);
 761 
 762                 if (dmp->next != NULL)
 763                         (void) fprintf(fp, "%s\n", prefix);
 764 
 765                 dmp = dmp->next;
 766         }
 767 
 768         dfree(buf, len);
 769 }
 770 
 771 static void
 772 print_cfgdata(cfgdata_t *cfgp, FILE *fp, char *prefix)
 773 {
 774         /* First, print the properties, then the disks */
 775 
 776         print_props(cfgp->props, fp, prefix);
 777         (void) fprintf(fp, "%s\n", prefix);
 778         print_disks(cfgp->disk_list, fp, prefix);
 779 }
 780 
 781 int
 782 config_init(void)
 783 {
 784         if (init_configuration_from_topo() == 0) {
 785                 config_data = new_cfgdata(NULL, NULL);
 786                 return (0);
 787         }
 788         return (-1);
 789 }
 790 
 791 int
 792 config_get(fmd_hdl_t *hdl, const fmd_prop_t *fmd_props)
 793 {
 794         int err, i = 0;
 795         char *str = NULL;
 796         namevalpr_t nvp;
 797         uint64_t u64;
 798         boolean_t intfound = B_FALSE, strfound = B_FALSE;
 799 #define INT64_BUF_LEN 128
 800         char buf[INT64_BUF_LEN];
 801 
 802         u64 = fmd_prop_get_int32(hdl, GLOBAL_PROP_LOG_LEVEL);
 803         g_verbose = (int)u64;
 804 
 805         err = update_configuration_from_topo(hdl, NULL);
 806 
 807         /* Pull in the properties from the DE configuration file */
 808         while (fmd_props[i].fmdp_name != NULL) {
 809 
 810                 nvp.name = (char *)fmd_props[i].fmdp_name;
 811 
 812                 switch (fmd_props[i].fmdp_type) {
 813                 case FMD_TYPE_UINT32:
 814                 case FMD_TYPE_INT32:
 815                         intfound = B_TRUE;
 816                         u64 = fmd_prop_get_int32(hdl, fmd_props[i].fmdp_name);
 817                         break;
 818                 case FMD_TYPE_UINT64:
 819                 case FMD_TYPE_INT64:
 820                         intfound = B_TRUE;
 821                         u64 = fmd_prop_get_int64(hdl, fmd_props[i].fmdp_name);
 822                         break;
 823                 case FMD_TYPE_STRING:
 824                         strfound = B_TRUE;
 825                         str = fmd_prop_get_string(hdl, fmd_props[i].fmdp_name);
 826                         break;
 827 
 828                 }
 829 
 830                 if (intfound) {
 831                         (void) snprintf(buf, INT64_BUF_LEN, "0x%llx", u64);
 832                         nvp.value = buf;
 833                         intfound = B_FALSE;
 834                 } else if (strfound) {
 835                         nvp.value = str;
 836                 }
 837 
 838                 log_msg(MM_CONF, "Adding property `%s' with value `%s'\n",
 839                     nvp.name, nvp.value);
 840 
 841                 cfgdata_add_namevalpr(config_data, &nvp);
 842 
 843                 if (strfound) {
 844                         strfound = B_FALSE;
 845                         fmd_prop_free_string(hdl, str);
 846                 }
 847 
 848 
 849                 i++;
 850         }
 851 
 852         if ((g_verbose & (MM_CONF|MM_OTHER)) == (MM_CONF|MM_OTHER))
 853                 print_cfgdata(config_data, stderr, "");
 854 
 855         return (err);
 856 }
 857 
 858 void
 859 config_fini(void)
 860 {
 861         fini_configuration_from_topo();
 862         cfgdata_free(config_data);
 863         config_data = NULL;
 864 }
 865 
 866 nvlist_t *
 867 dm_global_proplist(void)
 868 {
 869         return (config_data->props);
 870 }