xref: /titanic_52/usr/src/cmd/fm/fmd/common/fmd_conf.c (revision b0daa853ddd4c48b6374b8ac0dca46629b225c39)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*b0daa853SStephen Hanson  * Common Development and Distribution License (the "License").
6*b0daa853SStephen Hanson  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217aec1d6eScindi 
227c478bd9Sstevel@tonic-gate /*
23*b0daa853SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <pthread.h>
287c478bd9Sstevel@tonic-gate #include <unistd.h>
297c478bd9Sstevel@tonic-gate #include <signal.h>
307c478bd9Sstevel@tonic-gate #include <inttypes.h>
317c478bd9Sstevel@tonic-gate #include <alloca.h>
327c478bd9Sstevel@tonic-gate #include <strings.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <fmd_conf.h>
377c478bd9Sstevel@tonic-gate #include <fmd_alloc.h>
387c478bd9Sstevel@tonic-gate #include <fmd_error.h>
397c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
407c478bd9Sstevel@tonic-gate #include <fmd_string.h>
417c478bd9Sstevel@tonic-gate #include <fmd.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate const char FMD_PROP_SUBSCRIPTIONS[] = "_subscriptions";
447c478bd9Sstevel@tonic-gate const char FMD_PROP_DICTIONARIES[] = "_dictionaries";
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * The property formals defined in _fmd_conf_defv[] are added to every config
487c478bd9Sstevel@tonic-gate  * dictionary that is created.  Here we define several special FMD_PROP_*
497c478bd9Sstevel@tonic-gate  * properties that are used to implement the config file keyword actions, as
507c478bd9Sstevel@tonic-gate  * well as properties that should be inherited by fmd_conf_t's from fmd.d_conf.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate static const fmd_conf_formal_t _fmd_conf_defv[] = {
537c478bd9Sstevel@tonic-gate 	{ FMD_PROP_SUBSCRIPTIONS, &fmd_conf_list, "" },
547c478bd9Sstevel@tonic-gate 	{ FMD_PROP_DICTIONARIES, &fmd_conf_list, "" },
557c478bd9Sstevel@tonic-gate 	{ "fmd.isaname", &fmd_conf_parent, "isaname" },
567c478bd9Sstevel@tonic-gate 	{ "fmd.machine", &fmd_conf_parent, "machine" },
577c478bd9Sstevel@tonic-gate 	{ "fmd.platform", &fmd_conf_parent, "platform" },
587c478bd9Sstevel@tonic-gate 	{ "fmd.rootdir", &fmd_conf_parent, "rootdir" },
597c478bd9Sstevel@tonic-gate };
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate static const int _fmd_conf_defc =
627c478bd9Sstevel@tonic-gate     sizeof (_fmd_conf_defv) / sizeof (_fmd_conf_defv[0]);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static int
657c478bd9Sstevel@tonic-gate set_bool(fmd_conf_param_t *pp, const char *s)
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate 	if (strcasecmp(s, "true") == 0)
687c478bd9Sstevel@tonic-gate 		pp->cp_value.cpv_num = 1;
697c478bd9Sstevel@tonic-gate 	else if (strcasecmp(s, "false") == 0)
707c478bd9Sstevel@tonic-gate 		pp->cp_value.cpv_num = 0;
717c478bd9Sstevel@tonic-gate 	else
727c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	return (0);
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static void
787c478bd9Sstevel@tonic-gate get_bool(const fmd_conf_param_t *pp, void *ptr)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate 	*((int *)ptr) = (int)pp->cp_value.cpv_num;
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate static int
84d9638e54Smws set_i32x(fmd_conf_param_t *pp, const char *s, int64_t min, int64_t max)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	int64_t val;
877c478bd9Sstevel@tonic-gate 	char *end;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	errno = 0;
907c478bd9Sstevel@tonic-gate 	val = strtoll(s, &end, 0);
917c478bd9Sstevel@tonic-gate 
92d9638e54Smws 	if (errno == EOVERFLOW || val < min || val > max)
937c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_OVERFLOW));
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	if (errno != 0 || end == s || *end != '\0')
967c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_num = val;
997c478bd9Sstevel@tonic-gate 	return (0);
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
102d9638e54Smws static int
103d9638e54Smws set_i8(fmd_conf_param_t *pp, const char *s)
104d9638e54Smws {
105d9638e54Smws 	return (set_i32x(pp, s, INT8_MIN, INT8_MAX));
106d9638e54Smws }
107d9638e54Smws 
108d9638e54Smws static int
109d9638e54Smws set_i16(fmd_conf_param_t *pp, const char *s)
110d9638e54Smws {
111d9638e54Smws 	return (set_i32x(pp, s, INT16_MIN, INT16_MAX));
112d9638e54Smws }
113d9638e54Smws 
114d9638e54Smws static int
115d9638e54Smws set_i32(fmd_conf_param_t *pp, const char *s)
116d9638e54Smws {
117d9638e54Smws 	return (set_i32x(pp, s, INT32_MIN, INT32_MAX));
118d9638e54Smws }
119d9638e54Smws 
1207c478bd9Sstevel@tonic-gate static void
1217c478bd9Sstevel@tonic-gate get_i32(const fmd_conf_param_t *pp, void *ptr)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	*((int32_t *)ptr) = (int32_t)pp->cp_value.cpv_num;
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate static int
127d9638e54Smws set_ui32x(fmd_conf_param_t *pp, const char *s, uint64_t max)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	uint64_t val;
1307c478bd9Sstevel@tonic-gate 	char *end;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	errno = 0;
1337c478bd9Sstevel@tonic-gate 	val = strtoull(s, &end, 0);
1347c478bd9Sstevel@tonic-gate 
135d9638e54Smws 	if (errno == EOVERFLOW || val > max)
1367c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_OVERFLOW));
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (errno != 0 || end == s || *end != '\0')
1397c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_num = val;
1427c478bd9Sstevel@tonic-gate 	return (0);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate 
145d9638e54Smws static int
146d9638e54Smws set_ui8(fmd_conf_param_t *pp, const char *s)
147d9638e54Smws {
148d9638e54Smws 	return (set_ui32x(pp, s, UINT8_MAX));
149d9638e54Smws }
150d9638e54Smws 
151d9638e54Smws static int
152d9638e54Smws set_ui16(fmd_conf_param_t *pp, const char *s)
153d9638e54Smws {
154d9638e54Smws 	return (set_ui32x(pp, s, UINT16_MAX));
155d9638e54Smws }
156d9638e54Smws 
157d9638e54Smws static int
158d9638e54Smws set_ui32(fmd_conf_param_t *pp, const char *s)
159d9638e54Smws {
160d9638e54Smws 	return (set_ui32x(pp, s, UINT32_MAX));
161d9638e54Smws }
162d9638e54Smws 
1637c478bd9Sstevel@tonic-gate static void
1647c478bd9Sstevel@tonic-gate get_ui32(const fmd_conf_param_t *pp, void *ptr)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	*((uint32_t *)ptr) = (uint32_t)pp->cp_value.cpv_num;
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate static int
1707c478bd9Sstevel@tonic-gate set_i64(fmd_conf_param_t *pp, const char *s)
1717c478bd9Sstevel@tonic-gate {
1727c478bd9Sstevel@tonic-gate 	int64_t val;
1737c478bd9Sstevel@tonic-gate 	char *end;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	errno = 0;
1767c478bd9Sstevel@tonic-gate 	val = strtoll(s, &end, 0);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (errno == EOVERFLOW)
1797c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_OVERFLOW));
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (errno != 0 || end == s || *end != '\0')
1827c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_num = val;
1857c478bd9Sstevel@tonic-gate 	return (0);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate static void
1897c478bd9Sstevel@tonic-gate get_i64(const fmd_conf_param_t *pp, void *ptr)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	*((int64_t *)ptr) = (int64_t)pp->cp_value.cpv_num;
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate static int
1957c478bd9Sstevel@tonic-gate set_ui64(fmd_conf_param_t *pp, const char *s)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	uint64_t val;
1987c478bd9Sstevel@tonic-gate 	char *end;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	errno = 0;
2017c478bd9Sstevel@tonic-gate 	val = strtoull(s, &end, 0);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	if (errno == EOVERFLOW)
2047c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_OVERFLOW));
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (errno != 0 || end == s || *end != '\0')
2077c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_num = val;
2107c478bd9Sstevel@tonic-gate 	return (0);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate static void
2147c478bd9Sstevel@tonic-gate get_ui64(const fmd_conf_param_t *pp, void *ptr)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	*((uint64_t *)ptr) = pp->cp_value.cpv_num;
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate static int
2207c478bd9Sstevel@tonic-gate set_str(fmd_conf_param_t *pp, const char *s)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	fmd_strfree(pp->cp_value.cpv_str);
2237c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_str = fmd_strdup(s, FMD_SLEEP);
2247c478bd9Sstevel@tonic-gate 	return (0);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate static void
2287c478bd9Sstevel@tonic-gate get_str(const fmd_conf_param_t *pp, void *ptr)
2297c478bd9Sstevel@tonic-gate {
2307c478bd9Sstevel@tonic-gate 	*((const char **)ptr) = pp->cp_value.cpv_str;
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static void
2347c478bd9Sstevel@tonic-gate free_str(fmd_conf_param_t *pp)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	fmd_strfree(pp->cp_value.cpv_str);
2377c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_str = NULL;
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate static int
2417c478bd9Sstevel@tonic-gate set_path(fmd_conf_param_t *pp, const char *value)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	size_t len = strlen(value);
2447c478bd9Sstevel@tonic-gate 	char *s = alloca(len + 1);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	char **patv = alloca(sizeof (char *) * len / 2);
2477c478bd9Sstevel@tonic-gate 	int patc = 0;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	static const char *const percent_sign = "%";
2507c478bd9Sstevel@tonic-gate 	char *p, *q;
2517c478bd9Sstevel@tonic-gate 	int c, i;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	static const struct fmd_conf_token {
2547c478bd9Sstevel@tonic-gate 		char tok_tag;
2557c478bd9Sstevel@tonic-gate 		const char *const *tok_val;
2567c478bd9Sstevel@tonic-gate 	} tokens[] = {
2577c478bd9Sstevel@tonic-gate 		{ 'i', &fmd.d_platform },
2587c478bd9Sstevel@tonic-gate 		{ 'm', &fmd.d_machine },
2597c478bd9Sstevel@tonic-gate 		{ 'p', &fmd.d_isaname },
2607c478bd9Sstevel@tonic-gate 		{ 'r', &fmd.d_rootdir },
2617c478bd9Sstevel@tonic-gate 		{ '%', &percent_sign },
2627c478bd9Sstevel@tonic-gate 		{ 0, NULL }
2637c478bd9Sstevel@tonic-gate 	};
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	const struct fmd_conf_token *tok;
2667c478bd9Sstevel@tonic-gate 	fmd_conf_path_t *pap;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	pp->cp_formal->cf_ops->co_free(pp);
2697c478bd9Sstevel@tonic-gate 	(void) strcpy(s, value);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	for (p = strtok_r(s, ":", &q); p != NULL; p = strtok_r(NULL, ":", &q))
2727c478bd9Sstevel@tonic-gate 		patv[patc++] = p;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	pap = fmd_alloc(sizeof (fmd_conf_path_t), FMD_SLEEP);
2757c478bd9Sstevel@tonic-gate 	pap->cpa_argv = fmd_alloc(sizeof (char *) * patc, FMD_SLEEP);
2767c478bd9Sstevel@tonic-gate 	pap->cpa_argc = patc;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	for (i = 0; i < patc; i++) {
2797c478bd9Sstevel@tonic-gate 		for (len = 0, p = patv[i]; (c = *p) != '\0'; p++, len++) {
2807c478bd9Sstevel@tonic-gate 			if (c != '%' || (c = p[1]) == '\0')
2817c478bd9Sstevel@tonic-gate 				continue;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 			for (tok = tokens; tok->tok_tag != 0; tok++) {
2847c478bd9Sstevel@tonic-gate 				if (c == tok->tok_tag) {
2857c478bd9Sstevel@tonic-gate 					len += strlen(*tok->tok_val) - 1;
2867c478bd9Sstevel@tonic-gate 					p++;
2877c478bd9Sstevel@tonic-gate 					break;
2887c478bd9Sstevel@tonic-gate 				}
2897c478bd9Sstevel@tonic-gate 			}
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		pap->cpa_argv[i] = q = fmd_alloc(len + 1, FMD_SLEEP);
2937c478bd9Sstevel@tonic-gate 		q[len] = '\0';
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 		for (p = patv[i]; (c = *p) != '\0'; p++) {
2967c478bd9Sstevel@tonic-gate 			if (c != '%' || (c = p[1]) == '\0') {
2977c478bd9Sstevel@tonic-gate 				*q++ = c;
2987c478bd9Sstevel@tonic-gate 				continue;
2997c478bd9Sstevel@tonic-gate 			}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 			for (tok = tokens; tok->tok_tag != 0; tok++) {
3027c478bd9Sstevel@tonic-gate 				if (c == tok->tok_tag) {
3037c478bd9Sstevel@tonic-gate 					(void) strcpy(q, *tok->tok_val);
3047c478bd9Sstevel@tonic-gate 					q += strlen(q);
3057c478bd9Sstevel@tonic-gate 					p++;
3067c478bd9Sstevel@tonic-gate 					break;
3077c478bd9Sstevel@tonic-gate 				}
3087c478bd9Sstevel@tonic-gate 			}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 			if (tok->tok_tag == 0)
3117c478bd9Sstevel@tonic-gate 				*q++ = c;
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_ptr = pap;
3167c478bd9Sstevel@tonic-gate 	return (0);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate static int
3207c478bd9Sstevel@tonic-gate set_lst(fmd_conf_param_t *pp, const char *value)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	fmd_conf_path_t *old;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	old = pp->cp_value.cpv_ptr;
3257c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_ptr = NULL;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	if (set_path(pp, value) != 0) {
3287c478bd9Sstevel@tonic-gate 		pp->cp_value.cpv_ptr = old;
3297c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if (old != NULL) {
3337c478bd9Sstevel@tonic-gate 		fmd_conf_path_t *new = pp->cp_value.cpv_ptr;
3347c478bd9Sstevel@tonic-gate 		int i, totc = old->cpa_argc + new->cpa_argc;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 		int new_argc = new->cpa_argc;
3377c478bd9Sstevel@tonic-gate 		const char **new_argv = new->cpa_argv;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		new->cpa_argc = 0;
3407c478bd9Sstevel@tonic-gate 		new->cpa_argv = fmd_alloc(sizeof (char *) * totc, FMD_SLEEP);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 		for (i = 0; i < old->cpa_argc; i++)
3437c478bd9Sstevel@tonic-gate 			new->cpa_argv[new->cpa_argc++] = old->cpa_argv[i];
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 		for (i = 0; i < new_argc; i++)
3467c478bd9Sstevel@tonic-gate 			new->cpa_argv[new->cpa_argc++] = new_argv[i];
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 		ASSERT(new->cpa_argc == totc);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		fmd_free(new_argv, sizeof (char *) * new_argc);
3517c478bd9Sstevel@tonic-gate 		fmd_free(old->cpa_argv, sizeof (char *) * old->cpa_argc);
3527c478bd9Sstevel@tonic-gate 		fmd_free(old, sizeof (fmd_conf_path_t));
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	return (0);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate static int
3597c478bd9Sstevel@tonic-gate del_lst(fmd_conf_param_t *pp, const char *value)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	fmd_conf_path_t *pap = pp->cp_value.cpv_ptr;
3627c478bd9Sstevel@tonic-gate 	const char **new_argv;
3637c478bd9Sstevel@tonic-gate 	int i, new_argc;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	for (i = 0; i < pap->cpa_argc; i++) {
3667c478bd9Sstevel@tonic-gate 		if (strcmp(pap->cpa_argv[i], value) == 0)
3677c478bd9Sstevel@tonic-gate 			break;
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	if (i == pap->cpa_argc)
3717c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(ENOENT));
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	fmd_strfree((char *)pap->cpa_argv[i]);
3747c478bd9Sstevel@tonic-gate 	pap->cpa_argv[i] = NULL;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	new_argc = 0;
3777c478bd9Sstevel@tonic-gate 	new_argv = fmd_alloc(sizeof (char *) * (pap->cpa_argc - 1), FMD_SLEEP);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	for (i = 0; i < pap->cpa_argc; i++) {
3807c478bd9Sstevel@tonic-gate 		if (pap->cpa_argv[i] != NULL)
3817c478bd9Sstevel@tonic-gate 			new_argv[new_argc++] = pap->cpa_argv[i];
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	fmd_free(pap->cpa_argv, sizeof (char *) * pap->cpa_argc);
3857c478bd9Sstevel@tonic-gate 	pap->cpa_argv = new_argv;
3867c478bd9Sstevel@tonic-gate 	pap->cpa_argc = new_argc;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	return (0);
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate static void
3927c478bd9Sstevel@tonic-gate get_path(const fmd_conf_param_t *pp, void *ptr)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	*((fmd_conf_path_t **)ptr) = (fmd_conf_path_t *)pp->cp_value.cpv_ptr;
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate static void
3987c478bd9Sstevel@tonic-gate free_path(fmd_conf_param_t *pp)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	fmd_conf_path_t *pap = pp->cp_value.cpv_ptr;
4017c478bd9Sstevel@tonic-gate 	int i;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	if (pap == NULL)
4047c478bd9Sstevel@tonic-gate 		return; /* no value was ever set */
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	for (i = 0; i < pap->cpa_argc; i++)
4077c478bd9Sstevel@tonic-gate 		fmd_strfree((char *)pap->cpa_argv[i]);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	fmd_free(pap->cpa_argv, sizeof (char *) * pap->cpa_argc);
4107c478bd9Sstevel@tonic-gate 	fmd_free(pap, sizeof (fmd_conf_path_t));
4117c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_ptr = NULL;
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate static int
4157c478bd9Sstevel@tonic-gate set_time(fmd_conf_param_t *pp, const char *s)
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate 	static const struct {
4187c478bd9Sstevel@tonic-gate 		const char *name;
4197c478bd9Sstevel@tonic-gate 		hrtime_t mul;
4207c478bd9Sstevel@tonic-gate 	} suffix[] = {
4217c478bd9Sstevel@tonic-gate 		{ "ns", 	NANOSEC / NANOSEC },
4227c478bd9Sstevel@tonic-gate 		{ "nsec",	NANOSEC / NANOSEC },
4237c478bd9Sstevel@tonic-gate 		{ "us",		NANOSEC / MICROSEC },
4247c478bd9Sstevel@tonic-gate 		{ "usec",	NANOSEC / MICROSEC },
4257c478bd9Sstevel@tonic-gate 		{ "ms",		NANOSEC / MILLISEC },
4267c478bd9Sstevel@tonic-gate 		{ "msec",	NANOSEC / MILLISEC },
4277c478bd9Sstevel@tonic-gate 		{ "s",		NANOSEC / SEC },
4287c478bd9Sstevel@tonic-gate 		{ "sec",	NANOSEC / SEC },
4297c478bd9Sstevel@tonic-gate 		{ "m",		NANOSEC * (hrtime_t)60 },
4307c478bd9Sstevel@tonic-gate 		{ "min",	NANOSEC * (hrtime_t)60 },
4317c478bd9Sstevel@tonic-gate 		{ "h",		NANOSEC * (hrtime_t)(60 * 60) },
4327c478bd9Sstevel@tonic-gate 		{ "hour",	NANOSEC * (hrtime_t)(60 * 60) },
4337c478bd9Sstevel@tonic-gate 		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) },
4347c478bd9Sstevel@tonic-gate 		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
4357c478bd9Sstevel@tonic-gate 		{ "hz",		0 },
4367c478bd9Sstevel@tonic-gate 		{ NULL }
4377c478bd9Sstevel@tonic-gate 	};
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	hrtime_t val, mul = 1;
4407c478bd9Sstevel@tonic-gate 	char *end;
4417c478bd9Sstevel@tonic-gate 	int i;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	errno = 0;
4447c478bd9Sstevel@tonic-gate 	val = strtoull(s, &end, 0);
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	if (errno == EOVERFLOW)
4477c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_OVERFLOW));
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	if (errno != 0 || end == s)
4507c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	for (i = 0; suffix[i].name != NULL; i++) {
4537c478bd9Sstevel@tonic-gate 		if (strcasecmp(suffix[i].name, end) == 0) {
4547c478bd9Sstevel@tonic-gate 			mul = suffix[i].mul;
4557c478bd9Sstevel@tonic-gate 			break;
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (suffix[i].name == NULL && *end != '\0')
4607c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if (mul == 0) {
4637c478bd9Sstevel@tonic-gate 		if (val != 0)
4647c478bd9Sstevel@tonic-gate 			val = NANOSEC / val; /* compute val as value per sec */
4657c478bd9Sstevel@tonic-gate 	} else
4667c478bd9Sstevel@tonic-gate 		val *= mul;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_num = val;
4697c478bd9Sstevel@tonic-gate 	return (0);
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate static int
4737c478bd9Sstevel@tonic-gate set_size(fmd_conf_param_t *pp, const char *s)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	size_t len = strlen(s);
4767c478bd9Sstevel@tonic-gate 	uint64_t val, mul = 1;
4777c478bd9Sstevel@tonic-gate 	char *end;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	switch (s[len - 1]) {
4807c478bd9Sstevel@tonic-gate 	case 't':
4817c478bd9Sstevel@tonic-gate 	case 'T':
4827c478bd9Sstevel@tonic-gate 		mul *= 1024;
4837c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
4847c478bd9Sstevel@tonic-gate 	case 'g':
4857c478bd9Sstevel@tonic-gate 	case 'G':
4867c478bd9Sstevel@tonic-gate 		mul *= 1024;
4877c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
4887c478bd9Sstevel@tonic-gate 	case 'm':
4897c478bd9Sstevel@tonic-gate 	case 'M':
4907c478bd9Sstevel@tonic-gate 		mul *= 1024;
4917c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
4927c478bd9Sstevel@tonic-gate 	case 'k':
4937c478bd9Sstevel@tonic-gate 	case 'K':
4947c478bd9Sstevel@tonic-gate 		mul *= 1024;
4957c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
4967c478bd9Sstevel@tonic-gate 	default:
4977c478bd9Sstevel@tonic-gate 		break;
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	errno = 0;
5017c478bd9Sstevel@tonic-gate 	val = strtoull(s, &end, 0) * mul;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	if (errno == EOVERFLOW)
5047c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_OVERFLOW));
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	if ((mul != 1 && end != &s[len - 1]) ||
5077c478bd9Sstevel@tonic-gate 	    (mul == 1 && *end != '\0') || errno != 0)
5087c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_num = val;
5117c478bd9Sstevel@tonic-gate 	return (0);
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate static int
5157c478bd9Sstevel@tonic-gate set_sig(fmd_conf_param_t *pp, const char *s)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	int sig;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	if (strncasecmp(s, "SIG", 3) == 0)
5207c478bd9Sstevel@tonic-gate 		s += 3; /* be friendlier than strsig() and permit the prefix */
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if (str2sig(s, &sig) != 0)
5237c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_INVAL));
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_num = sig;
5267c478bd9Sstevel@tonic-gate 	return (0);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate static void
5307c478bd9Sstevel@tonic-gate get_par(const fmd_conf_param_t *pp, void *ptr)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	if (fmd_conf_getprop(fmd.d_conf, pp->cp_formal->cf_default, ptr) != 0) {
5337c478bd9Sstevel@tonic-gate 		fmd_panic("fmd.d_conf does not define '%s' (inherited as %s)\n",
5347c478bd9Sstevel@tonic-gate 		    (char *)pp->cp_formal->cf_default, pp->cp_formal->cf_name);
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5397c478bd9Sstevel@tonic-gate static int
5407c478bd9Sstevel@tonic-gate set_par(fmd_conf_param_t *pp, const char *s)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate 	return (fmd_set_errno(EFMD_CONF_RDONLY));
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate  * Utility routine for callers who define custom ops where a list of string
5477c478bd9Sstevel@tonic-gate  * tokens are translated into a bitmask.  'cmp' should be set to point to an
5487c478bd9Sstevel@tonic-gate  * array of fmd_conf_mode_t's where the final element has cm_name == NULL.
5497c478bd9Sstevel@tonic-gate  */
5507c478bd9Sstevel@tonic-gate int
551d9638e54Smws fmd_conf_mode_set(const fmd_conf_mode_t *cma,
5527c478bd9Sstevel@tonic-gate     fmd_conf_param_t *pp, const char *value)
5537c478bd9Sstevel@tonic-gate {
554d9638e54Smws 	const fmd_conf_mode_t *cmp;
5557c478bd9Sstevel@tonic-gate 	char *p, *q, *s = fmd_strdup(value, FMD_SLEEP);
5567c478bd9Sstevel@tonic-gate 	size_t len = value ? strlen(value) + 1 : 0;
5577c478bd9Sstevel@tonic-gate 	uint_t mode = 0;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	if (s == NULL) {
5607c478bd9Sstevel@tonic-gate 		pp->cp_value.cpv_num = 0;
5617c478bd9Sstevel@tonic-gate 		return (0);
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	for (p = strtok_r(s, ",", &q); p != NULL; p = strtok_r(NULL, ",", &q)) {
565d9638e54Smws 		for (cmp = cma; cmp->cm_name != NULL; cmp++) {
5667c478bd9Sstevel@tonic-gate 			if (strcmp(cmp->cm_name, p) == 0) {
5677c478bd9Sstevel@tonic-gate 				mode |= cmp->cm_bits;
5687c478bd9Sstevel@tonic-gate 				break;
5697c478bd9Sstevel@tonic-gate 			}
5707c478bd9Sstevel@tonic-gate 		}
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 		if (cmp->cm_name == NULL) {
5737c478bd9Sstevel@tonic-gate 			fmd_free(s, len);
5747c478bd9Sstevel@tonic-gate 			return (fmd_set_errno(EFMD_CONF_INVAL));
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	pp->cp_value.cpv_num = mode;
5797c478bd9Sstevel@tonic-gate 	fmd_free(s, len);
5807c478bd9Sstevel@tonic-gate 	return (0);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate void
5847c478bd9Sstevel@tonic-gate fmd_conf_mode_get(const fmd_conf_param_t *pp, void *ptr)
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate 	*((uint_t *)ptr) = (uint_t)pp->cp_value.cpv_num;
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5907c478bd9Sstevel@tonic-gate int
5917c478bd9Sstevel@tonic-gate fmd_conf_notsup(fmd_conf_param_t *pp, const char *value)
5927c478bd9Sstevel@tonic-gate {
5937c478bd9Sstevel@tonic-gate 	return (fmd_set_errno(ENOTSUP));
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5977c478bd9Sstevel@tonic-gate void
5987c478bd9Sstevel@tonic-gate fmd_conf_nop(fmd_conf_param_t *pp)
5997c478bd9Sstevel@tonic-gate {
6007c478bd9Sstevel@tonic-gate 	/* no free required for integer-type parameters */
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate #define	CONF_DEFINE(name, a, b, c, d) \
6047c478bd9Sstevel@tonic-gate 	const fmd_conf_ops_t name = { a, b, c, d }
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_bool, set_bool, get_bool, fmd_conf_notsup, fmd_conf_nop);
607d9638e54Smws CONF_DEFINE(fmd_conf_int8, set_i8, get_i32, fmd_conf_notsup, fmd_conf_nop);
608d9638e54Smws CONF_DEFINE(fmd_conf_uint8, set_ui8, get_ui32, fmd_conf_notsup, fmd_conf_nop);
609d9638e54Smws CONF_DEFINE(fmd_conf_int16, set_i16, get_i32, fmd_conf_notsup, fmd_conf_nop);
610d9638e54Smws CONF_DEFINE(fmd_conf_uint16, set_ui16, get_ui32, fmd_conf_notsup, fmd_conf_nop);
6117c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_int32, set_i32, get_i32, fmd_conf_notsup, fmd_conf_nop);
6127c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_uint32, set_ui32, get_ui32, fmd_conf_notsup, fmd_conf_nop);
6137c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_int64, set_i64, get_i64, fmd_conf_notsup, fmd_conf_nop);
6147c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_uint64, set_ui64, get_ui64, fmd_conf_notsup, fmd_conf_nop);
6157c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_string, set_str, get_str, fmd_conf_notsup, free_str);
6167c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_path, set_path, get_path, fmd_conf_notsup, free_path);
6177c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_list, set_lst, get_path, del_lst, free_path);
6187c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_time, set_time, get_ui64, fmd_conf_notsup, fmd_conf_nop);
6197c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_size, set_size, get_ui64, fmd_conf_notsup, fmd_conf_nop);
6207c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_signal, set_sig, get_i32, fmd_conf_notsup, fmd_conf_nop);
6217c478bd9Sstevel@tonic-gate CONF_DEFINE(fmd_conf_parent, set_par, get_par, fmd_conf_notsup, fmd_conf_nop);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate static char *
6247c478bd9Sstevel@tonic-gate fmd_conf_skipstr(char *s)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate 	int c;
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	while ((c = *s) != '\0') {
6297c478bd9Sstevel@tonic-gate 		if (c == '\\')
6307c478bd9Sstevel@tonic-gate 			s++;
6317c478bd9Sstevel@tonic-gate 		else if (c == '"')
6327c478bd9Sstevel@tonic-gate 			break;
6337c478bd9Sstevel@tonic-gate 		s++;
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	return (s);
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate static char *
6407c478bd9Sstevel@tonic-gate fmd_conf_skipnws(char *s)
6417c478bd9Sstevel@tonic-gate {
6427c478bd9Sstevel@tonic-gate 	while (strchr("\f\n\r\t\v ", *s) == NULL)
6437c478bd9Sstevel@tonic-gate 		s++;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	return (s);
6467c478bd9Sstevel@tonic-gate }
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate static int
6497c478bd9Sstevel@tonic-gate fmd_conf_tokenize(char *s, char *tokv[])
6507c478bd9Sstevel@tonic-gate {
6517c478bd9Sstevel@tonic-gate 	int c, tokc = 0;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	while ((c = *s) != '\0') {
6547c478bd9Sstevel@tonic-gate 		switch (c) {
6557c478bd9Sstevel@tonic-gate 		case '"':
6567c478bd9Sstevel@tonic-gate 			tokv[tokc] = s + 1;
6577c478bd9Sstevel@tonic-gate 			s = fmd_conf_skipstr(s + 1);
6587c478bd9Sstevel@tonic-gate 			*s++ = '\0';
6597c478bd9Sstevel@tonic-gate 			(void) fmd_stresc2chr(tokv[tokc++]);
6607c478bd9Sstevel@tonic-gate 			continue;
6617c478bd9Sstevel@tonic-gate 		case '\f': case '\n': case '\r':
6627c478bd9Sstevel@tonic-gate 		case '\t': case '\v': case ' ':
6637c478bd9Sstevel@tonic-gate 			s++;
6647c478bd9Sstevel@tonic-gate 			continue;
6657c478bd9Sstevel@tonic-gate 		default:
6667c478bd9Sstevel@tonic-gate 			tokv[tokc++] = s;
6677c478bd9Sstevel@tonic-gate 			s = fmd_conf_skipnws(s);
6687c478bd9Sstevel@tonic-gate 			*s++ = '\0';
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	return (tokc);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate static int
6767c478bd9Sstevel@tonic-gate fmd_conf_exec_setprop(fmd_conf_t *cfp, int argc, char *argv[])
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	if (argc != 2)
6797c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_USAGE));
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	return (fmd_conf_setprop(cfp, argv[0], argv[1]));
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate static int
6857c478bd9Sstevel@tonic-gate fmd_conf_exec_subscribe(fmd_conf_t *cfp, int argc, char *argv[])
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate 	if (argc != 1)
6887c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_USAGE));
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	return (fmd_conf_setprop(cfp, FMD_PROP_SUBSCRIPTIONS, argv[0]));
6917c478bd9Sstevel@tonic-gate }
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate static int
6947c478bd9Sstevel@tonic-gate fmd_conf_exec_dictionary(fmd_conf_t *cfp, int argc, char *argv[])
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate 	if (argc != 1)
6977c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_USAGE));
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	return (fmd_conf_setprop(cfp, FMD_PROP_DICTIONARIES, argv[0]));
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate static int
7037c478bd9Sstevel@tonic-gate fmd_conf_parse(fmd_conf_t *cfp, const char *file)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate 	static const fmd_conf_verb_t verbs[] = {
7067c478bd9Sstevel@tonic-gate 		{ "setprop", fmd_conf_exec_setprop },
7077c478bd9Sstevel@tonic-gate 		{ "subscribe", fmd_conf_exec_subscribe },
7087c478bd9Sstevel@tonic-gate 		{ "dictionary", fmd_conf_exec_dictionary },
7097c478bd9Sstevel@tonic-gate 		{ NULL, NULL }
7107c478bd9Sstevel@tonic-gate 	};
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	int line, errs = 0;
7137c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
7147c478bd9Sstevel@tonic-gate 	FILE *fp;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	if ((fp = fopen(file, "r")) == NULL) {
717*b0daa853SStephen Hanson 		if (errno == EMFILE)
718*b0daa853SStephen Hanson 			fmd_error(EFMD_EXIT, "failed to open %s: %s\n",
719*b0daa853SStephen Hanson 			    file, fmd_strerror(errno));
720*b0daa853SStephen Hanson 		else
7217c478bd9Sstevel@tonic-gate 			fmd_error(EFMD_CONF_OPEN, "failed to open %s: %s\n",
7227c478bd9Sstevel@tonic-gate 			    file, fmd_strerror(errno));
7237c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_OPEN));
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	for (line = 1; fgets(buf, sizeof (buf), fp) != NULL; line++) {
7277c478bd9Sstevel@tonic-gate 		char *tokv[sizeof (buf) / 2 + 1];
7287c478bd9Sstevel@tonic-gate 		int tokc = fmd_conf_tokenize(buf, tokv);
7297c478bd9Sstevel@tonic-gate 		const fmd_conf_verb_t *vp;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		if (tokc == 0 || tokv[0][0] == '#')
7327c478bd9Sstevel@tonic-gate 			continue; /* skip blank lines and comment lines */
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 		for (vp = verbs; vp->cv_name != NULL; vp++) {
7357c478bd9Sstevel@tonic-gate 			if (strcmp(tokv[0], vp->cv_name) == 0)
7367c478bd9Sstevel@tonic-gate 				break;
7377c478bd9Sstevel@tonic-gate 		}
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 		if (vp->cv_name == NULL) {
7407c478bd9Sstevel@tonic-gate 			fmd_error(EFMD_CONF_KEYWORD, "\"%s\", line %d: "
7417c478bd9Sstevel@tonic-gate 			    "invalid configuration file keyword: %s\n",
7427c478bd9Sstevel@tonic-gate 			    file, line, tokv[0]);
7437c478bd9Sstevel@tonic-gate 			errs++;
7447c478bd9Sstevel@tonic-gate 			continue;
7457c478bd9Sstevel@tonic-gate 		}
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 		if (vp->cv_exec(cfp, tokc - 1, tokv + 1) != 0) {
7487c478bd9Sstevel@tonic-gate 			fmd_error(errno, "\"%s\", line %d", file, line);
7497c478bd9Sstevel@tonic-gate 			errs++;
7507c478bd9Sstevel@tonic-gate 			continue;
7517c478bd9Sstevel@tonic-gate 		}
7527c478bd9Sstevel@tonic-gate 	}
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	if (ferror(fp) != 0 || fclose(fp) != 0)
7557c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_IO));
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (errs != 0)
7587c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EFMD_CONF_ERRS));
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	return (0);
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate static void
7647c478bd9Sstevel@tonic-gate fmd_conf_fill(fmd_conf_t *cfp, fmd_conf_param_t *ppbuf,
7657c478bd9Sstevel@tonic-gate     int argc, const fmd_conf_formal_t *argv, int checkid)
7667c478bd9Sstevel@tonic-gate {
7677c478bd9Sstevel@tonic-gate 	int i;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++, argv++) {
7707c478bd9Sstevel@tonic-gate 		fmd_conf_param_t *op, *pp = ppbuf + i;
7717c478bd9Sstevel@tonic-gate 		const char *name = argv->cf_name;
7727c478bd9Sstevel@tonic-gate 		ulong_t h = fmd_strhash(name) % cfp->cf_parhashlen;
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 		if (fmd_strbadid(name, checkid) != NULL) {
7757c478bd9Sstevel@tonic-gate 			fmd_error(EFMD_CONF_PROPNAME, "ignoring invalid formal "
7767c478bd9Sstevel@tonic-gate 			    "property %s\n", name);
7777c478bd9Sstevel@tonic-gate 			continue;
7787c478bd9Sstevel@tonic-gate 		}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		for (op = cfp->cf_parhash[h]; op != NULL; op = op->cp_next) {
7817c478bd9Sstevel@tonic-gate 			if (strcmp(op->cp_formal->cf_name, name) == 0) {
7827c478bd9Sstevel@tonic-gate 				fmd_error(EFMD_CONF_PROPDUP, "ignoring "
7837c478bd9Sstevel@tonic-gate 				    "duplicate formal property %s\n", name);
7847c478bd9Sstevel@tonic-gate 				break;
7857c478bd9Sstevel@tonic-gate 			}
7867c478bd9Sstevel@tonic-gate 		}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 		if (op != NULL)
7897c478bd9Sstevel@tonic-gate 			continue;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 		pp->cp_formal = argv;
7927c478bd9Sstevel@tonic-gate 		pp->cp_next = cfp->cf_parhash[h];
7937c478bd9Sstevel@tonic-gate 		cfp->cf_parhash[h] = pp;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 		if (argv->cf_default && argv->cf_ops != &fmd_conf_parent &&
7967c478bd9Sstevel@tonic-gate 		    fmd_conf_setprop(cfp, name, argv->cf_default) != 0) {
7977c478bd9Sstevel@tonic-gate 			fmd_error(EFMD_CONF_DEFAULT, "ignoring invalid default "
7987c478bd9Sstevel@tonic-gate 			    "<%s> for property %s: %s\n", argv->cf_default,
7997c478bd9Sstevel@tonic-gate 			    name, fmd_strerror(errno));
8007c478bd9Sstevel@tonic-gate 		}
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate fmd_conf_t *
805d9638e54Smws fmd_conf_open(const char *file, int argc,
806d9638e54Smws     const fmd_conf_formal_t *argv, uint_t flag)
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate 	fmd_conf_t *cfp = fmd_alloc(sizeof (fmd_conf_t), FMD_SLEEP);
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_init(&cfp->cf_lock, NULL);
8117c478bd9Sstevel@tonic-gate 	cfp->cf_argv = argv;
8127c478bd9Sstevel@tonic-gate 	cfp->cf_argc = argc;
813d9638e54Smws 	cfp->cf_flag = flag;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	cfp->cf_params = fmd_zalloc(
8167c478bd9Sstevel@tonic-gate 	    sizeof (fmd_conf_param_t) * (_fmd_conf_defc + argc), FMD_SLEEP);
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	cfp->cf_parhashlen = fmd.d_str_buckets;
8197c478bd9Sstevel@tonic-gate 	cfp->cf_parhash = fmd_zalloc(
8207c478bd9Sstevel@tonic-gate 	    sizeof (fmd_conf_param_t *) * cfp->cf_parhashlen, FMD_SLEEP);
8217c478bd9Sstevel@tonic-gate 
822d9638e54Smws 	cfp->cf_defer = NULL;
823d9638e54Smws 
8247c478bd9Sstevel@tonic-gate 	fmd_conf_fill(cfp, cfp->cf_params, _fmd_conf_defc, _fmd_conf_defv, 0);
8257c478bd9Sstevel@tonic-gate 	fmd_conf_fill(cfp, cfp->cf_params + _fmd_conf_defc, argc, argv, 1);
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	if (file != NULL && fmd_conf_parse(cfp, file) != 0) {
8287c478bd9Sstevel@tonic-gate 		fmd_conf_close(cfp);
8297c478bd9Sstevel@tonic-gate 		return (NULL);
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	return (cfp);
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate void
8367c478bd9Sstevel@tonic-gate fmd_conf_merge(fmd_conf_t *cfp, const char *file)
8377c478bd9Sstevel@tonic-gate {
8387c478bd9Sstevel@tonic-gate 	(void) fmd_conf_parse(cfp, file);
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate void
842d9638e54Smws fmd_conf_propagate(fmd_conf_t *src, fmd_conf_t *dst, const char *scope)
843d9638e54Smws {
844d9638e54Smws 	size_t len = strlen(scope);
845d9638e54Smws 	fmd_conf_defer_t *cdp;
846d9638e54Smws 
847d9638e54Smws 	(void) pthread_rwlock_rdlock(&src->cf_lock);
848d9638e54Smws 
849d9638e54Smws 	for (cdp = src->cf_defer; cdp != NULL; cdp = cdp->cd_next) {
850d9638e54Smws 		if (len == (size_t)(strchr(cdp->cd_name, ':') - cdp->cd_name) &&
851d9638e54Smws 		    strncmp(cdp->cd_name, scope, len) == 0 && fmd_conf_setprop(
852d9638e54Smws 		    dst, cdp->cd_name + len + 1, cdp->cd_value) != 0) {
853d9638e54Smws 			fmd_error(EFMD_CONF_DEFER,
854d9638e54Smws 			    "failed to apply deferred property %s to %s: %s\n",
855d9638e54Smws 			    cdp->cd_name, scope, fmd_strerror(errno));
856d9638e54Smws 		}
857d9638e54Smws 	}
858d9638e54Smws 
859d9638e54Smws 	(void) pthread_rwlock_unlock(&src->cf_lock);
860d9638e54Smws }
861d9638e54Smws 
862d9638e54Smws void
8637c478bd9Sstevel@tonic-gate fmd_conf_close(fmd_conf_t *cfp)
8647c478bd9Sstevel@tonic-gate {
8657c478bd9Sstevel@tonic-gate 	fmd_conf_param_t *pp = cfp->cf_params;
8667c478bd9Sstevel@tonic-gate 	int i, nparams = _fmd_conf_defc + cfp->cf_argc;
867d9638e54Smws 	fmd_conf_defer_t *cdp, *ndp;
868d9638e54Smws 
869d9638e54Smws 	for (cdp = cfp->cf_defer; cdp != NULL; cdp = ndp) {
870d9638e54Smws 		ndp = cdp->cd_next;
871d9638e54Smws 		fmd_strfree(cdp->cd_name);
872d9638e54Smws 		fmd_strfree(cdp->cd_value);
873d9638e54Smws 		fmd_free(cdp, sizeof (fmd_conf_defer_t));
874d9638e54Smws 	}
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	fmd_free(cfp->cf_parhash,
8777c478bd9Sstevel@tonic-gate 	    sizeof (fmd_conf_param_t *) * cfp->cf_parhashlen);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	for (i = 0; i < nparams; i++, pp++) {
8807c478bd9Sstevel@tonic-gate 		if (pp->cp_formal != NULL)
8817c478bd9Sstevel@tonic-gate 			pp->cp_formal->cf_ops->co_free(pp);
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	fmd_free(cfp->cf_params, sizeof (fmd_conf_param_t) * nparams);
8857c478bd9Sstevel@tonic-gate 	fmd_free(cfp, sizeof (fmd_conf_t));
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate static fmd_conf_param_t *
8897c478bd9Sstevel@tonic-gate fmd_conf_getparam(fmd_conf_t *cfp, const char *name)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate 	ulong_t h = fmd_strhash(name) % cfp->cf_parhashlen;
8927c478bd9Sstevel@tonic-gate 	fmd_conf_param_t *pp = cfp->cf_parhash[h];
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	ASSERT(RW_LOCK_HELD(&cfp->cf_lock));
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	for (; pp != NULL; pp = pp->cp_next) {
8977c478bd9Sstevel@tonic-gate 		if (strcmp(name, pp->cp_formal->cf_name) == 0)
8987c478bd9Sstevel@tonic-gate 			return (pp);
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	return (NULL);
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate 
9047aec1d6eScindi /*
9057aec1d6eScindi  * String-friendly version of fmd_conf_getprop(): return the string as our
9067aec1d6eScindi  * return value, and return NULL if the string is the empty string.
9077aec1d6eScindi  */
9087aec1d6eScindi const char *
9097aec1d6eScindi fmd_conf_getnzstr(fmd_conf_t *cfp, const char *name)
9107aec1d6eScindi {
9117aec1d6eScindi 	const fmd_conf_param_t *pp;
9127aec1d6eScindi 	char *s = NULL;
9137aec1d6eScindi 
9147aec1d6eScindi 	(void) pthread_rwlock_rdlock(&cfp->cf_lock);
9157aec1d6eScindi 
9167aec1d6eScindi 	if ((pp = fmd_conf_getparam(cfp, name)) != NULL) {
9177aec1d6eScindi 		ASSERT(pp->cp_formal->cf_ops == &fmd_conf_string);
9187aec1d6eScindi 		pp->cp_formal->cf_ops->co_get(pp, &s);
9197aec1d6eScindi 	} else
9207aec1d6eScindi 		(void) fmd_set_errno(EFMD_CONF_NOPROP);
9217aec1d6eScindi 
9227aec1d6eScindi 	(void) pthread_rwlock_unlock(&cfp->cf_lock);
9237aec1d6eScindi 
9247aec1d6eScindi 	if (s != NULL && s[0] == '\0') {
9257aec1d6eScindi 		(void) fmd_set_errno(EFMD_CONF_UNDEF);
9267aec1d6eScindi 		s = NULL;
9277aec1d6eScindi 	}
9287aec1d6eScindi 
9297aec1d6eScindi 	return (s);
9307aec1d6eScindi }
9317aec1d6eScindi 
9327c478bd9Sstevel@tonic-gate const fmd_conf_ops_t *
9337c478bd9Sstevel@tonic-gate fmd_conf_gettype(fmd_conf_t *cfp, const char *name)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate 	const fmd_conf_param_t *pp;
9367c478bd9Sstevel@tonic-gate 	const fmd_conf_ops_t *ops = NULL;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&cfp->cf_lock);
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	if ((pp = fmd_conf_getparam(cfp, name)) != NULL) {
9417c478bd9Sstevel@tonic-gate 		if ((ops = pp->cp_formal->cf_ops) == &fmd_conf_parent) {
9427c478bd9Sstevel@tonic-gate 			ops = fmd_conf_gettype(fmd.d_conf,
9437c478bd9Sstevel@tonic-gate 			    pp->cp_formal->cf_default);
9447c478bd9Sstevel@tonic-gate 		}
9457c478bd9Sstevel@tonic-gate 	} else
9467c478bd9Sstevel@tonic-gate 		(void) fmd_set_errno(EFMD_CONF_NOPROP);
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&cfp->cf_lock);
9497c478bd9Sstevel@tonic-gate 	return (ops);
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate int
9537c478bd9Sstevel@tonic-gate fmd_conf_getprop(fmd_conf_t *cfp, const char *name, void *data)
9547c478bd9Sstevel@tonic-gate {
9557c478bd9Sstevel@tonic-gate 	const fmd_conf_param_t *pp;
9567c478bd9Sstevel@tonic-gate 	int err = 0;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&cfp->cf_lock);
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	if ((pp = fmd_conf_getparam(cfp, name)) != NULL)
9617c478bd9Sstevel@tonic-gate 		pp->cp_formal->cf_ops->co_get(pp, data);
9627c478bd9Sstevel@tonic-gate 	else
9637c478bd9Sstevel@tonic-gate 		err = fmd_set_errno(EFMD_CONF_NOPROP);
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&cfp->cf_lock);
9667c478bd9Sstevel@tonic-gate 	return (err);
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate 
969d9638e54Smws static int
970d9638e54Smws fmd_conf_setdefer(fmd_conf_t *cfp, const char *name, const char *value)
971d9638e54Smws {
972d9638e54Smws 	fmd_conf_defer_t *cdp;
973d9638e54Smws 
974d9638e54Smws 	if (!(cfp->cf_flag & FMD_CONF_DEFER))
975d9638e54Smws 		return (fmd_set_errno(EFMD_CONF_NODEFER));
976d9638e54Smws 
977d9638e54Smws 	(void) pthread_rwlock_wrlock(&cfp->cf_lock);
978d9638e54Smws 
979d9638e54Smws 	for (cdp = cfp->cf_defer; cdp != NULL; cdp = cdp->cd_next) {
980d9638e54Smws 		if (strcmp(name, cdp->cd_name) == 0) {
981d9638e54Smws 			fmd_strfree(cdp->cd_value);
982d9638e54Smws 			cdp->cd_value = fmd_strdup(value, FMD_SLEEP);
983d9638e54Smws 			goto out;
984d9638e54Smws 		}
985d9638e54Smws 	}
986d9638e54Smws 
987d9638e54Smws 	cdp = fmd_alloc(sizeof (fmd_conf_defer_t), FMD_SLEEP);
988d9638e54Smws 
989d9638e54Smws 	cdp->cd_name = fmd_strdup(name, FMD_SLEEP);
990d9638e54Smws 	cdp->cd_value = fmd_strdup(value, FMD_SLEEP);
991d9638e54Smws 	cdp->cd_next = cfp->cf_defer;
992d9638e54Smws 
993d9638e54Smws 	cfp->cf_defer = cdp;
994d9638e54Smws out:
995d9638e54Smws 	(void) pthread_rwlock_unlock(&cfp->cf_lock);
996d9638e54Smws 	return (0);
997d9638e54Smws }
998d9638e54Smws 
9997c478bd9Sstevel@tonic-gate int
10007c478bd9Sstevel@tonic-gate fmd_conf_setprop(fmd_conf_t *cfp, const char *name, const char *value)
10017c478bd9Sstevel@tonic-gate {
10027c478bd9Sstevel@tonic-gate 	fmd_conf_param_t *pp;
10037c478bd9Sstevel@tonic-gate 	int err;
10047c478bd9Sstevel@tonic-gate 
1005d9638e54Smws 	if (strchr(name, ':') != NULL)
1006d9638e54Smws 		return (fmd_conf_setdefer(cfp, name, value));
1007d9638e54Smws 
10087c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_wrlock(&cfp->cf_lock);
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	if ((pp = fmd_conf_getparam(cfp, name)) != NULL)
10117c478bd9Sstevel@tonic-gate 		err = pp->cp_formal->cf_ops->co_set(pp, value);
10127c478bd9Sstevel@tonic-gate 	else
10137c478bd9Sstevel@tonic-gate 		err = fmd_set_errno(EFMD_CONF_NOPROP);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&cfp->cf_lock);
10167c478bd9Sstevel@tonic-gate 	return (err);
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate int
10207c478bd9Sstevel@tonic-gate fmd_conf_delprop(fmd_conf_t *cfp, const char *name, const char *value)
10217c478bd9Sstevel@tonic-gate {
10227c478bd9Sstevel@tonic-gate 	fmd_conf_param_t *pp;
10237c478bd9Sstevel@tonic-gate 	int err;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_wrlock(&cfp->cf_lock);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	if ((pp = fmd_conf_getparam(cfp, name)) != NULL)
10287c478bd9Sstevel@tonic-gate 		err = pp->cp_formal->cf_ops->co_del(pp, value);
10297c478bd9Sstevel@tonic-gate 	else
10307c478bd9Sstevel@tonic-gate 		err = fmd_set_errno(EFMD_CONF_NOPROP);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&cfp->cf_lock);
10337c478bd9Sstevel@tonic-gate 	return (err);
10347c478bd9Sstevel@tonic-gate }
1035