1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 28 #include <sys/types.h> 29 #include <sys/wait.h> 30 #include <stdio.h> 31 #include <sys/mnttab.h> 32 #include <sys/vtoc.h> 33 #include <errno.h> 34 #include <limits.h> 35 #include <fcntl.h> 36 #include <string.h> 37 #include <stdarg.h> 38 #include <strings.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <sys/mman.h> 42 #include <sys/stat.h> 43 44 #include <locale.h> 45 #include <langinfo.h> 46 #include <libintl.h> 47 #include <stdarg.h> 48 #include <netdb.h> 49 #include <ctype.h> 50 #include <sys/stat.h> 51 #include <sys/utsname.h> 52 53 #include "cfg_impl.h" 54 #include "cfg.h" 55 #include "cfg_lockd.h" 56 57 #if 0 58 #define DEBUG_CFGLIST 59 #define DEBUG_EXTRA 60 #define DEBUG_LIB 61 #define DEBUG_NOISY 62 #define DEBUG_OUT 63 #endif 64 65 #define MAX_CFG 16 /* Max. number of lines in /etc/dscfg_format */ 66 #define MAX_SET 12 /* number of chars in a set name */ 67 68 69 /* parser tree for config section */ 70 static struct parser chead[MAX_CFG] = { NULL }; 71 static int chead_loaded = 0; 72 static char config_file[CFG_MAX_BUF]; 73 static char dectohex[] = { '0', '1', '2', '3', '4', '5', '6', '7', 74 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 75 #define CHARS_TO_ENCODE "=;\t " 76 #define min(a, b) ((a) > (b) ? (b) : (a)) 77 78 /* field to be sorted on in sorting routines */ 79 static struct sortby_s { 80 char section[CFG_MAX_KEY]; 81 char field[CFG_MAX_KEY]; 82 int offset; 83 int comperror; 84 } sortby; 85 86 int cfg_severity = 0; 87 char *cfg_perror_str; 88 static int cfg_read(cfp_t *); 89 static void cfg_read_parser_config(cfp_t *); 90 static int cfg_rdlock(CFGFILE *); 91 static int cfg_wrlock(CFGFILE *); 92 static int cfg_lockd; 93 void cfg_replace_lists(cfp_t *); 94 void cfg_free_parser_tree(); 95 void cfg_invalidate_hsizes(int, const char *); 96 int cfg_map_cfglists(cfp_t *); 97 int cfg_hdrcmp(cfp_t *); 98 void cfg_free_cfglist(cfp_t *); 99 100 extern cfg_io_t *cfg_block_io_provider(void); 101 extern cfg_io_t *cfg_raw_io_provider(void); 102 extern int cl_initialized; 103 104 #ifdef DEBUG_LIB 105 static void 106 dump_status(cfp_t *cfp, char *str) 107 { 108 printf("called from %s\n", str); 109 printf(gettext("Header info:\n" 110 "\tmagic: %x\tstate: %x\n"), 111 cfp->cf_head->h_magic, cfp->cf_head->h_state); 112 printf(gettext("Parser section:\n" 113 "Start: %x\tsize: %d\toffset: %d\n"), 114 cfp->cf_mapped, cfp->cf_head->h_parsesize, 115 cfp->cf_head->h_parseoff); 116 printf(gettext("Config section:\n" 117 "Start: %x\tsize:%d\tacsize: %d\n"), 118 cfp->cf_head->h_cparse, cfp->cf_head->h_csize, 119 cfp->cf_head->h_acsize); 120 printf("\n\tccopy1: %x\tccopy2: %x\n", 121 cfp->cf_head->h_ccopy1, cfp->cf_head->h_ccopy2); 122 printf(gettext("Sequence:\n" 123 "\tseq1: %d\t\tseq2: %d\n"), 124 cfp->cf_head->h_seq1, cfp->cf_head->h_seq2); 125 } 126 #endif /* DEBUG */ 127 128 /* 129 * cfg_get_item 130 * return position from parser config given tag and field 131 */ 132 static int 133 cfg_get_item(struct parser *tbl, const char *tag, const char *field) 134 { 135 int i; 136 struct lookup *p; 137 138 for (i = 0; i < MAX_CFG; i++) { 139 /* only as many lists as defined */ 140 if (tbl[i].tag.l_word[0] == '\0') { 141 i = MAX_CFG; 142 break; 143 } 144 if (strcmp(tbl[i].tag.l_word, tag) == 0) 145 break; 146 } 147 148 /* Handle table size */ 149 if (i < MAX_CFG) { 150 p = tbl[i].fld; 151 while (p) { 152 if (strcmp(p->l_word, field) == 0) 153 return (p->l_value); 154 p = p->l_next; 155 } 156 } 157 158 /* Handle failure */ 159 return (-1); 160 } 161 162 /* 163 * cfg_get_num_flds 164 * return number of fields for given parser tag 165 */ 166 static int 167 cfg_get_num_flds(struct parser *tbl, const char *tag, int *table_index) 168 { 169 int i; 170 int pos = 0; 171 struct lookup *p; 172 173 for (i = 0; i < MAX_CFG; i++) { 174 /* only as many lists as defined */ 175 if (tbl[i].tag.l_word[0] == '\0') { 176 i = MAX_CFG; 177 break; 178 } 179 if (strcmp(tbl[i].tag.l_word, tag) == 0) { 180 *table_index = i; 181 break; 182 } 183 } 184 185 /* Handle table size */ 186 if (i < MAX_CFG) { 187 p = tbl[i].fld; 188 while (p) { 189 pos++; 190 p = p->l_next; 191 } 192 return (pos); 193 } 194 195 return (0); 196 } 197 198 /* 199 * count white space fields 200 */ 201 static int 202 cfg_cnt_flds(char *value) 203 { 204 char *ptr; 205 char buf[CFG_MAX_BUF]; 206 int flds = 0; 207 208 if ((value == NULL) || (strlen(value) >= CFG_MAX_BUF)) 209 return (0); 210 211 bzero(buf, CFG_MAX_BUF); 212 strcpy(buf, value); 213 ptr = strtok(buf, " "); 214 while (ptr) { 215 flds++; 216 ptr = strtok(NULL, " "); 217 } 218 return (flds); 219 } 220 221 /* 222 * cfg_get_parser_offset 223 * returns the index for each 224 * section of the parser.. 225 * ie. parser info for sndr is chead[3].tag.l_word 226 * this will help us find sndr quicker, as the 227 * the memory picture of the sets mimic this ordering 228 */ 229 static int 230 cfg_get_parser_offset(const char *section) 231 { 232 int i; 233 234 for (i = 0; i < MAX_CFG; i++) { 235 /* only as many lists as defined */ 236 if (chead[i].tag.l_word[0] == '\0') { 237 i = MAX_CFG; 238 break; 239 } 240 if (strcmp(chead[i].tag.l_word, section) == 0) 241 break; 242 } 243 244 /* Handle table size */ 245 if (i < MAX_CFG) 246 return (i); 247 248 /* Handle failure */ 249 cfg_perror_str = dgettext("cfg", 250 "cfg_get_parser_offset: section not found"); 251 cfg_severity = CFG_EFATAL; 252 errno = ESRCH; 253 return (-1); 254 } 255 256 /* 257 * cfg_fld_mov 258 * move fields from old buffer to new 259 * moving only specified fields 260 * concates newbuf 261 * returns fields moved 262 */ 263 static int 264 cfg_fld_mov(char *newbuf, char *oldbuf, int start, int end) 265 { 266 char buf[CFG_MAX_BUF]; 267 char *ptr; 268 int flds = 0; 269 270 bzero(buf, CFG_MAX_BUF); 271 if (oldbuf == NULL) 272 return (0); 273 274 if ((start > end) || (strlen(oldbuf) >= CFG_MAX_BUF)) { 275 return (0); 276 } 277 if (!start || !end) 278 return (-1); 279 strcpy(buf, oldbuf); 280 ptr = strtok(buf, " "); 281 while (ptr) { 282 flds++; 283 if (flds >= start && flds <= end) { 284 strcat(newbuf, ptr); 285 strcat(newbuf, " "); 286 } 287 ptr = strtok(NULL, " "); 288 } 289 290 return (flds); 291 } 292 293 /* 294 * cfg_filter_node 295 * return indication if this raw buf should be returned 296 * checks cfg->cf_node for filtering 297 * We already know that this buf meets most of our criteria 298 * find the cnode field in the buf and see if it matches 299 * returns 300 * TRUE Good entry 301 * FALSE Don't use it 302 */ 303 static int 304 cfg_filter_node(CFGFILE *cfg, struct parser *tbl, char *buf, char *tag) 305 { 306 char tmpbuf[CFG_MAX_BUF]; 307 int i = 1; 308 int fld; 309 char *ptr; 310 311 if (!cfg->cf_node) /* no filter always good */ 312 return (TRUE); 313 bzero(tmpbuf, CFG_MAX_BUF); 314 fld = cfg_get_item(tbl, tag, "cnode"); 315 if (fld < 0) /* no cnode field always good */ 316 return (TRUE); 317 strncpy(tmpbuf, buf, CFG_MAX_BUF); 318 if (tmpbuf[CFG_MAX_BUF - 1] != '\0') 319 return (FALSE); 320 ptr = strtok(tmpbuf, " "); 321 while (ptr && (i < fld)) { 322 ptr = strtok(NULL, " "); 323 i++; 324 } 325 if (!ptr) 326 return (FALSE); 327 #ifdef DEBUG_EXTRA 328 (void) fprintf(stderr, "cfg_filter_node: node=%s:%d cnode=%s:%d\n", 329 cfg->cf_node, strlen(cfg->cf_node), ptr, strlen(ptr)); 330 #endif 331 if (strcmp(ptr, cfg->cf_node) == 0) 332 return (TRUE); 333 return (FALSE); 334 } 335 /* 336 * cfg_insert_node 337 * insert resource in bufs which contain cnode parser field 338 */ 339 static void 340 cfg_insert_node(CFGFILE *cfg, struct parser *tbl, char *buf, char *tag) 341 { 342 char tmpbuf[CFG_MAX_BUF]; 343 int fld; 344 int nflds; 345 int table_index; 346 347 bzero(tmpbuf, CFG_MAX_BUF); 348 strcpy(tmpbuf, " "); 349 fld = cfg_get_item(tbl, tag, "cnode"); 350 nflds = cfg_get_num_flds(tbl, tag, &table_index); 351 if ((fld < 0) && !(cfg->cf_node)) /* no cnode field always good */ 352 return; 353 354 cfg_fld_mov(tmpbuf, buf, 1, (fld - 1)); 355 if (cfg->cf_node) 356 strcat(tmpbuf, cfg->cf_node); 357 else 358 strcat(tmpbuf, "-"); 359 strcat(tmpbuf, " "); 360 cfg_fld_mov(tmpbuf, buf, (fld + 1), nflds); 361 bcopy(tmpbuf, buf, strlen(tmpbuf) + 1); 362 } 363 364 /* 365 * cfg_is_cnode 366 * Parser current buffer to see if a non-empty " - " cnode exists 367 */ 368 /*ARGSUSED*/ 369 static int 370 cfg_is_cnode(CFGFILE *cfg, struct parser *tbl, char *buf, char *tag) 371 { 372 char tmpbuf[CFG_MAX_BUF]; 373 int fld = cfg_get_item(tbl, tag, "cnode"); 374 375 if (fld >= 0) { 376 tmpbuf[0] = '\0'; 377 cfg_fld_mov(tmpbuf, buf, fld, fld); 378 return (strcmp(tmpbuf, "- ") ? TRUE : FALSE); 379 } 380 return (FALSE); 381 } 382 /* 383 * cfg_get_cstring 384 * key determines section and value 385 * special considerations: 386 * AA.BB.CC... 387 * AA = data service tag 388 * BB = set number relative to first set (1..n) 389 * CC = field of set or if absent, all 390 */ 391 int 392 cfg_get_cstring(CFGFILE *cfg, const char *key, void *value, int value_len) 393 { 394 cfp_t *cfp; 395 char buf[CFG_MAX_BUF]; 396 char tmpkey[CFG_MAX_KEY]; 397 char *section; 398 char set[MAX_SET]; 399 char *setp; 400 char *itemp; 401 char *p; 402 int pos = 1; 403 int setnum; 404 int relnum; 405 int secnum; 406 int numfound; 407 int needed; 408 int table_offset; 409 410 if (cfg == NULL) { 411 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 412 cfg_severity = CFG_EFATAL; 413 return (-1); 414 } 415 416 if (!cfg_rdlock(cfg)) { 417 cfg_perror_str = dgettext("cfg", CFG_NOTLOCKED); 418 cfg_severity = CFG_EFATAL; 419 return (-1); 420 } 421 422 bzero(buf, sizeof (buf)); 423 bzero(set, sizeof (set)); 424 bzero(tmpkey, sizeof (tmpkey)); 425 strcpy(tmpkey, key); 426 section = strtok(tmpkey, "."); 427 setp = strtok(NULL, "."); 428 itemp = strtok(NULL, "."); 429 430 #ifdef DEBUG_EXTRA 431 if (!itemp) 432 (void) fprintf(stderr, "cfg_get_cstring:section:%s setp=%s\n", 433 section, setp); 434 else 435 (void) fprintf(stderr, 436 "cfg_get_cstring:section:%s setp=%s fld=%s\n", 437 section, setp, itemp); 438 #endif 439 440 table_offset = cfg_get_parser_offset(section); 441 setnum = atoi(setp + 3); 442 if ((setnum < 1) || (setnum > 0x7ffd)) { 443 errno = EINVAL; 444 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 445 cfg_severity = CFG_ENONFATAL; 446 return (-1); 447 } 448 449 /* 450 * we have to figure out where this set is 451 * in relation to other sets 452 */ 453 relnum = 1; 454 secnum = 0; 455 numfound = 0; 456 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 457 if (!cfp->cf_fd) continue; 458 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 459 if (!cfg_read(cfp)) { 460 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 461 cfg_severity = CFG_EFATAL; 462 return (-1); 463 } 464 } 465 while (numfound < setnum) { 466 if ((*cfp->cf_pp->readcf) 467 (cfp, buf, table_offset, relnum - secnum) == NULL) { 468 secnum = relnum - 1; 469 break; 470 } 471 if (cfg_filter_node(cfg, &chead[0], buf, section)) 472 numfound++; 473 474 if (numfound == setnum) 475 break; 476 477 relnum++; 478 } 479 if (numfound == setnum) 480 break; 481 } 482 483 /* Fail to find anything? */ 484 if (cfp >= &cfg->cf[2]) { 485 errno = ESRCH; 486 cfg_perror_str = dgettext("cfg", strerror(errno)); 487 cfg_severity = CFG_ENONFATAL; 488 return (-1); 489 } 490 491 if (buf) { 492 if (!itemp) { 493 strncpy(value, buf, value_len); 494 return (0); 495 } 496 497 if (itemp) { 498 needed = cfg_get_item(&chead[0], section, itemp); 499 p = strtok(buf, " "); 500 while (p) { 501 if (needed == pos) { 502 errno = 0; 503 if (*p == '-') { 504 strcpy(value, ""); 505 return (0); 506 } 507 else 508 if (strlen(p) > value_len) { 509 errno = E2BIG; 510 cfg_perror_str = 511 dgettext("cfg", 512 strerror(errno)); 513 cfg_severity = 514 CFG_ENONFATAL; 515 return (-1); 516 } 517 518 strncpy(value, p, value_len); 519 520 return (pos); 521 } 522 p = strtok(NULL, " "); 523 if (!p) 524 break; 525 pos++; 526 } 527 } 528 } 529 errno = ESRCH; 530 cfg_perror_str = dgettext("cfg", strerror(errno)); 531 cfg_severity = CFG_ENONFATAL; 532 return (-1); 533 } 534 535 /* 536 * cfg_find_cstring() 537 * search for a string in the specified section 538 * in the specified field(s) 539 * if nfld is 0, then the string is searched for in 540 * every field of the entry 541 * the set number of the first occurence of target is returned 542 * ie. if /dev/vx/rdsk/vol10 is found in sndr.set9, 9 will be returned 543 * that is, of course, if the correct field was searched on. 544 * -1 on error 545 * 546 */ 547 int 548 cfg_find_cstring(CFGFILE *cfg, const char *target, 549 const char *section, int numflds, ...) { 550 551 char **list = NULL; 552 va_list ap; 553 char buf[CFG_MAX_BUF]; 554 char *field, *p; 555 char **fldbuf = NULL; 556 int i, j, rc; 557 int pos = 1; 558 int fieldnum; 559 int nflds; 560 int tbl_off; 561 562 if (cfg == NULL) { 563 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 564 cfg_severity = CFG_EFATAL; 565 return (-1); 566 } 567 568 if (numflds == 0) { 569 nflds = cfg_get_num_flds(&chead[0], section, &tbl_off); 570 571 } else { 572 nflds = numflds; 573 } 574 if ((fldbuf = calloc(nflds, CFG_MAX_KEY)) == NULL) { 575 cfg_perror_str = dgettext("cfg", strerror(errno)); 576 cfg_severity = CFG_EFATAL; 577 return (-1); 578 } 579 580 if (numflds == 0) { /* search the whole string */ 581 if ((rc = cfg_get_section(cfg, &list, section)) <= 0) { 582 for (i = 0; i < nflds; i++) 583 free(fldbuf[i]); 584 free(fldbuf); 585 return (rc); 586 } 587 for (i = 0; i < rc; i++) { 588 bzero(buf, sizeof (buf)); 589 strcpy(buf, list[i]); 590 p = strtok(buf, " "); 591 while (p) { 592 if (strcmp(p, target) == 0) { /* we found it! */ 593 for (j = 0; j < rc; j++) 594 free(list[j]); 595 free(list); 596 for (j = 0; j < nflds; j++) 597 free(fldbuf[j]); 598 free(fldbuf); 599 return (i + 1); 600 } 601 p = strtok(NULL, " "); 602 } 603 } 604 for (i = 0; i < nflds; i++) 605 free(fldbuf[j]); 606 for (i = 0; i < rc; i++) 607 free(list[i]); 608 free(fldbuf); 609 free(list); 610 return (0); 611 } 612 613 if ((rc = cfg_get_section(cfg, &list, section)) <= 0) { 614 for (i = 0; i < nflds; i++) 615 free(fldbuf[i]); 616 free(fldbuf); 617 return (rc); 618 } 619 620 va_start(ap, numflds); 621 for (i = 0; i < numflds; i++) { 622 fldbuf[i] = strdup(va_arg(ap, char *)); 623 } 624 625 fldbuf[i] = NULL; 626 627 for (j = 0; j < numflds; j++) { 628 fieldnum = cfg_get_item(&chead[0], section, fldbuf[j]); 629 for (i = 0; i < rc; i++) { 630 bzero(buf, sizeof (buf)); 631 strcpy(buf, list[i]); 632 633 field = strtok(buf, " "); 634 pos = 1; 635 while (pos < fieldnum) { 636 field = strtok(NULL, " "); 637 pos++; 638 } 639 if (field == NULL) { 640 for (j = 0; j < numflds; j++) 641 free(fldbuf[j]); 642 for (j = 0; j < rc; j++) 643 free(list[j]); 644 free(fldbuf); 645 free(list); 646 return (-1); 647 } 648 649 if (strcmp(field, target) == 0) { 650 for (j = 0; j < numflds; j++) 651 free(fldbuf[j]); 652 for (j = 0; j < rc; j++) 653 free(list[j]); 654 free(fldbuf); 655 free(list); 656 657 return (i + 1); 658 } 659 660 } 661 662 } 663 for (i = 0; i < nflds; i++) 664 free(fldbuf[i]); 665 for (i = 0; i < rc; i++) 666 free(list[i]); 667 free(fldbuf); 668 free(list); 669 return (0); 670 } 671 672 /* 673 * cfg_put_cstring 674 * modify entry or add an entry to configuration section 675 * Key syntax supported 676 * tag Add entry (in entirely) to config 677 * tag.setn Add entry to setn If it exists overwrite old entry 678 * tag.setn.field Change field in setn 679 * value 680 * string to change 681 * NULL delete specified key 682 * 683 */ 684 685 int 686 cfg_put_cstring(CFGFILE *cfg, const char *key, void *value, int val_len) 687 { 688 cfp_t *cfp; 689 char buf[CFG_MAX_BUF]; 690 char newbuf[CFG_MAX_BUF]; 691 char *bufp; 692 char tmpkey[CFG_MAX_KEY]; 693 char *section; 694 char *setp; 695 char *itemp; 696 int nofield = 0; 697 int noset = 0; 698 int fldnum; 699 int setnum = 0; 700 int relnum; 701 int secnum; 702 int numfound; 703 int addcnode = 1; 704 int table_index; 705 int table_offset; 706 707 if (cfg == NULL) { 708 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 709 cfg_severity = CFG_EFATAL; 710 return (-1); 711 } 712 713 bzero(buf, sizeof (buf)); 714 strcpy(tmpkey, key); 715 section = strtok(tmpkey, "."); 716 setp = strtok(NULL, "."); 717 itemp = strtok(NULL, "."); 718 719 if (!cfg_wrlock(cfg)) { 720 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 721 cfg_severity = CFG_EFATAL; 722 return (-1); 723 } 724 725 if (!key) { 726 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 727 cfg_severity = CFG_ENONFATAL; 728 return (-1); 729 } 730 if (value && val_len == 0) { 731 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 732 cfg_severity = CFG_ENONFATAL; 733 return (-1); 734 } 735 if (!itemp) 736 nofield++; 737 if (!setp) 738 noset++; 739 else if (setp) { 740 setnum = atoi(setp + 3); 741 if (setnum < 1 || setnum > 0x7ffd) { 742 errno = EINVAL; 743 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 744 cfg_severity = CFG_ENONFATAL; 745 return (-1); 746 } 747 } 748 749 table_offset = cfg_get_parser_offset(section); 750 751 /* 752 * we have to figure out where this set is 753 * in relation to other sets 754 */ 755 relnum = 1; 756 secnum = 0; 757 numfound = 0; 758 759 if (setp && nofield) { 760 char tmpbuf[CFG_MAX_BUF]; 761 int rc; 762 int nflds; 763 int got; 764 765 /* 766 * Set specified but no field 767 */ 768 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 769 if (!cfp->cf_fd) continue; 770 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 771 if (!cfg_read(cfp)) { 772 cfg_perror_str = 773 dgettext("cfg", CFG_RDFAILED); 774 cfg_severity = CFG_EFATAL; 775 return (-1); 776 } 777 } 778 while (numfound < setnum) { 779 if ((*cfp->cf_pp->readcf) 780 (cfp, tmpbuf, table_offset, relnum - secnum) 781 == NULL) { 782 secnum = relnum - 1; 783 break; 784 } 785 if (cfg_filter_node(cfg, &chead[0], tmpbuf, 786 section)) 787 numfound++; 788 789 if (numfound == setnum) 790 break; 791 792 relnum++; 793 } 794 if (numfound == setnum) 795 break; 796 } 797 798 /* Fail to find anything? */ 799 if (cfp >= &cfg->cf[2]) { 800 errno = ESRCH; 801 cfg_perror_str = dgettext("cfg", strerror(errno)); 802 cfg_severity = CFG_ENONFATAL; 803 return (-1); 804 } 805 806 nflds = cfg_get_num_flds(&chead[0], section, &table_index); 807 808 if (value == NULL) { 809 /* Remove entry completely */ 810 811 if ((rc = ((*cfp->cf_pp->remcf) 812 (cfp, table_index, relnum - secnum))) < 0) 813 return (rc); 814 return (0); 815 } 816 817 got = cfg_cnt_flds(value); 818 bzero(buf, sizeof (buf)); 819 820 strncpy(buf, " ", 1); 821 if (strlen(value) > sizeof (buf) - 2) { 822 errno = E2BIG; 823 cfg_perror_str = dgettext("cfg", strerror(errno)); 824 cfg_severity = CFG_ENONFATAL; 825 return (-1); 826 } 827 strncat(buf, value, val_len); 828 if (got < nflds) { 829 for (/* CSTYLED */; got < nflds; got++) 830 strncat(buf, " - ", 3); 831 } else if (got > nflds) { 832 return (-1); 833 } else { 834 /* got == nflds, so cnode was included */ 835 addcnode = 0; 836 } 837 838 bufp = buf; 839 if (addcnode) { 840 cfg_insert_node(cfg, &chead[0], buf, section); 841 } 842 843 (*cfp->cf_pp->replacecf) 844 (cfp, bufp, table_index, relnum - secnum); 845 846 return (TRUE); 847 } 848 849 /* 850 * Both Set and field are specified 851 * needs to get current whole entry and old requested field 852 * copy good fields to buf, replace new field in buf 853 * move everything depending of new size 854 * replace entry so set# does not change 855 */ 856 if (setp && itemp) { 857 int rc; 858 int nflds; 859 int cnodepos; 860 861 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 862 if (!cfp->cf_fd) continue; 863 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 864 if (!cfg_read(cfp)) { 865 cfg_perror_str = 866 dgettext("cfg", CFG_RDFAILED); 867 cfg_severity = CFG_EFATAL; 868 return (-1); 869 } 870 } 871 while (numfound < setnum) { 872 if ((*cfp->cf_pp->readcf) 873 (cfp, buf, table_offset, relnum - secnum) 874 == NULL) { 875 secnum = relnum - 1; 876 break; 877 } 878 if (cfg_filter_node(cfg, &chead[0], buf, 879 section)) 880 numfound++; 881 882 if (numfound == setnum) 883 break; 884 885 relnum++; 886 } 887 if (numfound == setnum) 888 break; 889 } 890 891 /* Fail to find anything? */ 892 if (cfp >= &cfg->cf[2]) { 893 errno = ESRCH; 894 cfg_perror_str = dgettext("cfg", strerror(errno)); 895 cfg_severity = CFG_ENONFATAL; 896 return (-1); 897 } 898 899 nflds = cfg_get_num_flds(&chead[0], section, &table_index); 900 fldnum = cfg_get_item(&chead[0], section, itemp); 901 bzero(newbuf, sizeof (newbuf)); 902 strncpy(newbuf, " ", 1); 903 904 /* move good flds in */ 905 rc = cfg_fld_mov(newbuf, buf, 1, fldnum - 1); 906 if (rc < 0) 907 return (rc); 908 909 /* move new fld in */ 910 strncat(newbuf, value, strlen(value)); 911 strcat(newbuf, " "); 912 913 /* move remaining flds in */ 914 rc = cfg_fld_mov(newbuf, buf, fldnum + 1, nflds); 915 if (rc < 0) 916 return (rc); 917 918 cnodepos = cfg_get_item(&chead[0], section, "cnode"); 919 if ((cnodepos >= 0) && strcmp(itemp, "cnode") != 0) { 920 /* add cnode if user didn't specify it */ 921 cfg_insert_node(cfg, &chead[0], 922 newbuf, section); 923 } 924 925 (*cfp->cf_pp->replacecf) 926 (cfp, newbuf, table_index, relnum - secnum); 927 928 return (TRUE); 929 } 930 931 if (noset) { /* blast entire thing in */ 932 int nflds; 933 int got; 934 int cnodepos; 935 936 bufp = buf; 937 if (!value) { /* we shouldn't be here */ 938 errno = EINVAL; 939 return (-1); 940 } 941 strncat(buf, " ", 1); 942 if (strlen(value) > sizeof (buf) - 2) { 943 errno = E2BIG; 944 return (-1); 945 } 946 947 strncat(buf, value, val_len); 948 nflds = cfg_get_num_flds(&chead[0], section, &table_index); 949 got = cfg_cnt_flds(value); 950 951 cnodepos = cfg_get_item(&chead[0], section, "cnode"); 952 if (cnodepos < 0 || got >= cnodepos) { 953 /* no cnode, or cnode was specified by caller */ 954 addcnode = 0; 955 } 956 957 if (got < nflds) { 958 for (/* CSTYLED */; got < nflds; got++) 959 strncat(buf, " - ", 3); 960 } else if (got > nflds) { 961 errno = EINVAL; /* specified too many fields */ 962 return (-1); 963 } else { 964 /* got == nflds, so cnode was included */ 965 addcnode = 0; 966 } 967 968 if (addcnode) { 969 cfg_insert_node(cfg, &chead[0], buf, section); 970 } 971 972 /* Make sure we put this entry in the right database */ 973 if (cfg_is_cnode(cfg, &chead[0], buf, section) && 974 cfg->cf[1].cf_fd) 975 cfp = &cfg->cf[1]; 976 else 977 cfp = &cfg->cf[0]; 978 979 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 980 if (!cfg_read(cfp)) { 981 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 982 cfg_severity = CFG_EFATAL; 983 return (-1); 984 } 985 } 986 if (cfp->cf_head->h_csize + strlen(buf) > CFG_DEFAULT_SSIZE) { 987 errno = ENOSPC; 988 return (-1); 989 } 990 991 (*cfp->cf_pp->addcf)(cfp, bufp, table_index); 992 993 return (TRUE); 994 } 995 996 errno = EINVAL; 997 cfg_perror_str = strerror(errno); 998 cfg_severity = CFG_ENONFATAL; 999 return (-1); 1000 } 1001 1002 /* 1003 * cfg_encode_char 1004 * 1005 * Encode a single character into % + hex ascii value 1006 */ 1007 static void 1008 cfg_encode_char(char *result, char ch) 1009 { 1010 *result++ = '%'; 1011 *result++ = dectohex[ (ch >> 4) & 0xf ]; 1012 *result++ = dectohex[ ch & 0xf ]; 1013 } 1014 1015 /* 1016 * cfg_decode_char 1017 * 1018 * Reverses cfg_encode_char 1019 */ 1020 static char 1021 cfg_decode_char(char *code) 1022 { 1023 char retval; 1024 if (*code != '%') { 1025 return ('\0'); 1026 } 1027 ++code; 1028 if (!isxdigit(*code)) 1029 return ('\0'); 1030 retval = (isdigit(*code)? *code - '0' : *code - 'a' + 10); 1031 retval <<= 4; 1032 ++code; 1033 if (!isxdigit(*code)) 1034 return ('\0'); 1035 retval |= (isdigit(*code)? *code - '0' : *code - 'a' + 10); 1036 1037 return (retval); 1038 } 1039 1040 /* 1041 * cfg_encode_option 1042 * 1043 * Transforms the key and value strings so that special characters 1044 * can be used within the options field. 1045 * 1046 * Returns: 1047 * Length of encoded string; -1 on failure 1048 */ 1049 static int 1050 cfg_encode_string(char *str, char *output, int outlen) 1051 { 1052 char *mem, *p, *q; 1053 int curlen; 1054 1055 1056 /* first, scan through the tag string converting %-signs */ 1057 p = str; 1058 q = output; 1059 curlen = 0; 1060 while (*p && curlen < outlen) { 1061 if (*p == '%') { 1062 if (curlen + 3 >= outlen) { 1063 return (-1); 1064 } 1065 cfg_encode_char(q, *p); 1066 curlen += 3; 1067 q += 3; 1068 } else { 1069 *q++ = *p; 1070 ++curlen; 1071 } 1072 ++p; 1073 } 1074 if (curlen < outlen) 1075 *q = '\0'; 1076 1077 /* now encode special characters */ 1078 p = mem = strdup(output); 1079 q = output; 1080 curlen = 0; 1081 while (*p && curlen < outlen) { 1082 if (strchr(CHARS_TO_ENCODE, *p) != 0) { 1083 if (curlen + 3 >= outlen) { 1084 free(mem); 1085 return (-1); 1086 } 1087 cfg_encode_char(q, *p); 1088 curlen += 3; 1089 q += 3; 1090 } else { 1091 *q++ = *p; 1092 ++curlen; 1093 } 1094 ++p; 1095 } 1096 free(mem); 1097 1098 if (curlen < outlen) 1099 *q = '\0'; 1100 /* LINTED possible ptrdiff_t overflow */ 1101 return (q - output); 1102 } 1103 1104 /* 1105 * cfg_decode_option 1106 * 1107 * Given a string, decodes any %-encodes on it. 1108 */ 1109 static void 1110 cfg_decode_string(char *str, char *output, int outlen) 1111 { 1112 char *p, *q; 1113 int curlen; 1114 1115 p = str; 1116 q = output; 1117 curlen = 0; 1118 while (*p && curlen < outlen) { 1119 if (*p == '%') { 1120 char ch = cfg_decode_char(p); 1121 if (!ch) { 1122 *q++ = *p++; 1123 ++curlen; 1124 } else { 1125 *q++ = ch; 1126 p += 3; 1127 ++curlen; 1128 } 1129 } else { 1130 *q++ = *p++; 1131 ++curlen; 1132 } 1133 } 1134 if (curlen < outlen) 1135 *q = '\0'; 1136 } 1137 1138 /* 1139 * cfg_get_options 1140 * return first options set from basekey 1141 * Subsequent calls with basekey = NULL return next option if any 1142 * into tag and val 1143 * returns 1144 * true success and more options data 1145 * -1 no options data 1146 */ 1147 1148 int 1149 cfg_get_options(CFGFILE *cfg, int section, const char *basekey, char *tag, 1150 int tag_len, char *val, int val_len) 1151 { 1152 static char buf[CFG_MAX_BUF]; 1153 char decode_buf[CFG_MAX_BUF]; 1154 int rc; 1155 char *ttag, *tval; 1156 1157 if (cfg == NULL) { 1158 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1159 cfg_severity = CFG_EFATAL; 1160 return (-1); 1161 } 1162 1163 errno = ENOSYS; 1164 if (basekey == 0) { 1165 ttag = strtok(NULL, "="); 1166 } else { 1167 bzero(buf, CFG_MAX_BUF); 1168 if (section == CFG_SEC_CONF) { 1169 rc = cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF); 1170 } else 1171 return (-1); 1172 if (rc < 0) 1173 return (rc); 1174 /* buf now contains raw options data */ 1175 ttag = strtok(buf, "="); 1176 } 1177 tval = strtok(NULL, ";"); 1178 if (!(tval) || !(ttag)) 1179 return (-1); 1180 if ((strlen(tval) > val_len) || (strlen(ttag) > tag_len)) { 1181 errno = E2BIG; 1182 return (-1); 1183 } 1184 cfg_decode_string(tval, decode_buf, CFG_MAX_BUF); 1185 strncpy(val, decode_buf, val_len); 1186 cfg_decode_string(ttag, decode_buf, CFG_MAX_BUF); 1187 strncpy(tag, decode_buf, tag_len); 1188 errno = 0; 1189 return (TRUE); 1190 } 1191 1192 /* 1193 * cfg_put_options 1194 * 1195 * Replaces existing tag with new val. If tag doesn't exist, 1196 * then it adds a new tag with the specified val. 1197 * 1198 * Return: 1199 * true success 1200 * -1 incorrect section, or read error from cfg DB 1201 */ 1202 int 1203 cfg_put_options(CFGFILE *cfg, int section, const char *basekey, char *tag, 1204 char *val) 1205 { 1206 char buf[CFG_MAX_BUF]; 1207 char encode_buf[CFG_MAX_BUF]; 1208 char *p; 1209 int enclen; 1210 1211 if (cfg == NULL) { 1212 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1213 cfg_severity = CFG_EFATAL; 1214 return (-1); 1215 } 1216 1217 errno = ENOSYS; 1218 bzero(buf, CFG_MAX_BUF); 1219 if (section != CFG_SEC_CONF) { 1220 cfg_severity = CFG_ENONFATAL; 1221 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1222 return (-1); 1223 } 1224 if (!tag || !*tag || !val || !*val) 1225 return (-1); 1226 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) { 1227 /* cfg severity & perror_str set up cfg_get_cstring() */ 1228 return (-1); 1229 } 1230 *encode_buf = ';'; 1231 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1; 1232 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) { 1233 cfg_severity = CFG_ENONFATAL; 1234 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1235 return (-1); 1236 } 1237 encode_buf[enclen] = '='; 1238 encode_buf[enclen + 1] = '\0'; 1239 1240 /* check the start of the string */ 1241 if (strncmp(buf, &encode_buf[1], enclen) == 0) { 1242 /* locate the end of this option */ 1243 p = strchr(buf, ';'); 1244 if (p && *(p + 1) != '\0') { 1245 /* add the new tag to the end */ 1246 ++p; 1247 strcat(p, &encode_buf[1]); 1248 } else { 1249 /* completely overwrite the existing tag */ 1250 p = buf; 1251 strcpy(p, &encode_buf[1]); 1252 } 1253 if (cfg_encode_string(val, encode_buf, CFG_MAX_BUF) < 0) { 1254 cfg_severity = CFG_ENONFATAL; 1255 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1256 return (-1); 1257 } 1258 strcat(p, encode_buf); 1259 strcat(p, ";"); 1260 if (cfg_put_cstring(cfg, basekey, p, strlen(p)) < 0) { 1261 /* severity & perror_str set by cfg_put_cstring */ 1262 return (-1); 1263 } 1264 errno = 0; 1265 return (TRUE); 1266 } 1267 1268 /* it's hiding somewhere inside... */ 1269 p = strstr(buf, encode_buf); 1270 if (p) { 1271 /* delete the old value */ 1272 char *q = strchr(p + 1, ';'); 1273 if (q) { 1274 strcpy(p + 1, q + 1); 1275 } else { 1276 *p = '\0'; 1277 } 1278 strcat(buf, &encode_buf[1]); 1279 } else if (*buf) { 1280 strcat(buf, &encode_buf[1]); 1281 } else { 1282 strcpy(buf, &encode_buf[1]); 1283 } 1284 enclen = cfg_encode_string(val, encode_buf, CFG_MAX_BUF); 1285 if (enclen < 0 || (strlen(buf) + enclen) >= CFG_MAX_BUF) { 1286 cfg_severity = CFG_ENONFATAL; 1287 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1288 return (-1); 1289 } 1290 strcat(buf, encode_buf); 1291 strcat(buf, ";"); 1292 if (cfg_put_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) { 1293 /* severity & perror_str set by cfg_put_cstring */ 1294 return (-1); 1295 } 1296 errno = 0; 1297 return (TRUE); 1298 } 1299 1300 /* 1301 * cfg_get_single_option 1302 * 1303 * Scans the options string for the specified option and returns 1304 * the decoded value 1305 * 1306 * Return: 1307 * true success 1308 * -1 incorrect section, or read error from cfg DB 1309 */ 1310 int 1311 cfg_get_single_option(CFGFILE *cfg, int section, const char *basekey, char *tag, 1312 char *val, int val_len) 1313 { 1314 char buf[CFG_MAX_BUF]; 1315 char encode_buf[CFG_MAX_BUF]; 1316 char *p, *q; 1317 int enclen; 1318 1319 if (cfg == NULL) { 1320 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1321 cfg_severity = CFG_EFATAL; 1322 return (-1); 1323 } 1324 1325 errno = ENOSYS; 1326 bzero(buf, CFG_MAX_BUF); 1327 if (section != CFG_SEC_CONF) { 1328 cfg_severity = CFG_ENONFATAL; 1329 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1330 return (-1); 1331 } 1332 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) { 1333 /* severity & perror_str set by cfg_get_cstring */ 1334 return (-1); 1335 } 1336 1337 *encode_buf = ';'; 1338 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1; 1339 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) { 1340 cfg_severity = CFG_ENONFATAL; 1341 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1342 return (-1); 1343 } 1344 encode_buf[enclen] = '='; 1345 encode_buf[enclen + 1] = '\0'; 1346 1347 /* check the start of the string */ 1348 if (strncmp(buf, &encode_buf[1], enclen) == 0) { 1349 p = strchr(buf, '='); 1350 if (!p) { 1351 cfg_severity = CFG_ENONFATAL; 1352 cfg_perror_str = dgettext("cfg", "Option not found"); 1353 return (-1); 1354 } 1355 ++p; 1356 q = strchr(p, ';'); 1357 if (q) { 1358 *q = '\0'; 1359 } 1360 cfg_decode_string(p, val, val_len); 1361 errno = 0; 1362 return (TRUE); 1363 } 1364 1365 /* it's hiding somewhere inside... */ 1366 p = strstr(buf, encode_buf); 1367 if (p) { 1368 p += enclen + 1; 1369 q = strchr(p, ';'); 1370 if (q) { 1371 *q = '\0'; 1372 } 1373 cfg_decode_string(p, val, val_len); 1374 errno = 0; 1375 return (TRUE); 1376 } 1377 1378 /* key not found */ 1379 return (-1); 1380 1381 } 1382 1383 /* 1384 * cfg_del_option 1385 * 1386 * Removes a single key=val pair from the specified option field 1387 * 1388 * Return: 1389 * true success 1390 * -1 unable to update config 1391 */ 1392 int 1393 cfg_del_option(CFGFILE *cfg, int section, const char *basekey, char *tag) 1394 { 1395 char buf[CFG_MAX_BUF]; 1396 char encode_buf[CFG_MAX_BUF]; 1397 char *p, *q; 1398 int enclen, rc; 1399 1400 if (cfg == NULL) { 1401 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1402 cfg_severity = CFG_EFATAL; 1403 return (-1); 1404 } 1405 1406 bzero(buf, CFG_MAX_BUF); 1407 if (section != CFG_SEC_CONF) { 1408 cfg_severity = CFG_ENONFATAL; 1409 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1410 return (-1); 1411 } 1412 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) { 1413 /* severity & perror_str are set by cfg_get_cstring */ 1414 return (-1); 1415 } 1416 1417 *encode_buf = ';'; 1418 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1; 1419 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) { 1420 cfg_severity = CFG_ENONFATAL; 1421 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1422 return (-1); 1423 } 1424 encode_buf[enclen] = '='; 1425 encode_buf[enclen + 1] = '\0'; 1426 1427 /* check the start of the string */ 1428 if (strncmp(buf, &encode_buf[1], enclen) == 0) { 1429 p = strchr(buf, ';'); 1430 if (p && (*(p + 1) != '\0')) { 1431 rc = cfg_put_cstring(cfg, basekey, p + 1, strlen(p + 1)); 1432 } else { 1433 rc = cfg_put_cstring(cfg, basekey, "-", 1); 1434 } 1435 /* severity & perror_str are set by cfg_put_cstring */ 1436 return (rc); 1437 } 1438 1439 /* sigh */ 1440 p = strstr(buf, encode_buf); 1441 if (!p) { 1442 /* already removed */ 1443 return (TRUE); 1444 } 1445 q = strchr(p + 1, ';'); 1446 1447 /* 1448 * Now the string looks like: 1449 * | first few options | *p | option to remove | *q | rest | '\0' 1450 */ 1451 1452 if (!q) { 1453 /* hum... */ 1454 *p = '\0'; 1455 } else { 1456 strcpy(p, q); 1457 } 1458 1459 return (cfg_put_cstring(cfg, basekey, buf, strlen(buf))); 1460 } 1461 1462 static void 1463 cfg_set_memorymap(cfp_t *cfp) 1464 { 1465 cfgheader_t *hd = cfp->cf_head; 1466 1467 #ifdef DEBUG_CFGLIST 1468 (void) fprintf(stderr, "callocing %d for initial reads\n", hd->h_csize); 1469 #endif 1470 1471 hd->h_ccopy1 = (char *)calloc(hd->h_csize, sizeof (char)); 1472 hd->h_ccopy2 = (char *)calloc(hd->h_csize, sizeof (char)); 1473 hd->h_sizes1 = (int *)calloc(CFG_DEFAULT_PSIZE, sizeof (int)); 1474 hd->h_sizes2 = (int *)calloc(CFG_DEFAULT_PSIZE, sizeof (int)); 1475 } 1476 1477 /* 1478 * cfg_init_header 1479 * fill in default header info 1480 */ 1481 static void 1482 cfg_init_header(cfp_t *cfp) 1483 { 1484 time_t tloc; 1485 cfgheader_t *hd = cfp->cf_head; 1486 1487 hd->h_magic = (int32_t)CFG_NEW_MAGIC; 1488 hd->h_stamp = time(&tloc); 1489 hd->h_lock = 0; 1490 /* parser config */ 1491 hd->h_parsesize = 0; 1492 hd->h_parseoff = 0; 1493 hd->h_csize = 0; 1494 hd->h_psize = 0; 1495 hd->h_cfgs = NULL; 1496 hd->h_ncfgs = 0; 1497 hd->h_seq1 = hd->h_seq2 = 1; 1498 bzero(hd->h_cfgsizes, MAX_CFG * sizeof (int)); 1499 } 1500 /* 1501 * cfg_read 1502 * read header and all sections of configuration file 1503 * gets new data for incore copy 1504 * removes invalid header state 1505 * works even if config and persistent sections are empty 1506 * 1507 */ 1508 static int 1509 cfg_read(cfp_t *cfp) 1510 { 1511 int rc; 1512 cfgheader_t *hd; 1513 int readsize = 0; 1514 #ifdef DEBUG_CFGLIST 1515 (void) fprintf(stderr, "cfg_read\n"); 1516 #endif 1517 1518 if (!cfp->cf_head) { 1519 if ((hd = calloc(1, sizeof (*hd))) == NULL) 1520 return (FALSE); 1521 #ifdef DEBUG_HDR 1522 (void) fprintf(stderr, "initial cfg header read\n"); 1523 #endif 1524 cfp->cf_head = hd; 1525 } 1526 1527 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 1528 #ifdef DEBUG_LIB 1529 (void) fprintf(stderr, "cfg: seek header failed\n"); 1530 #endif 1531 return (FALSE); 1532 } 1533 1534 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head, 4); 1535 if (rc < 4) { 1536 #ifdef DEBUG_LIB 1537 (void) fprintf(stderr, "cfg: read magic number failed\n"); 1538 #endif 1539 return (FALSE); 1540 } 1541 1542 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 1543 #ifdef DEBUG_LIB 1544 (void) fprintf(stderr, "cfg: seek header failed\n"); 1545 #endif 1546 return (FALSE); 1547 } 1548 1549 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head, sizeof (*hd)); 1550 if (rc < sizeof (*hd)) { 1551 #ifdef DEBUG_LIB 1552 (void) fprintf(stderr, "cfg: read header failed\n"); 1553 #endif 1554 return (FALSE); 1555 } 1556 1557 cfp->cf_head->h_cfgs = NULL; 1558 cfg_set_memorymap(cfp); 1559 if (cfp->cf_head->h_magic != CFG_NEW_MAGIC) { 1560 #ifdef DEBUG_LIB 1561 (void) fprintf(stderr, "cfg_read: wrong MAGIC number %x\n", 1562 cfp->cf_head->h_magic); 1563 #endif 1564 return (FALSE); 1565 } 1566 1567 cfp->cf_head->h_state &= ~(CFG_HDR_INVALID); 1568 1569 #ifdef DEBUG_CFGLIST 1570 (void) fprintf(stderr, "reading parser\n"); 1571 #endif 1572 rc = (*cfp->cf_pp->read) 1573 (cfp, (char *)cfp->cf_mapped, CFG_DEFAULT_PARSE_SIZE); 1574 if (rc < sizeof (*hd)) { 1575 #ifdef DEBUG 1576 (void) fprintf(stderr, "cfg: read parse config failed\n"); 1577 #endif 1578 return (FALSE); 1579 } 1580 1581 readsize = cfp->cf_head->h_csize; 1582 1583 #ifdef DEBUG_CFGLIST 1584 (void) fprintf(stderr, "reading copy1 readsize = %d\n", readsize); 1585 #endif 1586 rc = (*cfp->cf_pp->read) 1587 (cfp, (char *)cfp->cf_head->h_ccopy1, readsize); 1588 if (rc < 0) { 1589 /* don't fail just return */ 1590 #ifdef DEBUG 1591 (void) fprintf(stderr, "cfg: read ccopy1 section failed\n"); 1592 #endif 1593 return (FALSE); 1594 } 1595 1596 if ((*cfp->cf_pp->seek) 1597 (cfp, CFG_DEFAULT_SSIZE - rc, SEEK_CUR) < 0) { 1598 #ifdef DEBUG 1599 (void) fprintf(stderr, "cfg: seek (SEEK_CUR) failed\n"); 1600 #endif 1601 return (FALSE); 1602 } 1603 1604 #ifdef DEBUG_CFGLIST 1605 (void) fprintf(stderr, "reading copy2 readsize = %d\n", readsize); 1606 #endif 1607 1608 rc = (*cfp->cf_pp->read) 1609 (cfp, (char *)cfp->cf_head->h_ccopy2, readsize); 1610 if (rc < 0) { 1611 /* don't fail just return */ 1612 #ifdef DEBUG 1613 (void) fprintf(stderr, "cfg: read ccopy2 section failed\n"); 1614 #endif 1615 return (FALSE); 1616 } 1617 1618 /* read the sizes of the lists from disk */ 1619 if ((*cfp->cf_pp->seek) 1620 (cfp, CFG_DEFAULT_SSIZE - rc, SEEK_CUR) < 0) { 1621 #ifdef DEBUG 1622 (void) fprintf(stderr, "cfg: seek (SEEK_CUR) failed\n"); 1623 #endif 1624 return (FALSE); 1625 } 1626 1627 #ifdef DEBUG_CFGLIST 1628 (void) fprintf(stderr, "reading sizes\n"); 1629 #endif 1630 rc = (*cfp->cf_pp->read) 1631 (cfp, (int *)cfp->cf_head->h_sizes1, CFG_DEFAULT_PSIZE); 1632 if (rc < 0) { 1633 #ifdef DEBUG 1634 (void) fprintf(stderr, "cfg: read h_sizes1 failed\n"); 1635 #endif 1636 return (FALSE); 1637 } 1638 1639 rc = (*cfp->cf_pp->read) 1640 (cfp, (int *)cfp->cf_head->h_sizes2, CFG_DEFAULT_PSIZE); 1641 if (rc < 0) { 1642 #ifdef DEBUG 1643 (void) fprintf(stderr, "cfg: read h_sizes2 failed\n"); 1644 #endif 1645 return (FALSE); 1646 } 1647 1648 /* 1649 * If initial or invalid sequence, use first section 1650 */ 1651 if ((cfp->cf_head->h_seq1 <= 0) && (cfp->cf_head->h_seq2 <= 0)) { 1652 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1; 1653 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1; 1654 } 1655 1656 if (cfp->cf_head->h_seq1 >= cfp->cf_head->h_seq2) { 1657 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1; 1658 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1; 1659 } else { 1660 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy2; 1661 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes2; 1662 } 1663 1664 #ifdef DEBUG_LIB 1665 dump_status(cfp, "cfg_read"); 1666 #endif 1667 1668 return (TRUE); 1669 } 1670 1671 /* 1672 * cfg_lock 1673 * Read-write locking of the configuration 1674 * reads into core all sections 1675 * builds parser trees for each section 1676 * Returns: TRUE if the lock was acquired, FALSE otherwise. 1677 */ 1678 int 1679 cfg_lock(CFGFILE *cfg, CFGLOCK mode) 1680 { 1681 cfp_t *cfp; 1682 int is_locked = 0; 1683 int rc; 1684 1685 if (cfg == NULL) { 1686 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1687 cfg_severity = CFG_EFATAL; 1688 return (FALSE); 1689 } 1690 1691 if (mode == CFG_UPGRADE) { 1692 mode = CFG_WRLOCK; 1693 } 1694 1695 if (mode == CFG_WRLOCK && (cfg->cf[0].cf_flag & CFG_RDONLY)) { 1696 goto fail; 1697 } 1698 1699 /* 1700 * if you don't even give me the right lock request, 1701 * why should I give you one? 1702 */ 1703 if (mode != CFG_RDLOCK && mode != CFG_WRLOCK) 1704 goto fail; 1705 1706 if (cfg_lockd) { 1707 if (mode == CFG_WRLOCK) 1708 cfg_lockd_wrlock(); 1709 else 1710 cfg_lockd_rdlock(); 1711 is_locked = 1; 1712 } else { 1713 1714 #ifdef DEBUG_CFGLIST 1715 (void) fprintf(stderr, "cfg_lock\n"); 1716 #endif 1717 /* Lock is always based on local file pointer */ 1718 cfg->cf[1].cf_lock = cfg->cf[0].cf_lock = cfg->cf[0].cf_fd; 1719 1720 if (!((cfg->cf[0].cf_flag & CFG_RDONLY) && 1721 (mode == CFG_RDLOCK))) { 1722 1723 struct flock lk = {0}; 1724 lk.l_type = (mode == CFG_RDLOCK ? F_RDLCK : F_WRLCK); 1725 lk.l_whence = SEEK_SET; 1726 lk.l_start = (off_t)0; 1727 lk.l_len = (off_t)0; 1728 1729 if (fcntl(cfg->cf[0].cf_lock, F_SETLKW, &lk) < 0) 1730 goto fail; 1731 } 1732 } 1733 1734 /* Determine number of files open */ 1735 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 1736 if (!cfp->cf_fd) continue; 1737 if ((cfp->cf_head) && 1738 (cfp->cf_head->h_state & CFG_HDR_INVALID)) { 1739 if ((rc = cfg_hdrcmp(cfp)) == 0) { 1740 #ifdef DEBUG_HDR 1741 (void) fprintf(stderr, 1742 "cfg header match, skipping re-read\n"); 1743 #endif 1744 cfp->cf_head->h_state |= CFG_HDR_RDLOCK; 1745 if (mode == CFG_WRLOCK) 1746 cfp->cf_head->h_state |= CFG_HDR_WRLOCK; 1747 1748 cfp->cf_head->h_state &= ~(CFG_HDR_INVALID); 1749 continue; 1750 } 1751 #ifdef DEBUG_HDR 1752 (void) fprintf(stderr, "re-reading cfg, header mismatch\n"); 1753 #endif 1754 /* 1755 * dump what we have, info is stale 1756 */ 1757 cfg_free_cfglist(cfp); 1758 cfg_free_parser_tree(); 1759 1760 if (cfp->cf_head->h_ccopy1) { 1761 free(cfp->cf_head->h_ccopy1); 1762 cfp->cf_head->h_ccopy1 = NULL; 1763 } 1764 if (cfp->cf_head->h_ccopy2) { 1765 free(cfp->cf_head->h_ccopy2); 1766 cfp->cf_head->h_ccopy2 = NULL; 1767 } 1768 if (cfp->cf_head->h_sizes1) { 1769 free(cfp->cf_head->h_sizes1); 1770 cfp->cf_head->h_sizes1 = NULL; 1771 } 1772 if (cfp->cf_head->h_sizes2) { 1773 free(cfp->cf_head->h_sizes2); 1774 cfp->cf_head->h_sizes2 = NULL; 1775 } 1776 1777 if (cfp->cf_head) 1778 free(cfp->cf_head); 1779 cfp->cf_head = NULL; 1780 } 1781 1782 if (cfp->cf_head == NULL) { 1783 if (!cfg_read(cfp)) { 1784 if (cfp->cf_head != NULL) 1785 cfg_init_header(cfp); 1786 else 1787 goto fail; 1788 } else { 1789 #ifdef DEBUG_CFGLIST 1790 (void) fprintf(stderr, 1791 "reading parser config\n"); 1792 #endif 1793 /* build parser trees */ 1794 cfg_read_parser_config(cfp); 1795 } 1796 1797 } 1798 cfp->cf_head->h_state |= CFG_HDR_RDLOCK; 1799 if (mode == CFG_WRLOCK) { 1800 if (cfp->cf_head->h_seq1 >= cfp->cf_head->h_seq2) { 1801 #ifdef DEBUG_LIB 1802 (void) fprintf(stderr, 1803 "cfg_lock: WRLOCK copying 1 to 2\n"); 1804 #endif 1805 memcpy(cfp->cf_head->h_ccopy2, 1806 cfp->cf_head->h_ccopy1, 1807 cfp->cf_head->h_csize); 1808 memcpy(cfp->cf_head->h_sizes2, 1809 cfp->cf_head->h_sizes1, 1810 CFG_DEFAULT_PSIZE); 1811 1812 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy2; 1813 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes2; 1814 } else { 1815 #ifdef DEBUG_LIB 1816 (void) fprintf(stderr, 1817 "cfg_lock: WRLOCK copying 2 to 1\n"); 1818 #endif 1819 memcpy(cfp->cf_head->h_ccopy1, 1820 cfp->cf_head->h_ccopy2, 1821 cfp->cf_head->h_csize); 1822 memcpy(cfp->cf_head->h_sizes1, 1823 cfp->cf_head->h_sizes2, 1824 CFG_DEFAULT_PSIZE); 1825 1826 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1; 1827 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1; 1828 } 1829 1830 cfp->cf_head->h_state |= CFG_HDR_WRLOCK; 1831 } 1832 1833 if (cfg_map_cfglists(cfp) < 0) { 1834 #ifdef DEBUG_LIB 1835 (void) fprintf(stderr, "cfg: map_cfglists failed\n"); 1836 #endif 1837 goto fail; 1838 } 1839 1840 #ifdef DEBUG_LIB 1841 dump_status(cfp, "cfg_lock"); 1842 #endif 1843 } 1844 1845 return (TRUE); 1846 1847 fail: 1848 if (is_locked) { 1849 cfg_lockd_unlock(); 1850 } 1851 cfg_perror_str = dgettext("cfg", CFG_EGENERIC); 1852 cfg_severity = CFG_ENONFATAL; 1853 return (FALSE); 1854 } 1855 1856 /* 1857 * Unlock the database 1858 */ 1859 void 1860 cfp_unlock(cfp_t *cfp) 1861 { 1862 1863 #ifdef DEBUG_CFGLIST 1864 (void) fprintf(stderr, "cfg_unlock\n"); 1865 #endif 1866 if (cfg_lockd) { 1867 cfg_lockd_unlock(); 1868 } else { 1869 struct flock lk = {0}; 1870 lk.l_type = F_UNLCK; 1871 lk.l_whence = SEEK_SET; 1872 lk.l_start = (off_t)0; 1873 lk.l_len = (off_t)0; 1874 (void) fcntl(cfp->cf_lock, F_SETLKW, &lk); 1875 } 1876 1877 if (cfp->cf_head != NULL) { 1878 cfp->cf_head->h_state &= ~(CFG_HDR_RDLOCK|CFG_HDR_WRLOCK); 1879 cfp->cf_head->h_state |= CFG_HDR_INVALID; 1880 } 1881 } 1882 void 1883 cfg_unlock(CFGFILE *cfg) 1884 { 1885 if (cfg == NULL) { 1886 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1887 cfg_severity = CFG_EFATAL; 1888 return; 1889 } 1890 1891 cfp_unlock(&cfg->cf[0]); 1892 cfp_unlock(&cfg->cf[1]); 1893 } 1894 1895 /* 1896 * Test for a read lock, set errno if failed. 1897 */ 1898 static int 1899 cfg_rdlock(CFGFILE *cfg) 1900 { 1901 int rc; 1902 cfp_t *cfp; 1903 1904 if (cfg == NULL) { 1905 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1906 cfg_severity = CFG_EFATAL; 1907 return (FALSE); 1908 } 1909 1910 /* Determine number of files open */ 1911 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 1912 if (!cfp->cf_fd) continue; 1913 if (cfp->cf_head == NULL) { 1914 #ifdef DEBUG_LIB 1915 (void) fprintf(stderr, "cfg_rdlock: cf_head == NULL\n"); 1916 #endif 1917 /* 1918 * 6335583, if header == NULL, 1919 * we can't call cfg_read to fill the header again 1920 * since it will change the lock state to 1921 * CFG_HDR_WRLOCK and dscfg will be the processer 1922 * that hold the lock, 1923 * just returning a FALSE if the case, 1924 * then retrieve the lock state from flock structure. 1925 */ 1926 rc = FALSE; 1927 break; 1928 } else { 1929 #ifdef DEBUG_LIB 1930 (void) fprintf(stderr, "cfg_rdlock: cf_head != NULL\n"); 1931 #endif 1932 if ((cfp->cf_head->h_state & CFG_HDR_RDLOCK) 1933 == CFG_HDR_RDLOCK) 1934 rc = TRUE; 1935 else { 1936 rc = FALSE; 1937 break; 1938 } 1939 } 1940 } 1941 1942 if (!rc) 1943 errno = EPERM; 1944 1945 return (rc); 1946 } 1947 1948 /* 1949 * Test for a write lock, set errno if failed. 1950 */ 1951 static int 1952 cfg_wrlock(CFGFILE *cfg) 1953 { 1954 int rc; 1955 cfp_t *cfp; 1956 1957 if (cfg == NULL) { 1958 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1959 cfg_severity = CFG_EFATAL; 1960 return (FALSE); 1961 } 1962 1963 /* Determine number of files open */ 1964 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 1965 if (!cfp->cf_fd) continue; 1966 if (cfp->cf_head == NULL) { 1967 #ifdef DEBUG_LIB 1968 (void) fprintf(stderr, "cfg wrlock: cf_head == NULL\n"); 1969 #endif 1970 /* 1971 * 6335583, see comments on cfg_rdlock 1972 */ 1973 rc = FALSE; 1974 break; 1975 } else { 1976 #ifdef DEBUG_LIB 1977 (void) fprintf(stderr, "cfg wrlock: cf_head != NULL\n"); 1978 #endif 1979 if ((cfp->cf_head->h_state & CFG_HDR_WRLOCK) 1980 == CFG_HDR_WRLOCK) 1981 rc = TRUE; 1982 else { 1983 rc = FALSE; 1984 break; 1985 } 1986 } 1987 } 1988 1989 if (!rc) 1990 errno = EPERM; 1991 1992 return (rc); 1993 } 1994 1995 /* 1996 * cfg_get_lock 1997 * Find lock status of CFG database. 1998 * Returns: TRUE and sets lock and pid if the lock is held, FALSE otherwise. 1999 */ 2000 int 2001 cfg_get_lock(CFGFILE *cfg, CFGLOCK *lock, pid_t *pid) 2002 { 2003 struct flock lk; 2004 int rc; 2005 2006 if (cfg == NULL) { 2007 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2008 cfg_severity = CFG_EFATAL; 2009 return (FALSE); 2010 } 2011 2012 if (cfg_lockd) { 2013 switch (cfg_lockedby(pid)) { 2014 case LOCK_READ: 2015 *lock = CFG_RDLOCK; 2016 return (TRUE); 2017 case LOCK_WRITE: 2018 *lock = CFG_WRLOCK; 2019 return (TRUE); 2020 case LOCK_NOTLOCKED: 2021 default: 2022 return (FALSE); 2023 } 2024 } else { 2025 if (cfg_wrlock(cfg)) { 2026 *lock = CFG_WRLOCK; 2027 *pid = getpid(); 2028 return (TRUE); 2029 } 2030 2031 if (cfg_rdlock(cfg)) { 2032 *lock = CFG_RDLOCK; 2033 *pid = getpid(); 2034 return (TRUE); 2035 } 2036 } 2037 /* Lock is always based on local file pointer */ 2038 cfg->cf[1].cf_lock = cfg->cf[0].cf_lock = cfg->cf[0].cf_fd; 2039 2040 bzero(&lk, sizeof (lk)); 2041 lk.l_type = F_WRLCK; 2042 lk.l_whence = SEEK_SET; 2043 lk.l_start = (off_t)0; 2044 lk.l_len = (off_t)0; 2045 2046 if (fcntl(cfg->cf[0].cf_lock, F_GETLK, &lk) < 0) 2047 rc = FALSE; 2048 else { 2049 if (lk.l_type == F_UNLCK) 2050 rc = FALSE; 2051 else { 2052 rc = TRUE; 2053 *pid = lk.l_pid; 2054 *lock = lk.l_type == F_WRLCK ? CFG_WRLOCK : CFG_RDLOCK; 2055 } 2056 } 2057 2058 return (rc); 2059 } 2060 2061 /* 2062 * cfg_commit 2063 * Write modified version of header, configuration and persistent 2064 * data using 2 stage commit. 2065 * If no valid data is found in header, it is assumed to be an initial 2066 * write and we will create the default header (could be dangerous) 2067 * another tricky part, if we are doing an upgrade we may be dealing 2068 * with an old database. we need to take care seeking and writing 2069 * until such time that it is upgraded. 2070 * 2071 * Mutual exclusion is checked using cfg_lock 2072 */ 2073 2074 int 2075 cfg_commit(CFGFILE *cfg) 2076 { 2077 cfp_t *cfp; 2078 int rc; 2079 time_t tloc; 2080 int section; 2081 int wrsize, *ip; 2082 2083 if (cfg == NULL) { 2084 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2085 cfg_severity = CFG_EFATAL; 2086 return (FALSE); 2087 } 2088 2089 if (!cfg_wrlock(cfg)) 2090 return (FALSE); 2091 2092 /* Determine number of files open */ 2093 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 2094 if (!cfp->cf_fd) continue; 2095 2096 /* 2097 * lets put everything back into one char * 2098 */ 2099 cfg_replace_lists(cfp); 2100 2101 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 2102 #ifdef DEBUG_LIB 2103 (void) fprintf(stderr, "cfg: seek header failed\n"); 2104 #endif 2105 return (FALSE); 2106 } 2107 2108 cfp->cf_head->h_size = cfp->cf_head->h_parsesize 2109 + cfp->cf_head->h_csize + cfp->cf_head->h_psize; 2110 cfp->cf_head->h_stamp = time(&tloc); 2111 2112 /* seeking into database */ 2113 if ((*cfp->cf_pp->seek) 2114 (cfp, sizeof (cfgheader_t), SEEK_CUR) < 0) 2115 return (FALSE); 2116 2117 if (cfp->cf_head->h_ccopy1 == cfp->cf_head->h_cparse) { 2118 if (cfp->cf_head->h_seq1 < 0) 2119 cfp->cf_head->h_seq1 = 1; 2120 else 2121 cfp->cf_head->h_seq1 = cfp->cf_head->h_seq2 + 1; 2122 section = 1; 2123 } else { 2124 if (cfp->cf_head->h_seq2 < 0) 2125 cfp->cf_head->h_seq2 = 1; 2126 else 2127 cfp->cf_head->h_seq2 = cfp->cf_head->h_seq1 + 1; 2128 section = 2; 2129 } 2130 #ifdef DEBUG_LIB 2131 dump_status(cfp, "cfg_commit"); 2132 #endif 2133 rc = (*cfp->cf_pp->write) 2134 (cfp, cfp->cf_mapped, CFG_DEFAULT_PARSE_SIZE); 2135 #ifdef DEBUG 2136 if (rc < 0) { 2137 (void) fprintf(stderr, 2138 "parse commit: rc %d h_parsesize %d\n", 2139 rc, cfp->cf_head->h_parsesize); 2140 } 2141 #endif 2142 if (section == 1) { 2143 rc = (*cfp->cf_pp->write) 2144 (cfp, cfp->cf_head->h_ccopy1, 2145 cfp->cf_head->h_csize); 2146 #ifdef DEBUG 2147 if (rc < 0) { 2148 (void) fprintf(stderr, 2149 "csection commit 1: rc %d h_csize %d\n", 2150 rc, cfp->cf_head->h_csize); 2151 } 2152 #endif 2153 if ((*cfp->cf_pp->seek) 2154 (cfp, (2 * CFG_DEFAULT_SSIZE) - rc, SEEK_CUR) < 0) 2155 return (FALSE); 2156 2157 /* 2158 * limit the write to only what we need 2159 */ 2160 ip = cfp->cf_head->h_sizes1; 2161 for (wrsize = 0; *ip; ip += *ip + 1) 2162 wrsize += *ip + 1; 2163 2164 rc = (*cfp->cf_pp->write)(cfp, 2165 cfp->cf_head->h_sizes1, wrsize * sizeof (int)); 2166 #ifdef DEBUG 2167 if (rc < 0) { 2168 (void) fprintf(stderr, 2169 "cfg: write list sizes1 failed rc\n"); 2170 } 2171 #endif 2172 } else { 2173 if ((*cfp->cf_pp->seek)(cfp, 2174 CFG_DEFAULT_SSIZE, SEEK_CUR) < 0) 2175 return (FALSE); 2176 2177 rc = (*cfp->cf_pp->write)(cfp, 2178 cfp->cf_head->h_ccopy2, cfp->cf_head->h_csize); 2179 #ifdef DEBUG 2180 if (rc < 0) { 2181 (void) fprintf(stderr, 2182 "csection commit 2: rc %d h_csize %d\n", 2183 rc, cfp->cf_head->h_csize); 2184 } 2185 #endif 2186 if ((*cfp->cf_pp->seek) 2187 (cfp, (CFG_DEFAULT_SSIZE + CFG_DEFAULT_PSIZE) - rc, 2188 SEEK_CUR) < 0) 2189 return (FALSE); 2190 2191 /* 2192 * limit the write to only what we need 2193 */ 2194 ip = cfp->cf_head->h_sizes2; 2195 for (wrsize = 0; *ip; ip += *ip + 1) 2196 wrsize += *ip + 1; 2197 2198 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head->h_sizes2, 2199 wrsize * sizeof (int)); 2200 #ifdef DEBUG 2201 if (rc < 0) { 2202 (void) fprintf(stderr, 2203 "cfg: write list sizes2 failed\n"); 2204 } 2205 #endif 2206 2207 } 2208 2209 2210 #ifdef DEBUG_CFGLIST 2211 (void) fprintf(stderr, 2212 "writing h_csize %d\n", cfp->cf_head->h_csize); 2213 #endif 2214 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) 2215 return (FALSE); 2216 2217 cfp->cf_head->h_size = cfp->cf_head->h_parsesize + 2218 cfp->cf_head->h_csize + cfp->cf_head->h_psize; 2219 2220 rc = (*cfp->cf_pp->write) 2221 (cfp, cfp->cf_head, sizeof (cfgheader_t)); 2222 if (rc < 0) { 2223 cfg_perror_str = dgettext("cfg", 2224 "cfg_commit: header write failed"); 2225 cfg_severity = CFG_EFATAL; 2226 return (FALSE); 2227 } 2228 } 2229 2230 return (TRUE); 2231 } 2232 2233 /* 2234 * cfg_rewind 2235 * rewind internal file pointer for specified section 2236 * empty now, rewind not necessary. But don't break 2237 * old code. 2238 */ 2239 /*ARGSUSED*/ 2240 void 2241 cfg_rewind(CFGFILE *cfg, int section) 2242 { 2243 switch (section) { 2244 case CFG_SEC_CONF: 2245 break; 2246 case CFG_SEC_ALL: 2247 break; 2248 }; 2249 } 2250 2251 /* 2252 * cfg_location 2253 * set or return the default location file to 2254 * determine the partition name of the configuration partition 2255 * location is stored in well known file location 2256 */ 2257 char * 2258 cfg_location(char *location, int mode, char *altroot) 2259 { 2260 int fd; 2261 int fmode; 2262 int rc; 2263 char wellknown[NSC_MAXPATH]; 2264 char loc[NSC_MAXPATH]; 2265 2266 if (mode == CFG_LOC_GET_LOCAL) { 2267 return (CFG_LOCAL_LOCATION); 2268 } else if (mode == CFG_LOC_GET_CLUSTER) { 2269 fmode = O_RDONLY; 2270 } else { 2271 fmode = O_RDWR | O_CREAT; 2272 } 2273 2274 if (altroot) { 2275 strcpy(wellknown, altroot); 2276 strcat(wellknown, CFG_CLUSTER_LOCATION); 2277 } else 2278 strcpy(wellknown, CFG_CLUSTER_LOCATION); 2279 2280 fd = open(wellknown, fmode, 0644); 2281 if (fd < 0) { 2282 cfg_perror_str = dgettext("cfg", strerror(errno)); 2283 cfg_severity = CFG_ENONFATAL; 2284 return (NULL); 2285 } 2286 2287 if (mode == CFG_LOC_SET_CLUSTER) { 2288 if (location == NULL || (strlen(location) > NSC_MAXPATH)) { 2289 cfg_perror_str = dgettext("cfg", 2290 "cfg_location: filename too big or missing"); 2291 cfg_severity = CFG_EFATAL; 2292 return (NULL); 2293 } 2294 2295 /* 2296 * 5082142 2297 * If we're in a cluster, make sure that the config location 2298 * is a raw device. Using non-raw did devices in a cluster 2299 * can result in data corruption, since inconsistent data 2300 * may reside in the block cache on one node, but has not 2301 * been flushed to disk. 2302 */ 2303 if (cfg_iscluster() > 0) { 2304 struct stat dscfg_stat; 2305 if (stat(location, &dscfg_stat) != 0) { 2306 cfg_perror_str = dgettext("cfg", 2307 "Unable to access dscfg location"); 2308 cfg_severity = CFG_EFATAL; 2309 return (NULL); 2310 } 2311 if (!S_ISCHR(dscfg_stat.st_mode)) { 2312 cfg_perror_str = dgettext("cfg", 2313 "dscfg location must be a raw device"); 2314 cfg_severity = CFG_EFATAL; 2315 return (NULL); 2316 } 2317 } 2318 2319 if (ftruncate(fd, 0) < 0) 2320 return (NULL); 2321 2322 rc = write(fd, location, strlen(location)); 2323 if (rc < 0) { 2324 cfg_perror_str = dgettext("cfg", 2325 "cfg_location: write to well known failed"); 2326 cfg_severity = CFG_EFATAL; 2327 return (NULL); 2328 } 2329 bzero(config_file, sizeof (config_file)); 2330 } 2331 if (lseek(fd, 0, SEEK_SET) < 0) 2332 return (NULL); 2333 2334 bzero(config_file, sizeof (config_file)); 2335 rc = read(fd, config_file, sizeof (config_file)); 2336 if (rc < 0) { 2337 cfg_perror_str = dgettext("cfg", 2338 "cfg_location: read from well known failed"); 2339 cfg_severity = CFG_EFATAL; 2340 return (NULL); 2341 } 2342 close(fd); 2343 if (altroot) { 2344 strcpy(loc, altroot); 2345 strcat(loc, config_file); 2346 bzero(config_file, sizeof (config_file)); 2347 strcpy(config_file, loc); 2348 } 2349 2350 /* 2351 * scan string out of config_file, to strip whitespace 2352 */ 2353 sscanf(config_file, "%s", loc); 2354 strcpy(config_file, loc); 2355 2356 return (config_file); 2357 } 2358 2359 /* 2360 * cfg_update_parser_config 2361 * If tag and key exist return -1 2362 * 2363 * XXX Currently does not append new field to existing parser rule 2364 */ 2365 2366 int 2367 cfg_update_parser_config(CFGFILE *cfg, const char *key, int section) 2368 { 2369 cfp_t *cfp; 2370 int size; 2371 char buf[CFG_MAX_BUF]; 2372 struct parser *tbl; 2373 char tmpkey[CFG_MAX_KEY]; 2374 char *ky, *fld; 2375 errno = 0; 2376 2377 if (cfg == NULL) { 2378 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2379 cfg_severity = CFG_EFATAL; 2380 return (-1); 2381 } 2382 2383 cfp = FP_SUN_CLUSTER(cfg); 2384 if (!cfg_wrlock(cfg)) 2385 return (-1); 2386 2387 bzero(buf, CFG_MAX_BUF); 2388 bzero(tmpkey, sizeof (tmpkey)); 2389 strcpy(tmpkey, key); 2390 if (section == CFG_PARSE_CONF) { 2391 strcat(buf, "C:"); 2392 tbl = chead; 2393 } else { 2394 errno = EINVAL; 2395 return (-1); 2396 } 2397 ky = strtok(tmpkey, "."); 2398 fld = strtok(NULL, "."); 2399 while (fld) { 2400 size = cfg_get_item(tbl, ky, fld); 2401 2402 /* 2403 * Assure we are loading a clean table, with do duplicates 2404 * based on our File Descriptor 2405 */ 2406 if (chead_loaded && (chead_loaded != cfp->cf_fd)) { 2407 if (size <= 0) 2408 return (-1); 2409 } else { 2410 if (size > 0) 2411 return (-1); 2412 } 2413 fld = strtok(NULL, "."); 2414 } 2415 size = strlen(key) + 2; 2416 strncat(buf, key, size); 2417 #ifdef DEBUG_LIB 2418 (void) fprintf(stderr, "update parser config %s size %d\n", buf, size); 2419 #endif 2420 if ((size + cfp->cf_head->h_parseoff) > CFG_DEFAULT_PARSE_SIZE) { 2421 cfg_perror_str = dgettext("cfg", 2422 "cfg_update_parser_config: header overrun"); 2423 cfg_severity = CFG_EFATAL; 2424 #ifdef DEBUG_LIB 2425 (void) fprintf(stderr, "update parser config: " 2426 "overrun siz %d poff %d parsesize %d\n", 2427 size, cfp->cf_head->h_parseoff, cfp->cf_head->h_parsesize); 2428 #endif 2429 errno = E2BIG; 2430 return (-1); 2431 } 2432 bcopy(buf, (cfp->cf_mapped + cfp->cf_head->h_parseoff), size); 2433 cfp->cf_head->h_parseoff += size; 2434 cfp->cf_head->h_state |= CFG_HDR_INVALID; 2435 if (cfp->cf_mapped[cfp->cf_head->h_parseoff - 1] != '\n') { 2436 cfp->cf_mapped[cfp->cf_head->h_parseoff] = '\n'; 2437 cfp->cf_head->h_parseoff++; 2438 } 2439 cfp->cf_head->h_parsesize = cfp->cf_head->h_parseoff; 2440 cfg_read_parser_config(cfp); 2441 return (TRUE); 2442 } 2443 /* 2444 * cfg_read_parser_config 2445 * reads parser config from file 2446 * converts it to internal tree for parsing 2447 * chead for configuration parser entries 2448 * 2449 */ 2450 static 2451 void 2452 cfg_read_parser_config(cfp_t *cfp) 2453 { 2454 struct lookup *p, *q; 2455 struct parser *thead; 2456 int off, foff; 2457 char *part; 2458 char *key; 2459 char *fld; 2460 int fldnum; 2461 char c; 2462 char buf[CFG_MAX_BUF]; 2463 int i = 0; 2464 int n = 0; 2465 2466 off = foff = 0; 2467 /*CONSTCOND*/ 2468 while (TRUE) { 2469 off = 0; 2470 bzero(buf, CFG_MAX_BUF); 2471 /* LINTED it assigns value to c */ 2472 while (c = cfp->cf_mapped[foff++]) { 2473 if (c == '\n') 2474 break; 2475 buf[off++] = c; 2476 } 2477 part = strtok(buf, ":"); 2478 if (!part) 2479 break; 2480 if (*part == 'C') { 2481 thead = chead; 2482 n = i; 2483 } 2484 key = strtok(NULL, "."); 2485 if (!key) 2486 break; 2487 strcpy(thead[n].tag.l_word, key); 2488 thead[n].tag.l_value = 0; 2489 thead[n].fld = NULL; 2490 fldnum = 1; 2491 while ((fld = strtok(NULL, ".")) != NULL) { 2492 p = thead[n].fld; 2493 if (p == NULL) { 2494 q = thead[n].fld = calloc(1, 2495 sizeof (struct lookup)); 2496 } else { 2497 for (q = thead[n].fld; q; q = q->l_next) 2498 p = q; 2499 q = calloc(1, sizeof (struct lookup)); 2500 p->l_next = q; 2501 } 2502 strcpy(q->l_word, fld); 2503 q->l_value = fldnum; 2504 q->l_next = NULL; 2505 #ifdef DEBUG_EXTRA 2506 (void) fprintf(stderr, 2507 "read parser: q: word %s value %d\n", 2508 q->l_word, q->l_value); 2509 #endif 2510 fldnum++; 2511 } 2512 if (*part == 'C') 2513 i++; 2514 } 2515 2516 /* All done, indicate parser table is loaded */ 2517 if (i && (chead_loaded == 0)) 2518 chead_loaded = cfp->cf_fd; 2519 2520 /* 2521 * before I go and alloc, why am I here? 2522 * do I need a bunch of cfglists, or do I just 2523 * need to accommodate a just added parser entry 2524 * if the latter, we already have a base, just set 2525 * i to the index of the cfg which members need allocing 2526 */ 2527 if ((cfp->cf_head->h_cfgs == NULL) || 2528 (cfp->cf_head->h_cfgs[n-1].l_entry == NULL)) { 2529 cfp->cf_head->h_cfgs = (cfglist_t *)calloc(MAX_CFG, 2530 sizeof (cfglist_t)); 2531 i = 0; 2532 } 2533 else 2534 i = n; 2535 2536 if (cfp->cf_head->h_cfgs) { 2537 2538 #ifdef DEBUG_CFGLIST 2539 (void) fprintf(stderr, "alloced %d cfg lists \n", n + 1); 2540 #endif 2541 for (cfp->cf_head->h_ncfgs = n + 1; 2542 i < min(cfp->cf_head->h_ncfgs, MAX_CFG); i++) { 2543 cfp->cf_head->h_cfgs[i].l_name = '\0'; 2544 cfp->cf_head->h_cfgs[i].l_name = 2545 strdup(chead[i].tag.l_word); 2546 cfp->cf_head->h_cfgs[i].l_index = i; 2547 cfp->cf_head->h_cfgs[i].l_entry = 2548 calloc(DEFAULT_ENTRY_SIZE, sizeof (char)); 2549 cfp->cf_head->h_cfgs[i].l_nentry = 0; 2550 cfp->cf_head->h_cfgs[i].l_esiz = 2551 calloc(DEFAULT_NENTRIES, sizeof (int)); 2552 cfp->cf_head->h_cfgs[i].l_size = 0; 2553 cfp->cf_head->h_cfgs[i].l_free = DEFAULT_ENTRY_SIZE; 2554 if ((cfp->cf_head->h_cfgs[i].l_entry == NULL) || 2555 (cfp->cf_head->h_cfgs[i].l_esiz == NULL)) { 2556 cfg_perror_str = dgettext("cfg", "unable to" 2557 " allocate cfglist members"); 2558 cfg_severity = CFG_EFATAL; 2559 } 2560 } 2561 } else { 2562 cfg_perror_str = dgettext("cfg", "unable to alloc cfglist"); 2563 cfg_severity = CFG_EFATAL; 2564 } 2565 } 2566 2567 /* 2568 * cfg_map_cfglists() 2569 * go through list of list sizes in header 2570 * and create separate lists 2571 */ 2572 int 2573 cfg_map_cfglists(cfp_t *cfp) 2574 { 2575 int i; 2576 int offset = 0; 2577 int *ip; 2578 int list_size = 0; 2579 int slot_inc; 2580 char *p; 2581 cfgheader_t *ch; 2582 2583 ch = cfp->cf_head; 2584 p = ch->h_cparse; 2585 2586 /* get the first list size */ 2587 ip = ch->h_sizes; 2588 2589 for (i = 0; i < min(ch->h_ncfgs, MAX_CFG); i++) { 2590 if (ch->h_cfgsizes[i] > 0) { 2591 if (ch->h_cfgsizes[i] > DEFAULT_ENTRY_SIZE) { 2592 2593 ch->h_cfgs[i].l_entry = (char *) 2594 realloc(ch->h_cfgs[i].l_entry, 2595 ch->h_cfgsizes[i] * sizeof (char)); 2596 /* set free to 0, we'll get more when we add */ 2597 ch->h_cfgs[i].l_free = 0; 2598 2599 } else 2600 ch->h_cfgs[i].l_free -= ch->h_cfgsizes[i]; 2601 2602 /* get lists and marry up to each cfgs structure */ 2603 2604 2605 list_size = *ip; 2606 ip++; 2607 2608 if (list_size > DEFAULT_NENTRIES) { 2609 /* 2610 * we're gonna need more slots 2611 * we want to alloc on DEFAULT_NENTRIES 2612 * boundry. ie. always a multiple of it 2613 * later on, when we add to the list 2614 * we can see if we need to add by mod'ding 2615 * l_nentry and DEFAULT_NENTRIES and check for 0 2616 */ 2617 slot_inc = DEFAULT_NENTRIES - 2618 (list_size % DEFAULT_NENTRIES); 2619 if (slot_inc == DEFAULT_NENTRIES) 2620 slot_inc = 0; /* addcfline reallocs */ 2621 2622 ch->h_cfgs[i].l_esiz = (int *)realloc( 2623 ch->h_cfgs[i].l_esiz, 2624 (list_size + slot_inc) * sizeof (int)); 2625 } 2626 memcpy(ch->h_cfgs[i].l_esiz, ip, 2627 list_size * sizeof (int)); 2628 2629 ch->h_cfgs[i].l_nentry = list_size; 2630 2631 ip += list_size; 2632 2633 } else 2634 2635 continue; 2636 2637 if (ch->h_cfgs[i].l_entry != NULL) { 2638 p = ch->h_cparse + offset; 2639 #ifdef DEBUG_CFGLIST 2640 (void) fprintf(stderr, "mapping list %d size %d offset %d, addr 0x%x\n", 2641 i, ch->h_cfgsizes[i], offset, p); 2642 #endif 2643 memcpy(ch->h_cfgs[i].l_entry, 2644 p, ch->h_cfgsizes[i]); 2645 ch->h_cfgs[i].l_size = ch->h_cfgsizes[i]; 2646 offset += ch->h_cfgsizes[i]; 2647 } else { 2648 #ifdef DEBUG_CFGLIST 2649 (void) fprintf(stderr, "NULL l_entry\n"); 2650 #endif 2651 return (-1); 2652 } 2653 } 2654 2655 2656 return (1); 2657 2658 } 2659 2660 void 2661 cfg_replace_lists(cfp_t *cfp) 2662 { 2663 int i; 2664 int offset = 0; 2665 int size_offset = 0; 2666 2667 int section = 0; 2668 cfgheader_t *cf; 2669 cfglist_t *cfl; 2670 2671 cf = cfp->cf_head; 2672 2673 if ((cfl = cfp->cf_head->h_cfgs) == NULL) 2674 return; 2675 2676 #ifdef DEBUG_CFGLIST 2677 (void) fprintf(stderr, "cfg_replace_lists\n"); 2678 #endif 2679 2680 if (cf->h_cparse == cf->h_ccopy1) 2681 section = 1; 2682 2683 /* 2684 * check to see if we are using copy1 or 2, 2685 * grow or shrink the size, fix h_cparse reference 2686 * in case realloc gave us a funky new address. 2687 * put stuff in it. 2688 */ 2689 cf->h_ccopy1 = (char *) 2690 realloc(cf->h_ccopy1, cf->h_csize * sizeof (char)); 2691 cf->h_ccopy2 = (char *) 2692 realloc(cf->h_ccopy2, cf->h_csize * sizeof (char)); 2693 if (section == 1) { 2694 /* we used copy1 */ 2695 cf->h_cparse = cf->h_ccopy1; 2696 } else 2697 cf->h_cparse = cf->h_ccopy2; 2698 2699 /* 2700 * just because, we'll zero out h_csize and recalc 2701 * after all, this is the number the next guy gets 2702 */ 2703 cf->h_csize = cf->h_sizes[0] = 0; 2704 for (i = 0; i < MAX_CFG; i++) { 2705 /* only as many lists as chead has */ 2706 if (chead[i].tag.l_word[0] == '\0') { 2707 break; 2708 } 2709 if (cfl[i].l_entry && cfl[i].l_entry[0] != '\0') { 2710 #ifdef DEBUG_CFGLIST 2711 (void) fprintf(stderr, 2712 "copying list %d at %x size %d\n", 2713 i, cf->h_cparse + offset, 2714 cfl[i].l_size); 2715 #endif 2716 memcpy((cf->h_cparse + offset), 2717 cfl[i].l_entry, cfl[i].l_size); 2718 offset += cfl[i].l_size; 2719 #ifdef DEBUG_CFGLIST 2720 (void) fprintf(stderr, 2721 "cfl[%d].l_nentry %d cfl[%d].l_esiz[%d] %d" 2722 " size offset %d\n", 2723 i, cfl[i].l_nentry, i, cfl[i].l_nentry - 1, 2724 cfl[i].l_esiz[cfl[i].l_nentry - 1], size_offset); 2725 #endif 2726 /* 2727 * first write the number of entries 2728 * then copy over the array ie. 2729 * a list with 5 elements would be copied 2730 * as a 6 element array slot 0 being the 2731 * number of elements 2732 */ 2733 cf->h_sizes[size_offset++] = cfl[i].l_nentry; 2734 memcpy((cf->h_sizes + size_offset), cfl[i].l_esiz, 2735 cfl[i].l_nentry * sizeof (int)); 2736 size_offset += cfl[i].l_nentry; 2737 cf->h_sizes[size_offset] = 0; 2738 } 2739 cf->h_csize += cfl[i].l_size; 2740 } 2741 } 2742 2743 void 2744 cfg_free_cfglist(cfp_t *cfp) 2745 { 2746 int i; 2747 2748 if (!cfp->cf_head || !cfp->cf_head->h_cfgs) 2749 return; 2750 2751 for (i = 0; cfp->cf_head && i < MAX_CFG; i++) { 2752 if (cfp->cf_head->h_cfgs[i].l_entry) { 2753 free(cfp->cf_head->h_cfgs[i].l_entry); 2754 cfp->cf_head->h_cfgs[i].l_entry = NULL; 2755 } 2756 2757 if (cfp->cf_head->h_cfgs[i].l_name) { 2758 free(cfp->cf_head->h_cfgs[i].l_name); 2759 cfp->cf_head->h_cfgs[i].l_entry = NULL; 2760 } 2761 2762 if (cfp->cf_head->h_cfgs[i].l_esiz) { 2763 free(cfp->cf_head->h_cfgs[i].l_esiz); 2764 cfp->cf_head->h_cfgs[i].l_esiz = NULL; 2765 } 2766 } 2767 2768 if (cfp->cf_head) { 2769 free(cfp->cf_head->h_cfgs); 2770 cfp->cf_head->h_cfgs = NULL; 2771 } 2772 } 2773 2774 void 2775 cfg_free_parser_tree() 2776 { 2777 struct lookup *p = NULL; 2778 struct lookup *q = NULL; 2779 int i; 2780 2781 for (i = 0; i < MAX_CFG; i++) { 2782 if (chead) 2783 p = chead[i].fld; 2784 while (p) { 2785 q = p->l_next; 2786 if (p) { 2787 free(p); 2788 p = NULL; 2789 } 2790 p = q; 2791 } 2792 } 2793 bzero(chead, MAX_CFG * sizeof (struct parser)); 2794 } 2795 2796 void 2797 cfg_close(CFGFILE *cfg) 2798 { 2799 cfp_t *cfp; 2800 2801 if (cfg == NULL) { 2802 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2803 cfg_severity = CFG_EFATAL; 2804 return; 2805 } 2806 2807 /* Determine number of files open */ 2808 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 2809 if (!cfp->cf_fd) continue; 2810 2811 (*cfp->cf_pp->close)(cfp); 2812 #ifdef DEBUG_CFGLIST 2813 (void) fprintf(stderr, "freeing cfglists\n"); 2814 #endif 2815 cfg_free_cfglist(cfp); 2816 2817 #ifdef DEBUG_CFGLIST 2818 (void) fprintf(stderr, "freeing cfp->cf_mapped\n"); 2819 #endif 2820 free(cfp->cf_mapped); 2821 cfp->cf_mapped = NULL; 2822 2823 #ifdef DEBUG_CFGLIST 2824 (void) fprintf(stderr, 2825 "freeing copy1, copy2, h_sizes and cf\n"); 2826 #endif 2827 if (cfp->cf_head) { 2828 if (cfp->cf_head->h_ccopy1) { 2829 free(cfp->cf_head->h_ccopy1); 2830 cfp->cf_head->h_ccopy1 = NULL; 2831 } 2832 if (cfp->cf_head->h_ccopy2) { 2833 free(cfp->cf_head->h_ccopy2); 2834 cfp->cf_head->h_ccopy2 = NULL; 2835 } 2836 if (cfp->cf_head->h_sizes1) { 2837 free(cfp->cf_head->h_sizes1); 2838 cfp->cf_head->h_sizes1 = NULL; 2839 } 2840 if (cfp->cf_head->h_sizes2) { 2841 free(cfp->cf_head->h_sizes2); 2842 cfp->cf_head->h_sizes2 = NULL; 2843 } 2844 2845 } 2846 if (cfp->cf_head) 2847 free(cfp->cf_head); 2848 } 2849 2850 free(cfg); 2851 cfg = NULL; 2852 cfg_free_parser_tree(); 2853 2854 #ifdef DEBUG_CFGLIST 2855 (void) fprintf(stderr, "cfg_close\n"); 2856 #endif 2857 } 2858 2859 2860 char * 2861 cfg_get_resource(CFGFILE *cfg) 2862 { 2863 if (cfg == NULL) { 2864 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2865 cfg_severity = CFG_EFATAL; 2866 return (NULL); 2867 } 2868 2869 return (cfg->cf_node); 2870 } 2871 2872 /* 2873 * cfg_resource 2874 * set or clear the cluster node filter for get/put 2875 */ 2876 2877 void 2878 cfg_resource(CFGFILE *cfg, const char *node) 2879 { 2880 if (cfg == NULL) { 2881 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2882 cfg_severity = CFG_EFATAL; 2883 return; 2884 } 2885 2886 if (cfg->cf_node) { 2887 #ifdef DEBUG_CFGLIST 2888 (void) fprintf(stderr, 2889 "cfg_resource: changing node from %s to %s\n", 2890 cfg->cf_node, (node?node:"NULL")); 2891 #endif 2892 free(cfg->cf_node); 2893 cfg->cf_node = NULL; 2894 } 2895 2896 /* 2897 * just in case someone passes in a non-NULL 2898 * node, but has no valid value 2899 */ 2900 if ((node) && (node[0] != '\0')) { 2901 cfg->cf_node = strdup(node); 2902 } 2903 } 2904 2905 /* 2906 * cfg_open 2907 * Open the current configuration file 2908 */ 2909 CFGFILE * 2910 cfg_open(char *name) 2911 { 2912 CFGFILE *cfg; 2913 cfp_t *cfp; 2914 int32_t magic; 2915 long needed; 2916 int rc; 2917 2918 #ifdef DEBUG_CFGLIST 2919 (void) fprintf(stderr, "cfg_open\n"); 2920 #endif 2921 2922 cfg_severity = 0; 2923 if ((cfg = (CFGFILE *)calloc(1, sizeof (*cfg))) == NULL) { 2924 cfg_perror_str = dgettext("cfg", 2925 "cfg_open: malloc failed"); 2926 cfg_severity = CFG_EFATAL; 2927 return (NULL); 2928 } 2929 2930 cfp = &cfg->cf[0]; 2931 if ((name) && strlen(name)) { 2932 #ifdef DEBUG 2933 (void) fprintf(stderr, "cfg_open: Using non-standard name\n"); 2934 #endif 2935 cfp->cf_name = name; 2936 cfp->cf_pp = (strstr(cfp->cf_name, "/rdsk/") == NULL) 2937 ? cfg_block_io_provider() 2938 : cfg_raw_io_provider(); 2939 } else { 2940 cfp->cf_name = cfg_location(NULL, CFG_LOC_GET_LOCAL, NULL); 2941 cfp->cf_pp = cfg_block_io_provider(); 2942 2943 /* Handle cfg_open(""), which is an open from boot tools */ 2944 if (name) 2945 cl_initialized = 1; 2946 if (cfg_iscluster() > 0) { 2947 cfp = &cfg->cf[1]; 2948 cfp->cf_name = 2949 cfg_location(NULL, CFG_LOC_GET_CLUSTER, NULL); 2950 if (cfp->cf_name) { 2951 cfp->cf_pp = cfg_raw_io_provider(); 2952 } 2953 } 2954 } 2955 2956 /* 2957 * Open one or two configuration files 2958 */ 2959 for (cfp = &cfg->cf[0]; cfp->cf_name && (cfp <= &cfg->cf[1]); cfp++) { 2960 if ((*cfp->cf_pp->open)(cfp, cfp->cf_name) == NULL) { 2961 cfg_perror_str = dgettext("cfg", 2962 "cfg_open: unable to open configuration location"); 2963 cfg_severity = CFG_EFATAL; 2964 break; 2965 } 2966 2967 /* block device smaller than repository? */ 2968 rc = (*cfp->cf_pp->read)(cfp, &magic, sizeof (magic)); 2969 if (rc < sizeof (magic)) { 2970 cfg_perror_str = dgettext("cfg", 2971 "cfg_open: unable to read configuration header"); 2972 cfg_severity = CFG_EFATAL; 2973 break; 2974 } 2975 2976 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 2977 cfg_perror_str = dgettext("cfg", 2978 "cfg_open: unable to seek configuration header"); 2979 cfg_severity = CFG_EFATAL; 2980 break; 2981 } 2982 2983 /* 2984 * we can't enforce size rules on an old database 2985 * so check the magic number before we test for size 2986 */ 2987 if (magic == CFG_NEW_MAGIC) { 2988 needed = FBA_NUM(FBA_SIZE(1) - 1 + 2989 (sizeof (struct cfgheader) + CFG_CONFIG_SIZE)); 2990 } else { 2991 needed = 0; 2992 } 2993 2994 if (cfp->cf_size < needed) { 2995 cfg_perror_str = dgettext("cfg", 2996 "cfg_open: configuration file too small"); 2997 cfg_severity = CFG_EFATAL; 2998 errno = ENOMEM; 2999 break; 3000 } 3001 3002 cfp->cf_mapped = (char *)malloc(CFG_DEFAULT_PARSE_SIZE); 3003 if (cfp->cf_mapped == NULL) { 3004 cfg_perror_str = dgettext("cfg", 3005 "cfg_open: malloc failed"); 3006 cfg_severity = CFG_EFATAL; 3007 break; 3008 } 3009 3010 bzero(cfp->cf_mapped, CFG_DEFAULT_PARSE_SIZE); 3011 cfp->cf_lock = -1; 3012 } 3013 3014 /* Processing errors, take care of one or more cfp pointers */ 3015 if (cfg_severity && (cfp <= &cfg->cf[1])) { 3016 cfp = &cfg->cf[0]; 3017 if (cfp->cf_fd) 3018 (*cfp->cf_pp->close)(cfp); 3019 cfp = &cfg->cf[1]; 3020 if (cfp->cf_fd) 3021 (*cfp->cf_pp->close)(cfp); 3022 free(cfg); 3023 return (NULL); 3024 } 3025 3026 cfg_lockd = cfg_lockd_init(); 3027 3028 3029 #ifdef DEBUG_CFGLIST 3030 (void) fprintf(stderr, "cfg_open ok\n"); 3031 #endif 3032 return (cfg); 3033 } 3034 3035 void 3036 cfg_invalidate_hsizes(int fd, const char *loc) { 3037 int offset; 3038 int rc = -1; 3039 int hdrsz; 3040 3041 char buf[2 * CFG_DEFAULT_PSIZE]; 3042 3043 hdrsz = sizeof (cfgheader_t) + 512 - 3044 (sizeof (cfgheader_t) % 512); 3045 3046 offset = hdrsz + CFG_DEFAULT_PARSE_SIZE + 3047 (CFG_DEFAULT_SSIZE * 2); 3048 3049 if (cfg_shldskip_vtoc(fd, loc) > 0) 3050 offset += CFG_VTOC_SKIP; 3051 3052 bzero(buf, sizeof (buf)); 3053 3054 if (lseek(fd, offset, SEEK_SET) > 0) 3055 rc = write(fd, buf, sizeof (buf)); 3056 if (rc < 0) 3057 (void) fprintf(stderr, "cfg: invalidate hsizes failed\n"); 3058 3059 } 3060 3061 char * 3062 cfg_error(int *severity) 3063 { 3064 if (severity != NULL) 3065 *severity = cfg_severity; 3066 return (cfg_perror_str ? cfg_perror_str : CFG_EGENERIC); 3067 } 3068 /* 3069 * cfg_cfg_isempty 3070 */ 3071 int 3072 cfg_cfg_isempty(CFGFILE *cfg) 3073 { 3074 cfp_t *cfp; 3075 3076 if (cfg == NULL) { 3077 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3078 cfg_severity = CFG_EFATAL; 3079 return (FALSE); 3080 } 3081 3082 cfp = FP_SUN_CLUSTER(cfg); 3083 if (cfp->cf_head->h_csize == 0) 3084 return (TRUE); 3085 else 3086 return (FALSE); 3087 } 3088 3089 /* 3090 * cfg_get_num_entries 3091 * return the number of entries in a given section of database 3092 * sndr, ii, ndr_ii... 3093 */ 3094 int 3095 cfg_get_num_entries(CFGFILE *cfg, char *section) 3096 { 3097 int count = 0; 3098 int table_offset; 3099 cfp_t *cfp; 3100 3101 if (cfg == NULL) { 3102 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3103 cfg_severity = CFG_EFATAL; 3104 return (-1); 3105 } 3106 3107 if ((table_offset = cfg_get_parser_offset(section)) < 0) { 3108 errno = ESRCH; 3109 return (-1); 3110 } 3111 3112 /* Determine number of files open */ 3113 for (cfp = &cfg->cf[0]; cfp->cf_fd && (cfp <= &cfg->cf[1]); cfp++) 3114 count += cfp->cf_head->h_cfgs[table_offset].l_nentry; 3115 3116 return (count); 3117 } 3118 3119 /* 3120 * cfg_get_section 3121 * all etries in a config file section is placed in 3122 * buf, allocation is done inside 3123 * freeing buf is responisbility of the caller 3124 * number of entries in section is returned 3125 * -1 on failure, errno is set 3126 */ 3127 int 3128 cfg_get_section(CFGFILE *cfg, char ***list, const char *section) 3129 { 3130 int table_offset; 3131 int i, count; 3132 cfglist_t *cfl; 3133 char *p = NULL; 3134 char **buf; 3135 cfp_t *cfp; 3136 3137 if (cfg == NULL) { 3138 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3139 cfg_severity = CFG_EFATAL; 3140 return (FALSE); 3141 } 3142 3143 if ((table_offset = cfg_get_parser_offset(section)) < 0) { 3144 errno = ESRCH; 3145 return (-1); 3146 } 3147 3148 /* Determine number of files open */ 3149 count = 0; 3150 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 3151 if (!cfp->cf_fd) continue; 3152 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 3153 if (!cfg_read(cfp)) { 3154 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 3155 cfg_severity = CFG_EFATAL; 3156 return (-1); 3157 } 3158 } 3159 3160 cfl = &cfp->cf_head->h_cfgs[table_offset]; 3161 if (cfl->l_nentry == 0) /* empty list */ 3162 continue; 3163 3164 if (count == 0) 3165 buf = (char **)malloc(cfl->l_nentry * sizeof (char *)); 3166 else 3167 buf = (char **)realloc(buf, (cfl->l_nentry + count) * 3168 sizeof (char *)); 3169 if (buf == NULL) { 3170 errno = ENOMEM; 3171 return (-1); 3172 } else { 3173 bzero(&buf[count], cfl->l_nentry * sizeof (char *)); 3174 } 3175 3176 p = cfl->l_entry; 3177 for (i = 0; i < cfl->l_nentry; i++) { 3178 if ((buf[i + count] = strdup(p)) == NULL) { 3179 errno = ENOMEM; 3180 return (-1); 3181 } 3182 p += cfl->l_esiz[i]; 3183 } 3184 count += cfl->l_nentry; 3185 } 3186 3187 *list = buf; 3188 return (count); 3189 } 3190 3191 /* 3192 * cluster upgrade helper functions. These support old database operations 3193 * while upgrading nodes on a cluster. 3194 */ 3195 3196 /* 3197 * returns the list of configured tags 3198 * return -1 on error, else the number 3199 * of tags returned in taglist 3200 * caller frees 3201 */ 3202 int 3203 cfg_get_tags(CFGFILE *cfg, char ***taglist) 3204 { 3205 char **list; 3206 int i = 0; 3207 3208 if (cfg == NULL) { 3209 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3210 cfg_severity = CFG_EFATAL; 3211 return (-1); 3212 } 3213 3214 if (!cfg_rdlock(cfg)) { 3215 return (-1); 3216 } 3217 list = calloc(1, MAX_CFG * sizeof (char *)); 3218 if (list == NULL) { 3219 errno = ENOMEM; 3220 return (-1); 3221 } 3222 3223 while ((i < MAX_CFG) && (chead[i].tag.l_word[0] != '\0')) { 3224 list[i] = strdup(chead[i].tag.l_word); 3225 if (list[i] == NULL) { 3226 for (/* CSTYLE */; i >= 0; i--) { 3227 if (list[i]) 3228 free(list[i]); 3229 } 3230 free(list); 3231 errno = ENOMEM; 3232 return (-1); 3233 } 3234 i++; 3235 } 3236 *taglist = list; 3237 return (i); 3238 3239 } 3240 3241 /* 3242 * is this a database? 3243 * check the header for the magic number 3244 * 0 no match 1 match, -1 on error 3245 */ 3246 int 3247 cfg_is_cfg(CFGFILE *cfg) 3248 { 3249 int32_t magic; 3250 int rc; 3251 cfp_t *cfp = FP_SUN_CLUSTER(cfg); 3252 3253 rc = (cfp->cf_pp->read)(cfp, &magic, sizeof (magic)); 3254 if (rc < sizeof (magic)) { 3255 cfg_perror_str = dgettext("cfg", "Fail to read configuration"); 3256 cfg_severity = CFG_EFATAL; 3257 return (-1); 3258 } 3259 3260 if (magic == CFG_NEW_MAGIC) 3261 return (1); 3262 3263 cfg_perror_str = dgettext("cfg", 3264 "configuration not initialized, bad magic"); 3265 cfg_severity = CFG_EFATAL; 3266 3267 return (0); 3268 } 3269 3270 int 3271 compare(const void* a, const void *b) 3272 { 3273 char *p; 3274 char *pbuf; 3275 char *q; 3276 char *qbuf; 3277 int needed; 3278 int cmp; 3279 int pos; 3280 3281 pbuf = strdup(a); 3282 qbuf = strdup(b); 3283 3284 if (!qbuf || !pbuf) 3285 return (0); 3286 3287 pos = 1; 3288 needed = sortby.offset; 3289 3290 p = strtok(pbuf, " "); 3291 while (p) { 3292 if (needed == pos) { 3293 break; 3294 } 3295 p = strtok(NULL, " "); 3296 if (!p) 3297 break; 3298 pos++; 3299 } 3300 3301 pos = 1; 3302 q = strtok(qbuf, " "); 3303 while (q) { 3304 if (needed == pos) { 3305 break; 3306 } 3307 q = strtok(NULL, " "); 3308 if (!q) 3309 break; 3310 pos++; 3311 } 3312 if (!p || !q) { 3313 sortby.comperror++; 3314 free(pbuf); 3315 free(qbuf); 3316 return (0); 3317 } 3318 cmp = strcmp(p, q); 3319 free(pbuf); 3320 free(qbuf); 3321 return (cmp); 3322 3323 3324 } 3325 /* 3326 * cfg_get_srtdsec 3327 * returns the section, sorted by supplied field 3328 * caller frees mem 3329 */ 3330 int 3331 cfg_get_srtdsec(CFGFILE *cfg, char ***list, const char *section, 3332 const char *field) 3333 { 3334 cfglist_t *cfl; 3335 cfp_t *cfp; 3336 char **buf; 3337 char *tmplst; 3338 char *p, *q; 3339 int table_offset; 3340 int count, i; 3341 3342 if (cfg == NULL) { 3343 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3344 cfg_severity = CFG_EFATAL; 3345 return (FALSE); 3346 } 3347 3348 if ((table_offset = cfg_get_parser_offset(section)) < 0) { 3349 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 3350 errno = ESRCH; 3351 return (-1); 3352 } 3353 3354 /* 3355 * do essentially what get_section does, 3356 * except stick entries in a static size 3357 * buf to make things easier to qsort 3358 */ 3359 count = 0; 3360 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 3361 if (!cfp->cf_fd) continue; 3362 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 3363 if (!cfg_read(cfp)) { 3364 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 3365 cfg_severity = CFG_EFATAL; 3366 return (-1); 3367 } 3368 } 3369 3370 cfl = &cfp->cf_head->h_cfgs[table_offset]; 3371 if (cfl->l_nentry == 0) /* empty list */ 3372 continue; 3373 3374 if (count == 0) 3375 buf = (char **)malloc(cfl->l_nentry * sizeof (char *)); 3376 else 3377 buf = (char **)realloc(buf, (cfl->l_nentry + count) * 3378 sizeof (char *)); 3379 if (buf == NULL) { 3380 errno = ENOMEM; 3381 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: " 3382 "malloc failed"); 3383 cfg_severity = CFG_EFATAL; 3384 return (-1); 3385 } else { 3386 bzero(&buf[count], cfl->l_nentry * sizeof (char *)); 3387 } 3388 3389 /* 3390 * allocate each line 3391 */ 3392 for (i = count; i < cfl->l_nentry + count; i++) { 3393 buf[i] = calloc(1, CFG_MAX_BUF); 3394 if (buf[i] == NULL) { 3395 free(buf); 3396 errno = ENOMEM; 3397 return (-1); 3398 } 3399 } 3400 3401 if (count == 0) 3402 tmplst = (char *)malloc(cfl->l_nentry * CFG_MAX_BUF); 3403 else 3404 tmplst = (char *)realloc(tmplst, 3405 (cfl->l_nentry + count) * CFG_MAX_BUF); 3406 if (tmplst == NULL) { 3407 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: " 3408 "malloc failed"); 3409 cfg_severity = CFG_EFATAL; 3410 free(buf); 3411 return (-1); 3412 } else { 3413 bzero(&tmplst[count], cfl->l_nentry * CFG_MAX_BUF); 3414 } 3415 3416 /* 3417 * put the section in tmplst and sort 3418 */ 3419 p = &tmplst[count]; 3420 q = cfl->l_entry; 3421 for (i = 0; i < cfl->l_nentry; i++) { 3422 bcopy(q, p, cfl->l_esiz[i]); 3423 p += CFG_MAX_BUF; 3424 q += cfl->l_esiz[i]; 3425 } 3426 count += cfl->l_nentry; 3427 } 3428 3429 bzero(sortby.section, CFG_MAX_KEY); 3430 bzero(sortby.field, CFG_MAX_KEY); 3431 3432 strcpy(sortby.section, section); 3433 strcpy(sortby.field, field); 3434 sortby.comperror = 0; 3435 sortby.offset = cfg_get_item(&chead[0], section, field); 3436 3437 qsort(tmplst, count, CFG_MAX_BUF, compare); 3438 3439 if (sortby.comperror) { 3440 sortby.comperror = 0; 3441 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: " 3442 "comparison error"); 3443 cfg_severity = CFG_ENONFATAL; 3444 cfg_free_section(&buf, cfl->l_nentry); 3445 free(tmplst); 3446 *list = NULL; 3447 return (-1); 3448 } 3449 3450 p = tmplst; 3451 for (i = 0; i < count; i++) { 3452 bcopy(p, buf[i], CFG_MAX_BUF); 3453 p += CFG_MAX_BUF; 3454 } 3455 3456 free(tmplst); 3457 *list = buf; 3458 return (count); 3459 } 3460 3461 /* 3462 * free an array alloc'd by get_*section 3463 * or some other array of size size 3464 */ 3465 3466 void 3467 cfg_free_section(char ***section, int size) 3468 { 3469 int i; 3470 char **secpp = *section; 3471 3472 for (i = 0; i < size; i++) { 3473 if (secpp[i]) { 3474 free(secpp[i]); 3475 secpp[i] = NULL; 3476 } 3477 } 3478 if (secpp) { 3479 free(secpp); 3480 secpp = NULL; 3481 } 3482 section = NULL; 3483 } 3484 3485 3486 int 3487 cfg_shldskip_vtoc(int fd, const char *loc) 3488 { 3489 struct vtoc vtoc; 3490 struct stat sb; 3491 int slice; 3492 int rfd; 3493 char char_name[PATH_MAX]; 3494 char *p; 3495 3496 if (fstat(fd, &sb) == -1) { 3497 cfg_perror_str = dgettext("cfg", "unable to stat config"); 3498 cfg_severity = CFG_EFATAL; 3499 return (-1); 3500 } 3501 if (S_ISREG(sb.st_mode)) 3502 return (0); 3503 3504 if (S_ISCHR(sb.st_mode)) { 3505 if ((slice = read_vtoc(fd, &vtoc)) < 0) 3506 return (-1); 3507 3508 if (vtoc.v_part[slice].p_start < CFG_VTOC_SIZE) 3509 return (1); 3510 else 3511 return (0); 3512 } 3513 3514 if (S_ISBLK(sb.st_mode)) { 3515 p = strstr(loc, "/dsk/"); 3516 if (p == NULL) 3517 return (-1); 3518 strcpy(char_name, loc); 3519 char_name[strlen(loc) - strlen(p)] = 0; 3520 strcat(char_name, "/rdsk/"); 3521 strcat(char_name, p + 5); 3522 3523 if ((rfd = open(char_name, O_RDONLY)) < 0) { 3524 return (-1); 3525 } 3526 if ((slice = read_vtoc(rfd, &vtoc)) < 0) { 3527 close(rfd); 3528 return (-1); 3529 } 3530 close(rfd); 3531 if (vtoc.v_part[slice].p_start < CFG_VTOC_SIZE) 3532 return (1); 3533 else 3534 return (0); 3535 } 3536 3537 return (-1); 3538 } 3539 3540 /* 3541 * comapares incore header with one on disk 3542 * returns 0 if equal, 1 if not, -1 error 3543 */ 3544 int 3545 cfg_hdrcmp(cfp_t *cfp) 3546 { 3547 cfgheader_t *dskhdr, *memhdr; 3548 int rc; 3549 3550 if ((dskhdr = calloc(1, sizeof (*dskhdr))) == NULL) { 3551 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: No memory"); 3552 cfg_severity = CFG_ENONFATAL; 3553 } 3554 3555 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 3556 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: seek failed"); 3557 cfg_severity = CFG_ENONFATAL; 3558 free(dskhdr); 3559 return (-1); 3560 } 3561 3562 rc = (*cfp->cf_pp->read)(cfp, (char *)dskhdr, sizeof (*dskhdr)); 3563 if (rc < 0) { 3564 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: read failed"); 3565 cfg_severity = CFG_ENONFATAL; 3566 free(dskhdr); 3567 return (-1); 3568 } 3569 3570 memhdr = cfp->cf_head; 3571 3572 if ((memhdr->h_seq1 == dskhdr->h_seq1) && 3573 (memhdr->h_seq2 == dskhdr->h_seq2)) 3574 rc = 0; 3575 else 3576 rc = 1; 3577 3578 3579 free(dskhdr); 3580 return (rc); 3581 } 3582