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 }