ncpl_rcfile.c revision 84213
152153Sbp/*
252153Sbp * Copyright (c) 1999, Boris Popov
352153Sbp * All rights reserved.
452153Sbp *
552153Sbp * Redistribution and use in source and binary forms, with or without
652153Sbp * modification, are permitted provided that the following conditions
752153Sbp * are met:
852153Sbp * 1. Redistributions of source code must retain the above copyright
952153Sbp *    notice, this list of conditions and the following disclaimer.
1052153Sbp * 2. Redistributions in binary form must reproduce the above copyright
1152153Sbp *    notice, this list of conditions and the following disclaimer in the
1252153Sbp *    documentation and/or other materials provided with the distribution.
1352153Sbp * 3. All advertising materials mentioning features or use of this software
1452153Sbp *    must display the following acknowledgement:
1552153Sbp *    This product includes software developed by Boris Popov.
1652153Sbp * 4. Neither the name of the author nor the names of any co-contributors
1752153Sbp *    may be used to endorse or promote products derived from this software
1852153Sbp *    without specific prior written permission.
1952153Sbp *
2052153Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2152153Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2252153Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2352153Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2452153Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2552153Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2652153Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2752153Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2852153Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2952153Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3052153Sbp * SUCH DAMAGE.
3152153Sbp */
3284213Sdillon
3384213Sdillon#include <sys/cdefs.h>
3484213Sdillon__FBSDID("$FreeBSD: head/lib/libncp/ncpl_rcfile.c 84213 2001-09-30 22:01:19Z dillon $");
3584213Sdillon
3652153Sbp#include <sys/types.h>
3752153Sbp#include <sys/queue.h>
3852153Sbp#include <ctype.h>
3952153Sbp#include <errno.h>
4052153Sbp#include <stdio.h>
4152153Sbp#include <string.h>
4252153Sbp#include <stdlib.h>
4352153Sbp#include <pwd.h>
4452153Sbp#include <unistd.h>
4552153Sbp
4652153Sbp#include <netncp/ncp_lib.h>
4752153Sbp#include <netncp/ncp_rcfile.h>
4852153Sbp#include <netncp/ncp_cfg.h>
4952153Sbp
5052153Sbp#define NWFS_CFG_FILE	NCP_PREFIX"/etc/nwfs.conf"
5152153Sbp
5252153Sbpstruct rcfile *ncp_rc = NULL;
5352153Sbp
5460938SjakeSLIST_HEAD(rcfile_head, rcfile);
5552153Sbpstatic struct rcfile_head pf_head = {NULL};
5652153Sbp
5752153Sbpint rc_merge(char *filename,struct rcfile **rcfile);
5852153Sbpstatic struct rcfile* rc_find(char *filename);
5952153Sbpstatic struct rcsection *rc_findsect(struct rcfile *rcp, char *sectname);
6052153Sbpstatic struct rcsection *rc_addsect(struct rcfile *rcp, char *sectname);
6152153Sbpstatic int rc_sect_free(struct rcsection *rsp);
6252153Sbpstatic struct rckey *rc_sect_findkey(struct rcsection *rsp, char *keyname);
6352153Sbpstatic struct rckey *rc_sect_addkey(struct rcsection *rsp, char *name, char *value);
6452153Sbpstatic void rc_key_free(struct rckey *p);
6552153Sbpstatic void rc_parse(struct rcfile *rcp);
6652153Sbp
6752153Sbp
6852153Sbp/*
6952153Sbp * open rcfile and load its content, if already open - return previous handle
7052153Sbp */
7152153Sbpint
7252153Sbprc_open(char *filename,char *mode,struct rcfile **rcfile) {
7352153Sbp	struct rcfile *rcp;
7452153Sbp	FILE *f;
7552153Sbp
7652153Sbp	rcp = rc_find(filename);
7752153Sbp	if( rcp ) {
7852153Sbp		*rcfile = rcp;
7952153Sbp		return 0;
8052153Sbp	}
8152153Sbp	f = fopen (filename, mode);
8252153Sbp	if (f==NULL)
8352153Sbp		return errno;
8452153Sbp	rcp = malloc(sizeof(struct rcfile));
8552153Sbp	if (rcp==NULL) {
8652153Sbp		fclose(f);
8752153Sbp		return ENOMEM;
8852153Sbp	}
8952153Sbp	bzero(rcp, sizeof(struct rcfile));
9052153Sbp	rcp->rf_name = strdup (filename);
9152153Sbp	rcp->rf_f = f;
9252153Sbp	SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
9352153Sbp	rc_parse(rcp);
9452153Sbp	*rcfile = rcp;
9552153Sbp	return 0;
9652153Sbp}
9752153Sbp
9852153Sbpint
9952153Sbprc_merge(char *filename,struct rcfile **rcfile) {
10052153Sbp	struct rcfile *rcp = *rcfile;
10152153Sbp	FILE *f, *t;
10252153Sbp
10352153Sbp	if (rcp == NULL) {
10452153Sbp		return rc_open(filename,"r",rcfile);
10552153Sbp	}
10652153Sbp	f = fopen (filename, "r");
10752153Sbp	if (f==NULL)
10852153Sbp		return errno;
10952153Sbp	t = rcp->rf_f;
11052153Sbp	rcp->rf_f = f;
11152153Sbp	rc_parse(rcp);
11252153Sbp	rcp->rf_f = t;
11352153Sbp	fclose(f);
11452153Sbp	return 0;
11552153Sbp}
11652153Sbp
11752153Sbpint
11852153Sbprc_close(struct rcfile *rcp) {
11952153Sbp	struct rcsection *p,*n;
12052153Sbp
12152153Sbp	fclose(rcp->rf_f);
12252153Sbp	for(p = SLIST_FIRST(&rcp->rf_sect);p;) {
12352153Sbp		n = p;
12452153Sbp		p = SLIST_NEXT(p,rs_next);
12552153Sbp		rc_sect_free(n);
12652153Sbp	}
12752153Sbp	free(rcp->rf_name);
12860938Sjake	SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
12952153Sbp	free(rcp);
13052153Sbp	return 0;
13152153Sbp}
13252153Sbp
13352153Sbpstatic struct rcfile*
13452153Sbprc_find(char *filename) {
13552153Sbp	struct rcfile *p;
13652153Sbp
13752153Sbp	SLIST_FOREACH(p, &pf_head, rf_next)
13852153Sbp		if (strcmp (filename, p->rf_name)==0)
13952153Sbp			return p;
14052153Sbp	return 0;
14152153Sbp}
14252153Sbp
14352153Sbpstatic struct rcsection *
14452153Sbprc_findsect(struct rcfile *rcp, char *sectname) {
14552153Sbp	struct rcsection *p;
14652153Sbp
14752153Sbp	SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
14852153Sbp		if (strcmp(p->rs_name, sectname)==0)
14952153Sbp			return p;
15052153Sbp	return NULL;
15152153Sbp}
15252153Sbp
15352153Sbpstatic struct rcsection *
15452153Sbprc_addsect(struct rcfile *rcp, char *sectname) {
15552153Sbp	struct rcsection *p;
15652153Sbp
15752153Sbp	p = rc_findsect(rcp, sectname);
15852153Sbp	if (p) return p;
15952153Sbp	p = malloc(sizeof(*p));
16052153Sbp	if (!p) return NULL;
16152153Sbp	p->rs_name = strdup(sectname);
16252153Sbp	SLIST_INIT(&p->rs_keys);
16352153Sbp	SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
16452153Sbp	return p;
16552153Sbp}
16652153Sbp
16752153Sbpstatic int
16852153Sbprc_sect_free(struct rcsection *rsp) {
16952153Sbp	struct rckey *p,*n;
17052153Sbp
17152153Sbp	for(p = SLIST_FIRST(&rsp->rs_keys);p;) {
17252153Sbp		n = p;
17352153Sbp		p = SLIST_NEXT(p,rk_next);
17452153Sbp		rc_key_free(n);
17552153Sbp	}
17652153Sbp	free(rsp->rs_name);
17752153Sbp	free(rsp);
17852153Sbp	return 0;
17952153Sbp}
18052153Sbp
18152153Sbpstatic struct rckey *
18252153Sbprc_sect_findkey(struct rcsection *rsp, char *keyname) {
18352153Sbp	struct rckey *p;
18452153Sbp
18552153Sbp	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
18652153Sbp		if (strcmp(p->rk_name, keyname)==0)
18752153Sbp			return p;
18852153Sbp	return NULL;
18952153Sbp}
19052153Sbp
19152153Sbpstatic struct rckey *
19252153Sbprc_sect_addkey(struct rcsection *rsp, char *name, char *value) {
19352153Sbp	struct rckey *p;
19452153Sbp
19552153Sbp	p = rc_sect_findkey(rsp, name);
19652153Sbp	if (p) {
19752153Sbp		free(p->rk_value);
19852153Sbp	} else {
19952153Sbp		p = malloc(sizeof(*p));
20052153Sbp		if (!p) return NULL;
20152153Sbp		SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
20252153Sbp		p->rk_name = strdup(name);
20352153Sbp	}
20452153Sbp	p->rk_value = value ? strdup(value) : strdup("");
20552153Sbp	return p;
20652153Sbp}
20752153Sbp
20852153Sbpvoid
20952153Sbprc_sect_delkey(struct rcsection *rsp, struct rckey *p) {
21052153Sbp
21160938Sjake	SLIST_REMOVE(&rsp->rs_keys,p,rckey,rk_next);
21252153Sbp	rc_key_free(p);
21352153Sbp	return;
21452153Sbp}
21552153Sbp
21652153Sbpstatic void
21752153Sbprc_key_free(struct rckey *p){
21852153Sbp	free(p->rk_value);
21952153Sbp	free(p->rk_name);
22052153Sbp	free(p);
22152153Sbp}
22252153Sbp
22352153Sbpenum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
22452153Sbp
22552153Sbpstatic void
22652153Sbprc_parse(struct rcfile *rcp) {
22752153Sbp	FILE *f = rcp->rf_f;
22852153Sbp	int state = stNewLine, c;
22952153Sbp	struct rcsection *rsp = NULL;
23052153Sbp	struct rckey *rkp = NULL;
23152153Sbp	char buf[2048];
23252153Sbp	char *next = buf, *last = &buf[sizeof(buf)-1];
23352153Sbp
23452153Sbp	while ((c = getc (f)) != EOF) {
23552153Sbp		if (c == '\r')
23652153Sbp			continue;
23752153Sbp		if (state == stNewLine) {
23852153Sbp			next = buf;
23952153Sbp			if (isspace(c))
24052153Sbp				continue;	/* skip leading junk */
24152153Sbp			if (c == '[') {
24252153Sbp				state = stHeader;
24352153Sbp				rsp = NULL;
24452153Sbp				continue;
24552153Sbp			}
24652153Sbp			if (c == '#' || c == ';') {
24752153Sbp				state = stSkipToEOL;
24852153Sbp			} else {		/* something meaningfull */
24952153Sbp				state = stGetKey;
25052153Sbp			}
25152153Sbp		}
25252153Sbp		if (state == stSkipToEOL || next == last) {/* ignore long lines */
25352153Sbp			if (c == '\n'){
25452153Sbp				state = stNewLine;
25552153Sbp				next = buf;
25652153Sbp			}
25752153Sbp			continue;
25852153Sbp		}
25952153Sbp		if (state == stHeader) {
26052153Sbp			if (c == ']') {
26152153Sbp				*next = 0;
26252153Sbp				next = buf;
26352153Sbp				rsp = rc_addsect(rcp, buf);
26452153Sbp				state = stSkipToEOL;
26552153Sbp			} else
26652153Sbp				*next++ = c;
26752153Sbp			continue;
26852153Sbp		}
26952153Sbp		if (state == stGetKey) {
27052153Sbp			if (c == ' ' || c == '\t')/* side effect: 'key name='*/
27152153Sbp				continue;	  /* become 'keyname=' 	     */
27252153Sbp			if (c == '\n') {		/* silently ignore ... */
27352153Sbp				state = stNewLine;
27452153Sbp				continue;
27552153Sbp			}
27652153Sbp			if (c != '=') {
27752153Sbp				*next++ = c;
27852153Sbp				continue;
27952153Sbp			}
28052153Sbp			*next = 0;
28152153Sbp			if (rsp == NULL) {
28252153Sbp				fprintf(stderr, "Key '%s' defined before section\n", buf);
28352153Sbp				state = stSkipToEOL;
28452153Sbp				continue;
28552153Sbp			}
28652153Sbp			rkp = rc_sect_addkey(rsp, buf, NULL);
28752153Sbp			next = buf;
28852153Sbp			state = stGetValue;
28952153Sbp			continue;
29052153Sbp		}
29152153Sbp		/* only stGetValue left */
29252153Sbp		if (state != stGetValue) {
29352153Sbp			fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name);
29452153Sbp			state = stSkipToEOL;
29552153Sbp		}
29652153Sbp		if (c != '\n') {
29752153Sbp			*next++ = c;
29852153Sbp			continue;
29952153Sbp		}
30052153Sbp		*next = 0;
30152153Sbp		rkp->rk_value = strdup(buf);
30252153Sbp		state = stNewLine;
30352153Sbp		rkp = NULL;
30452153Sbp	} 	/* while */
30552153Sbp	if (c == EOF && state == stGetValue) {
30652153Sbp		*next = 0;
30752153Sbp		rkp->rk_value = strdup(buf);
30852153Sbp	}
30952153Sbp	return;
31052153Sbp}
31152153Sbp
31252153Sbpint
31352153Sbprc_getstringptr(struct rcfile *rcp,char *section, char *key,char **dest) {
31452153Sbp	struct rcsection *rsp;
31552153Sbp	struct rckey *rkp;
31652153Sbp
31752153Sbp	*dest = NULL;
31852153Sbp	rsp = rc_findsect(rcp, section);
31952153Sbp	if (!rsp) return ENOENT;
32052153Sbp	rkp = rc_sect_findkey(rsp,key);
32152153Sbp	if (!rkp) return ENOENT;
32252153Sbp	*dest = rkp->rk_value;
32352153Sbp	return 0;
32452153Sbp}
32552153Sbp
32652153Sbpint
32752153Sbprc_getstring(struct rcfile *rcp,char *section, char *key,int maxlen,char *dest) {
32852153Sbp	char *value;
32952153Sbp	int error;
33052153Sbp
33152153Sbp	error = rc_getstringptr(rcp, section, key, &value);
33252153Sbp	if (error) return error;
33352153Sbp	if (strlen(value) >= maxlen) {
33452153Sbp		fprintf(stderr, "line too long for key '%s' in section '%s', max = %d\n",key, section, maxlen);
33552153Sbp		return EINVAL;
33652153Sbp	}
33752153Sbp	strcpy(dest,value);
33852153Sbp	return 0;
33952153Sbp}
34052153Sbp
34152153Sbpint
34252153Sbprc_getint(struct rcfile *rcp,char *section, char *key,int *value) {
34352153Sbp	struct rcsection *rsp;
34452153Sbp	struct rckey *rkp;
34552153Sbp
34652153Sbp	rsp = rc_findsect(rcp, section);
34752153Sbp	if (!rsp) return ENOENT;
34852153Sbp	rkp = rc_sect_findkey(rsp,key);
34952153Sbp	if (!rkp) return ENOENT;
35052153Sbp	errno = 0;
35152153Sbp	*value = strtol(rkp->rk_value,NULL,0);
35252153Sbp	if (errno) {
35352153Sbp		fprintf(stderr, "invalid int value '%s' for key '%s' in section '%s'\n",rkp->rk_value,key,section);
35452153Sbp		return errno;
35552153Sbp	}
35652153Sbp	return 0;
35752153Sbp}
35852153Sbp
35952153Sbp/*
36052153Sbp * 1,yes,true
36152153Sbp * 0,no,false
36252153Sbp */
36352153Sbpint
36452153Sbprc_getbool(struct rcfile *rcp,char *section, char *key,int *value) {
36552153Sbp	struct rcsection *rsp;
36652153Sbp	struct rckey *rkp;
36752153Sbp	char *p;
36852153Sbp
36952153Sbp	rsp = rc_findsect(rcp, section);
37052153Sbp	if (!rsp) return ENOENT;
37152153Sbp	rkp = rc_sect_findkey(rsp,key);
37252153Sbp	if (!rkp) return ENOENT;
37352153Sbp	p = rkp->rk_value;
37452153Sbp	while (*p && isspace(*p)) p++;
37552153Sbp	if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) {
37652153Sbp		*value = 0;
37752153Sbp		return 0;
37852153Sbp	}
37952153Sbp	if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) {
38052153Sbp		*value = 1;
38152153Sbp		return 0;
38252153Sbp	}
38352153Sbp	fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section);
38452153Sbp	return EINVAL;
38552153Sbp}
38652153Sbp
38752153Sbp/*
38852153Sbp * first read ~/.nwfsrc, next try to merge NWFS_CFG_FILE
38952153Sbp */
39052153Sbpint
39152153Sbpncp_open_rcfile(void) {
39252153Sbp	char *home, *fn;
39352153Sbp	int error;
39452153Sbp
39552153Sbp	home = getenv("HOME");
39652153Sbp	if (home) {
39752153Sbp		fn = malloc(strlen(home) + 20);
39852153Sbp		sprintf(fn, "%s/.nwfsrc", home);
39952153Sbp		error = rc_open(fn,"r",&ncp_rc);
40052153Sbp		free (fn);
40152153Sbp	}
40252153Sbp	error = rc_merge(NWFS_CFG_FILE, &ncp_rc);
40352153Sbp	if( ncp_rc == NULL ) {
40452153Sbp		printf("Warning: no cfg files found.\n");
40552153Sbp		return 1;
40652153Sbp	}
40752153Sbp	return 0;
40852153Sbp}
40952153Sbp
410