ncpl_rcfile.c revision 165920
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 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/lib/libncp/ncpl_rcfile.c 165920 2007-01-09 23:27:39Z imp $"); 32 33#include <sys/types.h> 34#include <sys/queue.h> 35#include <ctype.h> 36#include <errno.h> 37#include <stdio.h> 38#include <string.h> 39#include <stdlib.h> 40#include <pwd.h> 41#include <unistd.h> 42 43#include <netncp/ncp_lib.h> 44#include <netncp/ncp_rcfile.h> 45#include <netncp/ncp_cfg.h> 46 47#define NWFS_CFG_FILE NCP_PREFIX"/etc/nwfs.conf" 48 49struct rcfile *ncp_rc = NULL; 50 51SLIST_HEAD(rcfile_head, rcfile); 52static struct rcfile_head pf_head = {NULL}; 53 54int rc_merge(char *filename,struct rcfile **rcfile); 55static struct rcfile* rc_find(char *filename); 56static struct rcsection *rc_findsect(struct rcfile *rcp, char *sectname); 57static struct rcsection *rc_addsect(struct rcfile *rcp, char *sectname); 58static int rc_sect_free(struct rcsection *rsp); 59static struct rckey *rc_sect_findkey(struct rcsection *rsp, char *keyname); 60static struct rckey *rc_sect_addkey(struct rcsection *rsp, char *name, char *value); 61static void rc_key_free(struct rckey *p); 62static void rc_parse(struct rcfile *rcp); 63 64 65/* 66 * open rcfile and load its content, if already open - return previous handle 67 */ 68int 69rc_open(char *filename,char *mode,struct rcfile **rcfile) { 70 struct rcfile *rcp; 71 FILE *f; 72 73 rcp = rc_find(filename); 74 if( rcp ) { 75 *rcfile = rcp; 76 return 0; 77 } 78 f = fopen (filename, mode); 79 if (f==NULL) 80 return errno; 81 rcp = malloc(sizeof(struct rcfile)); 82 if (rcp==NULL) { 83 fclose(f); 84 return ENOMEM; 85 } 86 bzero(rcp, sizeof(struct rcfile)); 87 rcp->rf_name = strdup (filename); 88 rcp->rf_f = f; 89 SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 90 rc_parse(rcp); 91 *rcfile = rcp; 92 return 0; 93} 94 95int 96rc_merge(char *filename,struct rcfile **rcfile) { 97 struct rcfile *rcp = *rcfile; 98 FILE *f, *t; 99 100 if (rcp == NULL) { 101 return rc_open(filename,"r",rcfile); 102 } 103 f = fopen (filename, "r"); 104 if (f==NULL) 105 return errno; 106 t = rcp->rf_f; 107 rcp->rf_f = f; 108 rc_parse(rcp); 109 rcp->rf_f = t; 110 fclose(f); 111 return 0; 112} 113 114int 115rc_close(struct rcfile *rcp) { 116 struct rcsection *p,*n; 117 118 fclose(rcp->rf_f); 119 for(p = SLIST_FIRST(&rcp->rf_sect);p;) { 120 n = p; 121 p = SLIST_NEXT(p,rs_next); 122 rc_sect_free(n); 123 } 124 free(rcp->rf_name); 125 SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); 126 free(rcp); 127 return 0; 128} 129 130static struct rcfile* 131rc_find(char *filename) { 132 struct rcfile *p; 133 134 SLIST_FOREACH(p, &pf_head, rf_next) 135 if (strcmp (filename, p->rf_name)==0) 136 return p; 137 return 0; 138} 139 140static struct rcsection * 141rc_findsect(struct rcfile *rcp, char *sectname) { 142 struct rcsection *p; 143 144 SLIST_FOREACH(p, &rcp->rf_sect, rs_next) 145 if (strcmp(p->rs_name, sectname)==0) 146 return p; 147 return NULL; 148} 149 150static struct rcsection * 151rc_addsect(struct rcfile *rcp, char *sectname) { 152 struct rcsection *p; 153 154 p = rc_findsect(rcp, sectname); 155 if (p) return p; 156 p = malloc(sizeof(*p)); 157 if (!p) return NULL; 158 p->rs_name = strdup(sectname); 159 SLIST_INIT(&p->rs_keys); 160 SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 161 return p; 162} 163 164static int 165rc_sect_free(struct rcsection *rsp) { 166 struct rckey *p,*n; 167 168 for(p = SLIST_FIRST(&rsp->rs_keys);p;) { 169 n = p; 170 p = SLIST_NEXT(p,rk_next); 171 rc_key_free(n); 172 } 173 free(rsp->rs_name); 174 free(rsp); 175 return 0; 176} 177 178static struct rckey * 179rc_sect_findkey(struct rcsection *rsp, char *keyname) { 180 struct rckey *p; 181 182 SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 183 if (strcmp(p->rk_name, keyname)==0) 184 return p; 185 return NULL; 186} 187 188static struct rckey * 189rc_sect_addkey(struct rcsection *rsp, char *name, char *value) { 190 struct rckey *p; 191 192 p = rc_sect_findkey(rsp, name); 193 if (p) { 194 free(p->rk_value); 195 } else { 196 p = malloc(sizeof(*p)); 197 if (!p) return NULL; 198 SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 199 p->rk_name = strdup(name); 200 } 201 p->rk_value = value ? strdup(value) : strdup(""); 202 return p; 203} 204 205void 206rc_sect_delkey(struct rcsection *rsp, struct rckey *p) { 207 208 SLIST_REMOVE(&rsp->rs_keys,p,rckey,rk_next); 209 rc_key_free(p); 210 return; 211} 212 213static void 214rc_key_free(struct rckey *p){ 215 free(p->rk_value); 216 free(p->rk_name); 217 free(p); 218} 219 220enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 221 222static void 223rc_parse(struct rcfile *rcp) { 224 FILE *f = rcp->rf_f; 225 int state = stNewLine, c; 226 struct rcsection *rsp = NULL; 227 struct rckey *rkp = NULL; 228 char buf[2048]; 229 char *next = buf, *last = &buf[sizeof(buf)-1]; 230 231 while ((c = getc (f)) != EOF) { 232 if (c == '\r') 233 continue; 234 if (state == stNewLine) { 235 next = buf; 236 if (isspace(c)) 237 continue; /* skip leading junk */ 238 if (c == '[') { 239 state = stHeader; 240 rsp = NULL; 241 continue; 242 } 243 if (c == '#' || c == ';') { 244 state = stSkipToEOL; 245 } else { /* something meaningfull */ 246 state = stGetKey; 247 } 248 } 249 if (state == stSkipToEOL || next == last) {/* ignore long lines */ 250 if (c == '\n'){ 251 state = stNewLine; 252 next = buf; 253 } 254 continue; 255 } 256 if (state == stHeader) { 257 if (c == ']') { 258 *next = 0; 259 next = buf; 260 rsp = rc_addsect(rcp, buf); 261 state = stSkipToEOL; 262 } else 263 *next++ = c; 264 continue; 265 } 266 if (state == stGetKey) { 267 if (c == ' ' || c == '\t')/* side effect: 'key name='*/ 268 continue; /* become 'keyname=' */ 269 if (c == '\n') { /* silently ignore ... */ 270 state = stNewLine; 271 continue; 272 } 273 if (c != '=') { 274 *next++ = c; 275 continue; 276 } 277 *next = 0; 278 if (rsp == NULL) { 279 fprintf(stderr, "Key '%s' defined before section\n", buf); 280 state = stSkipToEOL; 281 continue; 282 } 283 rkp = rc_sect_addkey(rsp, buf, NULL); 284 next = buf; 285 state = stGetValue; 286 continue; 287 } 288 /* only stGetValue left */ 289 if (state != stGetValue) { 290 fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name); 291 state = stSkipToEOL; 292 } 293 if (c != '\n') { 294 *next++ = c; 295 continue; 296 } 297 *next = 0; 298 rkp->rk_value = strdup(buf); 299 state = stNewLine; 300 rkp = NULL; 301 } /* while */ 302 if (c == EOF && state == stGetValue) { 303 *next = 0; 304 rkp->rk_value = strdup(buf); 305 } 306 return; 307} 308 309int 310rc_getstringptr(struct rcfile *rcp,char *section, char *key,char **dest) { 311 struct rcsection *rsp; 312 struct rckey *rkp; 313 314 *dest = NULL; 315 rsp = rc_findsect(rcp, section); 316 if (!rsp) return ENOENT; 317 rkp = rc_sect_findkey(rsp,key); 318 if (!rkp) return ENOENT; 319 *dest = rkp->rk_value; 320 return 0; 321} 322 323int 324rc_getstring(struct rcfile *rcp,char *section, char *key,int maxlen,char *dest) { 325 char *value; 326 int error; 327 328 error = rc_getstringptr(rcp, section, key, &value); 329 if (error) return error; 330 if (strlen(value) >= maxlen) { 331 fprintf(stderr, "line too long for key '%s' in section '%s', 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,char *section, char *key,int *value) { 340 struct rcsection *rsp; 341 struct rckey *rkp; 342 343 rsp = rc_findsect(rcp, section); 344 if (!rsp) return ENOENT; 345 rkp = rc_sect_findkey(rsp,key); 346 if (!rkp) return ENOENT; 347 errno = 0; 348 *value = strtol(rkp->rk_value,NULL,0); 349 if (errno) { 350 fprintf(stderr, "invalid int value '%s' for key '%s' in section '%s'\n",rkp->rk_value,key,section); 351 return errno; 352 } 353 return 0; 354} 355 356/* 357 * 1,yes,true 358 * 0,no,false 359 */ 360int 361rc_getbool(struct rcfile *rcp,char *section, char *key,int *value) { 362 struct rcsection *rsp; 363 struct rckey *rkp; 364 char *p; 365 366 rsp = rc_findsect(rcp, section); 367 if (!rsp) return ENOENT; 368 rkp = rc_sect_findkey(rsp,key); 369 if (!rkp) return ENOENT; 370 p = rkp->rk_value; 371 while (*p && isspace(*p)) p++; 372 if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) { 373 *value = 0; 374 return 0; 375 } 376 if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) { 377 *value = 1; 378 return 0; 379 } 380 fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section); 381 return EINVAL; 382} 383 384/* 385 * first read ~/.nwfsrc, next try to merge NWFS_CFG_FILE 386 */ 387int 388ncp_open_rcfile(void) { 389 char *home, *fn; 390 int error; 391 392 home = getenv("HOME"); 393 if (home) { 394 fn = malloc(strlen(home) + 20); 395 sprintf(fn, "%s/.nwfsrc", home); 396 error = rc_open(fn,"r",&ncp_rc); 397 free (fn); 398 } 399 error = rc_merge(NWFS_CFG_FILE, &ncp_rc); 400 if( ncp_rc == NULL ) { 401 printf("Warning: no cfg files found.\n"); 402 return 1; 403 } 404 return 0; 405} 406 407