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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <pthread.h> 30 #include <unistd.h> 31 #include <signal.h> 32 #include <inttypes.h> 33 #include <alloca.h> 34 #include <strings.h> 35 #include <stdlib.h> 36 #include <stdio.h> 37 38 #include <fmd_conf.h> 39 #include <fmd_alloc.h> 40 #include <fmd_error.h> 41 #include <fmd_subr.h> 42 #include <fmd_string.h> 43 #include <fmd.h> 44 45 const char FMD_PROP_SUBSCRIPTIONS[] = "_subscriptions"; 46 const char FMD_PROP_DICTIONARIES[] = "_dictionaries"; 47 48 /* 49 * The property formals defined in _fmd_conf_defv[] are added to every config 50 * dictionary that is created. Here we define several special FMD_PROP_* 51 * properties that are used to implement the config file keyword actions, as 52 * well as properties that should be inherited by fmd_conf_t's from fmd.d_conf. 53 */ 54 static const fmd_conf_formal_t _fmd_conf_defv[] = { 55 { FMD_PROP_SUBSCRIPTIONS, &fmd_conf_list, "" }, 56 { FMD_PROP_DICTIONARIES, &fmd_conf_list, "" }, 57 { "fmd.isaname", &fmd_conf_parent, "isaname" }, 58 { "fmd.machine", &fmd_conf_parent, "machine" }, 59 { "fmd.platform", &fmd_conf_parent, "platform" }, 60 { "fmd.rootdir", &fmd_conf_parent, "rootdir" }, 61 }; 62 63 static const int _fmd_conf_defc = 64 sizeof (_fmd_conf_defv) / sizeof (_fmd_conf_defv[0]); 65 66 static int 67 set_bool(fmd_conf_param_t *pp, const char *s) 68 { 69 if (strcasecmp(s, "true") == 0) 70 pp->cp_value.cpv_num = 1; 71 else if (strcasecmp(s, "false") == 0) 72 pp->cp_value.cpv_num = 0; 73 else 74 return (fmd_set_errno(EFMD_CONF_INVAL)); 75 76 return (0); 77 } 78 79 static void 80 get_bool(const fmd_conf_param_t *pp, void *ptr) 81 { 82 *((int *)ptr) = (int)pp->cp_value.cpv_num; 83 } 84 85 static int 86 set_i32(fmd_conf_param_t *pp, const char *s) 87 { 88 int64_t val; 89 char *end; 90 91 errno = 0; 92 val = strtoll(s, &end, 0); 93 94 if (errno == EOVERFLOW || val < INT32_MIN || val > INT32_MAX) 95 return (fmd_set_errno(EFMD_CONF_OVERFLOW)); 96 97 if (errno != 0 || end == s || *end != '\0') 98 return (fmd_set_errno(EFMD_CONF_INVAL)); 99 100 pp->cp_value.cpv_num = val; 101 return (0); 102 } 103 104 static void 105 get_i32(const fmd_conf_param_t *pp, void *ptr) 106 { 107 *((int32_t *)ptr) = (int32_t)pp->cp_value.cpv_num; 108 } 109 110 static int 111 set_ui32(fmd_conf_param_t *pp, const char *s) 112 { 113 uint64_t val; 114 char *end; 115 116 errno = 0; 117 val = strtoull(s, &end, 0); 118 119 if (errno == EOVERFLOW || val > UINT32_MAX) 120 return (fmd_set_errno(EFMD_CONF_OVERFLOW)); 121 122 if (errno != 0 || end == s || *end != '\0') 123 return (fmd_set_errno(EFMD_CONF_INVAL)); 124 125 pp->cp_value.cpv_num = val; 126 return (0); 127 } 128 129 static void 130 get_ui32(const fmd_conf_param_t *pp, void *ptr) 131 { 132 *((uint32_t *)ptr) = (uint32_t)pp->cp_value.cpv_num; 133 } 134 135 static int 136 set_i64(fmd_conf_param_t *pp, const char *s) 137 { 138 int64_t val; 139 char *end; 140 141 errno = 0; 142 val = strtoll(s, &end, 0); 143 144 if (errno == EOVERFLOW) 145 return (fmd_set_errno(EFMD_CONF_OVERFLOW)); 146 147 if (errno != 0 || end == s || *end != '\0') 148 return (fmd_set_errno(EFMD_CONF_INVAL)); 149 150 pp->cp_value.cpv_num = val; 151 return (0); 152 } 153 154 static void 155 get_i64(const fmd_conf_param_t *pp, void *ptr) 156 { 157 *((int64_t *)ptr) = (int64_t)pp->cp_value.cpv_num; 158 } 159 160 static int 161 set_ui64(fmd_conf_param_t *pp, const char *s) 162 { 163 uint64_t val; 164 char *end; 165 166 errno = 0; 167 val = strtoull(s, &end, 0); 168 169 if (errno == EOVERFLOW) 170 return (fmd_set_errno(EFMD_CONF_OVERFLOW)); 171 172 if (errno != 0 || end == s || *end != '\0') 173 return (fmd_set_errno(EFMD_CONF_INVAL)); 174 175 pp->cp_value.cpv_num = val; 176 return (0); 177 } 178 179 static void 180 get_ui64(const fmd_conf_param_t *pp, void *ptr) 181 { 182 *((uint64_t *)ptr) = pp->cp_value.cpv_num; 183 } 184 185 static int 186 set_str(fmd_conf_param_t *pp, const char *s) 187 { 188 fmd_strfree(pp->cp_value.cpv_str); 189 pp->cp_value.cpv_str = fmd_strdup(s, FMD_SLEEP); 190 return (0); 191 } 192 193 static void 194 get_str(const fmd_conf_param_t *pp, void *ptr) 195 { 196 *((const char **)ptr) = pp->cp_value.cpv_str; 197 } 198 199 static void 200 free_str(fmd_conf_param_t *pp) 201 { 202 fmd_strfree(pp->cp_value.cpv_str); 203 pp->cp_value.cpv_str = NULL; 204 } 205 206 static int 207 set_path(fmd_conf_param_t *pp, const char *value) 208 { 209 size_t len = strlen(value); 210 char *s = alloca(len + 1); 211 212 char **patv = alloca(sizeof (char *) * len / 2); 213 int patc = 0; 214 215 static const char *const percent_sign = "%"; 216 char *p, *q; 217 int c, i; 218 219 static const struct fmd_conf_token { 220 char tok_tag; 221 const char *const *tok_val; 222 } tokens[] = { 223 { 'i', &fmd.d_platform }, 224 { 'm', &fmd.d_machine }, 225 { 'p', &fmd.d_isaname }, 226 { 'r', &fmd.d_rootdir }, 227 { '%', &percent_sign }, 228 { 0, NULL } 229 }; 230 231 const struct fmd_conf_token *tok; 232 fmd_conf_path_t *pap; 233 234 pp->cp_formal->cf_ops->co_free(pp); 235 (void) strcpy(s, value); 236 237 for (p = strtok_r(s, ":", &q); p != NULL; p = strtok_r(NULL, ":", &q)) 238 patv[patc++] = p; 239 240 pap = fmd_alloc(sizeof (fmd_conf_path_t), FMD_SLEEP); 241 pap->cpa_argv = fmd_alloc(sizeof (char *) * patc, FMD_SLEEP); 242 pap->cpa_argc = patc; 243 244 for (i = 0; i < patc; i++) { 245 for (len = 0, p = patv[i]; (c = *p) != '\0'; p++, len++) { 246 if (c != '%' || (c = p[1]) == '\0') 247 continue; 248 249 for (tok = tokens; tok->tok_tag != 0; tok++) { 250 if (c == tok->tok_tag) { 251 len += strlen(*tok->tok_val) - 1; 252 p++; 253 break; 254 } 255 } 256 } 257 258 pap->cpa_argv[i] = q = fmd_alloc(len + 1, FMD_SLEEP); 259 q[len] = '\0'; 260 261 for (p = patv[i]; (c = *p) != '\0'; p++) { 262 if (c != '%' || (c = p[1]) == '\0') { 263 *q++ = c; 264 continue; 265 } 266 267 for (tok = tokens; tok->tok_tag != 0; tok++) { 268 if (c == tok->tok_tag) { 269 (void) strcpy(q, *tok->tok_val); 270 q += strlen(q); 271 p++; 272 break; 273 } 274 } 275 276 if (tok->tok_tag == 0) 277 *q++ = c; 278 } 279 } 280 281 pp->cp_value.cpv_ptr = pap; 282 return (0); 283 } 284 285 static int 286 set_lst(fmd_conf_param_t *pp, const char *value) 287 { 288 fmd_conf_path_t *old; 289 290 old = pp->cp_value.cpv_ptr; 291 pp->cp_value.cpv_ptr = NULL; 292 293 if (set_path(pp, value) != 0) { 294 pp->cp_value.cpv_ptr = old; 295 return (-1); /* errno is set for us */ 296 } 297 298 if (old != NULL) { 299 fmd_conf_path_t *new = pp->cp_value.cpv_ptr; 300 int i, totc = old->cpa_argc + new->cpa_argc; 301 302 int new_argc = new->cpa_argc; 303 const char **new_argv = new->cpa_argv; 304 305 new->cpa_argc = 0; 306 new->cpa_argv = fmd_alloc(sizeof (char *) * totc, FMD_SLEEP); 307 308 for (i = 0; i < old->cpa_argc; i++) 309 new->cpa_argv[new->cpa_argc++] = old->cpa_argv[i]; 310 311 for (i = 0; i < new_argc; i++) 312 new->cpa_argv[new->cpa_argc++] = new_argv[i]; 313 314 ASSERT(new->cpa_argc == totc); 315 316 fmd_free(new_argv, sizeof (char *) * new_argc); 317 fmd_free(old->cpa_argv, sizeof (char *) * old->cpa_argc); 318 fmd_free(old, sizeof (fmd_conf_path_t)); 319 } 320 321 return (0); 322 } 323 324 static int 325 del_lst(fmd_conf_param_t *pp, const char *value) 326 { 327 fmd_conf_path_t *pap = pp->cp_value.cpv_ptr; 328 const char **new_argv; 329 int i, new_argc; 330 331 for (i = 0; i < pap->cpa_argc; i++) { 332 if (strcmp(pap->cpa_argv[i], value) == 0) 333 break; 334 } 335 336 if (i == pap->cpa_argc) 337 return (fmd_set_errno(ENOENT)); 338 339 fmd_strfree((char *)pap->cpa_argv[i]); 340 pap->cpa_argv[i] = NULL; 341 342 new_argc = 0; 343 new_argv = fmd_alloc(sizeof (char *) * (pap->cpa_argc - 1), FMD_SLEEP); 344 345 for (i = 0; i < pap->cpa_argc; i++) { 346 if (pap->cpa_argv[i] != NULL) 347 new_argv[new_argc++] = pap->cpa_argv[i]; 348 } 349 350 fmd_free(pap->cpa_argv, sizeof (char *) * pap->cpa_argc); 351 pap->cpa_argv = new_argv; 352 pap->cpa_argc = new_argc; 353 354 return (0); 355 } 356 357 static void 358 get_path(const fmd_conf_param_t *pp, void *ptr) 359 { 360 *((fmd_conf_path_t **)ptr) = (fmd_conf_path_t *)pp->cp_value.cpv_ptr; 361 } 362 363 static void 364 free_path(fmd_conf_param_t *pp) 365 { 366 fmd_conf_path_t *pap = pp->cp_value.cpv_ptr; 367 int i; 368 369 if (pap == NULL) 370 return; /* no value was ever set */ 371 372 for (i = 0; i < pap->cpa_argc; i++) 373 fmd_strfree((char *)pap->cpa_argv[i]); 374 375 fmd_free(pap->cpa_argv, sizeof (char *) * pap->cpa_argc); 376 fmd_free(pap, sizeof (fmd_conf_path_t)); 377 pp->cp_value.cpv_ptr = NULL; 378 } 379 380 static int 381 set_time(fmd_conf_param_t *pp, const char *s) 382 { 383 static const struct { 384 const char *name; 385 hrtime_t mul; 386 } suffix[] = { 387 { "ns", NANOSEC / NANOSEC }, 388 { "nsec", NANOSEC / NANOSEC }, 389 { "us", NANOSEC / MICROSEC }, 390 { "usec", NANOSEC / MICROSEC }, 391 { "ms", NANOSEC / MILLISEC }, 392 { "msec", NANOSEC / MILLISEC }, 393 { "s", NANOSEC / SEC }, 394 { "sec", NANOSEC / SEC }, 395 { "m", NANOSEC * (hrtime_t)60 }, 396 { "min", NANOSEC * (hrtime_t)60 }, 397 { "h", NANOSEC * (hrtime_t)(60 * 60) }, 398 { "hour", NANOSEC * (hrtime_t)(60 * 60) }, 399 { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 400 { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 401 { "hz", 0 }, 402 { NULL } 403 }; 404 405 hrtime_t val, mul = 1; 406 char *end; 407 int i; 408 409 errno = 0; 410 val = strtoull(s, &end, 0); 411 412 if (errno == EOVERFLOW) 413 return (fmd_set_errno(EFMD_CONF_OVERFLOW)); 414 415 if (errno != 0 || end == s) 416 return (fmd_set_errno(EFMD_CONF_INVAL)); 417 418 for (i = 0; suffix[i].name != NULL; i++) { 419 if (strcasecmp(suffix[i].name, end) == 0) { 420 mul = suffix[i].mul; 421 break; 422 } 423 } 424 425 if (suffix[i].name == NULL && *end != '\0') 426 return (fmd_set_errno(EFMD_CONF_INVAL)); 427 428 if (mul == 0) { 429 if (val != 0) 430 val = NANOSEC / val; /* compute val as value per sec */ 431 } else 432 val *= mul; 433 434 pp->cp_value.cpv_num = val; 435 return (0); 436 } 437 438 static int 439 set_size(fmd_conf_param_t *pp, const char *s) 440 { 441 size_t len = strlen(s); 442 uint64_t val, mul = 1; 443 char *end; 444 445 switch (s[len - 1]) { 446 case 't': 447 case 'T': 448 mul *= 1024; 449 /*FALLTHRU*/ 450 case 'g': 451 case 'G': 452 mul *= 1024; 453 /*FALLTHRU*/ 454 case 'm': 455 case 'M': 456 mul *= 1024; 457 /*FALLTHRU*/ 458 case 'k': 459 case 'K': 460 mul *= 1024; 461 /*FALLTHRU*/ 462 default: 463 break; 464 } 465 466 errno = 0; 467 val = strtoull(s, &end, 0) * mul; 468 469 if (errno == EOVERFLOW) 470 return (fmd_set_errno(EFMD_CONF_OVERFLOW)); 471 472 if ((mul != 1 && end != &s[len - 1]) || 473 (mul == 1 && *end != '\0') || errno != 0) 474 return (fmd_set_errno(EFMD_CONF_INVAL)); 475 476 pp->cp_value.cpv_num = val; 477 return (0); 478 } 479 480 static int 481 set_sig(fmd_conf_param_t *pp, const char *s) 482 { 483 int sig; 484 485 if (strncasecmp(s, "SIG", 3) == 0) 486 s += 3; /* be friendlier than strsig() and permit the prefix */ 487 488 if (str2sig(s, &sig) != 0) 489 return (fmd_set_errno(EFMD_CONF_INVAL)); 490 491 pp->cp_value.cpv_num = sig; 492 return (0); 493 } 494 495 static void 496 get_par(const fmd_conf_param_t *pp, void *ptr) 497 { 498 if (fmd_conf_getprop(fmd.d_conf, pp->cp_formal->cf_default, ptr) != 0) { 499 fmd_panic("fmd.d_conf does not define '%s' (inherited as %s)\n", 500 (char *)pp->cp_formal->cf_default, pp->cp_formal->cf_name); 501 } 502 } 503 504 /*ARGSUSED*/ 505 static int 506 set_par(fmd_conf_param_t *pp, const char *s) 507 { 508 return (fmd_set_errno(EFMD_CONF_RDONLY)); 509 } 510 511 /* 512 * Utility routine for callers who define custom ops where a list of string 513 * tokens are translated into a bitmask. 'cmp' should be set to point to an 514 * array of fmd_conf_mode_t's where the final element has cm_name == NULL. 515 */ 516 int 517 fmd_conf_mode_set(const fmd_conf_mode_t *cmp, 518 fmd_conf_param_t *pp, const char *value) 519 { 520 char *p, *q, *s = fmd_strdup(value, FMD_SLEEP); 521 size_t len = value ? strlen(value) + 1 : 0; 522 uint_t mode = 0; 523 524 if (s == NULL) { 525 pp->cp_value.cpv_num = 0; 526 return (0); 527 } 528 529 for (p = strtok_r(s, ",", &q); p != NULL; p = strtok_r(NULL, ",", &q)) { 530 for (; cmp->cm_name != NULL; cmp++) { 531 if (strcmp(cmp->cm_name, p) == 0) { 532 mode |= cmp->cm_bits; 533 break; 534 } 535 } 536 537 if (cmp->cm_name == NULL) { 538 fmd_free(s, len); 539 return (fmd_set_errno(EFMD_CONF_INVAL)); 540 } 541 } 542 543 pp->cp_value.cpv_num = mode; 544 fmd_free(s, len); 545 return (0); 546 } 547 548 void 549 fmd_conf_mode_get(const fmd_conf_param_t *pp, void *ptr) 550 { 551 *((uint_t *)ptr) = (uint_t)pp->cp_value.cpv_num; 552 } 553 554 /*ARGSUSED*/ 555 int 556 fmd_conf_notsup(fmd_conf_param_t *pp, const char *value) 557 { 558 return (fmd_set_errno(ENOTSUP)); 559 } 560 561 /*ARGSUSED*/ 562 void 563 fmd_conf_nop(fmd_conf_param_t *pp) 564 { 565 /* no free required for integer-type parameters */ 566 } 567 568 #define CONF_DEFINE(name, a, b, c, d) \ 569 const fmd_conf_ops_t name = { a, b, c, d } 570 571 CONF_DEFINE(fmd_conf_bool, set_bool, get_bool, fmd_conf_notsup, fmd_conf_nop); 572 CONF_DEFINE(fmd_conf_int32, set_i32, get_i32, fmd_conf_notsup, fmd_conf_nop); 573 CONF_DEFINE(fmd_conf_uint32, set_ui32, get_ui32, fmd_conf_notsup, fmd_conf_nop); 574 CONF_DEFINE(fmd_conf_int64, set_i64, get_i64, fmd_conf_notsup, fmd_conf_nop); 575 CONF_DEFINE(fmd_conf_uint64, set_ui64, get_ui64, fmd_conf_notsup, fmd_conf_nop); 576 CONF_DEFINE(fmd_conf_string, set_str, get_str, fmd_conf_notsup, free_str); 577 CONF_DEFINE(fmd_conf_path, set_path, get_path, fmd_conf_notsup, free_path); 578 CONF_DEFINE(fmd_conf_list, set_lst, get_path, del_lst, free_path); 579 CONF_DEFINE(fmd_conf_time, set_time, get_ui64, fmd_conf_notsup, fmd_conf_nop); 580 CONF_DEFINE(fmd_conf_size, set_size, get_ui64, fmd_conf_notsup, fmd_conf_nop); 581 CONF_DEFINE(fmd_conf_signal, set_sig, get_i32, fmd_conf_notsup, fmd_conf_nop); 582 CONF_DEFINE(fmd_conf_parent, set_par, get_par, fmd_conf_notsup, fmd_conf_nop); 583 584 static char * 585 fmd_conf_skipstr(char *s) 586 { 587 int c; 588 589 while ((c = *s) != '\0') { 590 if (c == '\\') 591 s++; 592 else if (c == '"') 593 break; 594 s++; 595 } 596 597 return (s); 598 } 599 600 static char * 601 fmd_conf_skipnws(char *s) 602 { 603 while (strchr("\f\n\r\t\v ", *s) == NULL) 604 s++; 605 606 return (s); 607 } 608 609 static int 610 fmd_conf_tokenize(char *s, char *tokv[]) 611 { 612 int c, tokc = 0; 613 614 while ((c = *s) != '\0') { 615 switch (c) { 616 case '"': 617 tokv[tokc] = s + 1; 618 s = fmd_conf_skipstr(s + 1); 619 *s++ = '\0'; 620 (void) fmd_stresc2chr(tokv[tokc++]); 621 continue; 622 case '\f': case '\n': case '\r': 623 case '\t': case '\v': case ' ': 624 s++; 625 continue; 626 default: 627 tokv[tokc++] = s; 628 s = fmd_conf_skipnws(s); 629 *s++ = '\0'; 630 } 631 } 632 633 return (tokc); 634 } 635 636 static int 637 fmd_conf_exec_setprop(fmd_conf_t *cfp, int argc, char *argv[]) 638 { 639 if (argc != 2) 640 return (fmd_set_errno(EFMD_CONF_USAGE)); 641 642 return (fmd_conf_setprop(cfp, argv[0], argv[1])); 643 } 644 645 static int 646 fmd_conf_exec_subscribe(fmd_conf_t *cfp, int argc, char *argv[]) 647 { 648 if (argc != 1) 649 return (fmd_set_errno(EFMD_CONF_USAGE)); 650 651 return (fmd_conf_setprop(cfp, FMD_PROP_SUBSCRIPTIONS, argv[0])); 652 } 653 654 static int 655 fmd_conf_exec_dictionary(fmd_conf_t *cfp, int argc, char *argv[]) 656 { 657 if (argc != 1) 658 return (fmd_set_errno(EFMD_CONF_USAGE)); 659 660 return (fmd_conf_setprop(cfp, FMD_PROP_DICTIONARIES, argv[0])); 661 } 662 663 static int 664 fmd_conf_parse(fmd_conf_t *cfp, const char *file) 665 { 666 static const fmd_conf_verb_t verbs[] = { 667 { "setprop", fmd_conf_exec_setprop }, 668 { "subscribe", fmd_conf_exec_subscribe }, 669 { "dictionary", fmd_conf_exec_dictionary }, 670 { NULL, NULL } 671 }; 672 673 int line, errs = 0; 674 char buf[BUFSIZ]; 675 FILE *fp; 676 677 if ((fp = fopen(file, "r")) == NULL) { 678 fmd_error(EFMD_CONF_OPEN, "failed to open %s: %s\n", 679 file, fmd_strerror(errno)); 680 return (fmd_set_errno(EFMD_CONF_OPEN)); 681 } 682 683 for (line = 1; fgets(buf, sizeof (buf), fp) != NULL; line++) { 684 char *tokv[sizeof (buf) / 2 + 1]; 685 int tokc = fmd_conf_tokenize(buf, tokv); 686 const fmd_conf_verb_t *vp; 687 688 if (tokc == 0 || tokv[0][0] == '#') 689 continue; /* skip blank lines and comment lines */ 690 691 for (vp = verbs; vp->cv_name != NULL; vp++) { 692 if (strcmp(tokv[0], vp->cv_name) == 0) 693 break; 694 } 695 696 if (vp->cv_name == NULL) { 697 fmd_error(EFMD_CONF_KEYWORD, "\"%s\", line %d: " 698 "invalid configuration file keyword: %s\n", 699 file, line, tokv[0]); 700 errs++; 701 continue; 702 } 703 704 if (vp->cv_exec(cfp, tokc - 1, tokv + 1) != 0) { 705 fmd_error(errno, "\"%s\", line %d", file, line); 706 errs++; 707 continue; 708 } 709 } 710 711 if (ferror(fp) != 0 || fclose(fp) != 0) 712 return (fmd_set_errno(EFMD_CONF_IO)); 713 714 if (errs != 0) 715 return (fmd_set_errno(EFMD_CONF_ERRS)); 716 717 return (0); 718 } 719 720 static void 721 fmd_conf_fill(fmd_conf_t *cfp, fmd_conf_param_t *ppbuf, 722 int argc, const fmd_conf_formal_t *argv, int checkid) 723 { 724 int i; 725 726 for (i = 0; i < argc; i++, argv++) { 727 fmd_conf_param_t *op, *pp = ppbuf + i; 728 const char *name = argv->cf_name; 729 ulong_t h = fmd_strhash(name) % cfp->cf_parhashlen; 730 731 if (fmd_strbadid(name, checkid) != NULL) { 732 fmd_error(EFMD_CONF_PROPNAME, "ignoring invalid formal " 733 "property %s\n", name); 734 continue; 735 } 736 737 for (op = cfp->cf_parhash[h]; op != NULL; op = op->cp_next) { 738 if (strcmp(op->cp_formal->cf_name, name) == 0) { 739 fmd_error(EFMD_CONF_PROPDUP, "ignoring " 740 "duplicate formal property %s\n", name); 741 break; 742 } 743 } 744 745 if (op != NULL) 746 continue; 747 748 pp->cp_formal = argv; 749 pp->cp_next = cfp->cf_parhash[h]; 750 cfp->cf_parhash[h] = pp; 751 752 if (argv->cf_default && argv->cf_ops != &fmd_conf_parent && 753 fmd_conf_setprop(cfp, name, argv->cf_default) != 0) { 754 fmd_error(EFMD_CONF_DEFAULT, "ignoring invalid default " 755 "<%s> for property %s: %s\n", argv->cf_default, 756 name, fmd_strerror(errno)); 757 } 758 } 759 } 760 761 fmd_conf_t * 762 fmd_conf_open(const char *file, int argc, const fmd_conf_formal_t *argv) 763 { 764 fmd_conf_t *cfp = fmd_alloc(sizeof (fmd_conf_t), FMD_SLEEP); 765 766 (void) pthread_rwlock_init(&cfp->cf_lock, NULL); 767 cfp->cf_argv = argv; 768 cfp->cf_argc = argc; 769 770 cfp->cf_params = fmd_zalloc( 771 sizeof (fmd_conf_param_t) * (_fmd_conf_defc + argc), FMD_SLEEP); 772 773 cfp->cf_parhashlen = fmd.d_str_buckets; 774 cfp->cf_parhash = fmd_zalloc( 775 sizeof (fmd_conf_param_t *) * cfp->cf_parhashlen, FMD_SLEEP); 776 777 fmd_conf_fill(cfp, cfp->cf_params, _fmd_conf_defc, _fmd_conf_defv, 0); 778 fmd_conf_fill(cfp, cfp->cf_params + _fmd_conf_defc, argc, argv, 1); 779 780 if (file != NULL && fmd_conf_parse(cfp, file) != 0) { 781 fmd_conf_close(cfp); 782 return (NULL); 783 } 784 785 return (cfp); 786 } 787 788 void 789 fmd_conf_merge(fmd_conf_t *cfp, const char *file) 790 { 791 (void) fmd_conf_parse(cfp, file); 792 } 793 794 void 795 fmd_conf_close(fmd_conf_t *cfp) 796 { 797 fmd_conf_param_t *pp = cfp->cf_params; 798 int i, nparams = _fmd_conf_defc + cfp->cf_argc; 799 800 fmd_free(cfp->cf_parhash, 801 sizeof (fmd_conf_param_t *) * cfp->cf_parhashlen); 802 803 for (i = 0; i < nparams; i++, pp++) { 804 if (pp->cp_formal != NULL) 805 pp->cp_formal->cf_ops->co_free(pp); 806 } 807 808 fmd_free(cfp->cf_params, sizeof (fmd_conf_param_t) * nparams); 809 fmd_free(cfp, sizeof (fmd_conf_t)); 810 } 811 812 static fmd_conf_param_t * 813 fmd_conf_getparam(fmd_conf_t *cfp, const char *name) 814 { 815 ulong_t h = fmd_strhash(name) % cfp->cf_parhashlen; 816 fmd_conf_param_t *pp = cfp->cf_parhash[h]; 817 818 ASSERT(RW_LOCK_HELD(&cfp->cf_lock)); 819 820 for (; pp != NULL; pp = pp->cp_next) { 821 if (strcmp(name, pp->cp_formal->cf_name) == 0) 822 return (pp); 823 } 824 825 return (NULL); 826 } 827 828 const fmd_conf_ops_t * 829 fmd_conf_gettype(fmd_conf_t *cfp, const char *name) 830 { 831 const fmd_conf_param_t *pp; 832 const fmd_conf_ops_t *ops = NULL; 833 834 (void) pthread_rwlock_rdlock(&cfp->cf_lock); 835 836 if ((pp = fmd_conf_getparam(cfp, name)) != NULL) { 837 if ((ops = pp->cp_formal->cf_ops) == &fmd_conf_parent) { 838 ops = fmd_conf_gettype(fmd.d_conf, 839 pp->cp_formal->cf_default); 840 } 841 } else 842 (void) fmd_set_errno(EFMD_CONF_NOPROP); 843 844 (void) pthread_rwlock_unlock(&cfp->cf_lock); 845 return (ops); 846 } 847 848 int 849 fmd_conf_getprop(fmd_conf_t *cfp, const char *name, void *data) 850 { 851 const fmd_conf_param_t *pp; 852 int err = 0; 853 854 (void) pthread_rwlock_rdlock(&cfp->cf_lock); 855 856 if ((pp = fmd_conf_getparam(cfp, name)) != NULL) 857 pp->cp_formal->cf_ops->co_get(pp, data); 858 else 859 err = fmd_set_errno(EFMD_CONF_NOPROP); 860 861 (void) pthread_rwlock_unlock(&cfp->cf_lock); 862 return (err); 863 } 864 865 int 866 fmd_conf_setprop(fmd_conf_t *cfp, const char *name, const char *value) 867 { 868 fmd_conf_param_t *pp; 869 int err; 870 871 (void) pthread_rwlock_wrlock(&cfp->cf_lock); 872 873 if ((pp = fmd_conf_getparam(cfp, name)) != NULL) 874 err = pp->cp_formal->cf_ops->co_set(pp, value); 875 else 876 err = fmd_set_errno(EFMD_CONF_NOPROP); 877 878 (void) pthread_rwlock_unlock(&cfp->cf_lock); 879 return (err); 880 } 881 882 int 883 fmd_conf_delprop(fmd_conf_t *cfp, const char *name, const char *value) 884 { 885 fmd_conf_param_t *pp; 886 int err; 887 888 (void) pthread_rwlock_wrlock(&cfp->cf_lock); 889 890 if ((pp = fmd_conf_getparam(cfp, name)) != NULL) 891 err = pp->cp_formal->cf_ops->co_del(pp, value); 892 else 893 err = fmd_set_errno(EFMD_CONF_NOPROP); 894 895 (void) pthread_rwlock_unlock(&cfp->cf_lock); 896 return (err); 897 } 898