1235537Sgber/* 2235537Sgber * Copyright (c) 1999, Boris Popov 3235537Sgber * All rights reserved. 4235537Sgber * 5235537Sgber * Redistribution and use in source and binary forms, with or without 6235537Sgber * modification, are permitted provided that the following conditions 7235537Sgber * are met: 8235537Sgber * 1. Redistributions of source code must retain the above copyright 9235537Sgber * notice, this list of conditions and the following disclaimer. 10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 11235537Sgber * notice, this list of conditions and the following disclaimer in the 12235537Sgber * documentation and/or other materials provided with the distribution. 13235537Sgber * 3. Neither the name of the author nor the names of any co-contributors 14235537Sgber * may be used to endorse or promote products derived from this software 15235537Sgber * without specific prior written permission. 16235537Sgber * 17235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20235537Sgber * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27235537Sgber * SUCH DAMAGE. 28235537Sgber * 29235537Sgber * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp 30235537Sgber */ 31235537Sgber 32235537Sgber#include <sys/cdefs.h> 33235537Sgber__FBSDID("$FreeBSD$"); 34235537Sgber#include <sys/types.h> 35235537Sgber#include <sys/queue.h> 36235537Sgber#include <ctype.h> 37235537Sgber#include <errno.h> 38235537Sgber#include <stdio.h> 39235537Sgber#include <string.h> 40235537Sgber#include <stdlib.h> 41235537Sgber#include <pwd.h> 42235537Sgber#include <unistd.h> 43235537Sgber 44235537Sgber#include "nandsim_rcfile.h" 45235537Sgber 46235537SgberSLIST_HEAD(rcfile_head, rcfile); 47235537Sgberstatic struct rcfile_head pf_head = {NULL}; 48235537Sgberstatic struct rcsection *rc_findsect(struct rcfile *rcp, 49235537Sgber const char *sectname, int sect_id); 50235537Sgberstatic struct rcsection *rc_addsect(struct rcfile *rcp, 51235537Sgber const char *sectname); 52235537Sgberstatic int rc_sect_free(struct rcsection *rsp); 53235537Sgberstatic struct rckey *rc_sect_findkey(struct rcsection *rsp, 54235537Sgber const char *keyname); 55235537Sgberstatic struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, 56235537Sgber char *value); 57235537Sgberstatic void rc_key_free(struct rckey *p); 58235537Sgberstatic void rc_parse(struct rcfile *rcp); 59235537Sgber 60235537Sgberstatic struct rcfile* rc_find(const char *filename); 61235537Sgber 62235537Sgber/* 63235537Sgber * open rcfile and load its content, if already open - return previous handle 64235537Sgber */ 65235537Sgberint 66235537Sgberrc_open(const char *filename, const char *mode,struct rcfile **rcfile) 67235537Sgber{ 68235537Sgber struct rcfile *rcp; 69235537Sgber FILE *f; 70235537Sgber rcp = rc_find(filename); 71235537Sgber if (rcp) { 72235537Sgber *rcfile = rcp; 73235537Sgber return (0); 74235537Sgber } 75235537Sgber f = fopen (filename, mode); 76235537Sgber if (f == NULL) 77235537Sgber return errno; 78235537Sgber rcp = malloc(sizeof(struct rcfile)); 79235537Sgber if (rcp == NULL) { 80235537Sgber fclose(f); 81235537Sgber return ENOMEM; 82235537Sgber } 83235537Sgber bzero(rcp, sizeof(struct rcfile)); 84235537Sgber rcp->rf_name = strdup(filename); 85235537Sgber rcp->rf_f = f; 86235537Sgber SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 87235537Sgber rc_parse(rcp); 88235537Sgber *rcfile = rcp; 89235537Sgber return (0); 90235537Sgber} 91235537Sgber 92235537Sgberint 93235537Sgberrc_close(struct rcfile *rcp) 94235537Sgber{ 95235537Sgber struct rcsection *p,*n; 96235537Sgber 97235537Sgber fclose(rcp->rf_f); 98235537Sgber for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { 99235537Sgber n = p; 100235537Sgber p = SLIST_NEXT(p,rs_next); 101235537Sgber rc_sect_free(n); 102235537Sgber } 103235537Sgber free(rcp->rf_name); 104235537Sgber SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); 105235537Sgber free(rcp); 106235537Sgber return (0); 107235537Sgber} 108235537Sgber 109235537Sgberstatic struct rcfile* 110235537Sgberrc_find(const char *filename) 111235537Sgber{ 112235537Sgber struct rcfile *p; 113235537Sgber 114235537Sgber SLIST_FOREACH(p, &pf_head, rf_next) 115235537Sgber if (strcmp (filename, p->rf_name) == 0) 116235537Sgber return (p); 117235537Sgber return (0); 118235537Sgber} 119235537Sgber 120235537Sgber/* Find section with given name and id */ 121235537Sgberstatic struct rcsection * 122235537Sgberrc_findsect(struct rcfile *rcp, const char *sectname, int sect_id) 123235537Sgber{ 124235537Sgber struct rcsection *p; 125235537Sgber 126235537Sgber SLIST_FOREACH(p, &rcp->rf_sect, rs_next) 127235537Sgber if (strcmp(p->rs_name, sectname) == 0 && p->rs_id == sect_id) 128235537Sgber return (p); 129235537Sgber return (NULL); 130235537Sgber} 131235537Sgber 132235537Sgberstatic struct rcsection * 133235537Sgberrc_addsect(struct rcfile *rcp, const char *sectname) 134235537Sgber{ 135235537Sgber struct rcsection *p; 136235537Sgber int id = 0; 137235537Sgber p = rc_findsect(rcp, sectname, 0); 138235537Sgber if (p) { 139235537Sgber /* 140235537Sgber * If section with that name already exists -- add one more, 141235537Sgber * same named, but with different id (higher by one) 142235537Sgber */ 143235537Sgber while (p != NULL) { 144235537Sgber id = p->rs_id + 1; 145235537Sgber p = rc_findsect(rcp, sectname, id); 146235537Sgber } 147235537Sgber } 148235537Sgber p = malloc(sizeof(*p)); 149235537Sgber if (!p) 150235537Sgber return (NULL); 151235537Sgber p->rs_name = strdup(sectname); 152235537Sgber p->rs_id = id; 153235537Sgber SLIST_INIT(&p->rs_keys); 154235537Sgber SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 155235537Sgber return (p); 156235537Sgber} 157235537Sgber 158235537Sgberstatic int 159235537Sgberrc_sect_free(struct rcsection *rsp) 160235537Sgber{ 161235537Sgber struct rckey *p,*n; 162235537Sgber 163235537Sgber for (p = SLIST_FIRST(&rsp->rs_keys); p; ) { 164235537Sgber n = p; 165235537Sgber p = SLIST_NEXT(p,rk_next); 166235537Sgber rc_key_free(n); 167235537Sgber } 168235537Sgber free(rsp->rs_name); 169235537Sgber free(rsp); 170235537Sgber return (0); 171235537Sgber} 172235537Sgber 173235537Sgberstatic struct rckey * 174235537Sgberrc_sect_findkey(struct rcsection *rsp, const char *keyname) 175235537Sgber{ 176235537Sgber struct rckey *p; 177235537Sgber 178235537Sgber SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 179235537Sgber if (strcmp(p->rk_name, keyname)==0) 180235537Sgber return (p); 181235537Sgber return (NULL); 182235537Sgber} 183235537Sgber 184235537Sgberstatic struct rckey * 185235537Sgberrc_sect_addkey(struct rcsection *rsp, const char *name, char *value) 186235537Sgber{ 187235537Sgber struct rckey *p; 188235537Sgber p = rc_sect_findkey(rsp, name); 189235537Sgber if (p) { 190235537Sgber free(p->rk_value); 191235537Sgber } else { 192235537Sgber p = malloc(sizeof(*p)); 193235537Sgber if (!p) 194235537Sgber return (NULL); 195235537Sgber SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 196235537Sgber p->rk_name = strdup(name); 197235537Sgber } 198235537Sgber p->rk_value = value ? strdup(value) : strdup(""); 199235537Sgber return (p); 200235537Sgber} 201235537Sgber 202235537Sgberstatic void 203235537Sgberrc_key_free(struct rckey *p) 204235537Sgber{ 205235537Sgber free(p->rk_value); 206235537Sgber free(p->rk_name); 207235537Sgber free(p); 208235537Sgber} 209235537Sgber 210235537Sgberenum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 211235537Sgber 212235537Sgberstatic void 213235537Sgberrc_parse(struct rcfile *rcp) 214235537Sgber{ 215235537Sgber FILE *f = rcp->rf_f; 216235537Sgber int state = stNewLine, c; 217235537Sgber struct rcsection *rsp = NULL; 218235537Sgber struct rckey *rkp = NULL; 219235537Sgber char buf[2048]; 220235537Sgber char *next = buf, *last = &buf[sizeof(buf)-1]; 221235537Sgber 222235537Sgber while ((c = getc (f)) != EOF) { 223235537Sgber if (c == '\r') 224235537Sgber continue; 225235537Sgber if (state == stNewLine) { 226235537Sgber next = buf; 227235537Sgber if (isspace(c)) 228235537Sgber continue; /* skip leading junk */ 229235537Sgber if (c == '[') { 230235537Sgber state = stHeader; 231235537Sgber rsp = NULL; 232235537Sgber continue; 233235537Sgber } 234235537Sgber if (c == '#' || c == ';') { 235235537Sgber state = stSkipToEOL; 236235537Sgber } else { /* something meaningful */ 237235537Sgber state = stGetKey; 238235537Sgber } 239235537Sgber } 240235537Sgber if (state == stSkipToEOL || next == last) {/* ignore long lines */ 241235537Sgber if (c == '\n') { 242235537Sgber state = stNewLine; 243235537Sgber next = buf; 244235537Sgber } 245235537Sgber continue; 246235537Sgber } 247235537Sgber if (state == stHeader) { 248235537Sgber if (c == ']') { 249235537Sgber *next = 0; 250235537Sgber next = buf; 251235537Sgber rsp = rc_addsect(rcp, buf); 252235537Sgber state = stSkipToEOL; 253235537Sgber } else 254235537Sgber *next++ = c; 255235537Sgber continue; 256235537Sgber } 257235537Sgber if (state == stGetKey) { 258235537Sgber if (c == ' ' || c == '\t')/* side effect: 'key name='*/ 259235537Sgber continue; /* become 'keyname=' */ 260235537Sgber if (c == '\n') { /* silently ignore ... */ 261235537Sgber state = stNewLine; 262235537Sgber continue; 263235537Sgber } 264235537Sgber if (c != '=') { 265235537Sgber *next++ = c; 266235537Sgber continue; 267235537Sgber } 268235537Sgber *next = 0; 269235537Sgber if (rsp == NULL) { 270235537Sgber fprintf(stderr, "Key '%s' defined before " 271235537Sgber "section\n", buf); 272235537Sgber state = stSkipToEOL; 273235537Sgber continue; 274235537Sgber } 275235537Sgber rkp = rc_sect_addkey(rsp, buf, NULL); 276235537Sgber next = buf; 277235537Sgber state = stGetValue; 278235537Sgber continue; 279235537Sgber } 280235537Sgber /* only stGetValue left */ 281235537Sgber if (state != stGetValue) { 282235537Sgber fprintf(stderr, "Well, I can't parse file " 283235537Sgber "'%s'\n",rcp->rf_name); 284235537Sgber state = stSkipToEOL; 285235537Sgber } 286235537Sgber if (c != '\n') { 287235537Sgber *next++ = c; 288235537Sgber continue; 289235537Sgber } 290235537Sgber *next = 0; 291235537Sgber rkp->rk_value = strdup(buf); 292235537Sgber state = stNewLine; 293235537Sgber rkp = NULL; 294235537Sgber } /* while */ 295235537Sgber if (c == EOF && state == stGetValue) { 296235537Sgber *next = 0; 297235537Sgber rkp->rk_value = strdup(buf); 298235537Sgber } 299235537Sgber} 300235537Sgber 301235537Sgberint 302235537Sgberrc_getstringptr(struct rcfile *rcp, const char *section, int sect_id, 303235537Sgber const char *key, char **dest) 304235537Sgber{ 305235537Sgber struct rcsection *rsp; 306235537Sgber struct rckey *rkp; 307235537Sgber 308235537Sgber *dest = NULL; 309235537Sgber rsp = rc_findsect(rcp, section, sect_id); 310235537Sgber if (!rsp) 311235537Sgber return (ENOENT); 312235537Sgber rkp = rc_sect_findkey(rsp,key); 313235537Sgber if (!rkp) 314235537Sgber return (ENOENT); 315235537Sgber *dest = rkp->rk_value; 316235537Sgber return (0); 317235537Sgber} 318235537Sgber 319235537Sgberint 320235537Sgberrc_getstring(struct rcfile *rcp, const char *section, int sect_id, 321235537Sgber const char *key, unsigned int maxlen, char *dest) 322235537Sgber{ 323235537Sgber char *value; 324235537Sgber int error; 325235537Sgber 326235537Sgber error = rc_getstringptr(rcp, section, sect_id, key, &value); 327235537Sgber if (error) 328235537Sgber return (error); 329235537Sgber if (strlen(value) >= maxlen) { 330235537Sgber fprintf(stderr, "line too long for key '%s' in section '%s'," 331235537Sgber "max = %d\n",key, section, maxlen); 332235537Sgber return (EINVAL); 333235537Sgber } 334235537Sgber strcpy(dest,value); 335235537Sgber return (0); 336235537Sgber} 337235537Sgber 338235537Sgberint 339235537Sgberrc_getint(struct rcfile *rcp, const char *section, int sect_id, 340235537Sgber const char *key, int *value) 341235537Sgber{ 342235537Sgber struct rcsection *rsp; 343235537Sgber struct rckey *rkp; 344235537Sgber 345235537Sgber rsp = rc_findsect(rcp, section, sect_id); 346235537Sgber if (!rsp) 347235537Sgber return (ENOENT); 348235537Sgber rkp = rc_sect_findkey(rsp,key); 349235537Sgber if (!rkp) 350235537Sgber return (ENOENT); 351235537Sgber errno = 0; 352235537Sgber *value = strtol(rkp->rk_value,NULL,0); 353235537Sgber if (errno) { 354235537Sgber fprintf(stderr, "invalid int value '%s' for key '%s' in " 355235537Sgber "section '%s'\n",rkp->rk_value,key,section); 356235537Sgber return (errno); 357235537Sgber } 358235537Sgber return (0); 359235537Sgber} 360235537Sgber 361235537Sgber/* 362235537Sgber * 1,yes,true 363235537Sgber * 0,no,false 364235537Sgber */ 365235537Sgberint 366235537Sgberrc_getbool(struct rcfile *rcp, const char *section, int sect_id, 367235537Sgber const char *key, int *value) 368235537Sgber{ 369235537Sgber struct rcsection *rsp; 370235537Sgber struct rckey *rkp; 371235537Sgber char *p; 372235537Sgber 373235537Sgber rsp = rc_findsect(rcp, section, sect_id); 374235537Sgber if (!rsp) 375235537Sgber return (ENOENT); 376235537Sgber rkp = rc_sect_findkey(rsp,key); 377235537Sgber if (!rkp) 378235537Sgber return (ENOENT); 379235537Sgber p = rkp->rk_value; 380235537Sgber while (*p && isspace(*p)) p++; 381235537Sgber if (*p == '0' || strcasecmp(p,"no") == 0 || 382235537Sgber strcasecmp(p, "false") == 0 || 383235537Sgber strcasecmp(p, "off") == 0) { 384235537Sgber *value = 0; 385235537Sgber return (0); 386235537Sgber } 387235537Sgber if (*p == '1' || strcasecmp(p,"yes") == 0 || 388235537Sgber strcasecmp(p, "true") == 0 || 389235537Sgber strcasecmp(p, "on") == 0) { 390235537Sgber *value = 1; 391235537Sgber return (0); 392235537Sgber } 393235537Sgber fprintf(stderr, "invalid boolean value '%s' for key '%s' in section " 394235537Sgber "'%s' \n",p, key, section); 395235537Sgber return (EINVAL); 396235537Sgber} 397235537Sgber 398235537Sgber/* Count how many sections with given name exists in configuration. */ 399235537Sgberint rc_getsectionscount(struct rcfile *f, const char *sectname) 400235537Sgber{ 401235537Sgber struct rcsection *p; 402235537Sgber int count = 0; 403235537Sgber 404235537Sgber p = rc_findsect(f, sectname, 0); 405235537Sgber if (p) { 406235537Sgber while (p != NULL) { 407235537Sgber count = p->rs_id + 1; 408235537Sgber p = rc_findsect(f, sectname, count); 409235537Sgber } 410235537Sgber return (count); 411235537Sgber } else 412235537Sgber return (0); 413235537Sgber} 414235537Sgber 415235537Sgberchar ** 416235537Sgberrc_getkeys(struct rcfile *rcp, const char *sectname, int sect_id) 417235537Sgber{ 418235537Sgber struct rcsection *rsp; 419235537Sgber struct rckey *p; 420235537Sgber char **names_tbl; 421235537Sgber int i = 0, count = 0; 422235537Sgber 423235537Sgber rsp = rc_findsect(rcp, sectname, sect_id); 424235537Sgber if (rsp == NULL) 425235537Sgber return (NULL); 426235537Sgber 427235537Sgber SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 428235537Sgber count++; 429235537Sgber 430235537Sgber names_tbl = malloc(sizeof(char *) * (count + 1)); 431235537Sgber if (names_tbl == NULL) 432235537Sgber return (NULL); 433235537Sgber 434235537Sgber SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 435235537Sgber names_tbl[i++] = p->rk_name; 436235537Sgber 437235537Sgber names_tbl[i] = NULL; 438235537Sgber return (names_tbl); 439235537Sgber} 440235537Sgber 441