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