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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
37 #include <fmd_alloc.h>
38 #include <fmd_error.h>
40 #include <fmd_string.h>
43 const char FMD_PROP_SUBSCRIPTIONS
[] = "_subscriptions";
44 const char FMD_PROP_DICTIONARIES
[] = "_dictionaries";
47 * The property formals defined in _fmd_conf_defv[] are added to every config
48 * dictionary that is created. Here we define several special FMD_PROP_*
49 * properties that are used to implement the config file keyword actions, as
50 * well as properties that should be inherited by fmd_conf_t's from fmd.d_conf.
52 static const fmd_conf_formal_t _fmd_conf_defv
[] = {
53 { FMD_PROP_SUBSCRIPTIONS
, &fmd_conf_list
, "" },
54 { FMD_PROP_DICTIONARIES
, &fmd_conf_list
, "" },
55 { "fmd.isaname", &fmd_conf_parent
, "isaname" },
56 { "fmd.machine", &fmd_conf_parent
, "machine" },
57 { "fmd.platform", &fmd_conf_parent
, "platform" },
58 { "fmd.rootdir", &fmd_conf_parent
, "rootdir" },
61 static const int _fmd_conf_defc
=
62 sizeof (_fmd_conf_defv
) / sizeof (_fmd_conf_defv
[0]);
65 set_bool(fmd_conf_param_t
*pp
, const char *s
)
67 if (strcasecmp(s
, "true") == 0)
68 pp
->cp_value
.cpv_num
= 1;
69 else if (strcasecmp(s
, "false") == 0)
70 pp
->cp_value
.cpv_num
= 0;
72 return (fmd_set_errno(EFMD_CONF_INVAL
));
78 get_bool(const fmd_conf_param_t
*pp
, void *ptr
)
80 *((int *)ptr
) = (int)pp
->cp_value
.cpv_num
;
84 set_i32x(fmd_conf_param_t
*pp
, const char *s
, int64_t min
, int64_t max
)
90 val
= strtoll(s
, &end
, 0);
92 if (errno
== EOVERFLOW
|| val
< min
|| val
> max
)
93 return (fmd_set_errno(EFMD_CONF_OVERFLOW
));
95 if (errno
!= 0 || end
== s
|| *end
!= '\0')
96 return (fmd_set_errno(EFMD_CONF_INVAL
));
98 pp
->cp_value
.cpv_num
= val
;
103 set_i8(fmd_conf_param_t
*pp
, const char *s
)
105 return (set_i32x(pp
, s
, INT8_MIN
, INT8_MAX
));
109 set_i16(fmd_conf_param_t
*pp
, const char *s
)
111 return (set_i32x(pp
, s
, INT16_MIN
, INT16_MAX
));
115 set_i32(fmd_conf_param_t
*pp
, const char *s
)
117 return (set_i32x(pp
, s
, INT32_MIN
, INT32_MAX
));
121 get_i32(const fmd_conf_param_t
*pp
, void *ptr
)
123 *((int32_t *)ptr
) = (int32_t)pp
->cp_value
.cpv_num
;
127 set_ui32x(fmd_conf_param_t
*pp
, const char *s
, uint64_t max
)
133 val
= strtoull(s
, &end
, 0);
135 if (errno
== EOVERFLOW
|| val
> max
)
136 return (fmd_set_errno(EFMD_CONF_OVERFLOW
));
138 if (errno
!= 0 || end
== s
|| *end
!= '\0')
139 return (fmd_set_errno(EFMD_CONF_INVAL
));
141 pp
->cp_value
.cpv_num
= val
;
146 set_ui8(fmd_conf_param_t
*pp
, const char *s
)
148 return (set_ui32x(pp
, s
, UINT8_MAX
));
152 set_ui16(fmd_conf_param_t
*pp
, const char *s
)
154 return (set_ui32x(pp
, s
, UINT16_MAX
));
158 set_ui32(fmd_conf_param_t
*pp
, const char *s
)
160 return (set_ui32x(pp
, s
, UINT32_MAX
));
164 get_ui32(const fmd_conf_param_t
*pp
, void *ptr
)
166 *((uint32_t *)ptr
) = (uint32_t)pp
->cp_value
.cpv_num
;
170 set_i64(fmd_conf_param_t
*pp
, const char *s
)
176 val
= strtoll(s
, &end
, 0);
178 if (errno
== EOVERFLOW
)
179 return (fmd_set_errno(EFMD_CONF_OVERFLOW
));
181 if (errno
!= 0 || end
== s
|| *end
!= '\0')
182 return (fmd_set_errno(EFMD_CONF_INVAL
));
184 pp
->cp_value
.cpv_num
= val
;
189 get_i64(const fmd_conf_param_t
*pp
, void *ptr
)
191 *((int64_t *)ptr
) = (int64_t)pp
->cp_value
.cpv_num
;
195 set_ui64(fmd_conf_param_t
*pp
, const char *s
)
201 val
= strtoull(s
, &end
, 0);
203 if (errno
== EOVERFLOW
)
204 return (fmd_set_errno(EFMD_CONF_OVERFLOW
));
206 if (errno
!= 0 || end
== s
|| *end
!= '\0')
207 return (fmd_set_errno(EFMD_CONF_INVAL
));
209 pp
->cp_value
.cpv_num
= val
;
214 get_ui64(const fmd_conf_param_t
*pp
, void *ptr
)
216 *((uint64_t *)ptr
) = pp
->cp_value
.cpv_num
;
220 set_str(fmd_conf_param_t
*pp
, const char *s
)
222 fmd_strfree(pp
->cp_value
.cpv_str
);
223 pp
->cp_value
.cpv_str
= fmd_strdup(s
, FMD_SLEEP
);
228 get_str(const fmd_conf_param_t
*pp
, void *ptr
)
230 *((const char **)ptr
) = pp
->cp_value
.cpv_str
;
234 free_str(fmd_conf_param_t
*pp
)
236 fmd_strfree(pp
->cp_value
.cpv_str
);
237 pp
->cp_value
.cpv_str
= NULL
;
241 set_path(fmd_conf_param_t
*pp
, const char *value
)
243 size_t len
= strlen(value
);
244 char *s
= alloca(len
+ 1);
246 char **patv
= alloca(sizeof (char *) * len
/ 2);
249 static const char *const percent_sign
= "%";
253 static const struct fmd_conf_token
{
255 const char *const *tok_val
;
257 { 'i', &fmd
.d_platform
},
258 { 'm', &fmd
.d_machine
},
259 { 'p', &fmd
.d_isaname
},
260 { 'r', &fmd
.d_rootdir
},
261 { '%', &percent_sign
},
265 const struct fmd_conf_token
*tok
;
266 fmd_conf_path_t
*pap
;
268 pp
->cp_formal
->cf_ops
->co_free(pp
);
269 (void) strcpy(s
, value
);
271 for (p
= strtok_r(s
, ":", &q
); p
!= NULL
; p
= strtok_r(NULL
, ":", &q
))
274 pap
= fmd_alloc(sizeof (fmd_conf_path_t
), FMD_SLEEP
);
275 pap
->cpa_argv
= fmd_alloc(sizeof (char *) * patc
, FMD_SLEEP
);
276 pap
->cpa_argc
= patc
;
278 for (i
= 0; i
< patc
; i
++) {
279 for (len
= 0, p
= patv
[i
]; (c
= *p
) != '\0'; p
++, len
++) {
280 if (c
!= '%' || (c
= p
[1]) == '\0')
283 for (tok
= tokens
; tok
->tok_tag
!= 0; tok
++) {
284 if (c
== tok
->tok_tag
) {
285 len
+= strlen(*tok
->tok_val
) - 1;
292 pap
->cpa_argv
[i
] = q
= fmd_alloc(len
+ 1, FMD_SLEEP
);
295 for (p
= patv
[i
]; (c
= *p
) != '\0'; p
++) {
296 if (c
!= '%' || (c
= p
[1]) == '\0') {
301 for (tok
= tokens
; tok
->tok_tag
!= 0; tok
++) {
302 if (c
== tok
->tok_tag
) {
303 (void) strcpy(q
, *tok
->tok_val
);
310 if (tok
->tok_tag
== 0)
315 pp
->cp_value
.cpv_ptr
= pap
;
320 set_lst(fmd_conf_param_t
*pp
, const char *value
)
322 fmd_conf_path_t
*old
;
324 old
= pp
->cp_value
.cpv_ptr
;
325 pp
->cp_value
.cpv_ptr
= NULL
;
327 if (set_path(pp
, value
) != 0) {
328 pp
->cp_value
.cpv_ptr
= old
;
329 return (-1); /* errno is set for us */
333 fmd_conf_path_t
*new = pp
->cp_value
.cpv_ptr
;
334 int i
, totc
= old
->cpa_argc
+ new->cpa_argc
;
336 int new_argc
= new->cpa_argc
;
337 const char **new_argv
= new->cpa_argv
;
340 new->cpa_argv
= fmd_alloc(sizeof (char *) * totc
, FMD_SLEEP
);
342 for (i
= 0; i
< old
->cpa_argc
; i
++)
343 new->cpa_argv
[new->cpa_argc
++] = old
->cpa_argv
[i
];
345 for (i
= 0; i
< new_argc
; i
++)
346 new->cpa_argv
[new->cpa_argc
++] = new_argv
[i
];
348 ASSERT(new->cpa_argc
== totc
);
350 fmd_free(new_argv
, sizeof (char *) * new_argc
);
351 fmd_free(old
->cpa_argv
, sizeof (char *) * old
->cpa_argc
);
352 fmd_free(old
, sizeof (fmd_conf_path_t
));
359 del_lst(fmd_conf_param_t
*pp
, const char *value
)
361 fmd_conf_path_t
*pap
= pp
->cp_value
.cpv_ptr
;
362 const char **new_argv
;
365 for (i
= 0; i
< pap
->cpa_argc
; i
++) {
366 if (strcmp(pap
->cpa_argv
[i
], value
) == 0)
370 if (i
== pap
->cpa_argc
)
371 return (fmd_set_errno(ENOENT
));
373 fmd_strfree((char *)pap
->cpa_argv
[i
]);
374 pap
->cpa_argv
[i
] = NULL
;
377 new_argv
= fmd_alloc(sizeof (char *) * (pap
->cpa_argc
- 1), FMD_SLEEP
);
379 for (i
= 0; i
< pap
->cpa_argc
; i
++) {
380 if (pap
->cpa_argv
[i
] != NULL
)
381 new_argv
[new_argc
++] = pap
->cpa_argv
[i
];
384 fmd_free(pap
->cpa_argv
, sizeof (char *) * pap
->cpa_argc
);
385 pap
->cpa_argv
= new_argv
;
386 pap
->cpa_argc
= new_argc
;
392 get_path(const fmd_conf_param_t
*pp
, void *ptr
)
394 *((fmd_conf_path_t
**)ptr
) = (fmd_conf_path_t
*)pp
->cp_value
.cpv_ptr
;
398 free_path(fmd_conf_param_t
*pp
)
400 fmd_conf_path_t
*pap
= pp
->cp_value
.cpv_ptr
;
404 return; /* no value was ever set */
406 for (i
= 0; i
< pap
->cpa_argc
; i
++)
407 fmd_strfree((char *)pap
->cpa_argv
[i
]);
409 fmd_free(pap
->cpa_argv
, sizeof (char *) * pap
->cpa_argc
);
410 fmd_free(pap
, sizeof (fmd_conf_path_t
));
411 pp
->cp_value
.cpv_ptr
= NULL
;
415 set_time(fmd_conf_param_t
*pp
, const char *s
)
417 static const struct {
421 { "ns", NANOSEC
/ NANOSEC
},
422 { "nsec", NANOSEC
/ NANOSEC
},
423 { "us", NANOSEC
/ MICROSEC
},
424 { "usec", NANOSEC
/ MICROSEC
},
425 { "ms", NANOSEC
/ MILLISEC
},
426 { "msec", NANOSEC
/ MILLISEC
},
427 { "s", NANOSEC
/ SEC
},
428 { "sec", NANOSEC
/ SEC
},
429 { "m", NANOSEC
* (hrtime_t
)60 },
430 { "min", NANOSEC
* (hrtime_t
)60 },
431 { "h", NANOSEC
* (hrtime_t
)(60 * 60) },
432 { "hour", NANOSEC
* (hrtime_t
)(60 * 60) },
433 { "d", NANOSEC
* (hrtime_t
)(24 * 60 * 60) },
434 { "day", NANOSEC
* (hrtime_t
)(24 * 60 * 60) },
439 hrtime_t val
, mul
= 1;
444 val
= strtoull(s
, &end
, 0);
446 if (errno
== EOVERFLOW
)
447 return (fmd_set_errno(EFMD_CONF_OVERFLOW
));
449 if (errno
!= 0 || end
== s
)
450 return (fmd_set_errno(EFMD_CONF_INVAL
));
452 for (i
= 0; suffix
[i
].name
!= NULL
; i
++) {
453 if (strcasecmp(suffix
[i
].name
, end
) == 0) {
459 if (suffix
[i
].name
== NULL
&& *end
!= '\0')
460 return (fmd_set_errno(EFMD_CONF_INVAL
));
464 val
= NANOSEC
/ val
; /* compute val as value per sec */
468 pp
->cp_value
.cpv_num
= val
;
473 set_size(fmd_conf_param_t
*pp
, const char *s
)
475 size_t len
= strlen(s
);
476 uint64_t val
, mul
= 1;
479 switch (s
[len
- 1]) {
501 val
= strtoull(s
, &end
, 0) * mul
;
503 if (errno
== EOVERFLOW
)
504 return (fmd_set_errno(EFMD_CONF_OVERFLOW
));
506 if ((mul
!= 1 && end
!= &s
[len
- 1]) ||
507 (mul
== 1 && *end
!= '\0') || errno
!= 0)
508 return (fmd_set_errno(EFMD_CONF_INVAL
));
510 pp
->cp_value
.cpv_num
= val
;
515 set_sig(fmd_conf_param_t
*pp
, const char *s
)
519 if (strncasecmp(s
, "SIG", 3) == 0)
520 s
+= 3; /* be friendlier than strsig() and permit the prefix */
522 if (str2sig(s
, &sig
) != 0)
523 return (fmd_set_errno(EFMD_CONF_INVAL
));
525 pp
->cp_value
.cpv_num
= sig
;
530 get_par(const fmd_conf_param_t
*pp
, void *ptr
)
532 if (fmd_conf_getprop(fmd
.d_conf
, pp
->cp_formal
->cf_default
, ptr
) != 0) {
533 fmd_panic("fmd.d_conf does not define '%s' (inherited as %s)\n",
534 (char *)pp
->cp_formal
->cf_default
, pp
->cp_formal
->cf_name
);
540 set_par(fmd_conf_param_t
*pp
, const char *s
)
542 return (fmd_set_errno(EFMD_CONF_RDONLY
));
546 * Utility routine for callers who define custom ops where a list of string
547 * tokens are translated into a bitmask. 'cmp' should be set to point to an
548 * array of fmd_conf_mode_t's where the final element has cm_name == NULL.
551 fmd_conf_mode_set(const fmd_conf_mode_t
*cma
,
552 fmd_conf_param_t
*pp
, const char *value
)
554 const fmd_conf_mode_t
*cmp
;
555 char *p
, *q
, *s
= fmd_strdup(value
, FMD_SLEEP
);
556 size_t len
= value
? strlen(value
) + 1 : 0;
560 pp
->cp_value
.cpv_num
= 0;
564 for (p
= strtok_r(s
, ",", &q
); p
!= NULL
; p
= strtok_r(NULL
, ",", &q
)) {
565 for (cmp
= cma
; cmp
->cm_name
!= NULL
; cmp
++) {
566 if (strcmp(cmp
->cm_name
, p
) == 0) {
567 mode
|= cmp
->cm_bits
;
572 if (cmp
->cm_name
== NULL
) {
574 return (fmd_set_errno(EFMD_CONF_INVAL
));
578 pp
->cp_value
.cpv_num
= mode
;
584 fmd_conf_mode_get(const fmd_conf_param_t
*pp
, void *ptr
)
586 *((uint_t
*)ptr
) = (uint_t
)pp
->cp_value
.cpv_num
;
591 fmd_conf_notsup(fmd_conf_param_t
*pp
, const char *value
)
593 return (fmd_set_errno(ENOTSUP
));
598 fmd_conf_nop(fmd_conf_param_t
*pp
)
600 /* no free required for integer-type parameters */
603 #define CONF_DEFINE(name, a, b, c, d) \
604 const fmd_conf_ops_t name = { a, b, c, d }
606 CONF_DEFINE(fmd_conf_bool
, set_bool
, get_bool
, fmd_conf_notsup
, fmd_conf_nop
);
607 CONF_DEFINE(fmd_conf_int8
, set_i8
, get_i32
, fmd_conf_notsup
, fmd_conf_nop
);
608 CONF_DEFINE(fmd_conf_uint8
, set_ui8
, get_ui32
, fmd_conf_notsup
, fmd_conf_nop
);
609 CONF_DEFINE(fmd_conf_int16
, set_i16
, get_i32
, fmd_conf_notsup
, fmd_conf_nop
);
610 CONF_DEFINE(fmd_conf_uint16
, set_ui16
, get_ui32
, fmd_conf_notsup
, fmd_conf_nop
);
611 CONF_DEFINE(fmd_conf_int32
, set_i32
, get_i32
, fmd_conf_notsup
, fmd_conf_nop
);
612 CONF_DEFINE(fmd_conf_uint32
, set_ui32
, get_ui32
, fmd_conf_notsup
, fmd_conf_nop
);
613 CONF_DEFINE(fmd_conf_int64
, set_i64
, get_i64
, fmd_conf_notsup
, fmd_conf_nop
);
614 CONF_DEFINE(fmd_conf_uint64
, set_ui64
, get_ui64
, fmd_conf_notsup
, fmd_conf_nop
);
615 CONF_DEFINE(fmd_conf_string
, set_str
, get_str
, fmd_conf_notsup
, free_str
);
616 CONF_DEFINE(fmd_conf_path
, set_path
, get_path
, fmd_conf_notsup
, free_path
);
617 CONF_DEFINE(fmd_conf_list
, set_lst
, get_path
, del_lst
, free_path
);
618 CONF_DEFINE(fmd_conf_time
, set_time
, get_ui64
, fmd_conf_notsup
, fmd_conf_nop
);
619 CONF_DEFINE(fmd_conf_size
, set_size
, get_ui64
, fmd_conf_notsup
, fmd_conf_nop
);
620 CONF_DEFINE(fmd_conf_signal
, set_sig
, get_i32
, fmd_conf_notsup
, fmd_conf_nop
);
621 CONF_DEFINE(fmd_conf_parent
, set_par
, get_par
, fmd_conf_notsup
, fmd_conf_nop
);
624 fmd_conf_skipstr(char *s
)
628 while ((c
= *s
) != '\0') {
640 fmd_conf_skipnws(char *s
)
642 while (strchr("\f\n\r\t\v ", *s
) == NULL
)
649 fmd_conf_tokenize(char *s
, char *tokv
[])
653 while ((c
= *s
) != '\0') {
657 s
= fmd_conf_skipstr(s
+ 1);
659 (void) fmd_stresc2chr(tokv
[tokc
++]);
661 case '\f': case '\n': case '\r':
662 case '\t': case '\v': case ' ':
667 s
= fmd_conf_skipnws(s
);
676 fmd_conf_exec_setprop(fmd_conf_t
*cfp
, int argc
, char *argv
[])
679 return (fmd_set_errno(EFMD_CONF_USAGE
));
681 return (fmd_conf_setprop(cfp
, argv
[0], argv
[1]));
685 fmd_conf_exec_subscribe(fmd_conf_t
*cfp
, int argc
, char *argv
[])
688 return (fmd_set_errno(EFMD_CONF_USAGE
));
690 return (fmd_conf_setprop(cfp
, FMD_PROP_SUBSCRIPTIONS
, argv
[0]));
694 fmd_conf_exec_dictionary(fmd_conf_t
*cfp
, int argc
, char *argv
[])
697 return (fmd_set_errno(EFMD_CONF_USAGE
));
699 return (fmd_conf_setprop(cfp
, FMD_PROP_DICTIONARIES
, argv
[0]));
703 fmd_conf_parse(fmd_conf_t
*cfp
, const char *file
)
705 static const fmd_conf_verb_t verbs
[] = {
706 { "setprop", fmd_conf_exec_setprop
},
707 { "subscribe", fmd_conf_exec_subscribe
},
708 { "dictionary", fmd_conf_exec_dictionary
},
716 if ((fp
= fopen(file
, "r")) == NULL
) {
718 fmd_error(EFMD_EXIT
, "failed to open %s: %s\n",
719 file
, fmd_strerror(errno
));
721 fmd_error(EFMD_CONF_OPEN
, "failed to open %s: %s\n",
722 file
, fmd_strerror(errno
));
723 return (fmd_set_errno(EFMD_CONF_OPEN
));
726 for (line
= 1; fgets(buf
, sizeof (buf
), fp
) != NULL
; line
++) {
727 char *tokv
[sizeof (buf
) / 2 + 1];
728 int tokc
= fmd_conf_tokenize(buf
, tokv
);
729 const fmd_conf_verb_t
*vp
;
731 if (tokc
== 0 || tokv
[0][0] == '#')
732 continue; /* skip blank lines and comment lines */
734 for (vp
= verbs
; vp
->cv_name
!= NULL
; vp
++) {
735 if (strcmp(tokv
[0], vp
->cv_name
) == 0)
739 if (vp
->cv_name
== NULL
) {
740 fmd_error(EFMD_CONF_KEYWORD
, "\"%s\", line %d: "
741 "invalid configuration file keyword: %s\n",
742 file
, line
, tokv
[0]);
747 if (vp
->cv_exec(cfp
, tokc
- 1, tokv
+ 1) != 0) {
748 fmd_error(errno
, "\"%s\", line %d", file
, line
);
754 if (ferror(fp
) != 0 || fclose(fp
) != 0)
755 return (fmd_set_errno(EFMD_CONF_IO
));
758 return (fmd_set_errno(EFMD_CONF_ERRS
));
764 fmd_conf_fill(fmd_conf_t
*cfp
, fmd_conf_param_t
*ppbuf
,
765 int argc
, const fmd_conf_formal_t
*argv
, int checkid
)
769 for (i
= 0; i
< argc
; i
++, argv
++) {
770 fmd_conf_param_t
*op
, *pp
= ppbuf
+ i
;
771 const char *name
= argv
->cf_name
;
772 ulong_t h
= fmd_strhash(name
) % cfp
->cf_parhashlen
;
774 if (fmd_strbadid(name
, checkid
) != NULL
) {
775 fmd_error(EFMD_CONF_PROPNAME
, "ignoring invalid formal "
776 "property %s\n", name
);
780 for (op
= cfp
->cf_parhash
[h
]; op
!= NULL
; op
= op
->cp_next
) {
781 if (strcmp(op
->cp_formal
->cf_name
, name
) == 0) {
782 fmd_error(EFMD_CONF_PROPDUP
, "ignoring "
783 "duplicate formal property %s\n", name
);
791 pp
->cp_formal
= argv
;
792 pp
->cp_next
= cfp
->cf_parhash
[h
];
793 cfp
->cf_parhash
[h
] = pp
;
795 if (argv
->cf_default
&& argv
->cf_ops
!= &fmd_conf_parent
&&
796 fmd_conf_setprop(cfp
, name
, argv
->cf_default
) != 0) {
797 fmd_error(EFMD_CONF_DEFAULT
, "ignoring invalid default "
798 "<%s> for property %s: %s\n", argv
->cf_default
,
799 name
, fmd_strerror(errno
));
805 fmd_conf_open(const char *file
, int argc
,
806 const fmd_conf_formal_t
*argv
, uint_t flag
)
808 fmd_conf_t
*cfp
= fmd_alloc(sizeof (fmd_conf_t
), FMD_SLEEP
);
810 (void) pthread_rwlock_init(&cfp
->cf_lock
, NULL
);
815 cfp
->cf_params
= fmd_zalloc(
816 sizeof (fmd_conf_param_t
) * (_fmd_conf_defc
+ argc
), FMD_SLEEP
);
818 cfp
->cf_parhashlen
= fmd
.d_str_buckets
;
819 cfp
->cf_parhash
= fmd_zalloc(
820 sizeof (fmd_conf_param_t
*) * cfp
->cf_parhashlen
, FMD_SLEEP
);
822 cfp
->cf_defer
= NULL
;
824 fmd_conf_fill(cfp
, cfp
->cf_params
, _fmd_conf_defc
, _fmd_conf_defv
, 0);
825 fmd_conf_fill(cfp
, cfp
->cf_params
+ _fmd_conf_defc
, argc
, argv
, 1);
827 if (file
!= NULL
&& fmd_conf_parse(cfp
, file
) != 0) {
836 fmd_conf_merge(fmd_conf_t
*cfp
, const char *file
)
838 (void) fmd_conf_parse(cfp
, file
);
842 fmd_conf_propagate(fmd_conf_t
*src
, fmd_conf_t
*dst
, const char *scope
)
844 size_t len
= strlen(scope
);
845 fmd_conf_defer_t
*cdp
;
847 (void) pthread_rwlock_rdlock(&src
->cf_lock
);
849 for (cdp
= src
->cf_defer
; cdp
!= NULL
; cdp
= cdp
->cd_next
) {
850 if (len
== (size_t)(strchr(cdp
->cd_name
, ':') - cdp
->cd_name
) &&
851 strncmp(cdp
->cd_name
, scope
, len
) == 0 && fmd_conf_setprop(
852 dst
, cdp
->cd_name
+ len
+ 1, cdp
->cd_value
) != 0) {
853 fmd_error(EFMD_CONF_DEFER
,
854 "failed to apply deferred property %s to %s: %s\n",
855 cdp
->cd_name
, scope
, fmd_strerror(errno
));
859 (void) pthread_rwlock_unlock(&src
->cf_lock
);
863 fmd_conf_close(fmd_conf_t
*cfp
)
865 fmd_conf_param_t
*pp
= cfp
->cf_params
;
866 int i
, nparams
= _fmd_conf_defc
+ cfp
->cf_argc
;
867 fmd_conf_defer_t
*cdp
, *ndp
;
869 for (cdp
= cfp
->cf_defer
; cdp
!= NULL
; cdp
= ndp
) {
871 fmd_strfree(cdp
->cd_name
);
872 fmd_strfree(cdp
->cd_value
);
873 fmd_free(cdp
, sizeof (fmd_conf_defer_t
));
876 fmd_free(cfp
->cf_parhash
,
877 sizeof (fmd_conf_param_t
*) * cfp
->cf_parhashlen
);
879 for (i
= 0; i
< nparams
; i
++, pp
++) {
880 if (pp
->cp_formal
!= NULL
)
881 pp
->cp_formal
->cf_ops
->co_free(pp
);
884 fmd_free(cfp
->cf_params
, sizeof (fmd_conf_param_t
) * nparams
);
885 fmd_free(cfp
, sizeof (fmd_conf_t
));
888 static fmd_conf_param_t
*
889 fmd_conf_getparam(fmd_conf_t
*cfp
, const char *name
)
891 ulong_t h
= fmd_strhash(name
) % cfp
->cf_parhashlen
;
892 fmd_conf_param_t
*pp
= cfp
->cf_parhash
[h
];
894 ASSERT(RW_LOCK_HELD(&cfp
->cf_lock
));
896 for (; pp
!= NULL
; pp
= pp
->cp_next
) {
897 if (strcmp(name
, pp
->cp_formal
->cf_name
) == 0)
905 * String-friendly version of fmd_conf_getprop(): return the string as our
906 * return value, and return NULL if the string is the empty string.
909 fmd_conf_getnzstr(fmd_conf_t
*cfp
, const char *name
)
911 const fmd_conf_param_t
*pp
;
914 (void) pthread_rwlock_rdlock(&cfp
->cf_lock
);
916 if ((pp
= fmd_conf_getparam(cfp
, name
)) != NULL
) {
917 ASSERT(pp
->cp_formal
->cf_ops
== &fmd_conf_string
);
918 pp
->cp_formal
->cf_ops
->co_get(pp
, &s
);
920 (void) fmd_set_errno(EFMD_CONF_NOPROP
);
922 (void) pthread_rwlock_unlock(&cfp
->cf_lock
);
924 if (s
!= NULL
&& s
[0] == '\0') {
925 (void) fmd_set_errno(EFMD_CONF_UNDEF
);
932 const fmd_conf_ops_t
*
933 fmd_conf_gettype(fmd_conf_t
*cfp
, const char *name
)
935 const fmd_conf_param_t
*pp
;
936 const fmd_conf_ops_t
*ops
= NULL
;
938 (void) pthread_rwlock_rdlock(&cfp
->cf_lock
);
940 if ((pp
= fmd_conf_getparam(cfp
, name
)) != NULL
) {
941 if ((ops
= pp
->cp_formal
->cf_ops
) == &fmd_conf_parent
) {
942 ops
= fmd_conf_gettype(fmd
.d_conf
,
943 pp
->cp_formal
->cf_default
);
946 (void) fmd_set_errno(EFMD_CONF_NOPROP
);
948 (void) pthread_rwlock_unlock(&cfp
->cf_lock
);
953 fmd_conf_getprop(fmd_conf_t
*cfp
, const char *name
, void *data
)
955 const fmd_conf_param_t
*pp
;
958 (void) pthread_rwlock_rdlock(&cfp
->cf_lock
);
960 if ((pp
= fmd_conf_getparam(cfp
, name
)) != NULL
)
961 pp
->cp_formal
->cf_ops
->co_get(pp
, data
);
963 err
= fmd_set_errno(EFMD_CONF_NOPROP
);
965 (void) pthread_rwlock_unlock(&cfp
->cf_lock
);
970 fmd_conf_setdefer(fmd_conf_t
*cfp
, const char *name
, const char *value
)
972 fmd_conf_defer_t
*cdp
;
974 if (!(cfp
->cf_flag
& FMD_CONF_DEFER
))
975 return (fmd_set_errno(EFMD_CONF_NODEFER
));
977 (void) pthread_rwlock_wrlock(&cfp
->cf_lock
);
979 for (cdp
= cfp
->cf_defer
; cdp
!= NULL
; cdp
= cdp
->cd_next
) {
980 if (strcmp(name
, cdp
->cd_name
) == 0) {
981 fmd_strfree(cdp
->cd_value
);
982 cdp
->cd_value
= fmd_strdup(value
, FMD_SLEEP
);
987 cdp
= fmd_alloc(sizeof (fmd_conf_defer_t
), FMD_SLEEP
);
989 cdp
->cd_name
= fmd_strdup(name
, FMD_SLEEP
);
990 cdp
->cd_value
= fmd_strdup(value
, FMD_SLEEP
);
991 cdp
->cd_next
= cfp
->cf_defer
;
995 (void) pthread_rwlock_unlock(&cfp
->cf_lock
);
1000 fmd_conf_setprop(fmd_conf_t
*cfp
, const char *name
, const char *value
)
1002 fmd_conf_param_t
*pp
;
1005 if (strchr(name
, ':') != NULL
)
1006 return (fmd_conf_setdefer(cfp
, name
, value
));
1008 (void) pthread_rwlock_wrlock(&cfp
->cf_lock
);
1010 if ((pp
= fmd_conf_getparam(cfp
, name
)) != NULL
)
1011 err
= pp
->cp_formal
->cf_ops
->co_set(pp
, value
);
1013 err
= fmd_set_errno(EFMD_CONF_NOPROP
);
1015 (void) pthread_rwlock_unlock(&cfp
->cf_lock
);
1020 fmd_conf_delprop(fmd_conf_t
*cfp
, const char *name
, const char *value
)
1022 fmd_conf_param_t
*pp
;
1025 (void) pthread_rwlock_wrlock(&cfp
->cf_lock
);
1027 if ((pp
= fmd_conf_getparam(cfp
, name
)) != NULL
)
1028 err
= pp
->cp_formal
->cf_ops
->co_del(pp
, value
);
1030 err
= fmd_set_errno(EFMD_CONF_NOPROP
);
1032 (void) pthread_rwlock_unlock(&cfp
->cf_lock
);