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