1/* 2 * Copyright (c) 1999, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34#include <sys/types.h> 35#include <sys/queue.h> 36#include <ctype.h> 37#include <errno.h> 38#include <stdio.h> 39#include <string.h> 40#include <stdlib.h> 41#include <pwd.h> 42#include <unistd.h> 43 44#include "nandsim_rcfile.h" 45 46SLIST_HEAD(rcfile_head, rcfile); 47static struct rcfile_head pf_head = {NULL}; 48static struct rcsection *rc_findsect(struct rcfile *rcp, 49 const char *sectname, int sect_id); 50static struct rcsection *rc_addsect(struct rcfile *rcp, 51 const char *sectname); 52static int rc_sect_free(struct rcsection *rsp); 53static struct rckey *rc_sect_findkey(struct rcsection *rsp, 54 const char *keyname); 55static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, 56 char *value); 57static void rc_key_free(struct rckey *p); 58static void rc_parse(struct rcfile *rcp); 59 60static struct rcfile* rc_find(const char *filename); 61 62/* 63 * open rcfile and load its content, if already open - return previous handle 64 */ 65int 66rc_open(const char *filename, const char *mode,struct rcfile **rcfile) 67{ 68 struct rcfile *rcp; 69 FILE *f; 70 rcp = rc_find(filename); 71 if (rcp) { 72 *rcfile = rcp; 73 return (0); 74 } 75 f = fopen (filename, mode); 76 if (f == NULL) 77 return errno; 78 rcp = malloc(sizeof(struct rcfile)); 79 if (rcp == NULL) { 80 fclose(f); 81 return ENOMEM; 82 } 83 bzero(rcp, sizeof(struct rcfile)); 84 rcp->rf_name = strdup(filename); 85 rcp->rf_f = f; 86 SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 87 rc_parse(rcp); 88 *rcfile = rcp; 89 return (0); 90} 91 92int 93rc_close(struct rcfile *rcp) 94{ 95 struct rcsection *p,*n; 96 97 fclose(rcp->rf_f); 98 for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { 99 n = p; 100 p = SLIST_NEXT(p,rs_next); 101 rc_sect_free(n); 102 } 103 free(rcp->rf_name); 104 SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); 105 free(rcp); 106 return (0); 107} 108 109static struct rcfile* 110rc_find(const char *filename) 111{ 112 struct rcfile *p; 113 114 SLIST_FOREACH(p, &pf_head, rf_next) 115 if (strcmp (filename, p->rf_name) == 0) 116 return (p); 117 return (0); 118} 119 120/* Find section with given name and id */ 121static struct rcsection * 122rc_findsect(struct rcfile *rcp, const char *sectname, int sect_id) 123{ 124 struct rcsection *p; 125 126 SLIST_FOREACH(p, &rcp->rf_sect, rs_next) 127 if (strcmp(p->rs_name, sectname) == 0 && p->rs_id == sect_id) 128 return (p); 129 return (NULL); 130} 131 132static struct rcsection * 133rc_addsect(struct rcfile *rcp, const char *sectname) 134{ 135 struct rcsection *p; 136 int id = 0; 137 p = rc_findsect(rcp, sectname, 0); 138 if (p) { 139 /* 140 * If section with that name already exists -- add one more, 141 * same named, but with different id (higher by one) 142 */ 143 while (p != NULL) { 144 id = p->rs_id + 1; 145 p = rc_findsect(rcp, sectname, id); 146 } 147 } 148 p = malloc(sizeof(*p)); 149 if (!p) 150 return (NULL); 151 p->rs_name = strdup(sectname); 152 p->rs_id = id; 153 SLIST_INIT(&p->rs_keys); 154 SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 155 return (p); 156} 157 158static int 159rc_sect_free(struct rcsection *rsp) 160{ 161 struct rckey *p,*n; 162 163 for (p = SLIST_FIRST(&rsp->rs_keys); p; ) { 164 n = p; 165 p = SLIST_NEXT(p,rk_next); 166 rc_key_free(n); 167 } 168 free(rsp->rs_name); 169 free(rsp); 170 return (0); 171} 172 173static struct rckey * 174rc_sect_findkey(struct rcsection *rsp, const char *keyname) 175{ 176 struct rckey *p; 177 178 SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 179 if (strcmp(p->rk_name, keyname)==0) 180 return (p); 181 return (NULL); 182} 183 184static struct rckey * 185rc_sect_addkey(struct rcsection *rsp, const char *name, char *value) 186{ 187 struct rckey *p; 188 p = rc_sect_findkey(rsp, name); 189 if (p) { 190 free(p->rk_value); 191 } else { 192 p = malloc(sizeof(*p)); 193 if (!p) 194 return (NULL); 195 SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 196 p->rk_name = strdup(name); 197 } 198 p->rk_value = value ? strdup(value) : strdup(""); 199 return (p); 200} 201 202static void 203rc_key_free(struct rckey *p) 204{ 205 free(p->rk_value); 206 free(p->rk_name); 207 free(p); 208} 209 210enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 211 212static void 213rc_parse(struct rcfile *rcp) 214{ 215 FILE *f = rcp->rf_f; 216 int state = stNewLine, c; 217 struct rcsection *rsp = NULL; 218 struct rckey *rkp = NULL; 219 char buf[2048]; 220 char *next = buf, *last = &buf[sizeof(buf)-1]; 221 222 while ((c = getc (f)) != EOF) { 223 if (c == '\r') 224 continue; 225 if (state == stNewLine) { 226 next = buf; 227 if (isspace(c)) 228 continue; /* skip leading junk */ 229 if (c == '[') { 230 state = stHeader; 231 rsp = NULL; 232 continue; 233 } 234 if (c == '#' || c == ';') { 235 state = stSkipToEOL; 236 } else { /* something meaningful */ 237 state = stGetKey; 238 } 239 } 240 if (state == stSkipToEOL || next == last) {/* ignore long lines */ 241 if (c == '\n') { 242 state = stNewLine; 243 next = buf; 244 } 245 continue; 246 } 247 if (state == stHeader) { 248 if (c == ']') { 249 *next = 0; 250 next = buf; 251 rsp = rc_addsect(rcp, buf); 252 state = stSkipToEOL; 253 } else 254 *next++ = c; 255 continue; 256 } 257 if (state == stGetKey) { 258 if (c == ' ' || c == '\t')/* side effect: 'key name='*/ 259 continue; /* become 'keyname=' */ 260 if (c == '\n') { /* silently ignore ... */ 261 state = stNewLine; 262 continue; 263 } 264 if (c != '=') { 265 *next++ = c; 266 continue; 267 } 268 *next = 0; 269 if (rsp == NULL) { 270 fprintf(stderr, "Key '%s' defined before " 271 "section\n", buf); 272 state = stSkipToEOL; 273 continue; 274 } 275 rkp = rc_sect_addkey(rsp, buf, NULL); 276 next = buf; 277 state = stGetValue; 278 continue; 279 } 280 /* only stGetValue left */ 281 if (state != stGetValue) { 282 fprintf(stderr, "Well, I can't parse file " 283 "'%s'\n",rcp->rf_name); 284 state = stSkipToEOL; 285 } 286 if (c != '\n') { 287 *next++ = c; 288 continue; 289 } 290 *next = 0; 291 rkp->rk_value = strdup(buf); 292 state = stNewLine; 293 rkp = NULL; 294 } /* while */ 295 if (c == EOF && state == stGetValue) { 296 *next = 0; 297 rkp->rk_value = strdup(buf); 298 } 299} 300 301int 302rc_getstringptr(struct rcfile *rcp, const char *section, int sect_id, 303 const char *key, char **dest) 304{ 305 struct rcsection *rsp; 306 struct rckey *rkp; 307 308 *dest = NULL; 309 rsp = rc_findsect(rcp, section, sect_id); 310 if (!rsp) 311 return (ENOENT); 312 rkp = rc_sect_findkey(rsp,key); 313 if (!rkp) 314 return (ENOENT); 315 *dest = rkp->rk_value; 316 return (0); 317} 318 319int 320rc_getstring(struct rcfile *rcp, const char *section, int sect_id, 321 const char *key, unsigned int maxlen, char *dest) 322{ 323 char *value; 324 int error; 325 326 error = rc_getstringptr(rcp, section, sect_id, key, &value); 327 if (error) 328 return (error); 329 if (strlen(value) >= maxlen) { 330 fprintf(stderr, "line too long for key '%s' in section '%s'," 331 "max = %d\n",key, section, maxlen); 332 return (EINVAL); 333 } 334 strcpy(dest,value); 335 return (0); 336} 337 338int 339rc_getint(struct rcfile *rcp, const char *section, int sect_id, 340 const char *key, int *value) 341{ 342 struct rcsection *rsp; 343 struct rckey *rkp; 344 345 rsp = rc_findsect(rcp, section, sect_id); 346 if (!rsp) 347 return (ENOENT); 348 rkp = rc_sect_findkey(rsp,key); 349 if (!rkp) 350 return (ENOENT); 351 errno = 0; 352 *value = strtol(rkp->rk_value,NULL,0); 353 if (errno) { 354 fprintf(stderr, "invalid int value '%s' for key '%s' in " 355 "section '%s'\n",rkp->rk_value,key,section); 356 return (errno); 357 } 358 return (0); 359} 360 361/* 362 * 1,yes,true 363 * 0,no,false 364 */ 365int 366rc_getbool(struct rcfile *rcp, const char *section, int sect_id, 367 const char *key, int *value) 368{ 369 struct rcsection *rsp; 370 struct rckey *rkp; 371 char *p; 372 373 rsp = rc_findsect(rcp, section, sect_id); 374 if (!rsp) 375 return (ENOENT); 376 rkp = rc_sect_findkey(rsp,key); 377 if (!rkp) 378 return (ENOENT); 379 p = rkp->rk_value; 380 while (*p && isspace(*p)) p++; 381 if (*p == '0' || strcasecmp(p,"no") == 0 || 382 strcasecmp(p, "false") == 0 || 383 strcasecmp(p, "off") == 0) { 384 *value = 0; 385 return (0); 386 } 387 if (*p == '1' || strcasecmp(p,"yes") == 0 || 388 strcasecmp(p, "true") == 0 || 389 strcasecmp(p, "on") == 0) { 390 *value = 1; 391 return (0); 392 } 393 fprintf(stderr, "invalid boolean value '%s' for key '%s' in section " 394 "'%s' \n",p, key, section); 395 return (EINVAL); 396} 397 398/* Count how many sections with given name exists in configuration. */ 399int rc_getsectionscount(struct rcfile *f, const char *sectname) 400{ 401 struct rcsection *p; 402 int count = 0; 403 404 p = rc_findsect(f, sectname, 0); 405 if (p) { 406 while (p != NULL) { 407 count = p->rs_id + 1; 408 p = rc_findsect(f, sectname, count); 409 } 410 return (count); 411 } else 412 return (0); 413} 414 415char ** 416rc_getkeys(struct rcfile *rcp, const char *sectname, int sect_id) 417{ 418 struct rcsection *rsp; 419 struct rckey *p; 420 char **names_tbl; 421 int i = 0, count = 0; 422 423 rsp = rc_findsect(rcp, sectname, sect_id); 424 if (rsp == NULL) 425 return (NULL); 426 427 SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 428 count++; 429 430 names_tbl = malloc(sizeof(char *) * (count + 1)); 431 if (names_tbl == NULL) 432 return (NULL); 433 434 SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 435 names_tbl[i++] = p->rk_name; 436 437 names_tbl[i] = NULL; 438 return (names_tbl); 439} 440 441