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