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