conf.c revision 1.3 1 /* $NetBSD: conf.c,v 1.3 1995/03/18 14:57:52 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 * All rights reserved.
7 *
8 * This code is derived from software donated to Berkeley by
9 * Jan-Simon Pendry.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * from: Id: conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp
40 * @(#)conf.c 8.2 (Berkeley) 3/27/94
41 */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <limits.h>
49 #include <regexp.h>
50 #include <sys/types.h>
51 #include <sys/param.h>
52 #include <sys/syslog.h>
53
54 #include "portald.h"
55
56 #define ALLOC(ty) (xmalloc(sizeof(ty)))
57
58 typedef struct path path;
59 struct path {
60 qelem p_q; /* 2-way linked list */
61 int p_lno; /* Line number of this record */
62 char *p_args; /* copy of arg string (malloc) */
63 char *p_key; /* Pathname to match (also p_argv[0]) */
64 regexp *p_re; /* RE to match against pathname (malloc) */
65 int p_argc; /* number of elements in arg string */
66 char **p_argv; /* argv[] pointers into arg string (malloc) */
67 };
68
69 static char *conf_file; /* XXX for regerror */
70 static path *curp; /* XXX for regerror */
71
72 /*
73 * Add an element to a 2-way list,
74 * just after (pred)
75 */
76 static void ins_que(elem, pred)
77 qelem *elem, *pred;
78 {
79 qelem *p = pred->q_forw;
80 elem->q_back = pred;
81 elem->q_forw = p;
82 pred->q_forw = elem;
83 p->q_back = elem;
84 }
85
86 /*
87 * Remove an element from a 2-way list
88 */
89 static void rem_que(elem)
90 qelem *elem;
91 {
92 qelem *p = elem->q_forw;
93 qelem *p2 = elem->q_back;
94 p2->q_forw = p;
95 p->q_back = p2;
96 }
97
98 /*
99 * Error checking malloc
100 */
101 static void *xmalloc(siz)
102 unsigned siz;
103 {
104 void *p = malloc(siz);
105 if (p)
106 return (p);
107 syslog(LOG_ALERT, "malloc: failed to get %d bytes", siz);
108 exit(1);
109 }
110
111 /*
112 * Insert the path in the list.
113 * If there is already an element with the same key then
114 * the *second* one is ignored (return 0). If the key is
115 * not found then the path is added to the end of the list
116 * and 1 is returned.
117 */
118 static int pinsert(p0, q0)
119 path *p0;
120 qelem *q0;
121 {
122 qelem *q;
123
124 if (p0->p_argc == 0)
125 return (0);
126
127 for (q = q0->q_forw; q != q0; q = q->q_forw) {
128 path *p = (path *) q;
129 if (strcmp(p->p_key, p0->p_key) == 0)
130 return (0);
131 }
132 ins_que(&p0->p_q, q0->q_back);
133 return (1);
134
135 }
136
137 void regerror(s)
138 const char *s;
139 {
140 syslog(LOG_ERR, "%s:%s: regcomp %s: %s",
141 conf_file, curp->p_lno, curp->p_key, s);
142 }
143
144 static path *palloc(cline, lno)
145 char *cline;
146 int lno;
147 {
148 int c;
149 char *s;
150 char *key;
151 path *p;
152 char **ap;
153
154 /*
155 * Implement comment chars
156 */
157 s = strchr(cline, '#');
158 if (s)
159 *s = 0;
160
161 /*
162 * Do a pass through the string to count the number
163 * of arguments
164 */
165 c = 0;
166 key = strdup(cline);
167 for (s = key; s != NULL; ) {
168 char *val;
169 while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
170 ;
171 if (val)
172 c++;
173 }
174 c++;
175 free(key);
176
177 if (c <= 1)
178 return (0);
179
180 /*
181 * Now do another pass and generate a new path structure
182 */
183 p = ALLOC(path);
184 p->p_argc = 0;
185 p->p_argv = xmalloc(c * sizeof(char *));
186 p->p_args = strdup(cline);
187 ap = p->p_argv;
188 for (s = p->p_args; s != NULL; ) {
189 char *val;
190 while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
191 ;
192 if (val) {
193 *ap++ = val;
194 p->p_argc++;
195 }
196 }
197 *ap = 0;
198
199 #ifdef DEBUG
200 for (c = 0; c < p->p_argc; c++)
201 printf("%sv[%d] = %s\n", c?"\t":"", c, p->p_argv[c]);
202 #endif
203
204 p->p_key = p->p_argv[0];
205 if (strpbrk(p->p_key, RE_CHARS)) {
206 curp = p; /* XXX */
207 p->p_re = regcomp(p->p_key);
208 curp = 0; /* XXX */
209 } else {
210 p->p_re = 0;
211 }
212 p->p_lno = lno;
213
214 return (p);
215 }
216
217 /*
218 * Free a path structure
219 */
220 static void pfree(p)
221 path *p;
222 {
223 free(p->p_args);
224 if (p->p_re)
225 free((char *) p->p_re);
226 free((char *) p->p_argv);
227 free((char *) p);
228 }
229
230 /*
231 * Discard all currently held path structures on q0.
232 * and add all the ones on xq.
233 */
234 static void preplace(q0, xq)
235 qelem *q0;
236 qelem *xq;
237 {
238 /*
239 * While the list is not empty,
240 * take the first element off the list
241 * and free it.
242 */
243 while (q0->q_forw != q0) {
244 qelem *q = q0->q_forw;
245 rem_que(q);
246 pfree((path *) q);
247 }
248 while (xq->q_forw != xq) {
249 qelem *q = xq->q_forw;
250 rem_que(q);
251 ins_que(q, q0);
252 }
253 }
254
255 /*
256 * Read the lines from the configuration file and
257 * add them to the list of paths.
258 */
259 static void readfp(q0, fp)
260 qelem *q0;
261 FILE *fp;
262 {
263 char cline[LINE_MAX];
264 int nread = 0;
265 qelem q;
266
267 /*
268 * Make a new empty list.
269 */
270 q.q_forw = q.q_back = &q;
271
272 /*
273 * Read the lines from the configuration file.
274 */
275 while (fgets(cline, sizeof(cline), fp)) {
276 path *p = palloc(cline, nread+1);
277 if (p && !pinsert(p, &q))
278 pfree(p);
279 nread++;
280 }
281
282 /*
283 * If some records were read, then throw
284 * away the old list and replace with the
285 * new one.
286 */
287 if (nread)
288 preplace(q0, &q);
289 }
290
291 /*
292 * Read the configuration file (conf) and replace
293 * the existing path list with the new version.
294 * If the file is not readable, then no changes take place
295 */
296 void conf_read(q, conf)
297 qelem *q;
298 char *conf;
299 {
300 FILE *fp = fopen(conf, "r");
301 if (fp) {
302 conf_file = conf; /* XXX */
303 readfp(q, fp);
304 conf_file = 0; /* XXX */
305 (void) fclose(fp);
306 } else {
307 syslog(LOG_ERR, "open config file \"%s\": %s", conf, strerror(errno));
308 }
309 }
310
311
312 char **conf_match(q0, key)
313 qelem *q0;
314 char *key;
315 {
316 qelem *q;
317
318 for (q = q0->q_forw; q != q0; q = q->q_forw) {
319 path *p = (path *) q;
320 if (p->p_re) {
321 if (regexec(p->p_re, key))
322 return (p->p_argv+1);
323 } else {
324 if (strncmp(p->p_key, key, strlen(p->p_key)) == 0)
325 return (p->p_argv+1);
326 }
327 }
328
329 return (0);
330 }
331