ncpl_rcfile.c revision 52153
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 *
3252153Sbp * $FreeBSD: head/lib/libncp/ncpl_rcfile.c 52153 1999-10-12 11:56:41Z bp $
3352153Sbp */
3452153Sbp#include <sys/types.h>
3552153Sbp#include <sys/queue.h>
3652153Sbp#include <ctype.h>
3752153Sbp#include <errno.h>
3852153Sbp#include <stdio.h>
3952153Sbp#include <string.h>
4052153Sbp#include <stdlib.h>
4152153Sbp#include <pwd.h>
4252153Sbp#include <unistd.h>
4352153Sbp
4452153Sbp#include <netncp/ncp_lib.h>
4552153Sbp#include <netncp/ncp_rcfile.h>
4652153Sbp#include <netncp/ncp_cfg.h>
4752153Sbp
4852153Sbp#define NWFS_CFG_FILE	NCP_PREFIX"/etc/nwfs.conf"
4952153Sbp
5052153Sbpstruct rcfile *ncp_rc = NULL;
5152153Sbp
5252153SbpSLIST_HEAD(rcfile_head, rcfile);
5352153Sbpstatic struct rcfile_head pf_head = {NULL};
5452153Sbp
5552153Sbpint rc_merge(char *filename,struct rcfile **rcfile);
5652153Sbpstatic struct rcfile* rc_find(char *filename);
5752153Sbpstatic struct rcsection *rc_findsect(struct rcfile *rcp, char *sectname);
5852153Sbpstatic struct rcsection *rc_addsect(struct rcfile *rcp, char *sectname);
5952153Sbpstatic int rc_sect_free(struct rcsection *rsp);
6052153Sbpstatic struct rckey *rc_sect_findkey(struct rcsection *rsp, char *keyname);
6152153Sbpstatic struct rckey *rc_sect_addkey(struct rcsection *rsp, char *name, char *value);
6252153Sbpstatic void rc_key_free(struct rckey *p);
6352153Sbpstatic void rc_parse(struct rcfile *rcp);
6452153Sbp
6552153Sbp
6652153Sbp/*
6752153Sbp * open rcfile and load its content, if already open - return previous handle
6852153Sbp */
6952153Sbpint
7052153Sbprc_open(char *filename,char *mode,struct rcfile **rcfile) {
7152153Sbp	struct rcfile *rcp;
7252153Sbp	FILE *f;
7352153Sbp
7452153Sbp	rcp = rc_find(filename);
7552153Sbp	if( rcp ) {
7652153Sbp		*rcfile = rcp;
7752153Sbp		return 0;
7852153Sbp	}
7952153Sbp	f = fopen (filename, mode);
8052153Sbp	if (f==NULL)
8152153Sbp		return errno;
8252153Sbp	rcp = malloc(sizeof(struct rcfile));
8352153Sbp	if (rcp==NULL) {
8452153Sbp		fclose(f);
8552153Sbp		return ENOMEM;
8652153Sbp	}
8752153Sbp	bzero(rcp, sizeof(struct rcfile));
8852153Sbp	rcp->rf_name = strdup (filename);
8952153Sbp	rcp->rf_f = f;
9052153Sbp	SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
9152153Sbp	rc_parse(rcp);
9252153Sbp	*rcfile = rcp;
9352153Sbp	return 0;
9452153Sbp}
9552153Sbp
9652153Sbpint
9752153Sbprc_merge(char *filename,struct rcfile **rcfile) {
9852153Sbp	struct rcfile *rcp = *rcfile;
9952153Sbp	FILE *f, *t;
10052153Sbp
10152153Sbp	if (rcp == NULL) {
10252153Sbp		return rc_open(filename,"r",rcfile);
10352153Sbp	}
10452153Sbp	f = fopen (filename, "r");
10552153Sbp	if (f==NULL)
10652153Sbp		return errno;
10752153Sbp	t = rcp->rf_f;
10852153Sbp	rcp->rf_f = f;
10952153Sbp	rc_parse(rcp);
11052153Sbp	rcp->rf_f = t;
11152153Sbp	fclose(f);
11252153Sbp	return 0;
11352153Sbp}
11452153Sbp
11552153Sbpint
11652153Sbprc_close(struct rcfile *rcp) {
11752153Sbp	struct rcsection *p,*n;
11852153Sbp
11952153Sbp	fclose(rcp->rf_f);
12052153Sbp	for(p = SLIST_FIRST(&rcp->rf_sect);p;) {
12152153Sbp		n = p;
12252153Sbp		p = SLIST_NEXT(p,rs_next);
12352153Sbp		rc_sect_free(n);
12452153Sbp	}
12552153Sbp	free(rcp->rf_name);
12652153Sbp	SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
12752153Sbp	free(rcp);
12852153Sbp	return 0;
12952153Sbp}
13052153Sbp
13152153Sbpstatic struct rcfile*
13252153Sbprc_find(char *filename) {
13352153Sbp	struct rcfile *p;
13452153Sbp
13552153Sbp	SLIST_FOREACH(p, &pf_head, rf_next)
13652153Sbp		if (strcmp (filename, p->rf_name)==0)
13752153Sbp			return p;
13852153Sbp	return 0;
13952153Sbp}
14052153Sbp
14152153Sbpstatic struct rcsection *
14252153Sbprc_findsect(struct rcfile *rcp, char *sectname) {
14352153Sbp	struct rcsection *p;
14452153Sbp
14552153Sbp	SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
14652153Sbp		if (strcmp(p->rs_name, sectname)==0)
14752153Sbp			return p;
14852153Sbp	return NULL;
14952153Sbp}
15052153Sbp
15152153Sbpstatic struct rcsection *
15252153Sbprc_addsect(struct rcfile *rcp, char *sectname) {
15352153Sbp	struct rcsection *p;
15452153Sbp
15552153Sbp	p = rc_findsect(rcp, sectname);
15652153Sbp	if (p) return p;
15752153Sbp	p = malloc(sizeof(*p));
15852153Sbp	if (!p) return NULL;
15952153Sbp	p->rs_name = strdup(sectname);
16052153Sbp	SLIST_INIT(&p->rs_keys);
16152153Sbp	SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
16252153Sbp	return p;
16352153Sbp}
16452153Sbp
16552153Sbpstatic int
16652153Sbprc_sect_free(struct rcsection *rsp) {
16752153Sbp	struct rckey *p,*n;
16852153Sbp
16952153Sbp	for(p = SLIST_FIRST(&rsp->rs_keys);p;) {
17052153Sbp		n = p;
17152153Sbp		p = SLIST_NEXT(p,rk_next);
17252153Sbp		rc_key_free(n);
17352153Sbp	}
17452153Sbp	free(rsp->rs_name);
17552153Sbp	free(rsp);
17652153Sbp	return 0;
17752153Sbp}
17852153Sbp
17952153Sbpstatic struct rckey *
18052153Sbprc_sect_findkey(struct rcsection *rsp, char *keyname) {
18152153Sbp	struct rckey *p;
18252153Sbp
18352153Sbp	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
18452153Sbp		if (strcmp(p->rk_name, keyname)==0)
18552153Sbp			return p;
18652153Sbp	return NULL;
18752153Sbp}
18852153Sbp
18952153Sbpstatic struct rckey *
19052153Sbprc_sect_addkey(struct rcsection *rsp, char *name, char *value) {
19152153Sbp	struct rckey *p;
19252153Sbp
19352153Sbp	p = rc_sect_findkey(rsp, name);
19452153Sbp	if (p) {
19552153Sbp		free(p->rk_value);
19652153Sbp	} else {
19752153Sbp		p = malloc(sizeof(*p));
19852153Sbp		if (!p) return NULL;
19952153Sbp		SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
20052153Sbp		p->rk_name = strdup(name);
20152153Sbp	}
20252153Sbp	p->rk_value = value ? strdup(value) : strdup("");
20352153Sbp	return p;
20452153Sbp}
20552153Sbp
20652153Sbpvoid
20752153Sbprc_sect_delkey(struct rcsection *rsp, struct rckey *p) {
20852153Sbp
20952153Sbp	SLIST_REMOVE(&rsp->rs_keys,p,rckey,rk_next);
21052153Sbp	rc_key_free(p);
21152153Sbp	return;
21252153Sbp}
21352153Sbp
21452153Sbpstatic void
21552153Sbprc_key_free(struct rckey *p){
21652153Sbp	free(p->rk_value);
21752153Sbp	free(p->rk_name);
21852153Sbp	free(p);
21952153Sbp}
22052153Sbp
22152153Sbpenum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
22252153Sbp
22352153Sbpstatic void
22452153Sbprc_parse(struct rcfile *rcp) {
22552153Sbp	FILE *f = rcp->rf_f;
22652153Sbp	int state = stNewLine, c;
22752153Sbp	struct rcsection *rsp = NULL;
22852153Sbp	struct rckey *rkp = NULL;
22952153Sbp	char buf[2048];
23052153Sbp	char *next = buf, *last = &buf[sizeof(buf)-1];
23152153Sbp
23252153Sbp	while ((c = getc (f)) != EOF) {
23352153Sbp		if (c == '\r')
23452153Sbp			continue;
23552153Sbp		if (state == stNewLine) {
23652153Sbp			next = buf;
23752153Sbp			if (isspace(c))
23852153Sbp				continue;	/* skip leading junk */
23952153Sbp			if (c == '[') {
24052153Sbp				state = stHeader;
24152153Sbp				rsp = NULL;
24252153Sbp				continue;
24352153Sbp			}
24452153Sbp			if (c == '#' || c == ';') {
24552153Sbp				state = stSkipToEOL;
24652153Sbp			} else {		/* something meaningfull */
24752153Sbp				state = stGetKey;
24852153Sbp			}
24952153Sbp		}
25052153Sbp		if (state == stSkipToEOL || next == last) {/* ignore long lines */
25152153Sbp			if (c == '\n'){
25252153Sbp				state = stNewLine;
25352153Sbp				next = buf;
25452153Sbp			}
25552153Sbp			continue;
25652153Sbp		}
25752153Sbp		if (state == stHeader) {
25852153Sbp			if (c == ']') {
25952153Sbp				*next = 0;
26052153Sbp				next = buf;
26152153Sbp				rsp = rc_addsect(rcp, buf);
26252153Sbp				state = stSkipToEOL;
26352153Sbp			} else
26452153Sbp				*next++ = c;
26552153Sbp			continue;
26652153Sbp		}
26752153Sbp		if (state == stGetKey) {
26852153Sbp			if (c == ' ' || c == '\t')/* side effect: 'key name='*/
26952153Sbp				continue;	  /* become 'keyname=' 	     */
27052153Sbp			if (c == '\n') {		/* silently ignore ... */
27152153Sbp				state = stNewLine;
27252153Sbp				continue;
27352153Sbp			}
27452153Sbp			if (c != '=') {
27552153Sbp				*next++ = c;
27652153Sbp				continue;
27752153Sbp			}
27852153Sbp			*next = 0;
27952153Sbp			if (rsp == NULL) {
28052153Sbp				fprintf(stderr, "Key '%s' defined before section\n", buf);
28152153Sbp				state = stSkipToEOL;
28252153Sbp				continue;
28352153Sbp			}
28452153Sbp			rkp = rc_sect_addkey(rsp, buf, NULL);
28552153Sbp			next = buf;
28652153Sbp			state = stGetValue;
28752153Sbp			continue;
28852153Sbp		}
28952153Sbp		/* only stGetValue left */
29052153Sbp		if (state != stGetValue) {
29152153Sbp			fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name);
29252153Sbp			state = stSkipToEOL;
29352153Sbp		}
29452153Sbp		if (c != '\n') {
29552153Sbp			*next++ = c;
29652153Sbp			continue;
29752153Sbp		}
29852153Sbp		*next = 0;
29952153Sbp		rkp->rk_value = strdup(buf);
30052153Sbp		state = stNewLine;
30152153Sbp		rkp = NULL;
30252153Sbp	} 	/* while */
30352153Sbp	if (c == EOF && state == stGetValue) {
30452153Sbp		*next = 0;
30552153Sbp		rkp->rk_value = strdup(buf);
30652153Sbp	}
30752153Sbp	return;
30852153Sbp}
30952153Sbp
31052153Sbpint
31152153Sbprc_getstringptr(struct rcfile *rcp,char *section, char *key,char **dest) {
31252153Sbp	struct rcsection *rsp;
31352153Sbp	struct rckey *rkp;
31452153Sbp
31552153Sbp	*dest = NULL;
31652153Sbp	rsp = rc_findsect(rcp, section);
31752153Sbp	if (!rsp) return ENOENT;
31852153Sbp	rkp = rc_sect_findkey(rsp,key);
31952153Sbp	if (!rkp) return ENOENT;
32052153Sbp	*dest = rkp->rk_value;
32152153Sbp	return 0;
32252153Sbp}
32352153Sbp
32452153Sbpint
32552153Sbprc_getstring(struct rcfile *rcp,char *section, char *key,int maxlen,char *dest) {
32652153Sbp	char *value;
32752153Sbp	int error;
32852153Sbp
32952153Sbp	error = rc_getstringptr(rcp, section, key, &value);
33052153Sbp	if (error) return error;
33152153Sbp	if (strlen(value) >= maxlen) {
33252153Sbp		fprintf(stderr, "line too long for key '%s' in section '%s', max = %d\n",key, section, maxlen);
33352153Sbp		return EINVAL;
33452153Sbp	}
33552153Sbp	strcpy(dest,value);
33652153Sbp	return 0;
33752153Sbp}
33852153Sbp
33952153Sbpint
34052153Sbprc_getint(struct rcfile *rcp,char *section, char *key,int *value) {
34152153Sbp	struct rcsection *rsp;
34252153Sbp	struct rckey *rkp;
34352153Sbp
34452153Sbp	rsp = rc_findsect(rcp, section);
34552153Sbp	if (!rsp) return ENOENT;
34652153Sbp	rkp = rc_sect_findkey(rsp,key);
34752153Sbp	if (!rkp) return ENOENT;
34852153Sbp	errno = 0;
34952153Sbp	*value = strtol(rkp->rk_value,NULL,0);
35052153Sbp	if (errno) {
35152153Sbp		fprintf(stderr, "invalid int value '%s' for key '%s' in section '%s'\n",rkp->rk_value,key,section);
35252153Sbp		return errno;
35352153Sbp	}
35452153Sbp	return 0;
35552153Sbp}
35652153Sbp
35752153Sbp/*
35852153Sbp * 1,yes,true
35952153Sbp * 0,no,false
36052153Sbp */
36152153Sbpint
36252153Sbprc_getbool(struct rcfile *rcp,char *section, char *key,int *value) {
36352153Sbp	struct rcsection *rsp;
36452153Sbp	struct rckey *rkp;
36552153Sbp	char *p;
36652153Sbp
36752153Sbp	rsp = rc_findsect(rcp, section);
36852153Sbp	if (!rsp) return ENOENT;
36952153Sbp	rkp = rc_sect_findkey(rsp,key);
37052153Sbp	if (!rkp) return ENOENT;
37152153Sbp	p = rkp->rk_value;
37252153Sbp	while (*p && isspace(*p)) p++;
37352153Sbp	if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) {
37452153Sbp		*value = 0;
37552153Sbp		return 0;
37652153Sbp	}
37752153Sbp	if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) {
37852153Sbp		*value = 1;
37952153Sbp		return 0;
38052153Sbp	}
38152153Sbp	fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section);
38252153Sbp	return EINVAL;
38352153Sbp}
38452153Sbp
38552153Sbp/*
38652153Sbp * first read ~/.nwfsrc, next try to merge NWFS_CFG_FILE
38752153Sbp */
38852153Sbpint
38952153Sbpncp_open_rcfile(void) {
39052153Sbp	char *home, *fn;
39152153Sbp	int error;
39252153Sbp
39352153Sbp	home = getenv("HOME");
39452153Sbp	if (home) {
39552153Sbp		fn = malloc(strlen(home) + 20);
39652153Sbp		sprintf(fn, "%s/.nwfsrc", home);
39752153Sbp		error = rc_open(fn,"r",&ncp_rc);
39852153Sbp		free (fn);
39952153Sbp	}
40052153Sbp	error = rc_merge(NWFS_CFG_FILE, &ncp_rc);
40152153Sbp	if( ncp_rc == NULL ) {
40252153Sbp		printf("Warning: no cfg files found.\n");
40352153Sbp		return 1;
40452153Sbp	}
40552153Sbp	return 0;
40652153Sbp}
40752153Sbp
408