ncpl_rcfile.c revision 52153
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. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: head/lib/libncp/ncpl_rcfile.c 52153 1999-10-12 11:56:41Z bp $ 33 */ 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 <netncp/ncp_lib.h> 45#include <netncp/ncp_rcfile.h> 46#include <netncp/ncp_cfg.h> 47 48#define NWFS_CFG_FILE NCP_PREFIX"/etc/nwfs.conf" 49 50struct rcfile *ncp_rc = NULL; 51 52SLIST_HEAD(rcfile_head, rcfile); 53static struct rcfile_head pf_head = {NULL}; 54 55int rc_merge(char *filename,struct rcfile **rcfile); 56static struct rcfile* rc_find(char *filename); 57static struct rcsection *rc_findsect(struct rcfile *rcp, char *sectname); 58static struct rcsection *rc_addsect(struct rcfile *rcp, char *sectname); 59static int rc_sect_free(struct rcsection *rsp); 60static struct rckey *rc_sect_findkey(struct rcsection *rsp, char *keyname); 61static struct rckey *rc_sect_addkey(struct rcsection *rsp, char *name, char *value); 62static void rc_key_free(struct rckey *p); 63static void rc_parse(struct rcfile *rcp); 64 65 66/* 67 * open rcfile and load its content, if already open - return previous handle 68 */ 69int 70rc_open(char *filename,char *mode,struct rcfile **rcfile) { 71 struct rcfile *rcp; 72 FILE *f; 73 74 rcp = rc_find(filename); 75 if( rcp ) { 76 *rcfile = rcp; 77 return 0; 78 } 79 f = fopen (filename, mode); 80 if (f==NULL) 81 return errno; 82 rcp = malloc(sizeof(struct rcfile)); 83 if (rcp==NULL) { 84 fclose(f); 85 return ENOMEM; 86 } 87 bzero(rcp, sizeof(struct rcfile)); 88 rcp->rf_name = strdup (filename); 89 rcp->rf_f = f; 90 SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 91 rc_parse(rcp); 92 *rcfile = rcp; 93 return 0; 94} 95 96int 97rc_merge(char *filename,struct rcfile **rcfile) { 98 struct rcfile *rcp = *rcfile; 99 FILE *f, *t; 100 101 if (rcp == NULL) { 102 return rc_open(filename,"r",rcfile); 103 } 104 f = fopen (filename, "r"); 105 if (f==NULL) 106 return errno; 107 t = rcp->rf_f; 108 rcp->rf_f = f; 109 rc_parse(rcp); 110 rcp->rf_f = t; 111 fclose(f); 112 return 0; 113} 114 115int 116rc_close(struct rcfile *rcp) { 117 struct rcsection *p,*n; 118 119 fclose(rcp->rf_f); 120 for(p = SLIST_FIRST(&rcp->rf_sect);p;) { 121 n = p; 122 p = SLIST_NEXT(p,rs_next); 123 rc_sect_free(n); 124 } 125 free(rcp->rf_name); 126 SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); 127 free(rcp); 128 return 0; 129} 130 131static struct rcfile* 132rc_find(char *filename) { 133 struct rcfile *p; 134 135 SLIST_FOREACH(p, &pf_head, rf_next) 136 if (strcmp (filename, p->rf_name)==0) 137 return p; 138 return 0; 139} 140 141static struct rcsection * 142rc_findsect(struct rcfile *rcp, char *sectname) { 143 struct rcsection *p; 144 145 SLIST_FOREACH(p, &rcp->rf_sect, rs_next) 146 if (strcmp(p->rs_name, sectname)==0) 147 return p; 148 return NULL; 149} 150 151static struct rcsection * 152rc_addsect(struct rcfile *rcp, char *sectname) { 153 struct rcsection *p; 154 155 p = rc_findsect(rcp, sectname); 156 if (p) return p; 157 p = malloc(sizeof(*p)); 158 if (!p) return NULL; 159 p->rs_name = strdup(sectname); 160 SLIST_INIT(&p->rs_keys); 161 SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 162 return p; 163} 164 165static int 166rc_sect_free(struct rcsection *rsp) { 167 struct rckey *p,*n; 168 169 for(p = SLIST_FIRST(&rsp->rs_keys);p;) { 170 n = p; 171 p = SLIST_NEXT(p,rk_next); 172 rc_key_free(n); 173 } 174 free(rsp->rs_name); 175 free(rsp); 176 return 0; 177} 178 179static struct rckey * 180rc_sect_findkey(struct rcsection *rsp, char *keyname) { 181 struct rckey *p; 182 183 SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 184 if (strcmp(p->rk_name, keyname)==0) 185 return p; 186 return NULL; 187} 188 189static struct rckey * 190rc_sect_addkey(struct rcsection *rsp, char *name, char *value) { 191 struct rckey *p; 192 193 p = rc_sect_findkey(rsp, name); 194 if (p) { 195 free(p->rk_value); 196 } else { 197 p = malloc(sizeof(*p)); 198 if (!p) return NULL; 199 SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 200 p->rk_name = strdup(name); 201 } 202 p->rk_value = value ? strdup(value) : strdup(""); 203 return p; 204} 205 206void 207rc_sect_delkey(struct rcsection *rsp, struct rckey *p) { 208 209 SLIST_REMOVE(&rsp->rs_keys,p,rckey,rk_next); 210 rc_key_free(p); 211 return; 212} 213 214static void 215rc_key_free(struct rckey *p){ 216 free(p->rk_value); 217 free(p->rk_name); 218 free(p); 219} 220 221enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 222 223static void 224rc_parse(struct rcfile *rcp) { 225 FILE *f = rcp->rf_f; 226 int state = stNewLine, c; 227 struct rcsection *rsp = NULL; 228 struct rckey *rkp = NULL; 229 char buf[2048]; 230 char *next = buf, *last = &buf[sizeof(buf)-1]; 231 232 while ((c = getc (f)) != EOF) { 233 if (c == '\r') 234 continue; 235 if (state == stNewLine) { 236 next = buf; 237 if (isspace(c)) 238 continue; /* skip leading junk */ 239 if (c == '[') { 240 state = stHeader; 241 rsp = NULL; 242 continue; 243 } 244 if (c == '#' || c == ';') { 245 state = stSkipToEOL; 246 } else { /* something meaningfull */ 247 state = stGetKey; 248 } 249 } 250 if (state == stSkipToEOL || next == last) {/* ignore long lines */ 251 if (c == '\n'){ 252 state = stNewLine; 253 next = buf; 254 } 255 continue; 256 } 257 if (state == stHeader) { 258 if (c == ']') { 259 *next = 0; 260 next = buf; 261 rsp = rc_addsect(rcp, buf); 262 state = stSkipToEOL; 263 } else 264 *next++ = c; 265 continue; 266 } 267 if (state == stGetKey) { 268 if (c == ' ' || c == '\t')/* side effect: 'key name='*/ 269 continue; /* become 'keyname=' */ 270 if (c == '\n') { /* silently ignore ... */ 271 state = stNewLine; 272 continue; 273 } 274 if (c != '=') { 275 *next++ = c; 276 continue; 277 } 278 *next = 0; 279 if (rsp == NULL) { 280 fprintf(stderr, "Key '%s' defined before section\n", buf); 281 state = stSkipToEOL; 282 continue; 283 } 284 rkp = rc_sect_addkey(rsp, buf, NULL); 285 next = buf; 286 state = stGetValue; 287 continue; 288 } 289 /* only stGetValue left */ 290 if (state != stGetValue) { 291 fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name); 292 state = stSkipToEOL; 293 } 294 if (c != '\n') { 295 *next++ = c; 296 continue; 297 } 298 *next = 0; 299 rkp->rk_value = strdup(buf); 300 state = stNewLine; 301 rkp = NULL; 302 } /* while */ 303 if (c == EOF && state == stGetValue) { 304 *next = 0; 305 rkp->rk_value = strdup(buf); 306 } 307 return; 308} 309 310int 311rc_getstringptr(struct rcfile *rcp,char *section, char *key,char **dest) { 312 struct rcsection *rsp; 313 struct rckey *rkp; 314 315 *dest = NULL; 316 rsp = rc_findsect(rcp, section); 317 if (!rsp) return ENOENT; 318 rkp = rc_sect_findkey(rsp,key); 319 if (!rkp) return ENOENT; 320 *dest = rkp->rk_value; 321 return 0; 322} 323 324int 325rc_getstring(struct rcfile *rcp,char *section, char *key,int maxlen,char *dest) { 326 char *value; 327 int error; 328 329 error = rc_getstringptr(rcp, section, key, &value); 330 if (error) return error; 331 if (strlen(value) >= maxlen) { 332 fprintf(stderr, "line too long for key '%s' in section '%s', max = %d\n",key, section, maxlen); 333 return EINVAL; 334 } 335 strcpy(dest,value); 336 return 0; 337} 338 339int 340rc_getint(struct rcfile *rcp,char *section, char *key,int *value) { 341 struct rcsection *rsp; 342 struct rckey *rkp; 343 344 rsp = rc_findsect(rcp, section); 345 if (!rsp) return ENOENT; 346 rkp = rc_sect_findkey(rsp,key); 347 if (!rkp) return ENOENT; 348 errno = 0; 349 *value = strtol(rkp->rk_value,NULL,0); 350 if (errno) { 351 fprintf(stderr, "invalid int value '%s' for key '%s' in section '%s'\n",rkp->rk_value,key,section); 352 return errno; 353 } 354 return 0; 355} 356 357/* 358 * 1,yes,true 359 * 0,no,false 360 */ 361int 362rc_getbool(struct rcfile *rcp,char *section, char *key,int *value) { 363 struct rcsection *rsp; 364 struct rckey *rkp; 365 char *p; 366 367 rsp = rc_findsect(rcp, section); 368 if (!rsp) return ENOENT; 369 rkp = rc_sect_findkey(rsp,key); 370 if (!rkp) return ENOENT; 371 p = rkp->rk_value; 372 while (*p && isspace(*p)) p++; 373 if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) { 374 *value = 0; 375 return 0; 376 } 377 if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) { 378 *value = 1; 379 return 0; 380 } 381 fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section); 382 return EINVAL; 383} 384 385/* 386 * first read ~/.nwfsrc, next try to merge NWFS_CFG_FILE 387 */ 388int 389ncp_open_rcfile(void) { 390 char *home, *fn; 391 int error; 392 393 home = getenv("HOME"); 394 if (home) { 395 fn = malloc(strlen(home) + 20); 396 sprintf(fn, "%s/.nwfsrc", home); 397 error = rc_open(fn,"r",&ncp_rc); 398 free (fn); 399 } 400 error = rc_merge(NWFS_CFG_FILE, &ncp_rc); 401 if( ncp_rc == NULL ) { 402 printf("Warning: no cfg files found.\n"); 403 return 1; 404 } 405 return 0; 406} 407 408