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