1 /* 2 * Copyright (c) 1992 The Regents of the University of California 3 * Copyright (c) 1990, 1992 Jan-Simon Pendry 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 5.1 (Berkeley) 07/13/92 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 */ 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 */ 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 */ 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 */ 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 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 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 */ 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 */ 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 = q->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 */ 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 */ 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 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