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