8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libdscfg / common / cfg.c
blob17f668744adc7d928da00936d9d241cc332ea8d7
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdio.h>
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>
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>
53 #include "cfg_impl.h"
54 #include "cfg.h"
55 #include "cfg_lockd.h"
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
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 */
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))
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;
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 *);
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;
104 #ifdef DEBUG_LIB
105 static void
106 dump_status(cfp_t *cfp, char *str)
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);
126 #endif /* DEBUG */
129 * cfg_get_item
130 * return position from parser config given tag and field
132 static int
133 cfg_get_item(struct parser *tbl, const char *tag, const char *field)
135 int i;
136 struct lookup *p;
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;
144 if (strcmp(tbl[i].tag.l_word, tag) == 0)
145 break;
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;
158 /* Handle failure */
159 return (-1);
163 * cfg_get_num_flds
164 * return number of fields for given parser tag
166 static int
167 cfg_get_num_flds(struct parser *tbl, const char *tag, int *table_index)
169 int i;
170 int pos = 0;
171 struct lookup *p;
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;
179 if (strcmp(tbl[i].tag.l_word, tag) == 0) {
180 *table_index = i;
181 break;
185 /* Handle table size */
186 if (i < MAX_CFG) {
187 p = tbl[i].fld;
188 while (p) {
189 pos++;
190 p = p->l_next;
192 return (pos);
195 return (0);
199 * count white space fields
201 static int
202 cfg_cnt_flds(char *value)
204 char *ptr;
205 char buf[CFG_MAX_BUF];
206 int flds = 0;
208 if ((value == NULL) || (strlen(value) >= CFG_MAX_BUF))
209 return (0);
211 bzero(buf, CFG_MAX_BUF);
212 strcpy(buf, value);
213 ptr = strtok(buf, " ");
214 while (ptr) {
215 flds++;
216 ptr = strtok(NULL, " ");
218 return (flds);
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
229 static int
230 cfg_get_parser_offset(const char *section)
232 int i;
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;
240 if (strcmp(chead[i].tag.l_word, section) == 0)
241 break;
244 /* Handle table size */
245 if (i < MAX_CFG)
246 return (i);
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);
257 * cfg_fld_mov
258 * move fields from old buffer to new
259 * moving only specified fields
260 * concates newbuf
261 * returns fields moved
263 static int
264 cfg_fld_mov(char *newbuf, char *oldbuf, int start, int end)
266 char buf[CFG_MAX_BUF];
267 char *ptr;
268 int flds = 0;
270 bzero(buf, CFG_MAX_BUF);
271 if (oldbuf == NULL)
272 return (0);
274 if ((start > end) || (strlen(oldbuf) >= CFG_MAX_BUF)) {
275 return (0);
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, " ");
287 ptr = strtok(NULL, " ");
290 return (flds);
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
303 static int
304 cfg_filter_node(CFGFILE *cfg, struct parser *tbl, char *buf, char *tag)
306 char tmpbuf[CFG_MAX_BUF];
307 int i = 1;
308 int fld;
309 char *ptr;
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++;
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);
336 * cfg_insert_node
337 * insert resource in bufs which contain cnode parser field
339 static void
340 cfg_insert_node(CFGFILE *cfg, struct parser *tbl, char *buf, char *tag)
342 char tmpbuf[CFG_MAX_BUF];
343 int fld;
344 int nflds;
345 int table_index;
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;
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);
365 * cfg_is_cnode
366 * Parser current buffer to see if a non-empty " - " cnode exists
368 /*ARGSUSED*/
369 static int
370 cfg_is_cnode(CFGFILE *cfg, struct parser *tbl, char *buf, char *tag)
372 char tmpbuf[CFG_MAX_BUF];
373 int fld = cfg_get_item(tbl, tag, "cnode");
375 if (fld >= 0) {
376 tmpbuf[0] = '\0';
377 cfg_fld_mov(tmpbuf, buf, fld, fld);
378 return (strcmp(tmpbuf, "- ") ? TRUE : FALSE);
380 return (FALSE);
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
392 cfg_get_cstring(CFGFILE *cfg, const char *key, void *value, int value_len)
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;
410 if (cfg == NULL) {
411 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
412 cfg_severity = CFG_EFATAL;
413 return (-1);
416 if (!cfg_rdlock(cfg)) {
417 cfg_perror_str = dgettext("cfg", CFG_NOTLOCKED);
418 cfg_severity = CFG_EFATAL;
419 return (-1);
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, ".");
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
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);
450 * we have to figure out where this set is
451 * in relation to other sets
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);
465 while (numfound < setnum) {
466 if ((*cfp->cf_pp->readcf)
467 (cfp, buf, table_offset, relnum - secnum) == NULL) {
468 secnum = relnum - 1;
469 break;
471 if (cfg_filter_node(cfg, &chead[0], buf, section))
472 numfound++;
474 if (numfound == setnum)
475 break;
477 relnum++;
479 if (numfound == setnum)
480 break;
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);
491 if (buf) {
492 if (!itemp) {
493 strncpy(value, buf, value_len);
494 return (0);
497 if (itemp) {
498 needed = cfg_get_item(&chead[0], section, itemp);
499 p = strtok(buf, " ");
500 while (p) {
501 if (needed == pos) {
502 errno = 0;
503 if (*p == '-') {
504 strcpy(value, "");
505 return (0);
506 } else {
507 if (strlen(p) > value_len) {
508 errno = E2BIG;
509 cfg_perror_str =
510 dgettext("cfg",
511 strerror(errno));
512 cfg_severity =
513 CFG_ENONFATAL;
514 return (-1);
517 strncpy(value, p, value_len);
519 return (pos);
521 p = strtok(NULL, " ");
522 if (!p)
523 break;
524 pos++;
528 errno = ESRCH;
529 cfg_perror_str = dgettext("cfg", strerror(errno));
530 cfg_severity = CFG_ENONFATAL;
531 return (-1);
535 * cfg_find_cstring()
536 * search for a string in the specified section
537 * in the specified field(s)
538 * if nfld is 0, then the string is searched for in
539 * every field of the entry
540 * the set number of the first occurence of target is returned
541 * ie. if /dev/vx/rdsk/vol10 is found in sndr.set9, 9 will be returned
542 * that is, of course, if the correct field was searched on.
543 * -1 on error
547 cfg_find_cstring(CFGFILE *cfg, const char *target,
548 const char *section, int numflds, ...)
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;
562 if (cfg == NULL) {
563 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
564 cfg_severity = CFG_EFATAL;
565 return (-1);
568 if (numflds == 0) {
569 nflds = cfg_get_num_flds(&chead[0], section, &tbl_off);
571 } else {
572 nflds = numflds;
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);
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);
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);
601 p = strtok(NULL, " ");
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);
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);
620 va_start(ap, numflds);
621 for (i = 0; i < numflds; i++) {
622 fldbuf[i] = strdup(va_arg(ap, char *));
625 fldbuf[i] = NULL;
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]);
633 field = strtok(buf, " ");
634 pos = 1;
635 while (pos < fieldnum) {
636 field = strtok(NULL, " ");
637 pos++;
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);
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);
657 return (i + 1);
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);
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
686 cfg_put_cstring(CFGFILE *cfg, const char *key, void *value, int val_len)
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;
707 if (cfg == NULL) {
708 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
709 cfg_severity = CFG_EFATAL;
710 return (-1);
713 bzero(buf, sizeof (buf));
714 strcpy(tmpkey, key);
715 section = strtok(tmpkey, ".");
716 setp = strtok(NULL, ".");
717 itemp = strtok(NULL, ".");
719 if (!cfg_wrlock(cfg)) {
720 cfg_perror_str = dgettext("cfg", CFG_RDFAILED);
721 cfg_severity = CFG_EFATAL;
722 return (-1);
725 if (!key) {
726 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
727 cfg_severity = CFG_ENONFATAL;
728 return (-1);
730 if (value && val_len == 0) {
731 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
732 cfg_severity = CFG_ENONFATAL;
733 return (-1);
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);
749 table_offset = cfg_get_parser_offset(section);
752 * we have to figure out where this set is
753 * in relation to other sets
755 relnum = 1;
756 secnum = 0;
757 numfound = 0;
759 if (setp && nofield) {
760 char tmpbuf[CFG_MAX_BUF];
761 int rc;
762 int nflds;
763 int got;
766 * Set specified but no field
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);
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;
785 if (cfg_filter_node(cfg, &chead[0], tmpbuf,
786 section))
787 numfound++;
789 if (numfound == setnum)
790 break;
792 relnum++;
794 if (numfound == setnum)
795 break;
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);
806 nflds = cfg_get_num_flds(&chead[0], section, &table_index);
808 if (value == NULL) {
809 /* Remove entry completely */
811 rc = (*cfp->cf_pp->remcf)(cfp, table_index,
812 relnum - secnum);
813 if (rc < 0)
814 return (rc);
815 return (0);
818 got = cfg_cnt_flds(value);
819 bzero(buf, sizeof (buf));
821 strncpy(buf, " ", 1);
822 if (strlen(value) > sizeof (buf) - 2) {
823 errno = E2BIG;
824 cfg_perror_str = dgettext("cfg", strerror(errno));
825 cfg_severity = CFG_ENONFATAL;
826 return (-1);
828 strncat(buf, value, val_len);
829 if (got < nflds) {
830 for (/* CSTYLED */; got < nflds; got++)
831 strncat(buf, " - ", 3);
832 } else if (got > nflds) {
833 return (-1);
834 } else {
835 /* got == nflds, so cnode was included */
836 addcnode = 0;
839 bufp = buf;
840 if (addcnode) {
841 cfg_insert_node(cfg, &chead[0], buf, section);
844 (*cfp->cf_pp->replacecf)(cfp, bufp, table_index,
845 relnum - secnum);
847 return (TRUE);
851 * Both Set and field are specified
852 * needs to get current whole entry and old requested field
853 * copy good fields to buf, replace new field in buf
854 * move everything depending of new size
855 * replace entry so set# does not change
857 if (setp && itemp) {
858 int rc;
859 int nflds;
860 int cnodepos;
862 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) {
863 if (!cfp->cf_fd) continue;
864 if (cfp->cf_head->h_state & CFG_HDR_INVALID) {
865 if (!cfg_read(cfp)) {
866 cfg_perror_str =
867 dgettext("cfg", CFG_RDFAILED);
868 cfg_severity = CFG_EFATAL;
869 return (-1);
872 while (numfound < setnum) {
873 if ((*cfp->cf_pp->readcf)
874 (cfp, buf, table_offset, relnum - secnum)
875 == NULL) {
876 secnum = relnum - 1;
877 break;
879 if (cfg_filter_node(cfg, &chead[0], buf,
880 section))
881 numfound++;
883 if (numfound == setnum)
884 break;
886 relnum++;
888 if (numfound == setnum)
889 break;
892 /* Fail to find anything? */
893 if (cfp >= &cfg->cf[2]) {
894 errno = ESRCH;
895 cfg_perror_str = dgettext("cfg", strerror(errno));
896 cfg_severity = CFG_ENONFATAL;
897 return (-1);
900 nflds = cfg_get_num_flds(&chead[0], section, &table_index);
901 fldnum = cfg_get_item(&chead[0], section, itemp);
902 bzero(newbuf, sizeof (newbuf));
903 strncpy(newbuf, " ", 1);
905 /* move good flds in */
906 rc = cfg_fld_mov(newbuf, buf, 1, fldnum - 1);
907 if (rc < 0)
908 return (rc);
910 /* move new fld in */
911 strncat(newbuf, value, strlen(value));
912 strcat(newbuf, " ");
914 /* move remaining flds in */
915 rc = cfg_fld_mov(newbuf, buf, fldnum + 1, nflds);
916 if (rc < 0)
917 return (rc);
919 cnodepos = cfg_get_item(&chead[0], section, "cnode");
920 if ((cnodepos >= 0) && strcmp(itemp, "cnode") != 0) {
921 /* add cnode if user didn't specify it */
922 cfg_insert_node(cfg, &chead[0],
923 newbuf, section);
926 (*cfp->cf_pp->replacecf)(cfp, newbuf, table_index,
927 relnum - secnum);
929 return (TRUE);
932 if (noset) { /* blast entire thing in */
933 int nflds;
934 int got;
935 int cnodepos;
937 bufp = buf;
938 if (!value) { /* we shouldn't be here */
939 errno = EINVAL;
940 return (-1);
942 strncat(buf, " ", 1);
943 if (strlen(value) > sizeof (buf) - 2) {
944 errno = E2BIG;
945 return (-1);
948 strncat(buf, value, val_len);
949 nflds = cfg_get_num_flds(&chead[0], section, &table_index);
950 got = cfg_cnt_flds(value);
952 cnodepos = cfg_get_item(&chead[0], section, "cnode");
953 if (cnodepos < 0 || got >= cnodepos) {
954 /* no cnode, or cnode was specified by caller */
955 addcnode = 0;
958 if (got < nflds) {
959 for (/* CSTYLED */; got < nflds; got++)
960 strncat(buf, " - ", 3);
961 } else if (got > nflds) {
962 errno = EINVAL; /* specified too many fields */
963 return (-1);
964 } else {
965 /* got == nflds, so cnode was included */
966 addcnode = 0;
969 if (addcnode) {
970 cfg_insert_node(cfg, &chead[0], buf, section);
973 /* Make sure we put this entry in the right database */
974 if (cfg_is_cnode(cfg, &chead[0], buf, section) &&
975 cfg->cf[1].cf_fd)
976 cfp = &cfg->cf[1];
977 else
978 cfp = &cfg->cf[0];
980 if (cfp->cf_head->h_state & CFG_HDR_INVALID) {
981 if (!cfg_read(cfp)) {
982 cfg_perror_str = dgettext("cfg", CFG_RDFAILED);
983 cfg_severity = CFG_EFATAL;
984 return (-1);
987 if (cfp->cf_head->h_csize + strlen(buf) > CFG_DEFAULT_SSIZE) {
988 errno = ENOSPC;
989 return (-1);
992 (*cfp->cf_pp->addcf)(cfp, bufp, table_index);
994 return (TRUE);
997 errno = EINVAL;
998 cfg_perror_str = strerror(errno);
999 cfg_severity = CFG_ENONFATAL;
1000 return (-1);
1004 * cfg_encode_char
1006 * Encode a single character into % + hex ascii value
1008 static void
1009 cfg_encode_char(char *result, char ch)
1011 *result++ = '%';
1012 *result++ = dectohex[ (ch >> 4) & 0xf ];
1013 *result++ = dectohex[ ch & 0xf ];
1017 * cfg_decode_char
1019 * Reverses cfg_encode_char
1021 static char
1022 cfg_decode_char(char *code)
1024 char retval;
1025 if (*code != '%') {
1026 return ('\0');
1028 ++code;
1029 if (!isxdigit(*code))
1030 return ('\0');
1031 retval = (isdigit(*code)? *code - '0' : *code - 'a' + 10);
1032 retval <<= 4;
1033 ++code;
1034 if (!isxdigit(*code))
1035 return ('\0');
1036 retval |= (isdigit(*code)? *code - '0' : *code - 'a' + 10);
1038 return (retval);
1042 * cfg_encode_option
1044 * Transforms the key and value strings so that special characters
1045 * can be used within the options field.
1047 * Returns:
1048 * Length of encoded string; -1 on failure
1050 static int
1051 cfg_encode_string(char *str, char *output, int outlen)
1053 char *mem, *p, *q;
1054 int curlen;
1057 /* first, scan through the tag string converting %-signs */
1058 p = str;
1059 q = output;
1060 curlen = 0;
1061 while (*p && curlen < outlen) {
1062 if (*p == '%') {
1063 if (curlen + 3 >= outlen) {
1064 return (-1);
1066 cfg_encode_char(q, *p);
1067 curlen += 3;
1068 q += 3;
1069 } else {
1070 *q++ = *p;
1071 ++curlen;
1073 ++p;
1075 if (curlen < outlen)
1076 *q = '\0';
1078 /* now encode special characters */
1079 p = mem = strdup(output);
1080 q = output;
1081 curlen = 0;
1082 while (*p && curlen < outlen) {
1083 if (strchr(CHARS_TO_ENCODE, *p) != 0) {
1084 if (curlen + 3 >= outlen) {
1085 free(mem);
1086 return (-1);
1088 cfg_encode_char(q, *p);
1089 curlen += 3;
1090 q += 3;
1091 } else {
1092 *q++ = *p;
1093 ++curlen;
1095 ++p;
1097 free(mem);
1099 if (curlen < outlen)
1100 *q = '\0';
1101 /* LINTED possible ptrdiff_t overflow */
1102 return (q - output);
1106 * cfg_decode_option
1108 * Given a string, decodes any %-encodes on it.
1110 static void
1111 cfg_decode_string(char *str, char *output, int outlen)
1113 char *p, *q;
1114 int curlen;
1116 p = str;
1117 q = output;
1118 curlen = 0;
1119 while (*p && curlen < outlen) {
1120 if (*p == '%') {
1121 char ch = cfg_decode_char(p);
1122 if (!ch) {
1123 *q++ = *p++;
1124 ++curlen;
1125 } else {
1126 *q++ = ch;
1127 p += 3;
1128 ++curlen;
1130 } else {
1131 *q++ = *p++;
1132 ++curlen;
1135 if (curlen < outlen)
1136 *q = '\0';
1140 * cfg_get_options
1141 * return first options set from basekey
1142 * Subsequent calls with basekey = NULL return next option if any
1143 * into tag and val
1144 * returns
1145 * true success and more options data
1146 * -1 no options data
1150 cfg_get_options(CFGFILE *cfg, int section, const char *basekey, char *tag,
1151 int tag_len, char *val, int val_len)
1153 static char buf[CFG_MAX_BUF];
1154 char decode_buf[CFG_MAX_BUF];
1155 int rc;
1156 char *ttag, *tval;
1158 if (cfg == NULL) {
1159 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1160 cfg_severity = CFG_EFATAL;
1161 return (-1);
1164 errno = ENOSYS;
1165 if (basekey == 0) {
1166 ttag = strtok(NULL, "=");
1167 } else {
1168 bzero(buf, CFG_MAX_BUF);
1169 if (section == CFG_SEC_CONF) {
1170 rc = cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF);
1171 } else
1172 return (-1);
1173 if (rc < 0)
1174 return (rc);
1175 /* buf now contains raw options data */
1176 ttag = strtok(buf, "=");
1178 tval = strtok(NULL, ";");
1179 if (!(tval) || !(ttag))
1180 return (-1);
1181 if ((strlen(tval) > val_len) || (strlen(ttag) > tag_len)) {
1182 errno = E2BIG;
1183 return (-1);
1185 cfg_decode_string(tval, decode_buf, CFG_MAX_BUF);
1186 strncpy(val, decode_buf, val_len);
1187 cfg_decode_string(ttag, decode_buf, CFG_MAX_BUF);
1188 strncpy(tag, decode_buf, tag_len);
1189 errno = 0;
1190 return (TRUE);
1194 * cfg_put_options
1196 * Replaces existing tag with new val. If tag doesn't exist,
1197 * then it adds a new tag with the specified val.
1199 * Return:
1200 * true success
1201 * -1 incorrect section, or read error from cfg DB
1204 cfg_put_options(CFGFILE *cfg, int section, const char *basekey, char *tag,
1205 char *val)
1207 char buf[CFG_MAX_BUF];
1208 char encode_buf[CFG_MAX_BUF];
1209 char *p;
1210 int enclen;
1212 if (cfg == NULL) {
1213 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1214 cfg_severity = CFG_EFATAL;
1215 return (-1);
1218 errno = ENOSYS;
1219 bzero(buf, CFG_MAX_BUF);
1220 if (section != CFG_SEC_CONF) {
1221 cfg_severity = CFG_ENONFATAL;
1222 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1223 return (-1);
1225 if (!tag || !*tag || !val || !*val)
1226 return (-1);
1227 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) {
1228 /* cfg severity & perror_str set up cfg_get_cstring() */
1229 return (-1);
1231 *encode_buf = ';';
1232 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1;
1233 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) {
1234 cfg_severity = CFG_ENONFATAL;
1235 cfg_perror_str = dgettext("cfg", "Buffer too small");
1236 return (-1);
1238 encode_buf[enclen] = '=';
1239 encode_buf[enclen + 1] = '\0';
1241 /* check the start of the string */
1242 if (strncmp(buf, &encode_buf[1], enclen) == 0) {
1243 /* locate the end of this option */
1244 p = strchr(buf, ';');
1245 if (p && *(p + 1) != '\0') {
1246 /* add the new tag to the end */
1247 ++p;
1248 strcat(p, &encode_buf[1]);
1249 } else {
1250 /* completely overwrite the existing tag */
1251 p = buf;
1252 strcpy(p, &encode_buf[1]);
1254 if (cfg_encode_string(val, encode_buf, CFG_MAX_BUF) < 0) {
1255 cfg_severity = CFG_ENONFATAL;
1256 cfg_perror_str = dgettext("cfg", "Buffer too small");
1257 return (-1);
1259 strcat(p, encode_buf);
1260 strcat(p, ";");
1261 if (cfg_put_cstring(cfg, basekey, p, strlen(p)) < 0) {
1262 /* severity & perror_str set by cfg_put_cstring */
1263 return (-1);
1265 errno = 0;
1266 return (TRUE);
1269 /* it's hiding somewhere inside... */
1270 p = strstr(buf, encode_buf);
1271 if (p) {
1272 /* delete the old value */
1273 char *q = strchr(p + 1, ';');
1274 if (q) {
1275 strcpy(p + 1, q + 1);
1276 } else {
1277 *p = '\0';
1279 strcat(buf, &encode_buf[1]);
1280 } else if (*buf) {
1281 strcat(buf, &encode_buf[1]);
1282 } else {
1283 strcpy(buf, &encode_buf[1]);
1285 enclen = cfg_encode_string(val, encode_buf, CFG_MAX_BUF);
1286 if (enclen < 0 || (strlen(buf) + enclen) >= CFG_MAX_BUF) {
1287 cfg_severity = CFG_ENONFATAL;
1288 cfg_perror_str = dgettext("cfg", "Buffer too small");
1289 return (-1);
1291 strcat(buf, encode_buf);
1292 strcat(buf, ";");
1293 if (cfg_put_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) {
1294 /* severity & perror_str set by cfg_put_cstring */
1295 return (-1);
1297 errno = 0;
1298 return (TRUE);
1302 * cfg_get_single_option
1304 * Scans the options string for the specified option and returns
1305 * the decoded value
1307 * Return:
1308 * true success
1309 * -1 incorrect section, or read error from cfg DB
1312 cfg_get_single_option(CFGFILE *cfg, int section, const char *basekey, char *tag,
1313 char *val, int val_len)
1315 char buf[CFG_MAX_BUF];
1316 char encode_buf[CFG_MAX_BUF];
1317 char *p, *q;
1318 int enclen;
1320 if (cfg == NULL) {
1321 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1322 cfg_severity = CFG_EFATAL;
1323 return (-1);
1326 errno = ENOSYS;
1327 bzero(buf, CFG_MAX_BUF);
1328 if (section != CFG_SEC_CONF) {
1329 cfg_severity = CFG_ENONFATAL;
1330 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1331 return (-1);
1333 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) {
1334 /* severity & perror_str set by cfg_get_cstring */
1335 return (-1);
1338 *encode_buf = ';';
1339 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1;
1340 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) {
1341 cfg_severity = CFG_ENONFATAL;
1342 cfg_perror_str = dgettext("cfg", "Buffer too small");
1343 return (-1);
1345 encode_buf[enclen] = '=';
1346 encode_buf[enclen + 1] = '\0';
1348 /* check the start of the string */
1349 if (strncmp(buf, &encode_buf[1], enclen) == 0) {
1350 p = strchr(buf, '=');
1351 if (!p) {
1352 cfg_severity = CFG_ENONFATAL;
1353 cfg_perror_str = dgettext("cfg", "Option not found");
1354 return (-1);
1356 ++p;
1357 q = strchr(p, ';');
1358 if (q) {
1359 *q = '\0';
1361 cfg_decode_string(p, val, val_len);
1362 errno = 0;
1363 return (TRUE);
1366 /* it's hiding somewhere inside... */
1367 p = strstr(buf, encode_buf);
1368 if (p) {
1369 p += enclen + 1;
1370 q = strchr(p, ';');
1371 if (q) {
1372 *q = '\0';
1374 cfg_decode_string(p, val, val_len);
1375 errno = 0;
1376 return (TRUE);
1379 /* key not found */
1380 return (-1);
1385 * cfg_del_option
1387 * Removes a single key=val pair from the specified option field
1389 * Return:
1390 * true success
1391 * -1 unable to update config
1394 cfg_del_option(CFGFILE *cfg, int section, const char *basekey, char *tag)
1396 char buf[CFG_MAX_BUF];
1397 char encode_buf[CFG_MAX_BUF];
1398 char *p, *q;
1399 int enclen, rc;
1401 if (cfg == NULL) {
1402 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1403 cfg_severity = CFG_EFATAL;
1404 return (-1);
1407 bzero(buf, CFG_MAX_BUF);
1408 if (section != CFG_SEC_CONF) {
1409 cfg_severity = CFG_ENONFATAL;
1410 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1411 return (-1);
1413 if (cfg_get_cstring(cfg, basekey, buf, CFG_MAX_BUF) < 0) {
1414 /* severity & perror_str are set by cfg_get_cstring */
1415 return (-1);
1418 *encode_buf = ';';
1419 enclen = cfg_encode_string(tag, &encode_buf[1], CFG_MAX_BUF - 1) + 1;
1420 if (enclen < 1 || (enclen + 1) >= CFG_MAX_BUF) {
1421 cfg_severity = CFG_ENONFATAL;
1422 cfg_perror_str = dgettext("cfg", "Buffer too small");
1423 return (-1);
1425 encode_buf[enclen] = '=';
1426 encode_buf[enclen + 1] = '\0';
1428 /* check the start of the string */
1429 if (strncmp(buf, &encode_buf[1], enclen) == 0) {
1430 p = strchr(buf, ';');
1431 if (p && (*(p + 1) != '\0')) {
1432 rc = cfg_put_cstring(cfg, basekey, p + 1,
1433 strlen(p + 1));
1434 } else {
1435 rc = cfg_put_cstring(cfg, basekey, "-", 1);
1437 /* severity & perror_str are set by cfg_put_cstring */
1438 return (rc);
1441 /* sigh */
1442 p = strstr(buf, encode_buf);
1443 if (!p) {
1444 /* already removed */
1445 return (TRUE);
1447 q = strchr(p + 1, ';');
1450 * Now the string looks like:
1451 * | first few options | *p | option to remove | *q | rest | '\0'
1454 if (!q) {
1455 /* hum... */
1456 *p = '\0';
1457 } else {
1458 strcpy(p, q);
1461 return (cfg_put_cstring(cfg, basekey, buf, strlen(buf)));
1464 static void
1465 cfg_set_memorymap(cfp_t *cfp)
1467 cfgheader_t *hd = cfp->cf_head;
1469 #ifdef DEBUG_CFGLIST
1470 (void) fprintf(stderr, "callocing %d for initial reads\n", hd->h_csize);
1471 #endif
1473 hd->h_ccopy1 = (char *)calloc(hd->h_csize, sizeof (char));
1474 hd->h_ccopy2 = (char *)calloc(hd->h_csize, sizeof (char));
1475 hd->h_sizes1 = (int *)calloc(CFG_DEFAULT_PSIZE, sizeof (int));
1476 hd->h_sizes2 = (int *)calloc(CFG_DEFAULT_PSIZE, sizeof (int));
1480 * cfg_init_header
1481 * fill in default header info
1483 static void
1484 cfg_init_header(cfp_t *cfp)
1486 time_t tloc;
1487 cfgheader_t *hd = cfp->cf_head;
1489 hd->h_magic = (int32_t)CFG_NEW_MAGIC;
1490 hd->h_stamp = time(&tloc);
1491 hd->h_lock = 0;
1492 /* parser config */
1493 hd->h_parsesize = 0;
1494 hd->h_parseoff = 0;
1495 hd->h_csize = 0;
1496 hd->h_psize = 0;
1497 hd->h_cfgs = NULL;
1498 hd->h_ncfgs = 0;
1499 hd->h_seq1 = hd->h_seq2 = 1;
1500 bzero(hd->h_cfgsizes, MAX_CFG * sizeof (int));
1503 * cfg_read
1504 * read header and all sections of configuration file
1505 * gets new data for incore copy
1506 * removes invalid header state
1507 * works even if config and persistent sections are empty
1510 static int
1511 cfg_read(cfp_t *cfp)
1513 int rc;
1514 cfgheader_t *hd;
1515 int readsize = 0;
1516 #ifdef DEBUG_CFGLIST
1517 (void) fprintf(stderr, "cfg_read\n");
1518 #endif
1520 if (!cfp->cf_head) {
1521 if ((hd = calloc(1, sizeof (*hd))) == NULL)
1522 return (FALSE);
1523 #ifdef DEBUG_HDR
1524 (void) fprintf(stderr, "initial cfg header read\n");
1525 #endif
1526 cfp->cf_head = hd;
1529 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) {
1530 #ifdef DEBUG_LIB
1531 (void) fprintf(stderr, "cfg: seek header failed\n");
1532 #endif
1533 return (FALSE);
1536 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head, 4);
1537 if (rc < 4) {
1538 #ifdef DEBUG_LIB
1539 (void) fprintf(stderr, "cfg: read magic number failed\n");
1540 #endif
1541 return (FALSE);
1544 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) {
1545 #ifdef DEBUG_LIB
1546 (void) fprintf(stderr, "cfg: seek header failed\n");
1547 #endif
1548 return (FALSE);
1551 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head, sizeof (*hd));
1552 if (rc < sizeof (*hd)) {
1553 #ifdef DEBUG_LIB
1554 (void) fprintf(stderr, "cfg: read header failed\n");
1555 #endif
1556 return (FALSE);
1559 cfp->cf_head->h_cfgs = NULL;
1560 cfg_set_memorymap(cfp);
1561 if (cfp->cf_head->h_magic != CFG_NEW_MAGIC) {
1562 #ifdef DEBUG_LIB
1563 (void) fprintf(stderr, "cfg_read: wrong MAGIC number %x\n",
1564 cfp->cf_head->h_magic);
1565 #endif
1566 return (FALSE);
1569 cfp->cf_head->h_state &= ~(CFG_HDR_INVALID);
1571 #ifdef DEBUG_CFGLIST
1572 (void) fprintf(stderr, "reading parser\n");
1573 #endif
1574 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_mapped,
1575 CFG_DEFAULT_PARSE_SIZE);
1576 if (rc < sizeof (*hd)) {
1577 #ifdef DEBUG
1578 (void) fprintf(stderr, "cfg: read parse config failed\n");
1579 #endif
1580 return (FALSE);
1583 readsize = cfp->cf_head->h_csize;
1585 #ifdef DEBUG_CFGLIST
1586 (void) fprintf(stderr, "reading copy1 readsize = %d\n", readsize);
1587 #endif
1588 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head->h_ccopy1,
1589 readsize);
1590 if (rc < 0) {
1591 /* don't fail just return */
1592 #ifdef DEBUG
1593 (void) fprintf(stderr, "cfg: read ccopy1 section failed\n");
1594 #endif
1595 return (FALSE);
1598 if ((*cfp->cf_pp->seek)
1599 (cfp, CFG_DEFAULT_SSIZE - rc, SEEK_CUR) < 0) {
1600 #ifdef DEBUG
1601 (void) fprintf(stderr, "cfg: seek (SEEK_CUR) failed\n");
1602 #endif
1603 return (FALSE);
1606 #ifdef DEBUG_CFGLIST
1607 (void) fprintf(stderr, "reading copy2 readsize = %d\n", readsize);
1608 #endif
1610 rc = (*cfp->cf_pp->read)(cfp, (char *)cfp->cf_head->h_ccopy2,
1611 readsize);
1612 if (rc < 0) {
1613 /* don't fail just return */
1614 #ifdef DEBUG
1615 (void) fprintf(stderr, "cfg: read ccopy2 section failed\n");
1616 #endif
1617 return (FALSE);
1620 /* read the sizes of the lists from disk */
1621 if ((*cfp->cf_pp->seek)
1622 (cfp, CFG_DEFAULT_SSIZE - rc, SEEK_CUR) < 0) {
1623 #ifdef DEBUG
1624 (void) fprintf(stderr, "cfg: seek (SEEK_CUR) failed\n");
1625 #endif
1626 return (FALSE);
1629 #ifdef DEBUG_CFGLIST
1630 (void) fprintf(stderr, "reading sizes\n");
1631 #endif
1632 rc = (*cfp->cf_pp->read)(cfp, (int *)cfp->cf_head->h_sizes1,
1633 CFG_DEFAULT_PSIZE);
1634 if (rc < 0) {
1635 #ifdef DEBUG
1636 (void) fprintf(stderr, "cfg: read h_sizes1 failed\n");
1637 #endif
1638 return (FALSE);
1641 rc = (*cfp->cf_pp->read)(cfp, (int *)cfp->cf_head->h_sizes2,
1642 CFG_DEFAULT_PSIZE);
1643 if (rc < 0) {
1644 #ifdef DEBUG
1645 (void) fprintf(stderr, "cfg: read h_sizes2 failed\n");
1646 #endif
1647 return (FALSE);
1651 * If initial or invalid sequence, use first section
1653 if ((cfp->cf_head->h_seq1 <= 0) && (cfp->cf_head->h_seq2 <= 0)) {
1654 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1;
1655 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1;
1658 if (cfp->cf_head->h_seq1 >= cfp->cf_head->h_seq2) {
1659 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1;
1660 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1;
1661 } else {
1662 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy2;
1663 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes2;
1666 #ifdef DEBUG_LIB
1667 dump_status(cfp, "cfg_read");
1668 #endif
1670 return (TRUE);
1674 * cfg_lock
1675 * Read-write locking of the configuration
1676 * reads into core all sections
1677 * builds parser trees for each section
1678 * Returns: TRUE if the lock was acquired, FALSE otherwise.
1681 cfg_lock(CFGFILE *cfg, CFGLOCK mode)
1683 cfp_t *cfp;
1684 int is_locked = 0;
1685 int rc;
1687 if (cfg == NULL) {
1688 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1689 cfg_severity = CFG_EFATAL;
1690 return (FALSE);
1693 if (mode == CFG_UPGRADE) {
1694 mode = CFG_WRLOCK;
1697 if (mode == CFG_WRLOCK && (cfg->cf[0].cf_flag & CFG_RDONLY)) {
1698 goto fail;
1702 * if you don't even give me the right lock request,
1703 * why should I give you one?
1705 if (mode != CFG_RDLOCK && mode != CFG_WRLOCK)
1706 goto fail;
1708 if (cfg_lockd) {
1709 if (mode == CFG_WRLOCK)
1710 cfg_lockd_wrlock();
1711 else
1712 cfg_lockd_rdlock();
1713 is_locked = 1;
1714 } else {
1716 #ifdef DEBUG_CFGLIST
1717 (void) fprintf(stderr, "cfg_lock\n");
1718 #endif
1719 /* Lock is always based on local file pointer */
1720 cfg->cf[1].cf_lock = cfg->cf[0].cf_lock = cfg->cf[0].cf_fd;
1722 if (!((cfg->cf[0].cf_flag & CFG_RDONLY) &&
1723 (mode == CFG_RDLOCK))) {
1725 struct flock lk = {0};
1726 lk.l_type = (mode == CFG_RDLOCK ? F_RDLCK : F_WRLCK);
1727 lk.l_whence = SEEK_SET;
1728 lk.l_start = (off_t)0;
1729 lk.l_len = (off_t)0;
1731 if (fcntl(cfg->cf[0].cf_lock, F_SETLKW, &lk) < 0)
1732 goto fail;
1736 /* Determine number of files open */
1737 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) {
1738 if (!cfp->cf_fd) continue;
1739 if ((cfp->cf_head) &&
1740 (cfp->cf_head->h_state & CFG_HDR_INVALID)) {
1741 if ((rc = cfg_hdrcmp(cfp)) == 0) {
1742 #ifdef DEBUG_HDR
1743 (void) fprintf(stderr,
1744 "cfg header match, skipping re-read\n");
1745 #endif
1746 cfp->cf_head->h_state |= CFG_HDR_RDLOCK;
1747 if (mode == CFG_WRLOCK)
1748 cfp->cf_head->h_state |= CFG_HDR_WRLOCK;
1750 cfp->cf_head->h_state &= ~(CFG_HDR_INVALID);
1751 continue;
1753 #ifdef DEBUG_HDR
1754 (void) fprintf(stderr, "re-reading cfg, header mismatch\n");
1755 #endif
1757 * dump what we have, info is stale
1759 cfg_free_cfglist(cfp);
1760 cfg_free_parser_tree();
1762 if (cfp->cf_head->h_ccopy1) {
1763 free(cfp->cf_head->h_ccopy1);
1764 cfp->cf_head->h_ccopy1 = NULL;
1766 if (cfp->cf_head->h_ccopy2) {
1767 free(cfp->cf_head->h_ccopy2);
1768 cfp->cf_head->h_ccopy2 = NULL;
1770 if (cfp->cf_head->h_sizes1) {
1771 free(cfp->cf_head->h_sizes1);
1772 cfp->cf_head->h_sizes1 = NULL;
1774 if (cfp->cf_head->h_sizes2) {
1775 free(cfp->cf_head->h_sizes2);
1776 cfp->cf_head->h_sizes2 = NULL;
1779 if (cfp->cf_head)
1780 free(cfp->cf_head);
1781 cfp->cf_head = NULL;
1784 if (cfp->cf_head == NULL) {
1785 if (!cfg_read(cfp)) {
1786 if (cfp->cf_head != NULL)
1787 cfg_init_header(cfp);
1788 else
1789 goto fail;
1790 } else {
1791 #ifdef DEBUG_CFGLIST
1792 (void) fprintf(stderr,
1793 "reading parser config\n");
1794 #endif
1795 /* build parser trees */
1796 cfg_read_parser_config(cfp);
1800 cfp->cf_head->h_state |= CFG_HDR_RDLOCK;
1801 if (mode == CFG_WRLOCK) {
1802 if (cfp->cf_head->h_seq1 >= cfp->cf_head->h_seq2) {
1803 #ifdef DEBUG_LIB
1804 (void) fprintf(stderr,
1805 "cfg_lock: WRLOCK copying 1 to 2\n");
1806 #endif
1807 memcpy(cfp->cf_head->h_ccopy2,
1808 cfp->cf_head->h_ccopy1,
1809 cfp->cf_head->h_csize);
1810 memcpy(cfp->cf_head->h_sizes2,
1811 cfp->cf_head->h_sizes1,
1812 CFG_DEFAULT_PSIZE);
1814 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy2;
1815 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes2;
1816 } else {
1817 #ifdef DEBUG_LIB
1818 (void) fprintf(stderr,
1819 "cfg_lock: WRLOCK copying 2 to 1\n");
1820 #endif
1821 memcpy(cfp->cf_head->h_ccopy1,
1822 cfp->cf_head->h_ccopy2,
1823 cfp->cf_head->h_csize);
1824 memcpy(cfp->cf_head->h_sizes1,
1825 cfp->cf_head->h_sizes2,
1826 CFG_DEFAULT_PSIZE);
1828 cfp->cf_head->h_cparse = cfp->cf_head->h_ccopy1;
1829 cfp->cf_head->h_sizes = cfp->cf_head->h_sizes1;
1832 cfp->cf_head->h_state |= CFG_HDR_WRLOCK;
1835 if (cfg_map_cfglists(cfp) < 0) {
1836 #ifdef DEBUG_LIB
1837 (void) fprintf(stderr, "cfg: map_cfglists failed\n");
1838 #endif
1839 goto fail;
1842 #ifdef DEBUG_LIB
1843 dump_status(cfp, "cfg_lock");
1844 #endif
1847 return (TRUE);
1849 fail:
1850 if (is_locked) {
1851 cfg_lockd_unlock();
1853 cfg_perror_str = dgettext("cfg", CFG_EGENERIC);
1854 cfg_severity = CFG_ENONFATAL;
1855 return (FALSE);
1859 * Unlock the database
1861 void
1862 cfp_unlock(cfp_t *cfp)
1865 #ifdef DEBUG_CFGLIST
1866 (void) fprintf(stderr, "cfg_unlock\n");
1867 #endif
1868 if (cfg_lockd) {
1869 cfg_lockd_unlock();
1870 } else {
1871 struct flock lk = {0};
1872 lk.l_type = F_UNLCK;
1873 lk.l_whence = SEEK_SET;
1874 lk.l_start = (off_t)0;
1875 lk.l_len = (off_t)0;
1876 (void) fcntl(cfp->cf_lock, F_SETLKW, &lk);
1879 if (cfp->cf_head != NULL) {
1880 cfp->cf_head->h_state &= ~(CFG_HDR_RDLOCK|CFG_HDR_WRLOCK);
1881 cfp->cf_head->h_state |= CFG_HDR_INVALID;
1884 void
1885 cfg_unlock(CFGFILE *cfg)
1887 if (cfg == NULL) {
1888 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1889 cfg_severity = CFG_EFATAL;
1890 return;
1893 cfp_unlock(&cfg->cf[0]);
1894 cfp_unlock(&cfg->cf[1]);
1898 * Test for a read lock, set errno if failed.
1900 static int
1901 cfg_rdlock(CFGFILE *cfg)
1903 int rc;
1904 cfp_t *cfp;
1906 if (cfg == NULL) {
1907 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1908 cfg_severity = CFG_EFATAL;
1909 return (FALSE);
1912 /* Determine number of files open */
1913 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) {
1914 if (!cfp->cf_fd)
1915 continue;
1916 if (cfp->cf_head == NULL) {
1917 #ifdef DEBUG_LIB
1918 (void) fprintf(stderr, "cfg_rdlock: cf_head == NULL\n");
1919 #endif
1921 * 6335583, if header == NULL,
1922 * we can't call cfg_read to fill the header again
1923 * since it will change the lock state to
1924 * CFG_HDR_WRLOCK and dscfg will be the processer
1925 * that hold the lock,
1926 * just returning a FALSE if the case,
1927 * then retrieve the lock state from flock structure.
1929 rc = FALSE;
1930 break;
1931 } else {
1932 #ifdef DEBUG_LIB
1933 (void) fprintf(stderr, "cfg_rdlock: cf_head != NULL\n");
1934 #endif
1935 if ((cfp->cf_head->h_state & CFG_HDR_RDLOCK)
1936 == CFG_HDR_RDLOCK) {
1937 rc = TRUE;
1938 } else {
1939 rc = FALSE;
1940 break;
1945 if (!rc)
1946 errno = EPERM;
1948 return (rc);
1952 * Test for a write lock, set errno if failed.
1954 static int
1955 cfg_wrlock(CFGFILE *cfg)
1957 int rc;
1958 cfp_t *cfp;
1960 if (cfg == NULL) {
1961 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
1962 cfg_severity = CFG_EFATAL;
1963 return (FALSE);
1966 /* Determine number of files open */
1967 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) {
1968 if (!cfp->cf_fd)
1969 continue;
1970 if (cfp->cf_head == NULL) {
1971 #ifdef DEBUG_LIB
1972 (void) fprintf(stderr, "cfg wrlock: cf_head == NULL\n");
1973 #endif
1975 * 6335583, see comments on cfg_rdlock
1977 rc = FALSE;
1978 break;
1979 } else {
1980 #ifdef DEBUG_LIB
1981 (void) fprintf(stderr, "cfg wrlock: cf_head != NULL\n");
1982 #endif
1983 if ((cfp->cf_head->h_state & CFG_HDR_WRLOCK)
1984 == CFG_HDR_WRLOCK) {
1985 rc = TRUE;
1986 } else {
1987 rc = FALSE;
1988 break;
1993 if (!rc)
1994 errno = EPERM;
1996 return (rc);
2000 * cfg_get_lock
2001 * Find lock status of CFG database.
2002 * Returns: TRUE and sets lock and pid if the lock is held, FALSE otherwise.
2005 cfg_get_lock(CFGFILE *cfg, CFGLOCK *lock, pid_t *pid)
2007 struct flock lk;
2008 int rc;
2010 if (cfg == NULL) {
2011 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
2012 cfg_severity = CFG_EFATAL;
2013 return (FALSE);
2016 if (cfg_lockd) {
2017 switch (cfg_lockedby(pid)) {
2018 case LOCK_READ:
2019 *lock = CFG_RDLOCK;
2020 return (TRUE);
2021 case LOCK_WRITE:
2022 *lock = CFG_WRLOCK;
2023 return (TRUE);
2024 case LOCK_NOTLOCKED:
2025 default:
2026 return (FALSE);
2028 } else {
2029 if (cfg_wrlock(cfg)) {
2030 *lock = CFG_WRLOCK;
2031 *pid = getpid();
2032 return (TRUE);
2035 if (cfg_rdlock(cfg)) {
2036 *lock = CFG_RDLOCK;
2037 *pid = getpid();
2038 return (TRUE);
2041 /* Lock is always based on local file pointer */
2042 cfg->cf[1].cf_lock = cfg->cf[0].cf_lock = cfg->cf[0].cf_fd;
2044 bzero(&lk, sizeof (lk));
2045 lk.l_type = F_WRLCK;
2046 lk.l_whence = SEEK_SET;
2047 lk.l_start = (off_t)0;
2048 lk.l_len = (off_t)0;
2050 if (fcntl(cfg->cf[0].cf_lock, F_GETLK, &lk) < 0)
2051 rc = FALSE;
2052 else {
2053 if (lk.l_type == F_UNLCK)
2054 rc = FALSE;
2055 else {
2056 rc = TRUE;
2057 *pid = lk.l_pid;
2058 *lock = lk.l_type == F_WRLCK ? CFG_WRLOCK : CFG_RDLOCK;
2062 return (rc);
2066 * cfg_commit
2067 * Write modified version of header, configuration and persistent
2068 * data using 2 stage commit.
2069 * If no valid data is found in header, it is assumed to be an initial
2070 * write and we will create the default header (could be dangerous)
2071 * another tricky part, if we are doing an upgrade we may be dealing
2072 * with an old database. we need to take care seeking and writing
2073 * until such time that it is upgraded.
2075 * Mutual exclusion is checked using cfg_lock
2079 cfg_commit(CFGFILE *cfg)
2081 cfp_t *cfp;
2082 int rc;
2083 time_t tloc;
2084 int section;
2085 int wrsize, *ip;
2087 if (cfg == NULL) {
2088 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
2089 cfg_severity = CFG_EFATAL;
2090 return (FALSE);
2093 if (!cfg_wrlock(cfg))
2094 return (FALSE);
2096 /* Determine number of files open */
2097 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) {
2098 if (!cfp->cf_fd)
2099 continue;
2102 * lets put everything back into one char *
2104 cfg_replace_lists(cfp);
2106 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) {
2107 #ifdef DEBUG_LIB
2108 (void) fprintf(stderr, "cfg: seek header failed\n");
2109 #endif
2110 return (FALSE);
2113 cfp->cf_head->h_size = cfp->cf_head->h_parsesize
2114 + cfp->cf_head->h_csize + cfp->cf_head->h_psize;
2115 cfp->cf_head->h_stamp = time(&tloc);
2117 /* seeking into database */
2118 if ((*cfp->cf_pp->seek)(cfp, sizeof (cfgheader_t),
2119 SEEK_CUR) < 0)
2120 return (FALSE);
2122 if (cfp->cf_head->h_ccopy1 == cfp->cf_head->h_cparse) {
2123 if (cfp->cf_head->h_seq1 < 0)
2124 cfp->cf_head->h_seq1 = 1;
2125 else
2126 cfp->cf_head->h_seq1 = cfp->cf_head->h_seq2 + 1;
2127 section = 1;
2128 } else {
2129 if (cfp->cf_head->h_seq2 < 0)
2130 cfp->cf_head->h_seq2 = 1;
2131 else
2132 cfp->cf_head->h_seq2 = cfp->cf_head->h_seq1 + 1;
2133 section = 2;
2135 #ifdef DEBUG_LIB
2136 dump_status(cfp, "cfg_commit");
2137 #endif
2138 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_mapped,
2139 CFG_DEFAULT_PARSE_SIZE);
2140 #ifdef DEBUG
2141 if (rc < 0) {
2142 (void) fprintf(stderr,
2143 "parse commit: rc %d h_parsesize %d\n",
2144 rc, cfp->cf_head->h_parsesize);
2146 #endif
2147 if (section == 1) {
2148 rc = (*cfp->cf_pp->write) (cfp, cfp->cf_head->h_ccopy1,
2149 cfp->cf_head->h_csize);
2150 #ifdef DEBUG
2151 if (rc < 0) {
2152 (void) fprintf(stderr,
2153 "csection commit 1: rc %d h_csize %d\n",
2154 rc, cfp->cf_head->h_csize);
2156 #endif
2157 if ((*cfp->cf_pp->seek)
2158 (cfp, (2 * CFG_DEFAULT_SSIZE) - rc, SEEK_CUR) < 0)
2159 return (FALSE);
2162 * limit the write to only what we need
2164 ip = cfp->cf_head->h_sizes1;
2165 for (wrsize = 0; *ip; ip += *ip + 1)
2166 wrsize += *ip + 1;
2168 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head->h_sizes1,
2169 wrsize * sizeof (int));
2170 #ifdef DEBUG
2171 if (rc < 0) {
2172 (void) fprintf(stderr,
2173 "cfg: write list sizes1 failed rc\n");
2175 #endif
2176 } else {
2177 if ((*cfp->cf_pp->seek)(cfp, CFG_DEFAULT_SSIZE,
2178 SEEK_CUR) < 0)
2179 return (FALSE);
2181 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head->h_ccopy2,
2182 cfp->cf_head->h_csize);
2183 #ifdef DEBUG
2184 if (rc < 0) {
2185 (void) fprintf(stderr,
2186 "csection commit 2: rc %d h_csize %d\n",
2187 rc, cfp->cf_head->h_csize);
2189 #endif
2190 if ((*cfp->cf_pp->seek)
2191 (cfp, (CFG_DEFAULT_SSIZE + CFG_DEFAULT_PSIZE) - rc,
2192 SEEK_CUR) < 0)
2193 return (FALSE);
2196 * limit the write to only what we need
2198 ip = cfp->cf_head->h_sizes2;
2199 for (wrsize = 0; *ip; ip += *ip + 1)
2200 wrsize += *ip + 1;
2202 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head->h_sizes2,
2203 wrsize * sizeof (int));
2204 #ifdef DEBUG
2205 if (rc < 0) {
2206 (void) fprintf(stderr,
2207 "cfg: write list sizes2 failed\n");
2209 #endif
2214 #ifdef DEBUG_CFGLIST
2215 (void) fprintf(stderr,
2216 "writing h_csize %d\n", cfp->cf_head->h_csize);
2217 #endif
2218 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0)
2219 return (FALSE);
2221 cfp->cf_head->h_size = cfp->cf_head->h_parsesize +
2222 cfp->cf_head->h_csize + cfp->cf_head->h_psize;
2224 rc = (*cfp->cf_pp->write)(cfp, cfp->cf_head,
2225 sizeof (cfgheader_t));
2226 if (rc < 0) {
2227 cfg_perror_str = dgettext("cfg",
2228 "cfg_commit: header write failed");
2229 cfg_severity = CFG_EFATAL;
2230 return (FALSE);
2234 return (TRUE);
2238 * cfg_rewind
2239 * rewind internal file pointer for specified section
2240 * empty now, rewind not necessary. But don't break
2241 * old code.
2243 /*ARGSUSED*/
2244 void
2245 cfg_rewind(CFGFILE *cfg, int section)
2247 switch (section) {
2248 case CFG_SEC_CONF:
2249 break;
2250 case CFG_SEC_ALL:
2251 break;
2256 * cfg_location
2257 * set or return the default location file to
2258 * determine the partition name of the configuration partition
2259 * location is stored in well known file location
2261 char *
2262 cfg_location(char *location, int mode, char *altroot)
2264 int fd;
2265 int fmode;
2266 int rc;
2267 char wellknown[NSC_MAXPATH];
2268 char loc[NSC_MAXPATH];
2270 if (mode == CFG_LOC_GET_LOCAL) {
2271 return (CFG_LOCAL_LOCATION);
2272 } else if (mode == CFG_LOC_GET_CLUSTER) {
2273 fmode = O_RDONLY;
2274 } else {
2275 fmode = O_RDWR | O_CREAT;
2278 if (altroot) {
2279 strcpy(wellknown, altroot);
2280 strcat(wellknown, CFG_CLUSTER_LOCATION);
2281 } else
2282 strcpy(wellknown, CFG_CLUSTER_LOCATION);
2284 fd = open(wellknown, fmode, 0644);
2285 if (fd < 0) {
2286 cfg_perror_str = dgettext("cfg", strerror(errno));
2287 cfg_severity = CFG_ENONFATAL;
2288 return (NULL);
2291 if (mode == CFG_LOC_SET_CLUSTER) {
2292 if (location == NULL || (strlen(location) > NSC_MAXPATH)) {
2293 cfg_perror_str = dgettext("cfg",
2294 "cfg_location: filename too big or missing");
2295 cfg_severity = CFG_EFATAL;
2296 return (NULL);
2300 * 5082142
2301 * If we're in a cluster, make sure that the config location
2302 * is a raw device. Using non-raw did devices in a cluster
2303 * can result in data corruption, since inconsistent data
2304 * may reside in the block cache on one node, but has not
2305 * been flushed to disk.
2307 if (cfg_iscluster() > 0) {
2308 struct stat dscfg_stat;
2309 if (stat(location, &dscfg_stat) != 0) {
2310 cfg_perror_str = dgettext("cfg",
2311 "Unable to access dscfg location");
2312 cfg_severity = CFG_EFATAL;
2313 return (NULL);
2315 if (!S_ISCHR(dscfg_stat.st_mode)) {
2316 cfg_perror_str = dgettext("cfg",
2317 "dscfg location must be a raw device");
2318 cfg_severity = CFG_EFATAL;
2319 return (NULL);
2323 if (ftruncate(fd, 0) < 0)
2324 return (NULL);
2326 rc = write(fd, location, strlen(location));
2327 if (rc < 0) {
2328 cfg_perror_str = dgettext("cfg",
2329 "cfg_location: write to well known failed");
2330 cfg_severity = CFG_EFATAL;
2331 return (NULL);
2333 bzero(config_file, sizeof (config_file));
2335 if (lseek(fd, 0, SEEK_SET) < 0)
2336 return (NULL);
2338 bzero(config_file, sizeof (config_file));
2339 rc = read(fd, config_file, sizeof (config_file));
2340 if (rc < 0) {
2341 cfg_perror_str = dgettext("cfg",
2342 "cfg_location: read from well known failed");
2343 cfg_severity = CFG_EFATAL;
2344 return (NULL);
2346 close(fd);
2347 if (altroot) {
2348 strcpy(loc, altroot);
2349 strcat(loc, config_file);
2350 bzero(config_file, sizeof (config_file));
2351 strcpy(config_file, loc);
2355 * scan string out of config_file, to strip whitespace
2357 sscanf(config_file, "%s", loc);
2358 strcpy(config_file, loc);
2360 return (config_file);
2364 * cfg_update_parser_config
2365 * If tag and key exist return -1
2367 * XXX Currently does not append new field to existing parser rule
2371 cfg_update_parser_config(CFGFILE *cfg, const char *key, int section)
2373 cfp_t *cfp;
2374 int size;
2375 char buf[CFG_MAX_BUF];
2376 struct parser *tbl;
2377 char tmpkey[CFG_MAX_KEY];
2378 char *ky, *fld;
2379 errno = 0;
2381 if (cfg == NULL) {
2382 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
2383 cfg_severity = CFG_EFATAL;
2384 return (-1);
2387 cfp = FP_SUN_CLUSTER(cfg);
2388 if (!cfg_wrlock(cfg))
2389 return (-1);
2391 bzero(buf, CFG_MAX_BUF);
2392 bzero(tmpkey, sizeof (tmpkey));
2393 strcpy(tmpkey, key);
2394 if (section == CFG_PARSE_CONF) {
2395 strcat(buf, "C:");
2396 tbl = chead;
2397 } else {
2398 errno = EINVAL;
2399 return (-1);
2401 ky = strtok(tmpkey, ".");
2402 fld = strtok(NULL, ".");
2403 while (fld) {
2404 size = cfg_get_item(tbl, ky, fld);
2407 * Assure we are loading a clean table, with do duplicates
2408 * based on our File Descriptor
2410 if (chead_loaded && (chead_loaded != cfp->cf_fd)) {
2411 if (size <= 0)
2412 return (-1);
2413 } else {
2414 if (size > 0)
2415 return (-1);
2417 fld = strtok(NULL, ".");
2419 size = strlen(key) + 2;
2420 strncat(buf, key, size);
2421 #ifdef DEBUG_LIB
2422 (void) fprintf(stderr, "update parser config %s size %d\n", buf, size);
2423 #endif
2424 if ((size + cfp->cf_head->h_parseoff) > CFG_DEFAULT_PARSE_SIZE) {
2425 cfg_perror_str = dgettext("cfg",
2426 "cfg_update_parser_config: header overrun");
2427 cfg_severity = CFG_EFATAL;
2428 #ifdef DEBUG_LIB
2429 (void) fprintf(stderr, "update parser config: "
2430 "overrun siz %d poff %d parsesize %d\n",
2431 size, cfp->cf_head->h_parseoff, cfp->cf_head->h_parsesize);
2432 #endif
2433 errno = E2BIG;
2434 return (-1);
2436 bcopy(buf, (cfp->cf_mapped + cfp->cf_head->h_parseoff), size);
2437 cfp->cf_head->h_parseoff += size;
2438 cfp->cf_head->h_state |= CFG_HDR_INVALID;
2439 if (cfp->cf_mapped[cfp->cf_head->h_parseoff - 1] != '\n') {
2440 cfp->cf_mapped[cfp->cf_head->h_parseoff] = '\n';
2441 cfp->cf_head->h_parseoff++;
2443 cfp->cf_head->h_parsesize = cfp->cf_head->h_parseoff;
2444 cfg_read_parser_config(cfp);
2445 return (TRUE);
2448 * cfg_read_parser_config
2449 * reads parser config from file
2450 * converts it to internal tree for parsing
2451 * chead for configuration parser entries
2454 static
2455 void
2456 cfg_read_parser_config(cfp_t *cfp)
2458 struct lookup *p, *q;
2459 struct parser *thead;
2460 int off, foff;
2461 char *part;
2462 char *key;
2463 char *fld;
2464 int fldnum;
2465 char c;
2466 char buf[CFG_MAX_BUF];
2467 int i = 0;
2468 int n = 0;
2470 off = foff = 0;
2471 /*CONSTCOND*/
2472 while (TRUE) {
2473 off = 0;
2474 bzero(buf, CFG_MAX_BUF);
2475 /* LINTED it assigns value to c */
2476 while (c = cfp->cf_mapped[foff++]) {
2477 if (c == '\n')
2478 break;
2479 buf[off++] = c;
2481 part = strtok(buf, ":");
2482 if (!part)
2483 break;
2484 if (*part == 'C') {
2485 thead = chead;
2486 n = i;
2488 key = strtok(NULL, ".");
2489 if (!key)
2490 break;
2491 strcpy(thead[n].tag.l_word, key);
2492 thead[n].tag.l_value = 0;
2493 thead[n].fld = NULL;
2494 fldnum = 1;
2495 while ((fld = strtok(NULL, ".")) != NULL) {
2496 p = thead[n].fld;
2497 if (p == NULL) {
2498 q = thead[n].fld = calloc(1,
2499 sizeof (struct lookup));
2500 } else {
2501 for (q = thead[n].fld; q; q = q->l_next)
2502 p = q;
2503 q = calloc(1, sizeof (struct lookup));
2504 p->l_next = q;
2506 strcpy(q->l_word, fld);
2507 q->l_value = fldnum;
2508 q->l_next = NULL;
2509 #ifdef DEBUG_EXTRA
2510 (void) fprintf(stderr,
2511 "read parser: q: word %s value %d\n",
2512 q->l_word, q->l_value);
2513 #endif
2514 fldnum++;
2516 if (*part == 'C')
2517 i++;
2520 /* All done, indicate parser table is loaded */
2521 if (i && (chead_loaded == 0))
2522 chead_loaded = cfp->cf_fd;
2525 * before I go and alloc, why am I here?
2526 * do I need a bunch of cfglists, or do I just
2527 * need to accommodate a just added parser entry
2528 * if the latter, we already have a base, just set
2529 * i to the index of the cfg which members need allocing
2531 if ((cfp->cf_head->h_cfgs == NULL) ||
2532 (cfp->cf_head->h_cfgs[n-1].l_entry == NULL)) {
2533 cfp->cf_head->h_cfgs = (cfglist_t *)calloc(MAX_CFG,
2534 sizeof (cfglist_t));
2535 i = 0;
2537 else
2538 i = n;
2540 if (cfp->cf_head->h_cfgs) {
2542 #ifdef DEBUG_CFGLIST
2543 (void) fprintf(stderr, "alloced %d cfg lists \n", n + 1);
2544 #endif
2545 for (cfp->cf_head->h_ncfgs = n + 1;
2546 i < min(cfp->cf_head->h_ncfgs, MAX_CFG); i++) {
2547 cfp->cf_head->h_cfgs[i].l_name = '\0';
2548 cfp->cf_head->h_cfgs[i].l_name =
2549 strdup(chead[i].tag.l_word);
2550 cfp->cf_head->h_cfgs[i].l_index = i;
2551 cfp->cf_head->h_cfgs[i].l_entry =
2552 calloc(DEFAULT_ENTRY_SIZE, sizeof (char));
2553 cfp->cf_head->h_cfgs[i].l_nentry = 0;
2554 cfp->cf_head->h_cfgs[i].l_esiz =
2555 calloc(DEFAULT_NENTRIES, sizeof (int));
2556 cfp->cf_head->h_cfgs[i].l_size = 0;
2557 cfp->cf_head->h_cfgs[i].l_free = DEFAULT_ENTRY_SIZE;
2558 if ((cfp->cf_head->h_cfgs[i].l_entry == NULL) ||
2559 (cfp->cf_head->h_cfgs[i].l_esiz == NULL)) {
2560 cfg_perror_str = dgettext("cfg", "unable to"
2561 " allocate cfglist members");
2562 cfg_severity = CFG_EFATAL;
2565 } else {
2566 cfg_perror_str = dgettext("cfg", "unable to alloc cfglist");
2567 cfg_severity = CFG_EFATAL;
2572 * cfg_map_cfglists()
2573 * go through list of list sizes in header
2574 * and create separate lists
2577 cfg_map_cfglists(cfp_t *cfp)
2579 int i;
2580 int offset = 0;
2581 int *ip;
2582 int list_size = 0;
2583 int slot_inc;
2584 char *p;
2585 cfgheader_t *ch;
2587 ch = cfp->cf_head;
2588 p = ch->h_cparse;
2590 /* get the first list size */
2591 ip = ch->h_sizes;
2593 for (i = 0; i < min(ch->h_ncfgs, MAX_CFG); i++) {
2594 if (ch->h_cfgsizes[i] > 0) {
2595 if (ch->h_cfgsizes[i] > DEFAULT_ENTRY_SIZE) {
2597 ch->h_cfgs[i].l_entry = (char *)
2598 realloc(ch->h_cfgs[i].l_entry,
2599 ch->h_cfgsizes[i] * sizeof (char));
2600 /* set free to 0, we'll get more when we add */
2601 ch->h_cfgs[i].l_free = 0;
2603 } else
2604 ch->h_cfgs[i].l_free -= ch->h_cfgsizes[i];
2606 /* get lists and marry up to each cfgs structure */
2609 list_size = *ip;
2610 ip++;
2612 if (list_size > DEFAULT_NENTRIES) {
2614 * we're gonna need more slots
2615 * we want to alloc on DEFAULT_NENTRIES
2616 * boundry. ie. always a multiple of it
2617 * later on, when we add to the list
2618 * we can see if we need to add by mod'ding
2619 * l_nentry and DEFAULT_NENTRIES and check for 0
2621 slot_inc = DEFAULT_NENTRIES -
2622 (list_size % DEFAULT_NENTRIES);
2623 if (slot_inc == DEFAULT_NENTRIES)
2624 slot_inc = 0; /* addcfline reallocs */
2626 ch->h_cfgs[i].l_esiz = (int *)realloc(
2627 ch->h_cfgs[i].l_esiz,
2628 (list_size + slot_inc) * sizeof (int));
2630 memcpy(ch->h_cfgs[i].l_esiz, ip,
2631 list_size * sizeof (int));
2633 ch->h_cfgs[i].l_nentry = list_size;
2635 ip += list_size;
2637 } else
2639 continue;
2641 if (ch->h_cfgs[i].l_entry != NULL) {
2642 p = ch->h_cparse + offset;
2643 #ifdef DEBUG_CFGLIST
2644 (void) fprintf(stderr, "mapping list %d size %d offset %d, addr 0x%x\n",
2645 i, ch->h_cfgsizes[i], offset, p);
2646 #endif
2647 memcpy(ch->h_cfgs[i].l_entry,
2648 p, ch->h_cfgsizes[i]);
2649 ch->h_cfgs[i].l_size = ch->h_cfgsizes[i];
2650 offset += ch->h_cfgsizes[i];
2651 } else {
2652 #ifdef DEBUG_CFGLIST
2653 (void) fprintf(stderr, "NULL l_entry\n");
2654 #endif
2655 return (-1);
2660 return (1);
2664 void
2665 cfg_replace_lists(cfp_t *cfp)
2667 int i;
2668 int offset = 0;
2669 int size_offset = 0;
2671 int section = 0;
2672 cfgheader_t *cf;
2673 cfglist_t *cfl;
2675 cf = cfp->cf_head;
2677 if ((cfl = cfp->cf_head->h_cfgs) == NULL)
2678 return;
2680 #ifdef DEBUG_CFGLIST
2681 (void) fprintf(stderr, "cfg_replace_lists\n");
2682 #endif
2684 if (cf->h_cparse == cf->h_ccopy1)
2685 section = 1;
2688 * check to see if we are using copy1 or 2,
2689 * grow or shrink the size, fix h_cparse reference
2690 * in case realloc gave us a funky new address.
2691 * put stuff in it.
2693 cf->h_ccopy1 = (char *)
2694 realloc(cf->h_ccopy1, cf->h_csize * sizeof (char));
2695 cf->h_ccopy2 = (char *)
2696 realloc(cf->h_ccopy2, cf->h_csize * sizeof (char));
2697 if (section == 1) {
2698 /* we used copy1 */
2699 cf->h_cparse = cf->h_ccopy1;
2700 } else
2701 cf->h_cparse = cf->h_ccopy2;
2704 * just because, we'll zero out h_csize and recalc
2705 * after all, this is the number the next guy gets
2707 cf->h_csize = cf->h_sizes[0] = 0;
2708 for (i = 0; i < MAX_CFG; i++) {
2709 /* only as many lists as chead has */
2710 if (chead[i].tag.l_word[0] == '\0') {
2711 break;
2713 if (cfl[i].l_entry && cfl[i].l_entry[0] != '\0') {
2714 #ifdef DEBUG_CFGLIST
2715 (void) fprintf(stderr,
2716 "copying list %d at %x size %d\n",
2717 i, cf->h_cparse + offset,
2718 cfl[i].l_size);
2719 #endif
2720 memcpy((cf->h_cparse + offset),
2721 cfl[i].l_entry, cfl[i].l_size);
2722 offset += cfl[i].l_size;
2723 #ifdef DEBUG_CFGLIST
2724 (void) fprintf(stderr,
2725 "cfl[%d].l_nentry %d cfl[%d].l_esiz[%d] %d"
2726 " size offset %d\n",
2727 i, cfl[i].l_nentry, i, cfl[i].l_nentry - 1,
2728 cfl[i].l_esiz[cfl[i].l_nentry - 1], size_offset);
2729 #endif
2731 * first write the number of entries
2732 * then copy over the array ie.
2733 * a list with 5 elements would be copied
2734 * as a 6 element array slot 0 being the
2735 * number of elements
2737 cf->h_sizes[size_offset++] = cfl[i].l_nentry;
2738 memcpy((cf->h_sizes + size_offset), cfl[i].l_esiz,
2739 cfl[i].l_nentry * sizeof (int));
2740 size_offset += cfl[i].l_nentry;
2741 cf->h_sizes[size_offset] = 0;
2743 cf->h_csize += cfl[i].l_size;
2747 void
2748 cfg_free_cfglist(cfp_t *cfp)
2750 int i;
2752 if (!cfp->cf_head || !cfp->cf_head->h_cfgs)
2753 return;
2755 for (i = 0; cfp->cf_head && i < MAX_CFG; i++) {
2756 if (cfp->cf_head->h_cfgs[i].l_entry) {
2757 free(cfp->cf_head->h_cfgs[i].l_entry);
2758 cfp->cf_head->h_cfgs[i].l_entry = NULL;
2761 if (cfp->cf_head->h_cfgs[i].l_name) {
2762 free(cfp->cf_head->h_cfgs[i].l_name);
2763 cfp->cf_head->h_cfgs[i].l_entry = NULL;
2766 if (cfp->cf_head->h_cfgs[i].l_esiz) {
2767 free(cfp->cf_head->h_cfgs[i].l_esiz);
2768 cfp->cf_head->h_cfgs[i].l_esiz = NULL;
2772 if (cfp->cf_head) {
2773 free(cfp->cf_head->h_cfgs);
2774 cfp->cf_head->h_cfgs = NULL;
2778 void
2779 cfg_free_parser_tree()
2781 struct lookup *p = NULL;
2782 struct lookup *q = NULL;
2783 int i;
2785 for (i = 0; i < MAX_CFG; i++) {
2786 if (chead)
2787 p = chead[i].fld;
2788 while (p) {
2789 q = p->l_next;
2790 if (p) {
2791 free(p);
2792 p = NULL;
2794 p = q;
2797 bzero(chead, MAX_CFG * sizeof (struct parser));
2800 void
2801 cfg_close(CFGFILE *cfg)
2803 cfp_t *cfp;
2805 if (cfg == NULL) {
2806 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
2807 cfg_severity = CFG_EFATAL;
2808 return;
2811 /* Determine number of files open */
2812 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) {
2813 if (!cfp->cf_fd) continue;
2815 (*cfp->cf_pp->close)(cfp);
2816 #ifdef DEBUG_CFGLIST
2817 (void) fprintf(stderr, "freeing cfglists\n");
2818 #endif
2819 cfg_free_cfglist(cfp);
2821 #ifdef DEBUG_CFGLIST
2822 (void) fprintf(stderr, "freeing cfp->cf_mapped\n");
2823 #endif
2824 free(cfp->cf_mapped);
2825 cfp->cf_mapped = NULL;
2827 #ifdef DEBUG_CFGLIST
2828 (void) fprintf(stderr,
2829 "freeing copy1, copy2, h_sizes and cf\n");
2830 #endif
2831 if (cfp->cf_head) {
2832 if (cfp->cf_head->h_ccopy1) {
2833 free(cfp->cf_head->h_ccopy1);
2834 cfp->cf_head->h_ccopy1 = NULL;
2836 if (cfp->cf_head->h_ccopy2) {
2837 free(cfp->cf_head->h_ccopy2);
2838 cfp->cf_head->h_ccopy2 = NULL;
2840 if (cfp->cf_head->h_sizes1) {
2841 free(cfp->cf_head->h_sizes1);
2842 cfp->cf_head->h_sizes1 = NULL;
2844 if (cfp->cf_head->h_sizes2) {
2845 free(cfp->cf_head->h_sizes2);
2846 cfp->cf_head->h_sizes2 = NULL;
2850 if (cfp->cf_head)
2851 free(cfp->cf_head);
2854 free(cfg);
2855 cfg = NULL;
2856 cfg_free_parser_tree();
2858 #ifdef DEBUG_CFGLIST
2859 (void) fprintf(stderr, "cfg_close\n");
2860 #endif
2864 char *
2865 cfg_get_resource(CFGFILE *cfg)
2867 if (cfg == NULL) {
2868 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
2869 cfg_severity = CFG_EFATAL;
2870 return (NULL);
2873 return (cfg->cf_node);
2877 * cfg_resource
2878 * set or clear the cluster node filter for get/put
2881 void
2882 cfg_resource(CFGFILE *cfg, const char *node)
2884 if (cfg == NULL) {
2885 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
2886 cfg_severity = CFG_EFATAL;
2887 return;
2890 if (cfg->cf_node) {
2891 #ifdef DEBUG_CFGLIST
2892 (void) fprintf(stderr,
2893 "cfg_resource: changing node from %s to %s\n",
2894 cfg->cf_node, (node?node:"NULL"));
2895 #endif
2896 free(cfg->cf_node);
2897 cfg->cf_node = NULL;
2901 * just in case someone passes in a non-NULL
2902 * node, but has no valid value
2904 if ((node) && (node[0] != '\0')) {
2905 cfg->cf_node = strdup(node);
2910 * cfg_open
2911 * Open the current configuration file
2913 CFGFILE *
2914 cfg_open(char *name)
2916 CFGFILE *cfg;
2917 cfp_t *cfp;
2918 int32_t magic;
2919 long needed;
2920 int rc;
2922 #ifdef DEBUG_CFGLIST
2923 (void) fprintf(stderr, "cfg_open\n");
2924 #endif
2926 cfg_severity = 0;
2927 if ((cfg = (CFGFILE *)calloc(1, sizeof (*cfg))) == NULL) {
2928 cfg_perror_str = dgettext("cfg",
2929 "cfg_open: malloc failed");
2930 cfg_severity = CFG_EFATAL;
2931 return (NULL);
2934 cfp = &cfg->cf[0];
2935 if ((name) && strlen(name)) {
2936 #ifdef DEBUG
2937 (void) fprintf(stderr, "cfg_open: Using non-standard name\n");
2938 #endif
2939 cfp->cf_name = name;
2940 cfp->cf_pp = (strstr(cfp->cf_name, "/rdsk/") == NULL) ?
2941 cfg_block_io_provider() : cfg_raw_io_provider();
2942 } else {
2943 cfp->cf_name = cfg_location(NULL, CFG_LOC_GET_LOCAL, NULL);
2944 cfp->cf_pp = cfg_block_io_provider();
2946 /* Handle cfg_open(""), which is an open from boot tools */
2947 if (name)
2948 cl_initialized = 1;
2949 if (cfg_iscluster() > 0) {
2950 cfp = &cfg->cf[1];
2951 cfp->cf_name =
2952 cfg_location(NULL, CFG_LOC_GET_CLUSTER, NULL);
2953 if (cfp->cf_name) {
2954 cfp->cf_pp = cfg_raw_io_provider();
2960 * Open one or two configuration files
2962 for (cfp = &cfg->cf[0]; cfp->cf_name && (cfp <= &cfg->cf[1]); cfp++) {
2963 if ((*cfp->cf_pp->open)(cfp, cfp->cf_name) == NULL) {
2964 cfg_perror_str = dgettext("cfg",
2965 "cfg_open: unable to open configuration location");
2966 cfg_severity = CFG_EFATAL;
2967 break;
2970 /* block device smaller than repository? */
2971 rc = (*cfp->cf_pp->read)(cfp, &magic, sizeof (magic));
2972 if (rc < sizeof (magic)) {
2973 cfg_perror_str = dgettext("cfg",
2974 "cfg_open: unable to read configuration header");
2975 cfg_severity = CFG_EFATAL;
2976 break;
2979 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) {
2980 cfg_perror_str = dgettext("cfg",
2981 "cfg_open: unable to seek configuration header");
2982 cfg_severity = CFG_EFATAL;
2983 break;
2987 * we can't enforce size rules on an old database
2988 * so check the magic number before we test for size
2990 if (magic == CFG_NEW_MAGIC) {
2991 needed = FBA_NUM(FBA_SIZE(1) - 1 +
2992 (sizeof (struct cfgheader) + CFG_CONFIG_SIZE));
2993 } else {
2994 needed = 0;
2997 if (cfp->cf_size < needed) {
2998 cfg_perror_str = dgettext("cfg",
2999 "cfg_open: configuration file too small");
3000 cfg_severity = CFG_EFATAL;
3001 errno = ENOMEM;
3002 break;
3005 cfp->cf_mapped = (char *)malloc(CFG_DEFAULT_PARSE_SIZE);
3006 if (cfp->cf_mapped == NULL) {
3007 cfg_perror_str = dgettext("cfg",
3008 "cfg_open: malloc failed");
3009 cfg_severity = CFG_EFATAL;
3010 break;
3013 bzero(cfp->cf_mapped, CFG_DEFAULT_PARSE_SIZE);
3014 cfp->cf_lock = -1;
3017 /* Processing errors, take care of one or more cfp pointers */
3018 if (cfg_severity && (cfp <= &cfg->cf[1])) {
3019 cfp = &cfg->cf[0];
3020 if (cfp->cf_fd)
3021 (*cfp->cf_pp->close)(cfp);
3022 cfp = &cfg->cf[1];
3023 if (cfp->cf_fd)
3024 (*cfp->cf_pp->close)(cfp);
3025 free(cfg);
3026 return (NULL);
3029 cfg_lockd = cfg_lockd_init();
3032 #ifdef DEBUG_CFGLIST
3033 (void) fprintf(stderr, "cfg_open ok\n");
3034 #endif
3035 return (cfg);
3038 void
3039 cfg_invalidate_hsizes(int fd, const char *loc)
3041 int offset;
3042 int rc = -1;
3043 int hdrsz;
3045 char buf[2 * CFG_DEFAULT_PSIZE];
3047 hdrsz = sizeof (cfgheader_t) + 512 -
3048 (sizeof (cfgheader_t) % 512);
3050 offset = hdrsz + CFG_DEFAULT_PARSE_SIZE +
3051 (CFG_DEFAULT_SSIZE * 2);
3053 if (cfg_shldskip_vtoc(fd, loc) > 0)
3054 offset += CFG_VTOC_SKIP;
3056 bzero(buf, sizeof (buf));
3058 if (lseek(fd, offset, SEEK_SET) > 0)
3059 rc = write(fd, buf, sizeof (buf));
3060 if (rc < 0)
3061 (void) fprintf(stderr, "cfg: invalidate hsizes failed\n");
3065 char *
3066 cfg_error(int *severity)
3068 if (severity != NULL)
3069 *severity = cfg_severity;
3070 return (cfg_perror_str ? cfg_perror_str : CFG_EGENERIC);
3073 * cfg_cfg_isempty
3076 cfg_cfg_isempty(CFGFILE *cfg)
3078 cfp_t *cfp;
3080 if (cfg == NULL) {
3081 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
3082 cfg_severity = CFG_EFATAL;
3083 return (FALSE);
3086 cfp = FP_SUN_CLUSTER(cfg);
3087 if (cfp->cf_head->h_csize == 0)
3088 return (TRUE);
3089 else
3090 return (FALSE);
3094 * cfg_get_num_entries
3095 * return the number of entries in a given section of database
3096 * sndr, ii, ndr_ii...
3099 cfg_get_num_entries(CFGFILE *cfg, char *section)
3101 int count = 0;
3102 int table_offset;
3103 cfp_t *cfp;
3105 if (cfg == NULL) {
3106 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
3107 cfg_severity = CFG_EFATAL;
3108 return (-1);
3111 if ((table_offset = cfg_get_parser_offset(section)) < 0) {
3112 errno = ESRCH;
3113 return (-1);
3116 /* Determine number of files open */
3117 for (cfp = &cfg->cf[0]; cfp->cf_fd && (cfp <= &cfg->cf[1]); cfp++)
3118 count += cfp->cf_head->h_cfgs[table_offset].l_nentry;
3120 return (count);
3124 * cfg_get_section
3125 * all etries in a config file section is placed in
3126 * buf, allocation is done inside
3127 * freeing buf is responisbility of the caller
3128 * number of entries in section is returned
3129 * -1 on failure, errno is set
3132 cfg_get_section(CFGFILE *cfg, char ***list, const char *section)
3134 int table_offset;
3135 int i, count;
3136 cfglist_t *cfl;
3137 char *p = NULL;
3138 char **buf;
3139 cfp_t *cfp;
3141 if (cfg == NULL) {
3142 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
3143 cfg_severity = CFG_EFATAL;
3144 return (FALSE);
3147 if ((table_offset = cfg_get_parser_offset(section)) < 0) {
3148 errno = ESRCH;
3149 return (-1);
3152 /* Determine number of files open */
3153 count = 0;
3154 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) {
3155 if (!cfp->cf_fd) continue;
3156 if (cfp->cf_head->h_state & CFG_HDR_INVALID) {
3157 if (!cfg_read(cfp)) {
3158 cfg_perror_str = dgettext("cfg", CFG_RDFAILED);
3159 cfg_severity = CFG_EFATAL;
3160 return (-1);
3164 cfl = &cfp->cf_head->h_cfgs[table_offset];
3165 if (cfl->l_nentry == 0) /* empty list */
3166 continue;
3168 if (count == 0)
3169 buf = (char **)malloc(cfl->l_nentry * sizeof (char *));
3170 else
3171 buf = (char **)realloc(buf, (cfl->l_nentry + count) *
3172 sizeof (char *));
3173 if (buf == NULL) {
3174 errno = ENOMEM;
3175 return (-1);
3176 } else {
3177 bzero(&buf[count], cfl->l_nentry * sizeof (char *));
3180 p = cfl->l_entry;
3181 for (i = 0; i < cfl->l_nentry; i++) {
3182 if ((buf[i + count] = strdup(p)) == NULL) {
3183 errno = ENOMEM;
3184 return (-1);
3186 p += cfl->l_esiz[i];
3188 count += cfl->l_nentry;
3191 *list = buf;
3192 return (count);
3196 * cluster upgrade helper functions. These support old database operations
3197 * while upgrading nodes on a cluster.
3201 * returns the list of configured tags
3202 * return -1 on error, else the number
3203 * of tags returned in taglist
3204 * caller frees
3207 cfg_get_tags(CFGFILE *cfg, char ***taglist)
3209 char **list;
3210 int i = 0;
3212 if (cfg == NULL) {
3213 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
3214 cfg_severity = CFG_EFATAL;
3215 return (-1);
3218 if (!cfg_rdlock(cfg)) {
3219 return (-1);
3221 list = calloc(1, MAX_CFG * sizeof (char *));
3222 if (list == NULL) {
3223 errno = ENOMEM;
3224 return (-1);
3227 while ((i < MAX_CFG) && (chead[i].tag.l_word[0] != '\0')) {
3228 list[i] = strdup(chead[i].tag.l_word);
3229 if (list[i] == NULL) {
3230 for (/* CSTYLE */; i >= 0; i--) {
3231 if (list[i])
3232 free(list[i]);
3234 free(list);
3235 errno = ENOMEM;
3236 return (-1);
3238 i++;
3240 *taglist = list;
3241 return (i);
3246 * is this a database?
3247 * check the header for the magic number
3248 * 0 no match 1 match, -1 on error
3251 cfg_is_cfg(CFGFILE *cfg)
3253 int32_t magic;
3254 int rc;
3255 cfp_t *cfp = FP_SUN_CLUSTER(cfg);
3257 rc = (cfp->cf_pp->read)(cfp, &magic, sizeof (magic));
3258 if (rc < sizeof (magic)) {
3259 cfg_perror_str = dgettext("cfg", "Fail to read configuration");
3260 cfg_severity = CFG_EFATAL;
3261 return (-1);
3264 if (magic == CFG_NEW_MAGIC)
3265 return (1);
3267 cfg_perror_str = dgettext("cfg",
3268 "configuration not initialized, bad magic");
3269 cfg_severity = CFG_EFATAL;
3271 return (0);
3275 compare(const void* a, const void *b)
3277 char *p;
3278 char *pbuf;
3279 char *q;
3280 char *qbuf;
3281 int needed;
3282 int cmp;
3283 int pos;
3285 pbuf = strdup(a);
3286 qbuf = strdup(b);
3288 if (!qbuf || !pbuf)
3289 return (0);
3291 pos = 1;
3292 needed = sortby.offset;
3294 p = strtok(pbuf, " ");
3295 while (p) {
3296 if (needed == pos) {
3297 break;
3299 p = strtok(NULL, " ");
3300 if (!p)
3301 break;
3302 pos++;
3305 pos = 1;
3306 q = strtok(qbuf, " ");
3307 while (q) {
3308 if (needed == pos) {
3309 break;
3311 q = strtok(NULL, " ");
3312 if (!q)
3313 break;
3314 pos++;
3316 if (!p || !q) {
3317 sortby.comperror++;
3318 free(pbuf);
3319 free(qbuf);
3320 return (0);
3322 cmp = strcmp(p, q);
3323 free(pbuf);
3324 free(qbuf);
3325 return (cmp);
3330 * cfg_get_srtdsec
3331 * returns the section, sorted by supplied field
3332 * caller frees mem
3335 cfg_get_srtdsec(CFGFILE *cfg, char ***list, const char *section,
3336 const char *field)
3338 cfglist_t *cfl;
3339 cfp_t *cfp;
3340 char **buf;
3341 char *tmplst;
3342 char *p, *q;
3343 int table_offset;
3344 int count, i;
3346 if (cfg == NULL) {
3347 cfg_perror_str = dgettext("cfg", CFG_EINVAL);
3348 cfg_severity = CFG_EFATAL;
3349 return (FALSE);
3352 if ((table_offset = cfg_get_parser_offset(section)) < 0) {
3353 cfg_perror_str = dgettext("cfg", CFG_RDFAILED);
3354 errno = ESRCH;
3355 return (-1);
3359 * do essentially what get_section does,
3360 * except stick entries in a static size
3361 * buf to make things easier to qsort
3363 count = 0;
3364 for (cfp = &cfg->cf[0]; cfp <= &cfg->cf[1]; cfp++) {
3365 if (!cfp->cf_fd) continue;
3366 if (cfp->cf_head->h_state & CFG_HDR_INVALID) {
3367 if (!cfg_read(cfp)) {
3368 cfg_perror_str = dgettext("cfg", CFG_RDFAILED);
3369 cfg_severity = CFG_EFATAL;
3370 return (-1);
3374 cfl = &cfp->cf_head->h_cfgs[table_offset];
3375 if (cfl->l_nentry == 0) /* empty list */
3376 continue;
3378 if (count == 0)
3379 buf = (char **)malloc(cfl->l_nentry * sizeof (char *));
3380 else
3381 buf = (char **)realloc(buf, (cfl->l_nentry + count) *
3382 sizeof (char *));
3383 if (buf == NULL) {
3384 errno = ENOMEM;
3385 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: "
3386 "malloc failed");
3387 cfg_severity = CFG_EFATAL;
3388 return (-1);
3389 } else {
3390 bzero(&buf[count], cfl->l_nentry * sizeof (char *));
3394 * allocate each line
3396 for (i = count; i < cfl->l_nentry + count; i++) {
3397 buf[i] = calloc(1, CFG_MAX_BUF);
3398 if (buf[i] == NULL) {
3399 free(buf);
3400 errno = ENOMEM;
3401 return (-1);
3405 if (count == 0)
3406 tmplst = (char *)malloc(cfl->l_nentry * CFG_MAX_BUF);
3407 else
3408 tmplst = (char *)realloc(tmplst,
3409 (cfl->l_nentry + count) * CFG_MAX_BUF);
3410 if (tmplst == NULL) {
3411 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: "
3412 "malloc failed");
3413 cfg_severity = CFG_EFATAL;
3414 free(buf);
3415 return (-1);
3416 } else {
3417 bzero(&tmplst[count], cfl->l_nentry * CFG_MAX_BUF);
3421 * put the section in tmplst and sort
3423 p = &tmplst[count];
3424 q = cfl->l_entry;
3425 for (i = 0; i < cfl->l_nentry; i++) {
3426 bcopy(q, p, cfl->l_esiz[i]);
3427 p += CFG_MAX_BUF;
3428 q += cfl->l_esiz[i];
3430 count += cfl->l_nentry;
3433 bzero(sortby.section, CFG_MAX_KEY);
3434 bzero(sortby.field, CFG_MAX_KEY);
3436 strcpy(sortby.section, section);
3437 strcpy(sortby.field, field);
3438 sortby.comperror = 0;
3439 sortby.offset = cfg_get_item(&chead[0], section, field);
3441 qsort(tmplst, count, CFG_MAX_BUF, compare);
3443 if (sortby.comperror) {
3444 sortby.comperror = 0;
3445 cfg_perror_str = dgettext("cfg", "cfg_get_srtdsec: "
3446 "comparison error");
3447 cfg_severity = CFG_ENONFATAL;
3448 cfg_free_section(&buf, cfl->l_nentry);
3449 free(tmplst);
3450 *list = NULL;
3451 return (-1);
3454 p = tmplst;
3455 for (i = 0; i < count; i++) {
3456 bcopy(p, buf[i], CFG_MAX_BUF);
3457 p += CFG_MAX_BUF;
3460 free(tmplst);
3461 *list = buf;
3462 return (count);
3466 * free an array alloc'd by get_*section
3467 * or some other array of size size
3470 void
3471 cfg_free_section(char ***section, int size)
3473 int i;
3474 char **secpp = *section;
3476 for (i = 0; i < size; i++) {
3477 if (secpp[i]) {
3478 free(secpp[i]);
3479 secpp[i] = NULL;
3482 if (secpp) {
3483 free(secpp);
3484 secpp = NULL;
3486 section = NULL;
3491 cfg_shldskip_vtoc(int fd, const char *loc)
3493 struct vtoc vtoc;
3494 struct stat sb;
3495 int slice;
3496 int rfd;
3497 char char_name[PATH_MAX];
3498 char *p;
3500 if (fstat(fd, &sb) == -1) {
3501 cfg_perror_str = dgettext("cfg", "unable to stat config");
3502 cfg_severity = CFG_EFATAL;
3503 return (-1);
3505 if (S_ISREG(sb.st_mode))
3506 return (0);
3508 if (S_ISCHR(sb.st_mode)) {
3509 if ((slice = read_vtoc(fd, &vtoc)) < 0)
3510 return (-1);
3512 if (vtoc.v_part[slice].p_start < CFG_VTOC_SIZE)
3513 return (1);
3514 else
3515 return (0);
3518 if (S_ISBLK(sb.st_mode)) {
3519 p = strstr(loc, "/dsk/");
3520 if (p == NULL)
3521 return (-1);
3522 strcpy(char_name, loc);
3523 char_name[strlen(loc) - strlen(p)] = 0;
3524 strcat(char_name, "/rdsk/");
3525 strcat(char_name, p + 5);
3527 if ((rfd = open(char_name, O_RDONLY)) < 0) {
3528 return (-1);
3530 if ((slice = read_vtoc(rfd, &vtoc)) < 0) {
3531 close(rfd);
3532 return (-1);
3534 close(rfd);
3535 if (vtoc.v_part[slice].p_start < CFG_VTOC_SIZE)
3536 return (1);
3537 else
3538 return (0);
3541 return (-1);
3545 * comapares incore header with one on disk
3546 * returns 0 if equal, 1 if not, -1 error
3549 cfg_hdrcmp(cfp_t *cfp)
3551 cfgheader_t *dskhdr, *memhdr;
3552 int rc;
3554 if ((dskhdr = calloc(1, sizeof (*dskhdr))) == NULL) {
3555 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: No memory");
3556 cfg_severity = CFG_ENONFATAL;
3559 if ((*cfp->cf_pp->seek)(cfp, 0, SEEK_SET) < 0) {
3560 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: seek failed");
3561 cfg_severity = CFG_ENONFATAL;
3562 free(dskhdr);
3563 return (-1);
3566 rc = (*cfp->cf_pp->read)(cfp, (char *)dskhdr, sizeof (*dskhdr));
3567 if (rc < 0) {
3568 cfg_perror_str = dgettext("cfg", "cfg_hdrcmp: read failed");
3569 cfg_severity = CFG_ENONFATAL;
3570 free(dskhdr);
3571 return (-1);
3574 memhdr = cfp->cf_head;
3576 if ((memhdr->h_seq1 == dskhdr->h_seq1) &&
3577 (memhdr->h_seq2 == dskhdr->h_seq2))
3578 rc = 0;
3579 else
3580 rc = 1;
3583 free(dskhdr);
3584 return (rc);