154851Spendry /* 2*61515Sbostic * Copyright (c) 1992, 1993 3*61515Sbostic * The Regents of the University of California. All rights reserved. 454851Spendry * All rights reserved. 554851Spendry * 654851Spendry * This code is derived from software donated to Berkeley by 754851Spendry * Jan-Simon Pendry. 854851Spendry * 954851Spendry * %sccs.include.redist.c% 1054851Spendry * 11*61515Sbostic * @(#)conf.c 8.1 (Berkeley) 06/05/93 1254851Spendry * 1354851Spendry * $Id: conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $ 1454851Spendry */ 1554851Spendry 1654851Spendry #include <stdio.h> 1754851Spendry #include <stdlib.h> 1854851Spendry #include <unistd.h> 1954851Spendry #include <string.h> 2054851Spendry #include <errno.h> 2154851Spendry #include <limits.h> 2254851Spendry #include <regexp.h> 2354851Spendry #include <sys/types.h> 2454979Spendry #include <sys/param.h> 2554851Spendry #include <sys/syslog.h> 2654851Spendry 2754851Spendry #include "portald.h" 2854851Spendry 2954851Spendry #define ALLOC(ty) (xmalloc(sizeof(ty))) 3054851Spendry 3154851Spendry typedef struct path path; 3254851Spendry struct path { 3354851Spendry qelem p_q; /* 2-way linked list */ 3454851Spendry int p_lno; /* Line number of this record */ 3554851Spendry char *p_args; /* copy of arg string (malloc) */ 3654851Spendry char *p_key; /* Pathname to match (also p_argv[0]) */ 3754851Spendry regexp *p_re; /* RE to match against pathname (malloc) */ 3854851Spendry int p_argc; /* number of elements in arg string */ 3954851Spendry char **p_argv; /* argv[] pointers into arg string (malloc) */ 4054851Spendry }; 4154851Spendry 4254851Spendry static char *conf_file; /* XXX for regerror */ 4354851Spendry static path *curp; /* XXX for regerror */ 4454851Spendry 4554851Spendry /* 4654851Spendry * Add an element to a 2-way list, 4754851Spendry * just after (pred) 4854851Spendry */ 4954851Spendry static void ins_que(elem, pred) 5054851Spendry qelem *elem, *pred; 5154851Spendry { 5254851Spendry qelem *p = pred->q_forw; 5354851Spendry elem->q_back = pred; 5454851Spendry elem->q_forw = p; 5554851Spendry pred->q_forw = elem; 5654851Spendry p->q_back = elem; 5754851Spendry } 5854851Spendry 5954851Spendry /* 6054851Spendry * Remove an element from a 2-way list 6154851Spendry */ 6254851Spendry static void rem_que(elem) 6354851Spendry qelem *elem; 6454851Spendry { 6554851Spendry qelem *p = elem->q_forw; 6654851Spendry qelem *p2 = elem->q_back; 6754851Spendry p2->q_forw = p; 6854851Spendry p->q_back = p2; 6954851Spendry } 7054851Spendry 7154851Spendry /* 7254851Spendry * Error checking malloc 7354851Spendry */ 7454851Spendry static void *xmalloc(siz) 7554851Spendry unsigned siz; 7654851Spendry { 7754851Spendry void *p = malloc(siz); 7854851Spendry if (p) 7954851Spendry return (p); 8054851Spendry syslog(LOG_ALERT, "malloc: failed to get %d bytes", siz); 8154851Spendry exit(1); 8254851Spendry } 8354851Spendry 8454851Spendry /* 8554851Spendry * Insert the path in the list. 8654851Spendry * If there is already an element with the same key then 8754851Spendry * the *second* one is ignored (return 0). If the key is 8854851Spendry * not found then the path is added to the end of the list 8954851Spendry * and 1 is returned. 9054851Spendry */ 9154851Spendry static int pinsert(p0, q0) 9254851Spendry path *p0; 9354851Spendry qelem *q0; 9454851Spendry { 9554851Spendry qelem *q; 9654851Spendry 9754851Spendry if (p0->p_argc == 0) 9854851Spendry return (0); 9954851Spendry 10054851Spendry for (q = q0->q_forw; q != q0; q = q->q_forw) { 10154851Spendry path *p = (path *) q; 10254851Spendry if (strcmp(p->p_key, p0->p_key) == 0) 10354851Spendry return (0); 10454851Spendry } 10554851Spendry ins_que(&p0->p_q, q0->q_back); 10654851Spendry return (1); 10754851Spendry 10854851Spendry } 10954851Spendry 11054851Spendry void regerror(s) 11154851Spendry const char *s; 11254851Spendry { 11354851Spendry syslog(LOG_ERR, "%s:%s: regcomp %s: %s", 11454851Spendry conf_file, curp->p_lno, curp->p_key, s); 11554851Spendry } 11654851Spendry 11754851Spendry static path *palloc(cline, lno) 11854851Spendry char *cline; 11954851Spendry int lno; 12054851Spendry { 12154851Spendry int c; 12254851Spendry char *s; 12354851Spendry char *key; 12454851Spendry path *p; 12554851Spendry char **ap; 12654851Spendry 12754851Spendry /* 12854851Spendry * Implement comment chars 12954851Spendry */ 13054851Spendry s = strchr(cline, '#'); 13154851Spendry if (s) 13254851Spendry *s = 0; 13354851Spendry 13454851Spendry /* 13554851Spendry * Do a pass through the string to count the number 13654851Spendry * of arguments 13754851Spendry */ 13854851Spendry c = 0; 13954851Spendry key = strdup(cline); 14054851Spendry for (s = key; s != NULL; ) { 14154851Spendry char *val; 14254851Spendry while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0') 14354851Spendry ; 14454851Spendry if (val) 14554851Spendry c++; 14654851Spendry } 14754851Spendry c++; 14854851Spendry free(key); 14954851Spendry 15054851Spendry if (c <= 1) 15154851Spendry return (0); 15254851Spendry 15354851Spendry /* 15454851Spendry * Now do another pass and generate a new path structure 15554851Spendry */ 15654851Spendry p = ALLOC(path); 15754851Spendry p->p_argc = 0; 15854851Spendry p->p_argv = xmalloc(c * sizeof(char *)); 15954851Spendry p->p_args = strdup(cline); 16054851Spendry ap = p->p_argv; 16154851Spendry for (s = p->p_args; s != NULL; ) { 16254851Spendry char *val; 16354851Spendry while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0') 16454851Spendry ; 16554851Spendry if (val) { 16654851Spendry *ap++ = val; 16754851Spendry p->p_argc++; 16854851Spendry } 16954851Spendry } 17054851Spendry *ap = 0; 17154851Spendry 17254851Spendry #ifdef DEBUG 17354851Spendry for (c = 0; c < p->p_argc; c++) 17454851Spendry printf("%sv[%d] = %s\n", c?"\t":"", c, p->p_argv[c]); 17554851Spendry #endif 17654851Spendry 17754851Spendry p->p_key = p->p_argv[0]; 17854851Spendry if (strpbrk(p->p_key, RE_CHARS)) { 17954851Spendry curp = p; /* XXX */ 18054851Spendry p->p_re = regcomp(p->p_key); 18154851Spendry curp = 0; /* XXX */ 18254851Spendry } else { 18354851Spendry p->p_re = 0; 18454851Spendry } 18554851Spendry p->p_lno = lno; 18654851Spendry 18754851Spendry return (p); 18854851Spendry } 18954851Spendry 19054851Spendry /* 19154851Spendry * Free a path structure 19254851Spendry */ 19354851Spendry static void pfree(p) 19454851Spendry path *p; 19554851Spendry { 19654851Spendry free(p->p_args); 19754851Spendry if (p->p_re) 19854851Spendry free((char *) p->p_re); 19954851Spendry free((char *) p->p_argv); 20054851Spendry free((char *) p); 20154851Spendry } 20254851Spendry 20354851Spendry /* 20454851Spendry * Discard all currently held path structures on q0. 20554851Spendry * and add all the ones on xq. 20654851Spendry */ 20754851Spendry static void preplace(q0, xq) 20854851Spendry qelem *q0; 20954851Spendry qelem *xq; 21054851Spendry { 21154851Spendry /* 21254851Spendry * While the list is not empty, 21354851Spendry * take the first element off the list 21454851Spendry * and free it. 21554851Spendry */ 21654851Spendry while (q0->q_forw != q0) { 21754851Spendry qelem *q = q->q_forw; 21854851Spendry rem_que(q); 21954851Spendry pfree((path *) q); 22054851Spendry } 22154851Spendry while (xq->q_forw != xq) { 22254851Spendry qelem *q = xq->q_forw; 22354851Spendry rem_que(q); 22454851Spendry ins_que(q, q0); 22554851Spendry } 22654851Spendry } 22754851Spendry 22854851Spendry /* 22954851Spendry * Read the lines from the configuration file and 23054851Spendry * add them to the list of paths. 23154851Spendry */ 23254851Spendry static void readfp(q0, fp) 23354851Spendry qelem *q0; 23454851Spendry FILE *fp; 23554851Spendry { 23654851Spendry char cline[LINE_MAX]; 23754851Spendry int nread = 0; 23854851Spendry qelem q; 23954851Spendry 24054851Spendry /* 24154851Spendry * Make a new empty list. 24254851Spendry */ 24354851Spendry q.q_forw = q.q_back = &q; 24454851Spendry 24554851Spendry /* 24654851Spendry * Read the lines from the configuration file. 24754851Spendry */ 24854851Spendry while (fgets(cline, sizeof(cline), fp)) { 24954851Spendry path *p = palloc(cline, nread+1); 25054851Spendry if (p && !pinsert(p, &q)) 25154851Spendry pfree(p); 25254851Spendry nread++; 25354851Spendry } 25454851Spendry 25554851Spendry /* 25654851Spendry * If some records were read, then throw 25754851Spendry * away the old list and replace with the 25854851Spendry * new one. 25954851Spendry */ 26054851Spendry if (nread) 26154851Spendry preplace(q0, &q); 26254851Spendry } 26354851Spendry 26454851Spendry /* 26554851Spendry * Read the configuration file (conf) and replace 26654851Spendry * the existing path list with the new version. 26754851Spendry * If the file is not readable, then no changes take place 26854851Spendry */ 26954851Spendry void conf_read(q, conf) 27054851Spendry qelem *q; 27154851Spendry char *conf; 27254851Spendry { 27354851Spendry FILE *fp = fopen(conf, "r"); 27454851Spendry if (fp) { 27554851Spendry conf_file = conf; /* XXX */ 27654851Spendry readfp(q, fp); 27754851Spendry conf_file = 0; /* XXX */ 27854851Spendry (void) fclose(fp); 27954851Spendry } else { 28054851Spendry syslog(LOG_ERR, "open config file \"%s\": %s", conf, strerror(errno)); 28154851Spendry } 28254851Spendry } 28354851Spendry 28454851Spendry 28554851Spendry char **conf_match(q0, key) 28654851Spendry qelem *q0; 28754851Spendry char *key; 28854851Spendry { 28954851Spendry qelem *q; 29054851Spendry 29154851Spendry for (q = q0->q_forw; q != q0; q = q->q_forw) { 29254851Spendry path *p = (path *) q; 29354851Spendry if (p->p_re) { 29454851Spendry if (regexec(p->p_re, key)) 29554851Spendry return (p->p_argv+1); 29654851Spendry } else { 29754851Spendry if (strncmp(p->p_key, key, strlen(p->p_key)) == 0) 29854851Spendry return (p->p_argv+1); 29954851Spendry } 30054851Spendry } 30154851Spendry 30254851Spendry return (0); 30354851Spendry } 304