1 /*
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 * All rights reserved.
5 *
6 * This code is derived from software donated to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * %sccs.include.redist.c%
10 *
11 * @(#)conf.c 8.2 (Berkeley) 03/27/94
12 *
13 * $Id: conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <limits.h>
22 #include <regexp.h>
23 #include <sys/types.h>
24 #include <sys/param.h>
25 #include <sys/syslog.h>
26
27 #include "portald.h"
28
29 #define ALLOC(ty) (xmalloc(sizeof(ty)))
30
31 typedef struct path path;
32 struct path {
33 qelem p_q; /* 2-way linked list */
34 int p_lno; /* Line number of this record */
35 char *p_args; /* copy of arg string (malloc) */
36 char *p_key; /* Pathname to match (also p_argv[0]) */
37 regexp *p_re; /* RE to match against pathname (malloc) */
38 int p_argc; /* number of elements in arg string */
39 char **p_argv; /* argv[] pointers into arg string (malloc) */
40 };
41
42 static char *conf_file; /* XXX for regerror */
43 static path *curp; /* XXX for regerror */
44
45 /*
46 * Add an element to a 2-way list,
47 * just after (pred)
48 */
ins_que(elem,pred)49 static void ins_que(elem, pred)
50 qelem *elem, *pred;
51 {
52 qelem *p = pred->q_forw;
53 elem->q_back = pred;
54 elem->q_forw = p;
55 pred->q_forw = elem;
56 p->q_back = elem;
57 }
58
59 /*
60 * Remove an element from a 2-way list
61 */
rem_que(elem)62 static void rem_que(elem)
63 qelem *elem;
64 {
65 qelem *p = elem->q_forw;
66 qelem *p2 = elem->q_back;
67 p2->q_forw = p;
68 p->q_back = p2;
69 }
70
71 /*
72 * Error checking malloc
73 */
xmalloc(siz)74 static void *xmalloc(siz)
75 unsigned siz;
76 {
77 void *p = malloc(siz);
78 if (p)
79 return (p);
80 syslog(LOG_ALERT, "malloc: failed to get %d bytes", siz);
81 exit(1);
82 }
83
84 /*
85 * Insert the path in the list.
86 * If there is already an element with the same key then
87 * the *second* one is ignored (return 0). If the key is
88 * not found then the path is added to the end of the list
89 * and 1 is returned.
90 */
pinsert(p0,q0)91 static int pinsert(p0, q0)
92 path *p0;
93 qelem *q0;
94 {
95 qelem *q;
96
97 if (p0->p_argc == 0)
98 return (0);
99
100 for (q = q0->q_forw; q != q0; q = q->q_forw) {
101 path *p = (path *) q;
102 if (strcmp(p->p_key, p0->p_key) == 0)
103 return (0);
104 }
105 ins_que(&p0->p_q, q0->q_back);
106 return (1);
107
108 }
109
regerror(s)110 void regerror(s)
111 const char *s;
112 {
113 syslog(LOG_ERR, "%s:%s: regcomp %s: %s",
114 conf_file, curp->p_lno, curp->p_key, s);
115 }
116
palloc(cline,lno)117 static path *palloc(cline, lno)
118 char *cline;
119 int lno;
120 {
121 int c;
122 char *s;
123 char *key;
124 path *p;
125 char **ap;
126
127 /*
128 * Implement comment chars
129 */
130 s = strchr(cline, '#');
131 if (s)
132 *s = 0;
133
134 /*
135 * Do a pass through the string to count the number
136 * of arguments
137 */
138 c = 0;
139 key = strdup(cline);
140 for (s = key; s != NULL; ) {
141 char *val;
142 while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
143 ;
144 if (val)
145 c++;
146 }
147 c++;
148 free(key);
149
150 if (c <= 1)
151 return (0);
152
153 /*
154 * Now do another pass and generate a new path structure
155 */
156 p = ALLOC(path);
157 p->p_argc = 0;
158 p->p_argv = xmalloc(c * sizeof(char *));
159 p->p_args = strdup(cline);
160 ap = p->p_argv;
161 for (s = p->p_args; s != NULL; ) {
162 char *val;
163 while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
164 ;
165 if (val) {
166 *ap++ = val;
167 p->p_argc++;
168 }
169 }
170 *ap = 0;
171
172 #ifdef DEBUG
173 for (c = 0; c < p->p_argc; c++)
174 printf("%sv[%d] = %s\n", c?"\t":"", c, p->p_argv[c]);
175 #endif
176
177 p->p_key = p->p_argv[0];
178 if (strpbrk(p->p_key, RE_CHARS)) {
179 curp = p; /* XXX */
180 p->p_re = regcomp(p->p_key);
181 curp = 0; /* XXX */
182 } else {
183 p->p_re = 0;
184 }
185 p->p_lno = lno;
186
187 return (p);
188 }
189
190 /*
191 * Free a path structure
192 */
pfree(p)193 static void pfree(p)
194 path *p;
195 {
196 free(p->p_args);
197 if (p->p_re)
198 free((char *) p->p_re);
199 free((char *) p->p_argv);
200 free((char *) p);
201 }
202
203 /*
204 * Discard all currently held path structures on q0.
205 * and add all the ones on xq.
206 */
preplace(q0,xq)207 static void preplace(q0, xq)
208 qelem *q0;
209 qelem *xq;
210 {
211 /*
212 * While the list is not empty,
213 * take the first element off the list
214 * and free it.
215 */
216 while (q0->q_forw != q0) {
217 qelem *q = q0->q_forw;
218 rem_que(q);
219 pfree((path *) q);
220 }
221 while (xq->q_forw != xq) {
222 qelem *q = xq->q_forw;
223 rem_que(q);
224 ins_que(q, q0);
225 }
226 }
227
228 /*
229 * Read the lines from the configuration file and
230 * add them to the list of paths.
231 */
readfp(q0,fp)232 static void readfp(q0, fp)
233 qelem *q0;
234 FILE *fp;
235 {
236 char cline[LINE_MAX];
237 int nread = 0;
238 qelem q;
239
240 /*
241 * Make a new empty list.
242 */
243 q.q_forw = q.q_back = &q;
244
245 /*
246 * Read the lines from the configuration file.
247 */
248 while (fgets(cline, sizeof(cline), fp)) {
249 path *p = palloc(cline, nread+1);
250 if (p && !pinsert(p, &q))
251 pfree(p);
252 nread++;
253 }
254
255 /*
256 * If some records were read, then throw
257 * away the old list and replace with the
258 * new one.
259 */
260 if (nread)
261 preplace(q0, &q);
262 }
263
264 /*
265 * Read the configuration file (conf) and replace
266 * the existing path list with the new version.
267 * If the file is not readable, then no changes take place
268 */
conf_read(q,conf)269 void conf_read(q, conf)
270 qelem *q;
271 char *conf;
272 {
273 FILE *fp = fopen(conf, "r");
274 if (fp) {
275 conf_file = conf; /* XXX */
276 readfp(q, fp);
277 conf_file = 0; /* XXX */
278 (void) fclose(fp);
279 } else {
280 syslog(LOG_ERR, "open config file \"%s\": %s", conf, strerror(errno));
281 }
282 }
283
284
conf_match(q0,key)285 char **conf_match(q0, key)
286 qelem *q0;
287 char *key;
288 {
289 qelem *q;
290
291 for (q = q0->q_forw; q != q0; q = q->q_forw) {
292 path *p = (path *) q;
293 if (p->p_re) {
294 if (regexec(p->p_re, key))
295 return (p->p_argv+1);
296 } else {
297 if (strncmp(p->p_key, key, strlen(p->p_key)) == 0)
298 return (p->p_argv+1);
299 }
300 }
301
302 return (0);
303 }
304