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