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
45extern log_class_t g_verbose;
46
47const char *
48hotplug_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
65void
66conf_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
119static int
120string_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
141const char *
142dm_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
152int
153dm_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
163nvlist_t *
164namevalpr_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
180indicator_t *
181new_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
192void
193link_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
209void
210ind_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
225ind_action_t *
226new_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
235void
236link_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
252void
253indaction_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
267indrule_t *
268new_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
278void
279link_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
295void
296indrule_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
310dm_fru_t *
311new_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
324void
325dmfru_free(dm_fru_t *frup)
326{
327	dfree(frup, sizeof (dm_fru_t));
328}
329
330diskmon_t *
331new_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
367void
368diskmon_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
392static cfgdata_t *
393new_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
409static void
410cfgdata_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
418void
419cfgdata_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
433static void
434cfgdata_free(cfgdata_t *cdp)
435{
436	nvlist_free(cdp->props);
437	diskmon_free(cdp->disk_list);
438	dfree(cdp, sizeof (cfgdata_t));
439}
440
441conf_err_t
442check_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
492conf_err_t
493check_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
545conf_err_t
546check_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
580conf_err_t
581check_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
638conf_err_t
639check_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
669static void
670print_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
684static void
685print_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
710static void
711print_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
725static void
726print_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
740static void
741print_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
771static void
772print_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
781int
782config_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
791int
792config_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
858void
859config_fini(void)
860{
861	fini_configuration_from_topo();
862	cfgdata_free(config_data);
863	config_data = NULL;
864}
865
866nvlist_t *
867dm_global_proplist(void)
868{
869	return (config_data->props);
870}
871