8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libdscfg / common / cfg_local.c
blob1b243b1a6d57979d73063cb5c9568509c4fa1940
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/vtoc.h>
30 #include <sys/wait.h>
31 #include <stdio.h>
32 #include <sys/mnttab.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <sys/mman.h>
42 #include <locale.h>
43 #include <langinfo.h>
44 #include <libintl.h>
45 #include <stdarg.h>
46 #include <netdb.h>
47 #include <ctype.h>
48 #include <sys/stat.h>
49 #include <sys/utsname.h>
51 #include "cfg_impl.h"
52 #include "cfg.h"
53 #include "cfg_local.h"
55 #if 0
56 #define DEBUG_CFGLIST
57 #define DEBUG_CFGLISTRM
58 #endif
60 extern int cfg_severity;
61 extern char *cfg_perror_str;
63 long
64 get_bsize(cfp_t *cfp, char *name)
66 char char_name[PATH_MAX];
67 char *rest;
68 struct vtoc vtoc;
69 int slice;
70 int fd;
72 if (strlen(name) >= PATH_MAX - 1)
73 return (0);
75 rest = strstr(name, "/dsk/");
76 if (rest == NULL) {
77 if ((rest = strstr(name, "/rdsk/")) == NULL)
78 return (0);
79 strcpy(char_name, name);
80 goto do_open;
83 strcpy(char_name, name);
84 char_name[strlen(name) - strlen(rest)] = 0;
85 strcat(char_name, "/rdsk/");
86 strcat(char_name, rest + 5);
88 do_open:
89 fd = open(char_name, O_RDONLY);
90 if (fd < 0)
91 return (0);
93 slice = read_vtoc(fd, &vtoc);
94 if (slice < 0) {
95 (void) close(fd);
96 return (0);
99 (void) close(fd);
100 if (vtoc.v_part[slice].p_start < CFG_VTOC_SIZE)
101 cfp->cf_flag |= CFG_NOWRVTOC;
103 return (vtoc.v_part[slice].p_size);
107 * round up to the next block size
110 get_block_size(int size)
112 int ret;
114 if (size % CFG_BLOCK_SIZE != 0)
115 ret = size + CFG_BLOCK_SIZE - (size % CFG_BLOCK_SIZE);
116 else
117 ret = size;
118 return (ret);
122 * get a chunk of mem rounded up to next block size
124 char *
125 get_block_buf(int size)
127 int blk_size;
128 char *blk_buf;
130 blk_size = get_block_size(size);
132 if ((blk_buf = (char *)calloc(blk_size, sizeof (char))) == NULL) {
133 cfg_severity = CFG_EFATAL;
134 cfg_perror_str = dgettext("cfg", strerror(errno));
135 return (NULL);
137 return (blk_buf);
140 void
141 free_block_buf(char *buf)
143 if (buf)
144 free(buf);
147 void
148 localcf_close(cfp_t *cfp)
150 fsync(cfp->cf_fd);
151 cfp_unlock(cfp);
152 close(cfp->cf_fd);
157 * cfg_open
158 * Open the current configuration file
159 * Sets file descriptor in cfp->cf_fd for use by other routines
161 cfp_t *
162 localcf_open(cfp_t *cfp, char *name)
164 struct stat sb;
165 int rc;
168 if (name == NULL) {
169 cfg_perror_str = dgettext("cfg",
170 "cfg_open: unable to open configuration location");
171 cfg_severity = CFG_EFATAL;
172 return (NULL);
175 cfp->cf_fd = open(name, O_RDWR|O_CREAT|O_DSYNC|O_RSYNC, 0640);
176 if (cfp->cf_fd == -1) {
177 if ((cfp->cf_fd = open(name, O_RDONLY, 0640)) == -1) {
178 cfg_perror_str = dgettext("cfg",
179 "cfg_open: unable to open configuration location");
180 cfg_severity = CFG_EFATAL;
181 return (NULL);
183 cfp->cf_flag |= CFG_RDONLY;
186 if (fstat(cfp->cf_fd, &sb) == -1) {
187 close(cfp->cf_fd);
188 cfg_perror_str = dgettext("cfg",
189 "cfg_open: unable to stat configuration location");
190 cfg_severity = CFG_EFATAL;
191 return (NULL);
195 if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
196 cfp->cf_size = get_bsize(cfp, name);
198 /* skip the vtoc if necessary */
199 if (cfp->cf_flag & CFG_NOWRVTOC) {
200 do {
201 rc = lseek(cfp->cf_fd, CFG_VTOC_SKIP, SEEK_SET);
202 } while (rc == -1 && errno == EINTR);
204 if (rc == -1) {
205 cfg_perror_str = dgettext("cfg",
206 strerror(errno));
207 cfg_severity = CFG_EFATAL;
208 close(cfp->cf_fd);
209 return (NULL);
213 } else if (S_ISREG(sb.st_mode)) {
214 cfp->cf_flag |= CFG_FILE;
215 cfp->cf_size = FBA_NUM(FBA_SIZE(1) - 1 + sb.st_size);
216 } else {
217 cfg_perror_str = dgettext("cfg", "cfg_open: unknown file type");
218 cfg_severity = CFG_EFATAL;
219 close(cfp->cf_fd);
220 cfp->cf_fd = NULL;
221 return (NULL);
223 return (cfp);
227 localcf_seekblk(cfp_t *cfp, int off, int mode)
229 int rc;
231 do {
232 rc = lseek(cfp->cf_fd, off, mode);
233 } while (rc == -1 && errno == EINTR);
235 return (rc);
239 localcf_readblk(cfp_t *cfp, void *buf, int size)
241 int rc;
243 do {
244 rc = read(cfp->cf_fd, buf, size);
245 } while (rc == -1 && errno == EINTR);
247 return (rc);
251 localcf_writeblk(cfp_t *cfp, void *buf, int size)
253 int rc;
255 do {
256 rc = write(cfp->cf_fd, buf, size);
257 } while (rc == -1 && errno == EINTR);
259 return (rc);
263 localcf_seek(cfp_t *cfp, int off, int mode)
265 int rc;
266 int offset;
268 offset = get_block_size(off);
270 if ((mode == SEEK_SET) && (cfp->cf_flag & CFG_NOWRVTOC)) {
271 offset += CFG_VTOC_SKIP;
274 do {
275 rc = lseek(cfp->cf_fd, offset, mode);
276 } while (rc == -1 && errno == EINTR);
278 return (rc);
282 localcf_read(cfp_t *cfp, void *buf, int size)
284 int rc;
285 int blk_size;
286 char *blk_buf;
288 blk_size = get_block_size(size);
289 if ((blk_buf = get_block_buf(size)) == NULL)
290 return (-1);
292 do {
293 rc = read(cfp->cf_fd, blk_buf, blk_size);
294 } while (rc == -1 && errno == EINTR);
296 bcopy(blk_buf, buf, size);
297 free_block_buf(blk_buf);
299 return (rc);
303 localcf_write(cfp_t *cfp, void *buf, int size)
305 int rc;
306 int blk_size;
307 char *blk_buf;
309 blk_size = get_block_size(size);
310 if ((blk_buf = get_block_buf(size)) == NULL)
311 return (-1);
313 bcopy(buf, blk_buf, size);
315 do {
316 rc = write(cfp->cf_fd, blk_buf, blk_size);
317 } while (rc == -1 && errno == EINTR);
319 free_block_buf(blk_buf);
321 return (rc);
324 * Routines which operate on internal version of configuration
328 * Add entry to end of configuration section
332 addcfline(cfp_t *cfp, char *line, int table_index)
334 int len = strlen(line)+1;
335 int newsize = DEFAULT_ENTRY_SIZE / 2;
336 cfgheader_t *hd;
337 cfglist_t *cfl;
338 char *q;
340 #ifdef DEBUG_CFGLIST
341 fprintf(stderr, "addcfline: pre l_size %d h_cfgsizes[%d]"
342 " %d l_free %u adding len %d\n",
343 cfp->cf_head->h_cfgs[table_index].l_size, table_index,
344 cfp->cf_head->h_cfgsizes[table_index],
345 cfp->cf_head->h_cfgs[table_index].l_free, len);
346 #endif
348 hd = cfp->cf_head;
349 cfl = &cfp->cf_head->h_cfgs[table_index];
350 if (cfl->l_free < len) {
352 #ifdef DEBUG_CFGLIST
353 fprintf(stderr, "resizing l_entry from %d to %d\n",
354 cfl->l_size + cfl->l_free, cfl->l_size +
355 cfl->l_free + newsize);
356 #endif
357 cfl->l_entry = (char *)realloc(cfl->l_entry, (cfl->l_size +
358 cfl->l_free + newsize) * sizeof (char));
359 if (cfl->l_entry == NULL) {
360 errno = ENOMEM;
361 return (-1);
363 cfl->l_free += newsize;
366 cfl->l_free -= len;
368 /* out of list slots, get some more */
369 if (cfl->l_nentry % DEFAULT_NENTRIES == 0) {
371 * first, figure out how much bigger, than realloc
374 #ifdef DEBUG_CFGLIST
375 fprintf(stderr,
376 "list %d getting more nentries, I have %d\n",
377 table_index, cfl->l_nentry);
378 #endif
379 cfl->l_esiz = (int *)
380 realloc(cfl->l_esiz, (cfl->l_nentry + DEFAULT_NENTRIES) *
381 sizeof (int));
382 if (cfl->l_esiz == NULL) {
383 errno = ENOMEM;
384 return (-1);
389 cfl->l_esiz[cfl->l_nentry] = len;
390 cfl->l_nentry++;
392 /* add line to end of list */
393 q = cfl->l_entry + cfl->l_size;
395 strcpy(q, line);
396 q += len;
398 /* set sizes */
399 hd->h_cfgs[table_index].l_size += len;
400 hd->h_cfgsizes[table_index] = cfl->l_size;
401 cfp->cf_head->h_csize += len;
403 #ifdef DEBUG_CFGLIST
404 fprintf(stderr, "addcfline: post l_size %d h_cfgsizes[%d]"
405 " %d l_free %u\n h_csize %d\n",
406 cfp->cf_head->h_cfgs[table_index].l_size,
407 table_index, cfp->cf_head->h_cfgsizes[table_index],
408 cfp->cf_head->h_cfgs[table_index].l_free, cfp->cf_head->h_csize);
409 #endif
411 return (1);
415 * remove entry from configuration section
418 remcfline(cfp_t *cfp, int table_offset, int setnum)
420 cfgheader_t *ch;
421 char *p, *q;
422 int len;
423 int copylen;
424 int i;
425 cfglist_t *cfl;
426 ch = cfp->cf_head;
428 cfl = &cfp->cf_head->h_cfgs[table_offset];
430 q = cfl->l_entry;
432 if (cfl->l_size == 0) {
433 /* list is empty */
434 return (-1);
437 if (!q) { /* somethings wrong here */
438 return (-1);
442 for (i = 1; i < setnum; i++) {
443 q += cfl->l_esiz[i - 1];
444 if (i >= cfl->l_nentry) { /* end of list */
445 return (-1);
449 if (q >= cfl->l_entry + cfl->l_size)
450 return (-1);
452 len = cfl->l_esiz[i - 1];
455 #ifdef DEBUG_CFGLISTRM
456 fprintf(stderr, "remcfline: pre: l_size %d h_cfgsizes[%d] %d free %d"
457 " removing len %d\n",
458 ch->h_cfgs[table_offset].l_size, table_offset,
459 ch->h_cfgsizes[table_offset],
460 ch->h_cfgs[table_offset].l_free, len);
461 #endif
463 p = q + len; /* next string */
465 if (!(p >= cfl->l_entry + cfl->l_size)) {
466 /* if we didn't delete the last string in list */
467 /* LINTED possible overflow */
468 copylen = cfl->l_entry + cfl->l_size - p;
469 bcopy(p, q, copylen);
470 copylen = (cfl->l_nentry - i) * sizeof (int);
471 bcopy(&cfl->l_esiz[i], &cfl->l_esiz[i - 1], copylen);
474 /* decrement the number of sets in this list */
475 cfl->l_nentry--;
476 /* not really necessary, but.. */
477 cfl->l_esiz[cfl->l_nentry] = 0;
479 cfl->l_size -= len;
480 cfl->l_free += len;
482 p = cfl->l_entry + cfl->l_size;
483 bzero(p, cfl->l_free);
485 ch->h_cfgsizes[table_offset] = cfl->l_size;
486 ch->h_csize -= len;
489 #ifdef DEBUG_CFGLIST
490 fprintf(stderr,
491 "remcfline: post: l_size %d h_cfgsizes[%d] %d free %d\n ",
492 ch->h_cfgs[table_offset].l_size, table_offset,
493 ch->h_cfgsizes[table_offset], ch->h_cfgs[table_offset].l_free);
494 #endif
496 return (0);
500 * Read entry from configuration section
502 char *
503 readcfline(cfp_t *cfp, char *buf, int table_offset, int num)
506 char *q;
507 int i;
508 cfgheader_t *ch;
509 cfglist_t *cfl;
511 /* this means they couldn't even find it in the parser tree */
512 if (table_offset < 0)
513 return (NULL);
515 ch = cfp->cf_head;
516 cfl = &ch->h_cfgs[table_offset];
518 q = cfl->l_entry;
520 for (i = 1; i < num; i++) {
521 q += cfl->l_esiz[i - 1];
522 if (i >= cfl->l_nentry) /* end of list */
523 return (NULL);
526 if (q >= cfl->l_entry + cfl->l_size)
527 return (NULL);
528 strcpy(buf, q);
529 return (q);
534 * overwrite from current position with new value
537 replacecfline(cfp_t *cfp, char *line, int table_offset, int num)
540 * take a table offset and a num to replace
541 * index in, bump the list up, leaving a hole big
542 * enough for the new string, or bcopying the rest of the list
543 * down only leaving a hole big enough.
544 * make sure not to overflow the
545 * allocated list size.
547 cfgheader_t *ch;
548 cfglist_t *cfl;
549 char *p, *q;
550 int len = strlen(line) + 1;
551 int diff = 0;
552 int i;
553 int newsize = DEFAULT_ENTRY_SIZE / 2;
556 ch = cfp->cf_head;
557 cfl = &ch->h_cfgs[table_offset];
559 q = cfl->l_entry;
560 for (i = 1; i < num; i++) {
561 q += cfl->l_esiz[i - 1];
562 if (i >= cfl->l_nentry) /* end of list */
563 return (-1);
565 diff = len - cfl->l_esiz[i - 1];
566 /* check for > 0, comparing uint to int */
567 if ((diff > 0) && (diff > cfl->l_free)) {
569 * we are going to overflow, get more mem, but only
570 * 1/2 as much as initial calloc, we don't need to be greedy
572 #ifdef DEBUG_CFGLIST
573 fprintf(stderr,
574 "resizing at replacecfline from %d to %d \n",
575 cfl->l_size + cfl->l_free, cfl->l_size +
576 cfl->l_free + newsize);
577 #endif
578 cfl->l_entry = (char *)realloc(cfl->l_entry,
579 (cfl->l_size + cfl->l_free + newsize) * sizeof (char));
580 if (cfl->l_entry == NULL) {
581 errno = ENOMEM;
582 return (-1);
584 cfl->l_free += (DEFAULT_ENTRY_SIZE / 2);
586 /* re-find q, we could have a whole new chunk of memory here */
587 q = cfl->l_entry;
588 for (i = 1; i < num; i++) {
589 q += cfl->l_esiz[i - 1];
590 if (i >= cfl->l_nentry) /* end of list */
591 return (-1);
595 p = q + cfl->l_esiz[i - 1]; /* next string */
596 cfl->l_esiz[i - 1] += diff; /* the new entry size */
597 if (diff != 0) { /* move stuff over/back for correct fit */
598 /* LINTED possible overflow */
599 bcopy(p, p + diff, (cfl->l_entry + cfl->l_size - p));
600 cfl->l_free -= diff; /* 0 - (-1) = 1 */
601 cfl->l_size += diff;
603 /* total of all h_cfgs[n].l_entry */
604 cfp->cf_head->h_csize += diff;
605 cfp->cf_head->h_cfgsizes[table_offset] = cfl->l_size; /* disk */
606 bzero((cfl->l_entry + cfl->l_size), cfl->l_free);
609 strcpy(q, line);
610 return (1);
614 static cfg_io_t _cfg_raw_io_def = {
615 NULL,
616 "Local",
617 localcf_open,
618 localcf_close,
619 localcf_seek,
620 localcf_read,
621 localcf_write,
622 readcfline,
623 addcfline,
624 remcfline,
625 replacecfline,
629 static cfg_io_t _cfg_block_io_def = {
630 NULL,
631 "Local",
632 localcf_open,
633 localcf_close,
634 localcf_seekblk,
635 localcf_readblk,
636 localcf_writeblk,
637 readcfline,
638 addcfline,
639 remcfline,
640 replacecfline,
643 cfg_io_t *
644 cfg_raw_io_provider(void)
646 return (&_cfg_raw_io_def);
649 cfg_io_t *
650 cfg_block_io_provider(void)
652 return (&_cfg_block_io_def);