Home | History | Annotate | Download | only in disk-monitor
      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 }
    875