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 } else { 507 if (strlen(p) > value_len) { 508 errno = E2BIG; 509 cfg_perror_str = 510 dgettext("cfg", 511 strerror(errno)); 512 cfg_severity = 513 CFG_ENONFATAL; 514 return (-1); 515 } 516 } 517 strncpy(value, p, value_len); 518 519 return (pos); 520 } 521 p = strtok(NULL, " "); 522 if (!p) 523 break; 524 pos++; 525 } 526 } 527 } 528 errno = ESRCH; 529 cfg_perror_str = dgettext("cfg", strerror(errno)); 530 cfg_severity = CFG_ENONFATAL; 531 return (-1); 532 } 533 534 /* 535 * cfg_find_cstring() 536 * search for a string in the specified section 537 * in the specified field(s) 538 * if nfld is 0, then the string is searched for in 539 * every field of the entry 540 * the set number of the first occurence of target is returned 541 * ie. if /dev/vx/rdsk/vol10 is found in sndr.set9, 9 will be returned 542 * that is, of course, if the correct field was searched on. 543 * -1 on error 544 * 545 */ 546 int 547 cfg_find_cstring(CFGFILE *cfg, const char *target, 548 const char *section, int numflds, ...) 549 { 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 rc = (*cfp->cf_pp->remcf)(cfp, table_index, 812 relnum - secnum); 813 if (rc < 0) 814 return (rc); 815 return (0); 816 } 817 818 got = cfg_cnt_flds(value); 819 bzero(buf, sizeof (buf)); 820 821 strncpy(buf, " ", 1); 822 if (strlen(value) > sizeof (buf) - 2) { 823 errno = E2BIG; 824 cfg_perror_str = dgettext("cfg", strerror(errno)); 825 cfg_severity = CFG_ENONFATAL; 826 return (-1); 827 } 828 strncat(buf, value, val_len); 829 if (got < nflds) { 830 for (/* CSTYLED */; got < nflds; got++) 831 strncat(buf, " - ", 3); 832 } else if (got > nflds) { 833 return (-1); 834 } else { 835 /* got == nflds, so cnode was included */ 836 addcnode = 0; 837 } 838 839 bufp = buf; 840 if (addcnode) { 841 cfg_insert_node(cfg, &chead[0], buf, section); 842 } 843 844 (*cfp->cf_pp->replacecf)(cfp, bufp, table_index, 845 relnum - secnum); 846 847 return (TRUE); 848 } 849 850 /* 851 * Both Set and field are specified 852 * needs to get current whole entry and old requested field 853 * copy good fields to buf, replace new field in buf 854 * move everything depending of new size 855 * replace entry so set# does not change 856 */ 857 if (setp && itemp) { 858 int rc; 859 int nflds; 860 int cnodepos; 861 862 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 863 if (!cfp->cf_fd) continue; 864 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 865 if (!cfg_read(cfp)) { 866 cfg_perror_str = 867 dgettext("cfg", CFG_RDFAILED); 868 cfg_severity = CFG_EFATAL; 869 return (-1); 870 } 871 } 872 while (numfound < setnum) { 873 if ((*cfp->cf_pp->readcf) 874 (cfp, buf, table_offset, relnum - secnum) 875 == NULL) { 876 secnum = relnum - 1; 877 break; 878 } 879 if (cfg_filter_node(cfg, &chead[0], buf, 880 section)) 881 numfound++; 882 883 if (numfound == setnum) 884 break; 885 886 relnum++; 887 } 888 if (numfound == setnum) 889 break; 890 } 891 892 /* Fail to find anything? */ 893 if (cfp >= &cfg->cf[2]) { 894 errno = ESRCH; 895 cfg_perror_str = dgettext("cfg", strerror(errno)); 896 cfg_severity = CFG_ENONFATAL; 897 return (-1); 898 } 899 900 nflds = cfg_get_num_flds(&chead[0], section, &table_index); 901 fldnum = cfg_get_item(&chead[0], section, itemp); 902 bzero(newbuf, sizeof (newbuf)); 903 strncpy(newbuf, " ", 1); 904 905 /* move good flds in */ 906 rc = cfg_fld_mov(newbuf, buf, 1, fldnum - 1); 907 if (rc < 0) 908 return (rc); 909 910 /* move new fld in */ 911 strncat(newbuf, value, strlen(value)); 912 strcat(newbuf, " "); 913 914 /* move remaining flds in */ 915 rc = cfg_fld_mov(newbuf, buf, fldnum + 1, nflds); 916 if (rc < 0) 917 return (rc); 918 919 cnodepos = cfg_get_item(&chead[0], section, "cnode"); 920 if ((cnodepos >= 0) && strcmp(itemp, "cnode") != 0) { 921 /* add cnode if user didn't specify it */ 922 cfg_insert_node(cfg, &chead[0], 923 newbuf, section); 924 } 925 926 (*cfp->cf_pp->replacecf)(cfp, newbuf, table_index, 927 relnum - secnum); 928 929 return (TRUE); 930 } 931 932 if (noset) { /* blast entire thing in */ 933 int nflds; 934 int got; 935 int cnodepos; 936 937 bufp = buf; 938 if (!value) { /* we shouldn't be here */ 939 errno = EINVAL; 940 return (-1); 941 } 942 strncat(buf, " ", 1); 943 if (strlen(value) > sizeof (buf) - 2) { 944 errno = E2BIG; 945 return (-1); 946 } 947 948 strncat(buf, value, val_len); 949 nflds = cfg_get_num_flds(&chead[0], section, &table_index); 950 got = cfg_cnt_flds(value); 951 952 cnodepos = cfg_get_item(&chead[0], section, "cnode"); 953 if (cnodepos < 0 || got >= cnodepos) { 954 /* no cnode, or cnode was specified by caller */ 955 addcnode = 0; 956 } 957 958 if (got < nflds) { 959 for (/* CSTYLED */; got < nflds; got++) 960 strncat(buf, " - ", 3); 961 } else if (got > nflds) { 962 errno = EINVAL; /* specified too many fields */ 963 return (-1); 964 } else { 965 /* got == nflds, so cnode was included */ 966 addcnode = 0; 967 } 968 969 if (addcnode) { 970 cfg_insert_node(cfg, &chead[0], buf, section); 971 } 972 973 /* Make sure we put this entry in the right database */ 974 if (cfg_is_cnode(cfg, &chead[0], buf, section) && 975 cfg->cf[1].cf_fd) 976 cfp = &cfg->cf[1]; 977 else 978 cfp = &cfg->cf[0]; 979 980 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 981 if (!cfg_read(cfp)) { 982 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 983 cfg_severity = CFG_EFATAL; 984 return (-1); 985 } 986 } 987 if (cfp->cf_head->h_csize + strlen(buf) > CFG_DEFAULT_SSIZE) { 988 errno = ENOSPC; 989 return (-1); 990 } 991 992 (*cfp->cf_pp->addcf)(cfp, bufp, table_index); 993 994 return (TRUE); 995 } 996 997 errno = EINVAL; 998 cfg_perror_str = strerror(errno); 999 cfg_severity = CFG_ENONFATAL; 1000 return (-1); 1001 } 1002 1003 /* 1004 * cfg_encode_char 1005 * 1006 * Encode a single character into % + hex ascii value 1007 */ 1008 static void 1009 cfg_encode_char(char *result, char ch) 1010 { 1011 *result++ = '%'; 1012 *result++ = dectohex[ (ch >> 4) & 0xf ]; 1013 *result++ = dectohex[ ch & 0xf ]; 1014 } 1015 1016 /* 1017 * cfg_decode_char 1018 * 1019 * Reverses cfg_encode_char 1020 */ 1021 static char 1022 cfg_decode_char(char *code) 1023 { 1024 char retval; 1025 if (*code != '%') { 1026 return ('\0'); 1027 } 1028 ++code; 1029 if (!isxdigit(*code)) 1030 return ('\0'); 1031 retval = (isdigit(*code)? *code - '0' : *code - 'a' + 10); 1032 retval <<= 4; 1033 ++code; 1034 if (!isxdigit(*code)) 1035 return ('\0'); 1036 retval |= (isdigit(*code)? *code - '0' : *code - 'a' + 10); 1037 1038 return (retval); 1039 } 1040 1041 /* 1042 * cfg_encode_option 1043 * 1044 * Transforms the key and value strings so that special characters 1045 * can be used within the options field. 1046 * 1047 * Returns: 1048 * Length of encoded string; -1 on failure 1049 */ 1050 static int 1051 cfg_encode_string(char *str, char *output, int outlen) 1052 { 1053 char *mem, *p, *q; 1054 int curlen; 1055 1056 1057 /* first, scan through the tag string converting %-signs */ 1058 p = str; 1059 q = output; 1060 curlen = 0; 1061 while (*p && curlen < outlen) { 1062 if (*p == '%') { 1063 if (curlen + 3 >= outlen) { 1064 return (-1); 1065 } 1066 cfg_encode_char(q, *p); 1067 curlen += 3; 1068 q += 3; 1069 } else { 1070 *q++ = *p; 1071 ++curlen; 1072 } 1073 ++p; 1074 } 1075 if (curlen < outlen) 1076 *q = '\0'; 1077 1078 /* now encode special characters */ 1079 p = mem = strdup(output); 1080 q = output; 1081 curlen = 0; 1082 while (*p && curlen < outlen) { 1083 if (strchr(CHARS_TO_ENCODE, *p) != 0) { 1084 if (curlen + 3 >= outlen) { 1085 free(mem); 1086 return (-1); 1087 } 1088 cfg_encode_char(q, *p); 1089 curlen += 3; 1090 q += 3; 1091 } else { 1092 *q++ = *p; 1093 ++curlen; 1094 } 1095 ++p; 1096 } 1097 free(mem); 1098 1099 if (curlen < outlen) 1100 *q = '\0'; 1101 /* LINTED possible ptrdiff_t overflow */ 1102 return (q - output); 1103 } 1104 1105 /* 1106 * cfg_decode_option 1107 * 1108 * Given a string, decodes any %-encodes on it. 1109 */ 1110 static void 1111 cfg_decode_string(char *str, char *output, int outlen) 1112 { 1113 char *p, *q; 1114 int curlen; 1115 1116 p = str; 1117 q = output; 1118 curlen = 0; 1119 while (*p && curlen < outlen) { 1120 if (*p == '%') { 1121 char ch = cfg_decode_char(p); 1122 if (!ch) { 1123 *q++ = *p++; 1124 ++curlen; 1125 } else { 1126 *q++ = ch; 1127 p += 3; 1128 ++curlen; 1129 } 1130 } else { 1131 *q++ = *p++; 1132 ++curlen; 1133 } 1134 } 1135 if (curlen < outlen) 1136 *q = '\0'; 1137 } 1138 1139 /* 1140 * cfg_get_options 1141 * return first options set from basekey 1142 * Subsequent calls with basekey = NULL return next option if any 1143 * into tag and val 1144 * returns 1145 * true success and more options data 1146 * -1 no options data 1147 */ 1148 1149 int 1150 cfg_get_options(CFGFILE *cfg, int section, const char *basekey, char *tag, 1151 int tag_len, char *val, int val_len) 1152 { 1153 static char buf[CFG_MAX_BUF]; 1154 char decode_buf[CFG_MAX_BUF]; 1155 int rc; 1156 char *ttag, *tval; 1157 1158 if (cfg == NULL) { 1159 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1160 cfg_severity = CFG_EFATAL; 1161 return (-1); 1162 } 1163 1164 errno = ENOSYS; 1165 if (basekey == 0) { 1166 ttag = strtok(NULL, "="); 1167 } else { 1168 bzero(buf, CFG_MAX_BUF); 1169 if (section == CFG_SEC_CONF) { 1170 rc = cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF); 1171 } else 1172 return (-1); 1173 if (rc < 0) 1174 return (rc); 1175 /* buf now contains raw options data */ 1176 ttag = strtok(buf, "="); 1177 } 1178 tval = strtok(NULL, ";"); 1179 if (!(tval) || !(ttag)) 1180 return (-1); 1181 if ((strlen(tval) > val_len) || (strlen(ttag) > tag_len)) { 1182 errno = E2BIG; 1183 return (-1); 1184 } 1185 cfg_decode_string(tval, decode_buf, CFG_MAX_BUF); 1186 strncpy(val, decode_buf, val_len); 1187 cfg_decode_string(ttag, decode_buf, CFG_MAX_BUF); 1188 strncpy(tag, decode_buf, tag_len); 1189 errno = 0; 1190 return (TRUE); 1191 } 1192 1193 /* 1194 * cfg_put_options 1195 * 1196 * Replaces existing tag with new val. If tag doesn't exist, 1197 * then it adds a new tag with the specified val. 1198 * 1199 * Return: 1200 * true success 1201 * -1 incorrect section, or read error from cfg DB 1202 */ 1203 int 1204 cfg_put_options(CFGFILE *cfg, int section, const char *basekey, char *tag, 1205 char *val) 1206 { 1207 char buf[CFG_MAX_BUF]; 1208 char encode_buf[CFG_MAX_BUF]; 1209 char *p; 1210 int enclen; 1211 1212 if (cfg == NULL) { 1213 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1214 cfg_severity = CFG_EFATAL; 1215 return (-1); 1216 } 1217 1218 errno = ENOSYS; 1219 bzero(buf, CFG_MAX_BUF); 1220 if (section != CFG_SEC_CONF) { 1221 cfg_severity = CFG_ENONFATAL; 1222 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1223 return (-1); 1224 } 1225 if (!tag || !*tag || !val || !*val) 1226 return (-1); 1227 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) { 1228 /* cfg severity & perror_str set up cfg_get_cstring() */ 1229 return (-1); 1230 } 1231 *encode_buf = ';'; 1232 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1; 1233 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) { 1234 cfg_severity = CFG_ENONFATAL; 1235 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1236 return (-1); 1237 } 1238 encode_buf[enclen] = '='; 1239 encode_buf[enclen + 1] = '\0'; 1240 1241 /* check the start of the string */ 1242 if (strncmp(buf, &encode_buf[1], enclen) == 0) { 1243 /* locate the end of this option */ 1244 p = strchr(buf, ';'); 1245 if (p && *(p + 1) != '\0') { 1246 /* add the new tag to the end */ 1247 ++p; 1248 strcat(p, &encode_buf[1]); 1249 } else { 1250 /* completely overwrite the existing tag */ 1251 p = buf; 1252 strcpy(p, &encode_buf[1]); 1253 } 1254 if (cfg_encode_string(val, encode_buf, CFG_MAX_BUF) < 0) { 1255 cfg_severity = CFG_ENONFATAL; 1256 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1257 return (-1); 1258 } 1259 strcat(p, encode_buf); 1260 strcat(p, ";"); 1261 if (cfg_put_cstring(cfg, basekey, p, strlen(p)) < 0) { 1262 /* severity & perror_str set by cfg_put_cstring */ 1263 return (-1); 1264 } 1265 errno = 0; 1266 return (TRUE); 1267 } 1268 1269 /* it's hiding somewhere inside... */ 1270 p = strstr(buf, encode_buf); 1271 if (p) { 1272 /* delete the old value */ 1273 char *q = strchr(p + 1, ';'); 1274 if (q) { 1275 strcpy(p + 1, q + 1); 1276 } else { 1277 *p = '\0'; 1278 } 1279 strcat(buf, &encode_buf[1]); 1280 } else if (*buf) { 1281 strcat(buf, &encode_buf[1]); 1282 } else { 1283 strcpy(buf, &encode_buf[1]); 1284 } 1285 enclen = cfg_encode_string(val, encode_buf, CFG_MAX_BUF); 1286 if (enclen < 0 || (strlen(buf) + enclen) >= CFG_MAX_BUF) { 1287 cfg_severity = CFG_ENONFATAL; 1288 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1289 return (-1); 1290 } 1291 strcat(buf, encode_buf); 1292 strcat(buf, ";"); 1293 if (cfg_put_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) { 1294 /* severity & perror_str set by cfg_put_cstring */ 1295 return (-1); 1296 } 1297 errno = 0; 1298 return (TRUE); 1299 } 1300 1301 /* 1302 * cfg_get_single_option 1303 * 1304 * Scans the options string for the specified option and returns 1305 * the decoded value 1306 * 1307 * Return: 1308 * true success 1309 * -1 incorrect section, or read error from cfg DB 1310 */ 1311 int 1312 cfg_get_single_option(CFGFILE *cfg, int section, const char *basekey, char *tag, 1313 char *val, int val_len) 1314 { 1315 char buf[CFG_MAX_BUF]; 1316 char encode_buf[CFG_MAX_BUF]; 1317 char *p, *q; 1318 int enclen; 1319 1320 if (cfg == NULL) { 1321 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1322 cfg_severity = CFG_EFATAL; 1323 return (-1); 1324 } 1325 1326 errno = ENOSYS; 1327 bzero(buf, CFG_MAX_BUF); 1328 if (section != CFG_SEC_CONF) { 1329 cfg_severity = CFG_ENONFATAL; 1330 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1331 return (-1); 1332 } 1333 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) { 1334 /* severity & perror_str set by cfg_get_cstring */ 1335 return (-1); 1336 } 1337 1338 *encode_buf = ';'; 1339 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1; 1340 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) { 1341 cfg_severity = CFG_ENONFATAL; 1342 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1343 return (-1); 1344 } 1345 encode_buf[enclen] = '='; 1346 encode_buf[enclen + 1] = '\0'; 1347 1348 /* check the start of the string */ 1349 if (strncmp(buf, &encode_buf[1], enclen) == 0) { 1350 p = strchr(buf, '='); 1351 if (!p) { 1352 cfg_severity = CFG_ENONFATAL; 1353 cfg_perror_str = dgettext("cfg", "Option not found"); 1354 return (-1); 1355 } 1356 ++p; 1357 q = strchr(p, ';'); 1358 if (q) { 1359 *q = '\0'; 1360 } 1361 cfg_decode_string(p, val, val_len); 1362 errno = 0; 1363 return (TRUE); 1364 } 1365 1366 /* it's hiding somewhere inside... */ 1367 p = strstr(buf, encode_buf); 1368 if (p) { 1369 p += enclen + 1; 1370 q = strchr(p, ';'); 1371 if (q) { 1372 *q = '\0'; 1373 } 1374 cfg_decode_string(p, val, val_len); 1375 errno = 0; 1376 return (TRUE); 1377 } 1378 1379 /* key not found */ 1380 return (-1); 1381 1382 } 1383 1384 /* 1385 * cfg_del_option 1386 * 1387 * Removes a single key=val pair from the specified option field 1388 * 1389 * Return: 1390 * true success 1391 * -1 unable to update config 1392 */ 1393 int 1394 cfg_del_option(CFGFILE *cfg, int section, const char *basekey, char *tag) 1395 { 1396 char buf[CFG_MAX_BUF]; 1397 char encode_buf[CFG_MAX_BUF]; 1398 char *p, *q; 1399 int enclen, rc; 1400 1401 if (cfg == NULL) { 1402 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1403 cfg_severity = CFG_EFATAL; 1404 return (-1); 1405 } 1406 1407 bzero(buf, CFG_MAX_BUF); 1408 if (section != CFG_SEC_CONF) { 1409 cfg_severity = CFG_ENONFATAL; 1410 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1411 return (-1); 1412 } 1413 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) { 1414 /* severity & perror_str are set by cfg_get_cstring */ 1415 return (-1); 1416 } 1417 1418 *encode_buf = ';'; 1419 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1; 1420 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) { 1421 cfg_severity = CFG_ENONFATAL; 1422 cfg_perror_str = dgettext("cfg", "Buffer too small"); 1423 return (-1); 1424 } 1425 encode_buf[enclen] = '='; 1426 encode_buf[enclen + 1] = '\0'; 1427 1428 /* check the start of the string */ 1429 if (strncmp(buf, &encode_buf[1], enclen) == 0) { 1430 p = strchr(buf, ';'); 1431 if (p && (*(p + 1) != '\0')) { 1432 rc = cfg_put_cstring(cfg, basekey, p + 1, 1433 strlen(p + 1)); 1434 } else { 1435 rc = cfg_put_cstring(cfg, basekey, "-", 1); 1436 } 1437 /* severity & perror_str are set by cfg_put_cstring */ 1438 return (rc); 1439 } 1440 1441 /* sigh */ 1442 p = strstr(buf, encode_buf); 1443 if (!p) { 1444 /* already removed */ 1445 return (TRUE); 1446 } 1447 q = strchr(p + 1, ';'); 1448 1449 /* 1450 * Now the string looks like: 1451 * | first few options | *p | option to remove | *q | rest | '\0' 1452 */ 1453 1454 if (!q) { 1455 /* hum... */ 1456 *p = '\0'; 1457 } else { 1458 strcpy(p, q); 1459 } 1460 1461 return (cfg_put_cstring(cfg, basekey, buf, strlen(buf))); 1462 } 1463 1464 static void 1465 cfg_set_memorymap(cfp_t *cfp) 1466 { 1467 cfgheader_t *hd = cfp->cf_head; 1468 1469 #ifdef DEBUG_CFGLIST 1470 (void) fprintf(stderr, "callocing %d for initial reads\n", hd->h_csize); 1471 #endif 1472 1473 hd->h_ccopy1 = (char *)calloc(hd->h_csize, sizeof (char)); 1474 hd->h_ccopy2 = (char *)calloc(hd->h_csize, sizeof (char)); 1475 hd->h_sizes1 = (int *)calloc(CFG_DEFAULT_PSIZE, sizeof (int)); 1476 hd->h_sizes2 = (int *)calloc(CFG_DEFAULT_PSIZE, sizeof (int)); 1477 } 1478 1479 /* 1480 * cfg_init_header 1481 * fill in default header info 1482 */ 1483 static void 1484 cfg_init_header(cfp_t *cfp) 1485 { 1486 time_t tloc; 1487 cfgheader_t *hd = cfp->cf_head; 1488 1489 hd->h_magic = (int32_t)CFG_NEW_MAGIC; 1490 hd->h_stamp = time(&tloc); 1491 hd->h_lock = 0; 1492 /* parser config */ 1493 hd->h_parsesize = 0; 1494 hd->h_parseoff = 0; 1495 hd->h_csize = 0; 1496 hd->h_psize = 0; 1497 hd->h_cfgs = NULL; 1498 hd->h_ncfgs = 0; 1499 hd->h_seq1 = hd->h_seq2 = 1; 1500 bzero(hd->h_cfgsizes, MAX_CFG * sizeof (int)); 1501 } 1502 /* 1503 * cfg_read 1504 * read header and all sections of configuration file 1505 * gets new data for incore copy 1506 * removes invalid header state 1507 * works even if config and persistent sections are empty 1508 * 1509 */ 1510 static int 1511 cfg_read(cfp_t *cfp) 1512 { 1513 int rc; 1514 cfgheader_t *hd; 1515 int readsize = 0; 1516 #ifdef DEBUG_CFGLIST 1517 (void) fprintf(stderr, "cfg_read\n"); 1518 #endif 1519 1520 if (!cfp->cf_head) { 1521 if ((hd = calloc(1, sizeof (*hd))) == NULL) 1522 return (FALSE); 1523 #ifdef DEBUG_HDR 1524 (void) fprintf(stderr, "initial cfg header read\n"); 1525 #endif 1526 cfp->cf_head = hd; 1527 } 1528 1529 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 1530 #ifdef DEBUG_LIB 1531 (void) fprintf(stderr, "cfg: seek header failed\n"); 1532 #endif 1533 return (FALSE); 1534 } 1535 1536 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head, 4); 1537 if (rc < 4) { 1538 #ifdef DEBUG_LIB 1539 (void) fprintf(stderr, "cfg: read magic number failed\n"); 1540 #endif 1541 return (FALSE); 1542 } 1543 1544 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 1545 #ifdef DEBUG_LIB 1546 (void) fprintf(stderr, "cfg: seek header failed\n"); 1547 #endif 1548 return (FALSE); 1549 } 1550 1551 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head, sizeof (*hd)); 1552 if (rc < sizeof (*hd)) { 1553 #ifdef DEBUG_LIB 1554 (void) fprintf(stderr, "cfg: read header failed\n"); 1555 #endif 1556 return (FALSE); 1557 } 1558 1559 cfp->cf_head->h_cfgs = NULL; 1560 cfg_set_memorymap(cfp); 1561 if (cfp->cf_head->h_magic != CFG_NEW_MAGIC) { 1562 #ifdef DEBUG_LIB 1563 (void) fprintf(stderr, "cfg_read: wrong MAGIC number %x\n", 1564 cfp->cf_head->h_magic); 1565 #endif 1566 return (FALSE); 1567 } 1568 1569 cfp->cf_head->h_state &= ~(CFG_HDR_INVALID); 1570 1571 #ifdef DEBUG_CFGLIST 1572 (void) fprintf(stderr, "reading parser\n"); 1573 #endif 1574 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_mapped, 1575 CFG_DEFAULT_PARSE_SIZE); 1576 if (rc < sizeof (*hd)) { 1577 #ifdef DEBUG 1578 (void) fprintf(stderr, "cfg: read parse config failed\n"); 1579 #endif 1580 return (FALSE); 1581 } 1582 1583 readsize = cfp->cf_head->h_csize; 1584 1585 #ifdef DEBUG_CFGLIST 1586 (void) fprintf(stderr, "reading copy1 readsize = %d\n", readsize); 1587 #endif 1588 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head->h_ccopy1, 1589 readsize); 1590 if (rc < 0) { 1591 /* don't fail just return */ 1592 #ifdef DEBUG 1593 (void) fprintf(stderr, "cfg: read ccopy1 section failed\n"); 1594 #endif 1595 return (FALSE); 1596 } 1597 1598 if ((*cfp->cf_pp->seek) 1599 (cfp, CFG_DEFAULT_SSIZE - rc, SEEK_CUR) < 0) { 1600 #ifdef DEBUG 1601 (void) fprintf(stderr, "cfg: seek (SEEK_CUR) failed\n"); 1602 #endif 1603 return (FALSE); 1604 } 1605 1606 #ifdef DEBUG_CFGLIST 1607 (void) fprintf(stderr, "reading copy2 readsize = %d\n", readsize); 1608 #endif 1609 1610 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head->h_ccopy2, 1611 readsize); 1612 if (rc < 0) { 1613 /* don't fail just return */ 1614 #ifdef DEBUG 1615 (void) fprintf(stderr, "cfg: read ccopy2 section failed\n"); 1616 #endif 1617 return (FALSE); 1618 } 1619 1620 /* read the sizes of the lists from disk */ 1621 if ((*cfp->cf_pp->seek) 1622 (cfp, CFG_DEFAULT_SSIZE - rc, SEEK_CUR) < 0) { 1623 #ifdef DEBUG 1624 (void) fprintf(stderr, "cfg: seek (SEEK_CUR) failed\n"); 1625 #endif 1626 return (FALSE); 1627 } 1628 1629 #ifdef DEBUG_CFGLIST 1630 (void) fprintf(stderr, "reading sizes\n"); 1631 #endif 1632 rc = (*cfp->cf_pp->read)(cfp, (int *)cfp->cf_head->h_sizes1, 1633 CFG_DEFAULT_PSIZE); 1634 if (rc < 0) { 1635 #ifdef DEBUG 1636 (void) fprintf(stderr, "cfg: read h_sizes1 failed\n"); 1637 #endif 1638 return (FALSE); 1639 } 1640 1641 rc = (*cfp->cf_pp->read)(cfp, (int *)cfp->cf_head->h_sizes2, 1642 CFG_DEFAULT_PSIZE); 1643 if (rc < 0) { 1644 #ifdef DEBUG 1645 (void) fprintf(stderr, "cfg: read h_sizes2 failed\n"); 1646 #endif 1647 return (FALSE); 1648 } 1649 1650 /* 1651 * If initial or invalid sequence, use first section 1652 */ 1653 if ((cfp->cf_head->h_seq1 <= 0) && (cfp->cf_head->h_seq2 <= 0)) { 1654 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1; 1655 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1; 1656 } 1657 1658 if (cfp->cf_head->h_seq1 >= cfp->cf_head->h_seq2) { 1659 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1; 1660 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1; 1661 } else { 1662 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy2; 1663 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes2; 1664 } 1665 1666 #ifdef DEBUG_LIB 1667 dump_status(cfp, "cfg_read"); 1668 #endif 1669 1670 return (TRUE); 1671 } 1672 1673 /* 1674 * cfg_lock 1675 * Read-write locking of the configuration 1676 * reads into core all sections 1677 * builds parser trees for each section 1678 * Returns: TRUE if the lock was acquired, FALSE otherwise. 1679 */ 1680 int 1681 cfg_lock(CFGFILE *cfg, CFGLOCK mode) 1682 { 1683 cfp_t *cfp; 1684 int is_locked = 0; 1685 int rc; 1686 1687 if (cfg == NULL) { 1688 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1689 cfg_severity = CFG_EFATAL; 1690 return (FALSE); 1691 } 1692 1693 if (mode == CFG_UPGRADE) { 1694 mode = CFG_WRLOCK; 1695 } 1696 1697 if (mode == CFG_WRLOCK && (cfg->cf[0].cf_flag & CFG_RDONLY)) { 1698 goto fail; 1699 } 1700 1701 /* 1702 * if you don't even give me the right lock request, 1703 * why should I give you one? 1704 */ 1705 if (mode != CFG_RDLOCK && mode != CFG_WRLOCK) 1706 goto fail; 1707 1708 if (cfg_lockd) { 1709 if (mode == CFG_WRLOCK) 1710 cfg_lockd_wrlock(); 1711 else 1712 cfg_lockd_rdlock(); 1713 is_locked = 1; 1714 } else { 1715 1716 #ifdef DEBUG_CFGLIST 1717 (void) fprintf(stderr, "cfg_lock\n"); 1718 #endif 1719 /* Lock is always based on local file pointer */ 1720 cfg->cf[1].cf_lock = cfg->cf[0].cf_lock = cfg->cf[0].cf_fd; 1721 1722 if (!((cfg->cf[0].cf_flag & CFG_RDONLY) && 1723 (mode == CFG_RDLOCK))) { 1724 1725 struct flock lk = {0}; 1726 lk.l_type = (mode == CFG_RDLOCK ? F_RDLCK : F_WRLCK); 1727 lk.l_whence = SEEK_SET; 1728 lk.l_start = (off_t)0; 1729 lk.l_len = (off_t)0; 1730 1731 if (fcntl(cfg->cf[0].cf_lock, F_SETLKW, &lk) < 0) 1732 goto fail; 1733 } 1734 } 1735 1736 /* Determine number of files open */ 1737 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 1738 if (!cfp->cf_fd) continue; 1739 if ((cfp->cf_head) && 1740 (cfp->cf_head->h_state & CFG_HDR_INVALID)) { 1741 if ((rc = cfg_hdrcmp(cfp)) == 0) { 1742 #ifdef DEBUG_HDR 1743 (void) fprintf(stderr, 1744 "cfg header match, skipping re-read\n"); 1745 #endif 1746 cfp->cf_head->h_state |= CFG_HDR_RDLOCK; 1747 if (mode == CFG_WRLOCK) 1748 cfp->cf_head->h_state |= CFG_HDR_WRLOCK; 1749 1750 cfp->cf_head->h_state &= ~(CFG_HDR_INVALID); 1751 continue; 1752 } 1753 #ifdef DEBUG_HDR 1754 (void) fprintf(stderr, "re-reading cfg, header mismatch\n"); 1755 #endif 1756 /* 1757 * dump what we have, info is stale 1758 */ 1759 cfg_free_cfglist(cfp); 1760 cfg_free_parser_tree(); 1761 1762 if (cfp->cf_head->h_ccopy1) { 1763 free(cfp->cf_head->h_ccopy1); 1764 cfp->cf_head->h_ccopy1 = NULL; 1765 } 1766 if (cfp->cf_head->h_ccopy2) { 1767 free(cfp->cf_head->h_ccopy2); 1768 cfp->cf_head->h_ccopy2 = NULL; 1769 } 1770 if (cfp->cf_head->h_sizes1) { 1771 free(cfp->cf_head->h_sizes1); 1772 cfp->cf_head->h_sizes1 = NULL; 1773 } 1774 if (cfp->cf_head->h_sizes2) { 1775 free(cfp->cf_head->h_sizes2); 1776 cfp->cf_head->h_sizes2 = NULL; 1777 } 1778 1779 if (cfp->cf_head) 1780 free(cfp->cf_head); 1781 cfp->cf_head = NULL; 1782 } 1783 1784 if (cfp->cf_head == NULL) { 1785 if (!cfg_read(cfp)) { 1786 if (cfp->cf_head != NULL) 1787 cfg_init_header(cfp); 1788 else 1789 goto fail; 1790 } else { 1791 #ifdef DEBUG_CFGLIST 1792 (void) fprintf(stderr, 1793 "reading parser config\n"); 1794 #endif 1795 /* build parser trees */ 1796 cfg_read_parser_config(cfp); 1797 } 1798 1799 } 1800 cfp->cf_head->h_state |= CFG_HDR_RDLOCK; 1801 if (mode == CFG_WRLOCK) { 1802 if (cfp->cf_head->h_seq1 >= cfp->cf_head->h_seq2) { 1803 #ifdef DEBUG_LIB 1804 (void) fprintf(stderr, 1805 "cfg_lock: WRLOCK copying 1 to 2\n"); 1806 #endif 1807 memcpy(cfp->cf_head->h_ccopy2, 1808 cfp->cf_head->h_ccopy1, 1809 cfp->cf_head->h_csize); 1810 memcpy(cfp->cf_head->h_sizes2, 1811 cfp->cf_head->h_sizes1, 1812 CFG_DEFAULT_PSIZE); 1813 1814 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy2; 1815 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes2; 1816 } else { 1817 #ifdef DEBUG_LIB 1818 (void) fprintf(stderr, 1819 "cfg_lock: WRLOCK copying 2 to 1\n"); 1820 #endif 1821 memcpy(cfp->cf_head->h_ccopy1, 1822 cfp->cf_head->h_ccopy2, 1823 cfp->cf_head->h_csize); 1824 memcpy(cfp->cf_head->h_sizes1, 1825 cfp->cf_head->h_sizes2, 1826 CFG_DEFAULT_PSIZE); 1827 1828 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1; 1829 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1; 1830 } 1831 1832 cfp->cf_head->h_state |= CFG_HDR_WRLOCK; 1833 } 1834 1835 if (cfg_map_cfglists(cfp) < 0) { 1836 #ifdef DEBUG_LIB 1837 (void) fprintf(stderr, "cfg: map_cfglists failed\n"); 1838 #endif 1839 goto fail; 1840 } 1841 1842 #ifdef DEBUG_LIB 1843 dump_status(cfp, "cfg_lock"); 1844 #endif 1845 } 1846 1847 return (TRUE); 1848 1849 fail: 1850 if (is_locked) { 1851 cfg_lockd_unlock(); 1852 } 1853 cfg_perror_str = dgettext("cfg", CFG_EGENERIC); 1854 cfg_severity = CFG_ENONFATAL; 1855 return (FALSE); 1856 } 1857 1858 /* 1859 * Unlock the database 1860 */ 1861 void 1862 cfp_unlock(cfp_t *cfp) 1863 { 1864 1865 #ifdef DEBUG_CFGLIST 1866 (void) fprintf(stderr, "cfg_unlock\n"); 1867 #endif 1868 if (cfg_lockd) { 1869 cfg_lockd_unlock(); 1870 } else { 1871 struct flock lk = {0}; 1872 lk.l_type = F_UNLCK; 1873 lk.l_whence = SEEK_SET; 1874 lk.l_start = (off_t)0; 1875 lk.l_len = (off_t)0; 1876 (void) fcntl(cfp->cf_lock, F_SETLKW, &lk); 1877 } 1878 1879 if (cfp->cf_head != NULL) { 1880 cfp->cf_head->h_state &= ~(CFG_HDR_RDLOCK|CFG_HDR_WRLOCK); 1881 cfp->cf_head->h_state |= CFG_HDR_INVALID; 1882 } 1883 } 1884 void 1885 cfg_unlock(CFGFILE *cfg) 1886 { 1887 if (cfg == NULL) { 1888 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1889 cfg_severity = CFG_EFATAL; 1890 return; 1891 } 1892 1893 cfp_unlock(&cfg->cf[0]); 1894 cfp_unlock(&cfg->cf[1]); 1895 } 1896 1897 /* 1898 * Test for a read lock, set errno if failed. 1899 */ 1900 static int 1901 cfg_rdlock(CFGFILE *cfg) 1902 { 1903 int rc; 1904 cfp_t *cfp; 1905 1906 if (cfg == NULL) { 1907 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1908 cfg_severity = CFG_EFATAL; 1909 return (FALSE); 1910 } 1911 1912 /* Determine number of files open */ 1913 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 1914 if (!cfp->cf_fd) 1915 continue; 1916 if (cfp->cf_head == NULL) { 1917 #ifdef DEBUG_LIB 1918 (void) fprintf(stderr, "cfg_rdlock: cf_head == NULL\n"); 1919 #endif 1920 /* 1921 * 6335583, if header == NULL, 1922 * we can't call cfg_read to fill the header again 1923 * since it will change the lock state to 1924 * CFG_HDR_WRLOCK and dscfg will be the processer 1925 * that hold the lock, 1926 * just returning a FALSE if the case, 1927 * then retrieve the lock state from flock structure. 1928 */ 1929 rc = FALSE; 1930 break; 1931 } else { 1932 #ifdef DEBUG_LIB 1933 (void) fprintf(stderr, "cfg_rdlock: cf_head != NULL\n"); 1934 #endif 1935 if ((cfp->cf_head->h_state & CFG_HDR_RDLOCK) 1936 == CFG_HDR_RDLOCK) { 1937 rc = TRUE; 1938 } else { 1939 rc = FALSE; 1940 break; 1941 } 1942 } 1943 } 1944 1945 if (!rc) 1946 errno = EPERM; 1947 1948 return (rc); 1949 } 1950 1951 /* 1952 * Test for a write lock, set errno if failed. 1953 */ 1954 static int 1955 cfg_wrlock(CFGFILE *cfg) 1956 { 1957 int rc; 1958 cfp_t *cfp; 1959 1960 if (cfg == NULL) { 1961 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 1962 cfg_severity = CFG_EFATAL; 1963 return (FALSE); 1964 } 1965 1966 /* Determine number of files open */ 1967 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 1968 if (!cfp->cf_fd) 1969 continue; 1970 if (cfp->cf_head == NULL) { 1971 #ifdef DEBUG_LIB 1972 (void) fprintf(stderr, "cfg wrlock: cf_head == NULL\n"); 1973 #endif 1974 /* 1975 * 6335583, see comments on cfg_rdlock 1976 */ 1977 rc = FALSE; 1978 break; 1979 } else { 1980 #ifdef DEBUG_LIB 1981 (void) fprintf(stderr, "cfg wrlock: cf_head != NULL\n"); 1982 #endif 1983 if ((cfp->cf_head->h_state & CFG_HDR_WRLOCK) 1984 == CFG_HDR_WRLOCK) { 1985 rc = TRUE; 1986 } else { 1987 rc = FALSE; 1988 break; 1989 } 1990 } 1991 } 1992 1993 if (!rc) 1994 errno = EPERM; 1995 1996 return (rc); 1997 } 1998 1999 /* 2000 * cfg_get_lock 2001 * Find lock status of CFG database. 2002 * Returns: TRUE and sets lock and pid if the lock is held, FALSE otherwise. 2003 */ 2004 int 2005 cfg_get_lock(CFGFILE *cfg, CFGLOCK *lock, pid_t *pid) 2006 { 2007 struct flock lk; 2008 int rc; 2009 2010 if (cfg == NULL) { 2011 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2012 cfg_severity = CFG_EFATAL; 2013 return (FALSE); 2014 } 2015 2016 if (cfg_lockd) { 2017 switch (cfg_lockedby(pid)) { 2018 case LOCK_READ: 2019 *lock = CFG_RDLOCK; 2020 return (TRUE); 2021 case LOCK_WRITE: 2022 *lock = CFG_WRLOCK; 2023 return (TRUE); 2024 case LOCK_NOTLOCKED: 2025 default: 2026 return (FALSE); 2027 } 2028 } else { 2029 if (cfg_wrlock(cfg)) { 2030 *lock = CFG_WRLOCK; 2031 *pid = getpid(); 2032 return (TRUE); 2033 } 2034 2035 if (cfg_rdlock(cfg)) { 2036 *lock = CFG_RDLOCK; 2037 *pid = getpid(); 2038 return (TRUE); 2039 } 2040 } 2041 /* Lock is always based on local file pointer */ 2042 cfg->cf[1].cf_lock = cfg->cf[0].cf_lock = cfg->cf[0].cf_fd; 2043 2044 bzero(&lk, sizeof (lk)); 2045 lk.l_type = F_WRLCK; 2046 lk.l_whence = SEEK_SET; 2047 lk.l_start = (off_t)0; 2048 lk.l_len = (off_t)0; 2049 2050 if (fcntl(cfg->cf[0].cf_lock, F_GETLK, &lk) < 0) 2051 rc = FALSE; 2052 else { 2053 if (lk.l_type == F_UNLCK) 2054 rc = FALSE; 2055 else { 2056 rc = TRUE; 2057 *pid = lk.l_pid; 2058 *lock = lk.l_type == F_WRLCK ? CFG_WRLOCK : CFG_RDLOCK; 2059 } 2060 } 2061 2062 return (rc); 2063 } 2064 2065 /* 2066 * cfg_commit 2067 * Write modified version of header, configuration and persistent 2068 * data using 2 stage commit. 2069 * If no valid data is found in header, it is assumed to be an initial 2070 * write and we will create the default header (could be dangerous) 2071 * another tricky part, if we are doing an upgrade we may be dealing 2072 * with an old database. we need to take care seeking and writing 2073 * until such time that it is upgraded. 2074 * 2075 * Mutual exclusion is checked using cfg_lock 2076 */ 2077 2078 int 2079 cfg_commit(CFGFILE *cfg) 2080 { 2081 cfp_t *cfp; 2082 int rc; 2083 time_t tloc; 2084 int section; 2085 int wrsize, *ip; 2086 2087 if (cfg == NULL) { 2088 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2089 cfg_severity = CFG_EFATAL; 2090 return (FALSE); 2091 } 2092 2093 if (!cfg_wrlock(cfg)) 2094 return (FALSE); 2095 2096 /* Determine number of files open */ 2097 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 2098 if (!cfp->cf_fd) 2099 continue; 2100 2101 /* 2102 * lets put everything back into one char * 2103 */ 2104 cfg_replace_lists(cfp); 2105 2106 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 2107 #ifdef DEBUG_LIB 2108 (void) fprintf(stderr, "cfg: seek header failed\n"); 2109 #endif 2110 return (FALSE); 2111 } 2112 2113 cfp->cf_head->h_size = cfp->cf_head->h_parsesize 2114 + cfp->cf_head->h_csize + cfp->cf_head->h_psize; 2115 cfp->cf_head->h_stamp = time(&tloc); 2116 2117 /* seeking into database */ 2118 if ((*cfp->cf_pp->seek)(cfp, sizeof (cfgheader_t), 2119 SEEK_CUR) < 0) 2120 return (FALSE); 2121 2122 if (cfp->cf_head->h_ccopy1 == cfp->cf_head->h_cparse) { 2123 if (cfp->cf_head->h_seq1 < 0) 2124 cfp->cf_head->h_seq1 = 1; 2125 else 2126 cfp->cf_head->h_seq1 = cfp->cf_head->h_seq2 + 1; 2127 section = 1; 2128 } else { 2129 if (cfp->cf_head->h_seq2 < 0) 2130 cfp->cf_head->h_seq2 = 1; 2131 else 2132 cfp->cf_head->h_seq2 = cfp->cf_head->h_seq1 + 1; 2133 section = 2; 2134 } 2135 #ifdef DEBUG_LIB 2136 dump_status(cfp, "cfg_commit"); 2137 #endif 2138 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_mapped, 2139 CFG_DEFAULT_PARSE_SIZE); 2140 #ifdef DEBUG 2141 if (rc < 0) { 2142 (void) fprintf(stderr, 2143 "parse commit: rc %d h_parsesize %d\n", 2144 rc, cfp->cf_head->h_parsesize); 2145 } 2146 #endif 2147 if (section == 1) { 2148 rc = (*cfp->cf_pp->write) (cfp, cfp->cf_head->h_ccopy1, 2149 cfp->cf_head->h_csize); 2150 #ifdef DEBUG 2151 if (rc < 0) { 2152 (void) fprintf(stderr, 2153 "csection commit 1: rc %d h_csize %d\n", 2154 rc, cfp->cf_head->h_csize); 2155 } 2156 #endif 2157 if ((*cfp->cf_pp->seek) 2158 (cfp, (2 * CFG_DEFAULT_SSIZE) - rc, SEEK_CUR) < 0) 2159 return (FALSE); 2160 2161 /* 2162 * limit the write to only what we need 2163 */ 2164 ip = cfp->cf_head->h_sizes1; 2165 for (wrsize = 0; *ip; ip += *ip + 1) 2166 wrsize += *ip + 1; 2167 2168 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head->h_sizes1, 2169 wrsize * sizeof (int)); 2170 #ifdef DEBUG 2171 if (rc < 0) { 2172 (void) fprintf(stderr, 2173 "cfg: write list sizes1 failed rc\n"); 2174 } 2175 #endif 2176 } else { 2177 if ((*cfp->cf_pp->seek)(cfp, CFG_DEFAULT_SSIZE, 2178 SEEK_CUR) < 0) 2179 return (FALSE); 2180 2181 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head->h_ccopy2, 2182 cfp->cf_head->h_csize); 2183 #ifdef DEBUG 2184 if (rc < 0) { 2185 (void) fprintf(stderr, 2186 "csection commit 2: rc %d h_csize %d\n", 2187 rc, cfp->cf_head->h_csize); 2188 } 2189 #endif 2190 if ((*cfp->cf_pp->seek) 2191 (cfp, (CFG_DEFAULT_SSIZE + CFG_DEFAULT_PSIZE) - rc, 2192 SEEK_CUR) < 0) 2193 return (FALSE); 2194 2195 /* 2196 * limit the write to only what we need 2197 */ 2198 ip = cfp->cf_head->h_sizes2; 2199 for (wrsize = 0; *ip; ip += *ip + 1) 2200 wrsize += *ip + 1; 2201 2202 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head->h_sizes2, 2203 wrsize * sizeof (int)); 2204 #ifdef DEBUG 2205 if (rc < 0) { 2206 (void) fprintf(stderr, 2207 "cfg: write list sizes2 failed\n"); 2208 } 2209 #endif 2210 2211 } 2212 2213 2214 #ifdef DEBUG_CFGLIST 2215 (void) fprintf(stderr, 2216 "writing h_csize %d\n", cfp->cf_head->h_csize); 2217 #endif 2218 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) 2219 return (FALSE); 2220 2221 cfp->cf_head->h_size = cfp->cf_head->h_parsesize + 2222 cfp->cf_head->h_csize + cfp->cf_head->h_psize; 2223 2224 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head, 2225 sizeof (cfgheader_t)); 2226 if (rc < 0) { 2227 cfg_perror_str = dgettext("cfg", 2228 "cfg_commit: header write failed"); 2229 cfg_severity = CFG_EFATAL; 2230 return (FALSE); 2231 } 2232 } 2233 2234 return (TRUE); 2235 } 2236 2237 /* 2238 * cfg_rewind 2239 * rewind internal file pointer for specified section 2240 * empty now, rewind not necessary. But don't break 2241 * old code. 2242 */ 2243 /*ARGSUSED*/ 2244 void 2245 cfg_rewind(CFGFILE *cfg, int section) 2246 { 2247 switch (section) { 2248 case CFG_SEC_CONF: 2249 break; 2250 case CFG_SEC_ALL: 2251 break; 2252 }; 2253 } 2254 2255 /* 2256 * cfg_location 2257 * set or return the default location file to 2258 * determine the partition name of the configuration partition 2259 * location is stored in well known file location 2260 */ 2261 char * 2262 cfg_location(char *location, int mode, char *altroot) 2263 { 2264 int fd; 2265 int fmode; 2266 int rc; 2267 char wellknown[NSC_MAXPATH]; 2268 char loc[NSC_MAXPATH]; 2269 2270 if (mode == CFG_LOC_GET_LOCAL) { 2271 return (CFG_LOCAL_LOCATION); 2272 } else if (mode == CFG_LOC_GET_CLUSTER) { 2273 fmode = O_RDONLY; 2274 } else { 2275 fmode = O_RDWR | O_CREAT; 2276 } 2277 2278 if (altroot) { 2279 strcpy(wellknown, altroot); 2280 strcat(wellknown, CFG_CLUSTER_LOCATION); 2281 } else 2282 strcpy(wellknown, CFG_CLUSTER_LOCATION); 2283 2284 fd = open(wellknown, fmode, 0644); 2285 if (fd < 0) { 2286 cfg_perror_str = dgettext("cfg", strerror(errno)); 2287 cfg_severity = CFG_ENONFATAL; 2288 return (NULL); 2289 } 2290 2291 if (mode == CFG_LOC_SET_CLUSTER) { 2292 if (location == NULL || (strlen(location) > NSC_MAXPATH)) { 2293 cfg_perror_str = dgettext("cfg", 2294 "cfg_location: filename too big or missing"); 2295 cfg_severity = CFG_EFATAL; 2296 return (NULL); 2297 } 2298 2299 /* 2300 * 5082142 2301 * If we're in a cluster, make sure that the config location 2302 * is a raw device. Using non-raw did devices in a cluster 2303 * can result in data corruption, since inconsistent data 2304 * may reside in the block cache on one node, but has not 2305 * been flushed to disk. 2306 */ 2307 if (cfg_iscluster() > 0) { 2308 struct stat dscfg_stat; 2309 if (stat(location, &dscfg_stat) != 0) { 2310 cfg_perror_str = dgettext("cfg", 2311 "Unable to access dscfg location"); 2312 cfg_severity = CFG_EFATAL; 2313 return (NULL); 2314 } 2315 if (!S_ISCHR(dscfg_stat.st_mode)) { 2316 cfg_perror_str = dgettext("cfg", 2317 "dscfg location must be a raw device"); 2318 cfg_severity = CFG_EFATAL; 2319 return (NULL); 2320 } 2321 } 2322 2323 if (ftruncate(fd, 0) < 0) 2324 return (NULL); 2325 2326 rc = write(fd, location, strlen(location)); 2327 if (rc < 0) { 2328 cfg_perror_str = dgettext("cfg", 2329 "cfg_location: write to well known failed"); 2330 cfg_severity = CFG_EFATAL; 2331 return (NULL); 2332 } 2333 bzero(config_file, sizeof (config_file)); 2334 } 2335 if (lseek(fd, 0, SEEK_SET) < 0) 2336 return (NULL); 2337 2338 bzero(config_file, sizeof (config_file)); 2339 rc = read(fd, config_file, sizeof (config_file)); 2340 if (rc < 0) { 2341 cfg_perror_str = dgettext("cfg", 2342 "cfg_location: read from well known failed"); 2343 cfg_severity = CFG_EFATAL; 2344 return (NULL); 2345 } 2346 close(fd); 2347 if (altroot) { 2348 strcpy(loc, altroot); 2349 strcat(loc, config_file); 2350 bzero(config_file, sizeof (config_file)); 2351 strcpy(config_file, loc); 2352 } 2353 2354 /* 2355 * scan string out of config_file, to strip whitespace 2356 */ 2357 sscanf(config_file, "%s", loc); 2358 strcpy(config_file, loc); 2359 2360 return (config_file); 2361 } 2362 2363 /* 2364 * cfg_update_parser_config 2365 * If tag and key exist return -1 2366 * 2367 * XXX Currently does not append new field to existing parser rule 2368 */ 2369 2370 int 2371 cfg_update_parser_config(CFGFILE *cfg, const char *key, int section) 2372 { 2373 cfp_t *cfp; 2374 int size; 2375 char buf[CFG_MAX_BUF]; 2376 struct parser *tbl; 2377 char tmpkey[CFG_MAX_KEY]; 2378 char *ky, *fld; 2379 errno = 0; 2380 2381 if (cfg == NULL) { 2382 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2383 cfg_severity = CFG_EFATAL; 2384 return (-1); 2385 } 2386 2387 cfp = FP_SUN_CLUSTER(cfg); 2388 if (!cfg_wrlock(cfg)) 2389 return (-1); 2390 2391 bzero(buf, CFG_MAX_BUF); 2392 bzero(tmpkey, sizeof (tmpkey)); 2393 strcpy(tmpkey, key); 2394 if (section == CFG_PARSE_CONF) { 2395 strcat(buf, "C:"); 2396 tbl = chead; 2397 } else { 2398 errno = EINVAL; 2399 return (-1); 2400 } 2401 ky = strtok(tmpkey, "."); 2402 fld = strtok(NULL, "."); 2403 while (fld) { 2404 size = cfg_get_item(tbl, ky, fld); 2405 2406 /* 2407 * Assure we are loading a clean table, with do duplicates 2408 * based on our File Descriptor 2409 */ 2410 if (chead_loaded && (chead_loaded != cfp->cf_fd)) { 2411 if (size <= 0) 2412 return (-1); 2413 } else { 2414 if (size > 0) 2415 return (-1); 2416 } 2417 fld = strtok(NULL, "."); 2418 } 2419 size = strlen(key) + 2; 2420 strncat(buf, key, size); 2421 #ifdef DEBUG_LIB 2422 (void) fprintf(stderr, "update parser config %s size %d\n", buf, size); 2423 #endif 2424 if ((size + cfp->cf_head->h_parseoff) > CFG_DEFAULT_PARSE_SIZE) { 2425 cfg_perror_str = dgettext("cfg", 2426 "cfg_update_parser_config: header overrun"); 2427 cfg_severity = CFG_EFATAL; 2428 #ifdef DEBUG_LIB 2429 (void) fprintf(stderr, "update parser config: " 2430 "overrun siz %d poff %d parsesize %d\n", 2431 size, cfp->cf_head->h_parseoff, cfp->cf_head->h_parsesize); 2432 #endif 2433 errno = E2BIG; 2434 return (-1); 2435 } 2436 bcopy(buf, (cfp->cf_mapped + cfp->cf_head->h_parseoff), size); 2437 cfp->cf_head->h_parseoff += size; 2438 cfp->cf_head->h_state |= CFG_HDR_INVALID; 2439 if (cfp->cf_mapped[cfp->cf_head->h_parseoff - 1] != '\n') { 2440 cfp->cf_mapped[cfp->cf_head->h_parseoff] = '\n'; 2441 cfp->cf_head->h_parseoff++; 2442 } 2443 cfp->cf_head->h_parsesize = cfp->cf_head->h_parseoff; 2444 cfg_read_parser_config(cfp); 2445 return (TRUE); 2446 } 2447 /* 2448 * cfg_read_parser_config 2449 * reads parser config from file 2450 * converts it to internal tree for parsing 2451 * chead for configuration parser entries 2452 * 2453 */ 2454 static 2455 void 2456 cfg_read_parser_config(cfp_t *cfp) 2457 { 2458 struct lookup *p, *q; 2459 struct parser *thead; 2460 int off, foff; 2461 char *part; 2462 char *key; 2463 char *fld; 2464 int fldnum; 2465 char c; 2466 char buf[CFG_MAX_BUF]; 2467 int i = 0; 2468 int n = 0; 2469 2470 off = foff = 0; 2471 /*CONSTCOND*/ 2472 while (TRUE) { 2473 off = 0; 2474 bzero(buf, CFG_MAX_BUF); 2475 /* LINTED it assigns value to c */ 2476 while (c = cfp->cf_mapped[foff++]) { 2477 if (c == '\n') 2478 break; 2479 buf[off++] = c; 2480 } 2481 part = strtok(buf, ":"); 2482 if (!part) 2483 break; 2484 if (*part == 'C') { 2485 thead = chead; 2486 n = i; 2487 } 2488 key = strtok(NULL, "."); 2489 if (!key) 2490 break; 2491 strcpy(thead[n].tag.l_word, key); 2492 thead[n].tag.l_value = 0; 2493 thead[n].fld = NULL; 2494 fldnum = 1; 2495 while ((fld = strtok(NULL, ".")) != NULL) { 2496 p = thead[n].fld; 2497 if (p == NULL) { 2498 q = thead[n].fld = calloc(1, 2499 sizeof (struct lookup)); 2500 } else { 2501 for (q = thead[n].fld; q; q = q->l_next) 2502 p = q; 2503 q = calloc(1, sizeof (struct lookup)); 2504 p->l_next = q; 2505 } 2506 strcpy(q->l_word, fld); 2507 q->l_value = fldnum; 2508 q->l_next = NULL; 2509 #ifdef DEBUG_EXTRA 2510 (void) fprintf(stderr, 2511 "read parser: q: word %s value %d\n", 2512 q->l_word, q->l_value); 2513 #endif 2514 fldnum++; 2515 } 2516 if (*part == 'C') 2517 i++; 2518 } 2519 2520 /* All done, indicate parser table is loaded */ 2521 if (i && (chead_loaded == 0)) 2522 chead_loaded = cfp->cf_fd; 2523 2524 /* 2525 * before I go and alloc, why am I here? 2526 * do I need a bunch of cfglists, or do I just 2527 * need to accommodate a just added parser entry 2528 * if the latter, we already have a base, just set 2529 * i to the index of the cfg which members need allocing 2530 */ 2531 if ((cfp->cf_head->h_cfgs == NULL) || 2532 (cfp->cf_head->h_cfgs[n-1].l_entry == NULL)) { 2533 cfp->cf_head->h_cfgs = (cfglist_t *)calloc(MAX_CFG, 2534 sizeof (cfglist_t)); 2535 i = 0; 2536 } 2537 else 2538 i = n; 2539 2540 if (cfp->cf_head->h_cfgs) { 2541 2542 #ifdef DEBUG_CFGLIST 2543 (void) fprintf(stderr, "alloced %d cfg lists \n", n + 1); 2544 #endif 2545 for (cfp->cf_head->h_ncfgs = n + 1; 2546 i < min(cfp->cf_head->h_ncfgs, MAX_CFG); i++) { 2547 cfp->cf_head->h_cfgs[i].l_name = '\0'; 2548 cfp->cf_head->h_cfgs[i].l_name = 2549 strdup(chead[i].tag.l_word); 2550 cfp->cf_head->h_cfgs[i].l_index = i; 2551 cfp->cf_head->h_cfgs[i].l_entry = 2552 calloc(DEFAULT_ENTRY_SIZE, sizeof (char)); 2553 cfp->cf_head->h_cfgs[i].l_nentry = 0; 2554 cfp->cf_head->h_cfgs[i].l_esiz = 2555 calloc(DEFAULT_NENTRIES, sizeof (int)); 2556 cfp->cf_head->h_cfgs[i].l_size = 0; 2557 cfp->cf_head->h_cfgs[i].l_free = DEFAULT_ENTRY_SIZE; 2558 if ((cfp->cf_head->h_cfgs[i].l_entry == NULL) || 2559 (cfp->cf_head->h_cfgs[i].l_esiz == NULL)) { 2560 cfg_perror_str = dgettext("cfg", "unable to" 2561 " allocate cfglist members"); 2562 cfg_severity = CFG_EFATAL; 2563 } 2564 } 2565 } else { 2566 cfg_perror_str = dgettext("cfg", "unable to alloc cfglist"); 2567 cfg_severity = CFG_EFATAL; 2568 } 2569 } 2570 2571 /* 2572 * cfg_map_cfglists() 2573 * go through list of list sizes in header 2574 * and create separate lists 2575 */ 2576 int 2577 cfg_map_cfglists(cfp_t *cfp) 2578 { 2579 int i; 2580 int offset = 0; 2581 int *ip; 2582 int list_size = 0; 2583 int slot_inc; 2584 char *p; 2585 cfgheader_t *ch; 2586 2587 ch = cfp->cf_head; 2588 p = ch->h_cparse; 2589 2590 /* get the first list size */ 2591 ip = ch->h_sizes; 2592 2593 for (i = 0; i < min(ch->h_ncfgs, MAX_CFG); i++) { 2594 if (ch->h_cfgsizes[i] > 0) { 2595 if (ch->h_cfgsizes[i] > DEFAULT_ENTRY_SIZE) { 2596 2597 ch->h_cfgs[i].l_entry = (char *) 2598 realloc(ch->h_cfgs[i].l_entry, 2599 ch->h_cfgsizes[i] * sizeof (char)); 2600 /* set free to 0, we'll get more when we add */ 2601 ch->h_cfgs[i].l_free = 0; 2602 2603 } else 2604 ch->h_cfgs[i].l_free -= ch->h_cfgsizes[i]; 2605 2606 /* get lists and marry up to each cfgs structure */ 2607 2608 2609 list_size = *ip; 2610 ip++; 2611 2612 if (list_size > DEFAULT_NENTRIES) { 2613 /* 2614 * we're gonna need more slots 2615 * we want to alloc on DEFAULT_NENTRIES 2616 * boundry. ie. always a multiple of it 2617 * later on, when we add to the list 2618 * we can see if we need to add by mod'ding 2619 * l_nentry and DEFAULT_NENTRIES and check for 0 2620 */ 2621 slot_inc = DEFAULT_NENTRIES - 2622 (list_size % DEFAULT_NENTRIES); 2623 if (slot_inc == DEFAULT_NENTRIES) 2624 slot_inc = 0; /* addcfline reallocs */ 2625 2626 ch->h_cfgs[i].l_esiz = (int *)realloc( 2627 ch->h_cfgs[i].l_esiz, 2628 (list_size + slot_inc) * sizeof (int)); 2629 } 2630 memcpy(ch->h_cfgs[i].l_esiz, ip, 2631 list_size * sizeof (int)); 2632 2633 ch->h_cfgs[i].l_nentry = list_size; 2634 2635 ip += list_size; 2636 2637 } else 2638 2639 continue; 2640 2641 if (ch->h_cfgs[i].l_entry != NULL) { 2642 p = ch->h_cparse + offset; 2643 #ifdef DEBUG_CFGLIST 2644 (void) fprintf(stderr, "mapping list %d size %d offset %d, addr 0x%x\n", 2645 i, ch->h_cfgsizes[i], offset, p); 2646 #endif 2647 memcpy(ch->h_cfgs[i].l_entry, 2648 p, ch->h_cfgsizes[i]); 2649 ch->h_cfgs[i].l_size = ch->h_cfgsizes[i]; 2650 offset += ch->h_cfgsizes[i]; 2651 } else { 2652 #ifdef DEBUG_CFGLIST 2653 (void) fprintf(stderr, "NULL l_entry\n"); 2654 #endif 2655 return (-1); 2656 } 2657 } 2658 2659 2660 return (1); 2661 2662 } 2663 2664 void 2665 cfg_replace_lists(cfp_t *cfp) 2666 { 2667 int i; 2668 int offset = 0; 2669 int size_offset = 0; 2670 2671 int section = 0; 2672 cfgheader_t *cf; 2673 cfglist_t *cfl; 2674 2675 cf = cfp->cf_head; 2676 2677 if ((cfl = cfp->cf_head->h_cfgs) == NULL) 2678 return; 2679 2680 #ifdef DEBUG_CFGLIST 2681 (void) fprintf(stderr, "cfg_replace_lists\n"); 2682 #endif 2683 2684 if (cf->h_cparse == cf->h_ccopy1) 2685 section = 1; 2686 2687 /* 2688 * check to see if we are using copy1 or 2, 2689 * grow or shrink the size, fix h_cparse reference 2690 * in case realloc gave us a funky new address. 2691 * put stuff in it. 2692 */ 2693 cf->h_ccopy1 = (char *) 2694 realloc(cf->h_ccopy1, cf->h_csize * sizeof (char)); 2695 cf->h_ccopy2 = (char *) 2696 realloc(cf->h_ccopy2, cf->h_csize * sizeof (char)); 2697 if (section == 1) { 2698 /* we used copy1 */ 2699 cf->h_cparse = cf->h_ccopy1; 2700 } else 2701 cf->h_cparse = cf->h_ccopy2; 2702 2703 /* 2704 * just because, we'll zero out h_csize and recalc 2705 * after all, this is the number the next guy gets 2706 */ 2707 cf->h_csize = cf->h_sizes[0] = 0; 2708 for (i = 0; i < MAX_CFG; i++) { 2709 /* only as many lists as chead has */ 2710 if (chead[i].tag.l_word[0] == '\0') { 2711 break; 2712 } 2713 if (cfl[i].l_entry && cfl[i].l_entry[0] != '\0') { 2714 #ifdef DEBUG_CFGLIST 2715 (void) fprintf(stderr, 2716 "copying list %d at %x size %d\n", 2717 i, cf->h_cparse + offset, 2718 cfl[i].l_size); 2719 #endif 2720 memcpy((cf->h_cparse + offset), 2721 cfl[i].l_entry, cfl[i].l_size); 2722 offset += cfl[i].l_size; 2723 #ifdef DEBUG_CFGLIST 2724 (void) fprintf(stderr, 2725 "cfl[%d].l_nentry %d cfl[%d].l_esiz[%d] %d" 2726 " size offset %d\n", 2727 i, cfl[i].l_nentry, i, cfl[i].l_nentry - 1, 2728 cfl[i].l_esiz[cfl[i].l_nentry - 1], size_offset); 2729 #endif 2730 /* 2731 * first write the number of entries 2732 * then copy over the array ie. 2733 * a list with 5 elements would be copied 2734 * as a 6 element array slot 0 being the 2735 * number of elements 2736 */ 2737 cf->h_sizes[size_offset++] = cfl[i].l_nentry; 2738 memcpy((cf->h_sizes + size_offset), cfl[i].l_esiz, 2739 cfl[i].l_nentry * sizeof (int)); 2740 size_offset += cfl[i].l_nentry; 2741 cf->h_sizes[size_offset] = 0; 2742 } 2743 cf->h_csize += cfl[i].l_size; 2744 } 2745 } 2746 2747 void 2748 cfg_free_cfglist(cfp_t *cfp) 2749 { 2750 int i; 2751 2752 if (!cfp->cf_head || !cfp->cf_head->h_cfgs) 2753 return; 2754 2755 for (i = 0; cfp->cf_head && i < MAX_CFG; i++) { 2756 if (cfp->cf_head->h_cfgs[i].l_entry) { 2757 free(cfp->cf_head->h_cfgs[i].l_entry); 2758 cfp->cf_head->h_cfgs[i].l_entry = NULL; 2759 } 2760 2761 if (cfp->cf_head->h_cfgs[i].l_name) { 2762 free(cfp->cf_head->h_cfgs[i].l_name); 2763 cfp->cf_head->h_cfgs[i].l_entry = NULL; 2764 } 2765 2766 if (cfp->cf_head->h_cfgs[i].l_esiz) { 2767 free(cfp->cf_head->h_cfgs[i].l_esiz); 2768 cfp->cf_head->h_cfgs[i].l_esiz = NULL; 2769 } 2770 } 2771 2772 if (cfp->cf_head) { 2773 free(cfp->cf_head->h_cfgs); 2774 cfp->cf_head->h_cfgs = NULL; 2775 } 2776 } 2777 2778 void 2779 cfg_free_parser_tree() 2780 { 2781 struct lookup *p = NULL; 2782 struct lookup *q = NULL; 2783 int i; 2784 2785 for (i = 0; i < MAX_CFG; i++) { 2786 if (chead) 2787 p = chead[i].fld; 2788 while (p) { 2789 q = p->l_next; 2790 if (p) { 2791 free(p); 2792 p = NULL; 2793 } 2794 p = q; 2795 } 2796 } 2797 bzero(chead, MAX_CFG * sizeof (struct parser)); 2798 } 2799 2800 void 2801 cfg_close(CFGFILE *cfg) 2802 { 2803 cfp_t *cfp; 2804 2805 if (cfg == NULL) { 2806 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2807 cfg_severity = CFG_EFATAL; 2808 return; 2809 } 2810 2811 /* Determine number of files open */ 2812 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 2813 if (!cfp->cf_fd) continue; 2814 2815 (*cfp->cf_pp->close)(cfp); 2816 #ifdef DEBUG_CFGLIST 2817 (void) fprintf(stderr, "freeing cfglists\n"); 2818 #endif 2819 cfg_free_cfglist(cfp); 2820 2821 #ifdef DEBUG_CFGLIST 2822 (void) fprintf(stderr, "freeing cfp->cf_mapped\n"); 2823 #endif 2824 free(cfp->cf_mapped); 2825 cfp->cf_mapped = NULL; 2826 2827 #ifdef DEBUG_CFGLIST 2828 (void) fprintf(stderr, 2829 "freeing copy1, copy2, h_sizes and cf\n"); 2830 #endif 2831 if (cfp->cf_head) { 2832 if (cfp->cf_head->h_ccopy1) { 2833 free(cfp->cf_head->h_ccopy1); 2834 cfp->cf_head->h_ccopy1 = NULL; 2835 } 2836 if (cfp->cf_head->h_ccopy2) { 2837 free(cfp->cf_head->h_ccopy2); 2838 cfp->cf_head->h_ccopy2 = NULL; 2839 } 2840 if (cfp->cf_head->h_sizes1) { 2841 free(cfp->cf_head->h_sizes1); 2842 cfp->cf_head->h_sizes1 = NULL; 2843 } 2844 if (cfp->cf_head->h_sizes2) { 2845 free(cfp->cf_head->h_sizes2); 2846 cfp->cf_head->h_sizes2 = NULL; 2847 } 2848 2849 } 2850 if (cfp->cf_head) 2851 free(cfp->cf_head); 2852 } 2853 2854 free(cfg); 2855 cfg = NULL; 2856 cfg_free_parser_tree(); 2857 2858 #ifdef DEBUG_CFGLIST 2859 (void) fprintf(stderr, "cfg_close\n"); 2860 #endif 2861 } 2862 2863 2864 char * 2865 cfg_get_resource(CFGFILE *cfg) 2866 { 2867 if (cfg == NULL) { 2868 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2869 cfg_severity = CFG_EFATAL; 2870 return (NULL); 2871 } 2872 2873 return (cfg->cf_node); 2874 } 2875 2876 /* 2877 * cfg_resource 2878 * set or clear the cluster node filter for get/put 2879 */ 2880 2881 void 2882 cfg_resource(CFGFILE *cfg, const char *node) 2883 { 2884 if (cfg == NULL) { 2885 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 2886 cfg_severity = CFG_EFATAL; 2887 return; 2888 } 2889 2890 if (cfg->cf_node) { 2891 #ifdef DEBUG_CFGLIST 2892 (void) fprintf(stderr, 2893 "cfg_resource: changing node from %s to %s\n", 2894 cfg->cf_node, (node?node:"NULL")); 2895 #endif 2896 free(cfg->cf_node); 2897 cfg->cf_node = NULL; 2898 } 2899 2900 /* 2901 * just in case someone passes in a non-NULL 2902 * node, but has no valid value 2903 */ 2904 if ((node) && (node[0] != '\0')) { 2905 cfg->cf_node = strdup(node); 2906 } 2907 } 2908 2909 /* 2910 * cfg_open 2911 * Open the current configuration file 2912 */ 2913 CFGFILE * 2914 cfg_open(char *name) 2915 { 2916 CFGFILE *cfg; 2917 cfp_t *cfp; 2918 int32_t magic; 2919 long needed; 2920 int rc; 2921 2922 #ifdef DEBUG_CFGLIST 2923 (void) fprintf(stderr, "cfg_open\n"); 2924 #endif 2925 2926 cfg_severity = 0; 2927 if ((cfg = (CFGFILE *)calloc(1, sizeof (*cfg))) == NULL) { 2928 cfg_perror_str = dgettext("cfg", 2929 "cfg_open: malloc failed"); 2930 cfg_severity = CFG_EFATAL; 2931 return (NULL); 2932 } 2933 2934 cfp = &cfg->cf[0]; 2935 if ((name) && strlen(name)) { 2936 #ifdef DEBUG 2937 (void) fprintf(stderr, "cfg_open: Using non-standard name\n"); 2938 #endif 2939 cfp->cf_name = name; 2940 cfp->cf_pp = (strstr(cfp->cf_name, "/rdsk/") == NULL) ? 2941 cfg_block_io_provider() : cfg_raw_io_provider(); 2942 } else { 2943 cfp->cf_name = cfg_location(NULL, CFG_LOC_GET_LOCAL, NULL); 2944 cfp->cf_pp = cfg_block_io_provider(); 2945 2946 /* Handle cfg_open(""), which is an open from boot tools */ 2947 if (name) 2948 cl_initialized = 1; 2949 if (cfg_iscluster() > 0) { 2950 cfp = &cfg->cf[1]; 2951 cfp->cf_name = 2952 cfg_location(NULL, CFG_LOC_GET_CLUSTER, NULL); 2953 if (cfp->cf_name) { 2954 cfp->cf_pp = cfg_raw_io_provider(); 2955 } 2956 } 2957 } 2958 2959 /* 2960 * Open one or two configuration files 2961 */ 2962 for (cfp = &cfg->cf[0]; cfp->cf_name && (cfp <= &cfg->cf[1]); cfp++) { 2963 if ((*cfp->cf_pp->open)(cfp, cfp->cf_name) == NULL) { 2964 cfg_perror_str = dgettext("cfg", 2965 "cfg_open: unable to open configuration location"); 2966 cfg_severity = CFG_EFATAL; 2967 break; 2968 } 2969 2970 /* block device smaller than repository? */ 2971 rc = (*cfp->cf_pp->read)(cfp, &magic, sizeof (magic)); 2972 if (rc < sizeof (magic)) { 2973 cfg_perror_str = dgettext("cfg", 2974 "cfg_open: unable to read configuration header"); 2975 cfg_severity = CFG_EFATAL; 2976 break; 2977 } 2978 2979 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 2980 cfg_perror_str = dgettext("cfg", 2981 "cfg_open: unable to seek configuration header"); 2982 cfg_severity = CFG_EFATAL; 2983 break; 2984 } 2985 2986 /* 2987 * we can't enforce size rules on an old database 2988 * so check the magic number before we test for size 2989 */ 2990 if (magic == CFG_NEW_MAGIC) { 2991 needed = FBA_NUM(FBA_SIZE(1) - 1 + 2992 (sizeof (struct cfgheader) + CFG_CONFIG_SIZE)); 2993 } else { 2994 needed = 0; 2995 } 2996 2997 if (cfp->cf_size < needed) { 2998 cfg_perror_str = dgettext("cfg", 2999 "cfg_open: configuration file too small"); 3000 cfg_severity = CFG_EFATAL; 3001 errno = ENOMEM; 3002 break; 3003 } 3004 3005 cfp->cf_mapped = (char *)malloc(CFG_DEFAULT_PARSE_SIZE); 3006 if (cfp->cf_mapped == NULL) { 3007 cfg_perror_str = dgettext("cfg", 3008 "cfg_open: malloc failed"); 3009 cfg_severity = CFG_EFATAL; 3010 break; 3011 } 3012 3013 bzero(cfp->cf_mapped, CFG_DEFAULT_PARSE_SIZE); 3014 cfp->cf_lock = -1; 3015 } 3016 3017 /* Processing errors, take care of one or more cfp pointers */ 3018 if (cfg_severity && (cfp <= &cfg->cf[1])) { 3019 cfp = &cfg->cf[0]; 3020 if (cfp->cf_fd) 3021 (*cfp->cf_pp->close)(cfp); 3022 cfp = &cfg->cf[1]; 3023 if (cfp->cf_fd) 3024 (*cfp->cf_pp->close)(cfp); 3025 free(cfg); 3026 return (NULL); 3027 } 3028 3029 cfg_lockd = cfg_lockd_init(); 3030 3031 3032 #ifdef DEBUG_CFGLIST 3033 (void) fprintf(stderr, "cfg_open ok\n"); 3034 #endif 3035 return (cfg); 3036 } 3037 3038 void 3039 cfg_invalidate_hsizes(int fd, const char *loc) 3040 { 3041 int offset; 3042 int rc = -1; 3043 int hdrsz; 3044 3045 char buf[2 * CFG_DEFAULT_PSIZE]; 3046 3047 hdrsz = sizeof (cfgheader_t) + 512 - 3048 (sizeof (cfgheader_t) % 512); 3049 3050 offset = hdrsz + CFG_DEFAULT_PARSE_SIZE + 3051 (CFG_DEFAULT_SSIZE * 2); 3052 3053 if (cfg_shldskip_vtoc(fd, loc) > 0) 3054 offset += CFG_VTOC_SKIP; 3055 3056 bzero(buf, sizeof (buf)); 3057 3058 if (lseek(fd, offset, SEEK_SET) > 0) 3059 rc = write(fd, buf, sizeof (buf)); 3060 if (rc < 0) 3061 (void) fprintf(stderr, "cfg: invalidate hsizes failed\n"); 3062 3063 } 3064 3065 char * 3066 cfg_error(int *severity) 3067 { 3068 if (severity != NULL) 3069 *severity = cfg_severity; 3070 return (cfg_perror_str ? cfg_perror_str : CFG_EGENERIC); 3071 } 3072 /* 3073 * cfg_cfg_isempty 3074 */ 3075 int 3076 cfg_cfg_isempty(CFGFILE *cfg) 3077 { 3078 cfp_t *cfp; 3079 3080 if (cfg == NULL) { 3081 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3082 cfg_severity = CFG_EFATAL; 3083 return (FALSE); 3084 } 3085 3086 cfp = FP_SUN_CLUSTER(cfg); 3087 if (cfp->cf_head->h_csize == 0) 3088 return (TRUE); 3089 else 3090 return (FALSE); 3091 } 3092 3093 /* 3094 * cfg_get_num_entries 3095 * return the number of entries in a given section of database 3096 * sndr, ii, ndr_ii... 3097 */ 3098 int 3099 cfg_get_num_entries(CFGFILE *cfg, char *section) 3100 { 3101 int count = 0; 3102 int table_offset; 3103 cfp_t *cfp; 3104 3105 if (cfg == NULL) { 3106 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3107 cfg_severity = CFG_EFATAL; 3108 return (-1); 3109 } 3110 3111 if ((table_offset = cfg_get_parser_offset(section)) < 0) { 3112 errno = ESRCH; 3113 return (-1); 3114 } 3115 3116 /* Determine number of files open */ 3117 for (cfp = &cfg->cf[0]; cfp->cf_fd && (cfp <= &cfg->cf[1]); cfp++) 3118 count += cfp->cf_head->h_cfgs[table_offset].l_nentry; 3119 3120 return (count); 3121 } 3122 3123 /* 3124 * cfg_get_section 3125 * all etries in a config file section is placed in 3126 * buf, allocation is done inside 3127 * freeing buf is responisbility of the caller 3128 * number of entries in section is returned 3129 * -1 on failure, errno is set 3130 */ 3131 int 3132 cfg_get_section(CFGFILE *cfg, char ***list, const char *section) 3133 { 3134 int table_offset; 3135 int i, count; 3136 cfglist_t *cfl; 3137 char *p = NULL; 3138 char **buf; 3139 cfp_t *cfp; 3140 3141 if (cfg == NULL) { 3142 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3143 cfg_severity = CFG_EFATAL; 3144 return (FALSE); 3145 } 3146 3147 if ((table_offset = cfg_get_parser_offset(section)) < 0) { 3148 errno = ESRCH; 3149 return (-1); 3150 } 3151 3152 /* Determine number of files open */ 3153 count = 0; 3154 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 3155 if (!cfp->cf_fd) continue; 3156 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 3157 if (!cfg_read(cfp)) { 3158 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 3159 cfg_severity = CFG_EFATAL; 3160 return (-1); 3161 } 3162 } 3163 3164 cfl = &cfp->cf_head->h_cfgs[table_offset]; 3165 if (cfl->l_nentry == 0) /* empty list */ 3166 continue; 3167 3168 if (count == 0) 3169 buf = (char **)malloc(cfl->l_nentry * sizeof (char *)); 3170 else 3171 buf = (char **)realloc(buf, (cfl->l_nentry + count) * 3172 sizeof (char *)); 3173 if (buf == NULL) { 3174 errno = ENOMEM; 3175 return (-1); 3176 } else { 3177 bzero(&buf[count], cfl->l_nentry * sizeof (char *)); 3178 } 3179 3180 p = cfl->l_entry; 3181 for (i = 0; i < cfl->l_nentry; i++) { 3182 if ((buf[i + count] = strdup(p)) == NULL) { 3183 errno = ENOMEM; 3184 return (-1); 3185 } 3186 p += cfl->l_esiz[i]; 3187 } 3188 count += cfl->l_nentry; 3189 } 3190 3191 *list = buf; 3192 return (count); 3193 } 3194 3195 /* 3196 * cluster upgrade helper functions. These support old database operations 3197 * while upgrading nodes on a cluster. 3198 */ 3199 3200 /* 3201 * returns the list of configured tags 3202 * return -1 on error, else the number 3203 * of tags returned in taglist 3204 * caller frees 3205 */ 3206 int 3207 cfg_get_tags(CFGFILE *cfg, char ***taglist) 3208 { 3209 char **list; 3210 int i = 0; 3211 3212 if (cfg == NULL) { 3213 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3214 cfg_severity = CFG_EFATAL; 3215 return (-1); 3216 } 3217 3218 if (!cfg_rdlock(cfg)) { 3219 return (-1); 3220 } 3221 list = calloc(1, MAX_CFG * sizeof (char *)); 3222 if (list == NULL) { 3223 errno = ENOMEM; 3224 return (-1); 3225 } 3226 3227 while ((i < MAX_CFG) && (chead[i].tag.l_word[0] != '\0')) { 3228 list[i] = strdup(chead[i].tag.l_word); 3229 if (list[i] == NULL) { 3230 for (/* CSTYLE */; i >= 0; i--) { 3231 if (list[i]) 3232 free(list[i]); 3233 } 3234 free(list); 3235 errno = ENOMEM; 3236 return (-1); 3237 } 3238 i++; 3239 } 3240 *taglist = list; 3241 return (i); 3242 3243 } 3244 3245 /* 3246 * is this a database? 3247 * check the header for the magic number 3248 * 0 no match 1 match, -1 on error 3249 */ 3250 int 3251 cfg_is_cfg(CFGFILE *cfg) 3252 { 3253 int32_t magic; 3254 int rc; 3255 cfp_t *cfp = FP_SUN_CLUSTER(cfg); 3256 3257 rc = (cfp->cf_pp->read)(cfp, &magic, sizeof (magic)); 3258 if (rc < sizeof (magic)) { 3259 cfg_perror_str = dgettext("cfg", "Fail to read configuration"); 3260 cfg_severity = CFG_EFATAL; 3261 return (-1); 3262 } 3263 3264 if (magic == CFG_NEW_MAGIC) 3265 return (1); 3266 3267 cfg_perror_str = dgettext("cfg", 3268 "configuration not initialized, bad magic"); 3269 cfg_severity = CFG_EFATAL; 3270 3271 return (0); 3272 } 3273 3274 int 3275 compare(const void* a, const void *b) 3276 { 3277 char *p; 3278 char *pbuf; 3279 char *q; 3280 char *qbuf; 3281 int needed; 3282 int cmp; 3283 int pos; 3284 3285 pbuf = strdup(a); 3286 qbuf = strdup(b); 3287 3288 if (!qbuf || !pbuf) 3289 return (0); 3290 3291 pos = 1; 3292 needed = sortby.offset; 3293 3294 p = strtok(pbuf, " "); 3295 while (p) { 3296 if (needed == pos) { 3297 break; 3298 } 3299 p = strtok(NULL, " "); 3300 if (!p) 3301 break; 3302 pos++; 3303 } 3304 3305 pos = 1; 3306 q = strtok(qbuf, " "); 3307 while (q) { 3308 if (needed == pos) { 3309 break; 3310 } 3311 q = strtok(NULL, " "); 3312 if (!q) 3313 break; 3314 pos++; 3315 } 3316 if (!p || !q) { 3317 sortby.comperror++; 3318 free(pbuf); 3319 free(qbuf); 3320 return (0); 3321 } 3322 cmp = strcmp(p, q); 3323 free(pbuf); 3324 free(qbuf); 3325 return (cmp); 3326 3327 3328 } 3329 /* 3330 * cfg_get_srtdsec 3331 * returns the section, sorted by supplied field 3332 * caller frees mem 3333 */ 3334 int 3335 cfg_get_srtdsec(CFGFILE *cfg, char ***list, const char *section, 3336 const char *field) 3337 { 3338 cfglist_t *cfl; 3339 cfp_t *cfp; 3340 char **buf; 3341 char *tmplst; 3342 char *p, *q; 3343 int table_offset; 3344 int count, i; 3345 3346 if (cfg == NULL) { 3347 cfg_perror_str = dgettext("cfg", CFG_EINVAL); 3348 cfg_severity = CFG_EFATAL; 3349 return (FALSE); 3350 } 3351 3352 if ((table_offset = cfg_get_parser_offset(section)) < 0) { 3353 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 3354 errno = ESRCH; 3355 return (-1); 3356 } 3357 3358 /* 3359 * do essentially what get_section does, 3360 * except stick entries in a static size 3361 * buf to make things easier to qsort 3362 */ 3363 count = 0; 3364 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) { 3365 if (!cfp->cf_fd) continue; 3366 if (cfp->cf_head->h_state & CFG_HDR_INVALID) { 3367 if (!cfg_read(cfp)) { 3368 cfg_perror_str = dgettext("cfg", CFG_RDFAILED); 3369 cfg_severity = CFG_EFATAL; 3370 return (-1); 3371 } 3372 } 3373 3374 cfl = &cfp->cf_head->h_cfgs[table_offset]; 3375 if (cfl->l_nentry == 0) /* empty list */ 3376 continue; 3377 3378 if (count == 0) 3379 buf = (char **)malloc(cfl->l_nentry * sizeof (char *)); 3380 else 3381 buf = (char **)realloc(buf, (cfl->l_nentry + count) * 3382 sizeof (char *)); 3383 if (buf == NULL) { 3384 errno = ENOMEM; 3385 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: " 3386 "malloc failed"); 3387 cfg_severity = CFG_EFATAL; 3388 return (-1); 3389 } else { 3390 bzero(&buf[count], cfl->l_nentry * sizeof (char *)); 3391 } 3392 3393 /* 3394 * allocate each line 3395 */ 3396 for (i = count; i < cfl->l_nentry + count; i++) { 3397 buf[i] = calloc(1, CFG_MAX_BUF); 3398 if (buf[i] == NULL) { 3399 free(buf); 3400 errno = ENOMEM; 3401 return (-1); 3402 } 3403 } 3404 3405 if (count == 0) 3406 tmplst = (char *)malloc(cfl->l_nentry * CFG_MAX_BUF); 3407 else 3408 tmplst = (char *)realloc(tmplst, 3409 (cfl->l_nentry + count) * CFG_MAX_BUF); 3410 if (tmplst == NULL) { 3411 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: " 3412 "malloc failed"); 3413 cfg_severity = CFG_EFATAL; 3414 free(buf); 3415 return (-1); 3416 } else { 3417 bzero(&tmplst[count], cfl->l_nentry * CFG_MAX_BUF); 3418 } 3419 3420 /* 3421 * put the section in tmplst and sort 3422 */ 3423 p = &tmplst[count]; 3424 q = cfl->l_entry; 3425 for (i = 0; i < cfl->l_nentry; i++) { 3426 bcopy(q, p, cfl->l_esiz[i]); 3427 p += CFG_MAX_BUF; 3428 q += cfl->l_esiz[i]; 3429 } 3430 count += cfl->l_nentry; 3431 } 3432 3433 bzero(sortby.section, CFG_MAX_KEY); 3434 bzero(sortby.field, CFG_MAX_KEY); 3435 3436 strcpy(sortby.section, section); 3437 strcpy(sortby.field, field); 3438 sortby.comperror = 0; 3439 sortby.offset = cfg_get_item(&chead[0], section, field); 3440 3441 qsort(tmplst, count, CFG_MAX_BUF, compare); 3442 3443 if (sortby.comperror) { 3444 sortby.comperror = 0; 3445 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: " 3446 "comparison error"); 3447 cfg_severity = CFG_ENONFATAL; 3448 cfg_free_section(&buf, cfl->l_nentry); 3449 free(tmplst); 3450 *list = NULL; 3451 return (-1); 3452 } 3453 3454 p = tmplst; 3455 for (i = 0; i < count; i++) { 3456 bcopy(p, buf[i], CFG_MAX_BUF); 3457 p += CFG_MAX_BUF; 3458 } 3459 3460 free(tmplst); 3461 *list = buf; 3462 return (count); 3463 } 3464 3465 /* 3466 * free an array alloc'd by get_*section 3467 * or some other array of size size 3468 */ 3469 3470 void 3471 cfg_free_section(char ***section, int size) 3472 { 3473 int i; 3474 char **secpp = *section; 3475 3476 for (i = 0; i < size; i++) { 3477 if (secpp[i]) { 3478 free(secpp[i]); 3479 secpp[i] = NULL; 3480 } 3481 } 3482 if (secpp) { 3483 free(secpp); 3484 secpp = NULL; 3485 } 3486 section = NULL; 3487 } 3488 3489 3490 int 3491 cfg_shldskip_vtoc(int fd, const char *loc) 3492 { 3493 struct vtoc vtoc; 3494 struct stat sb; 3495 int slice; 3496 int rfd; 3497 char char_name[PATH_MAX]; 3498 char *p; 3499 3500 if (fstat(fd, &sb) == -1) { 3501 cfg_perror_str = dgettext("cfg", "unable to stat config"); 3502 cfg_severity = CFG_EFATAL; 3503 return (-1); 3504 } 3505 if (S_ISREG(sb.st_mode)) 3506 return (0); 3507 3508 if (S_ISCHR(sb.st_mode)) { 3509 if ((slice = read_vtoc(fd, &vtoc)) < 0) 3510 return (-1); 3511 3512 if (vtoc.v_part[slice].p_start < CFG_VTOC_SIZE) 3513 return (1); 3514 else 3515 return (0); 3516 } 3517 3518 if (S_ISBLK(sb.st_mode)) { 3519 p = strstr(loc, "/dsk/"); 3520 if (p == NULL) 3521 return (-1); 3522 strcpy(char_name, loc); 3523 char_name[strlen(loc) - strlen(p)] = 0; 3524 strcat(char_name, "/rdsk/"); 3525 strcat(char_name, p + 5); 3526 3527 if ((rfd = open(char_name, O_RDONLY)) < 0) { 3528 return (-1); 3529 } 3530 if ((slice = read_vtoc(rfd, &vtoc)) < 0) { 3531 close(rfd); 3532 return (-1); 3533 } 3534 close(rfd); 3535 if (vtoc.v_part[slice].p_start < CFG_VTOC_SIZE) 3536 return (1); 3537 else 3538 return (0); 3539 } 3540 3541 return (-1); 3542 } 3543 3544 /* 3545 * comapares incore header with one on disk 3546 * returns 0 if equal, 1 if not, -1 error 3547 */ 3548 int 3549 cfg_hdrcmp(cfp_t *cfp) 3550 { 3551 cfgheader_t *dskhdr, *memhdr; 3552 int rc; 3553 3554 if ((dskhdr = calloc(1, sizeof (*dskhdr))) == NULL) { 3555 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: No memory"); 3556 cfg_severity = CFG_ENONFATAL; 3557 } 3558 3559 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) { 3560 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: seek failed"); 3561 cfg_severity = CFG_ENONFATAL; 3562 free(dskhdr); 3563 return (-1); 3564 } 3565 3566 rc = (*cfp->cf_pp->read)(cfp, (char *)dskhdr, sizeof (*dskhdr)); 3567 if (rc < 0) { 3568 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: read failed"); 3569 cfg_severity = CFG_ENONFATAL; 3570 free(dskhdr); 3571 return (-1); 3572 } 3573 3574 memhdr = cfp->cf_head; 3575 3576 if ((memhdr->h_seq1 == dskhdr->h_seq1) && 3577 (memhdr->h_seq2 == dskhdr->h_seq2)) 3578 rc = 0; 3579 else 3580 rc = 1; 3581 3582 3583 free(dskhdr); 3584 return (rc); 3585 }