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