chiark / gitweb /
www-cgi/: Coding style fixes
[userv-utils.git] / www-cgi / ucgicommon.c
1 /*
2  * Copyright (C) 1998-1999,2003 Ian Jackson
3  *
4  * This is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with userv-utils; if not, write to the Free Software
16  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * $Id$
19  */
20
21 #include <assert.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include <unistd.h>
29
30 #include "ucgi.h"
31
32 int debugmode= 0;
33
34 static void outerror(void) {
35   perror("stdout");
36   exit(debugmode ? 0 : -1);
37 }
38
39 void syserror(const char *m) {
40   if (printf("Content-Type: text/plain\n"
41              "Status: 500\n\n"
42              "ucgi: system call error:\n"
43              "%s: %s\n",
44              m,strerror(errno))==EOF || fflush(stdout)) outerror();
45   exit(0);
46 }
47
48 void error(const char *m, int st) {
49   if (printf("Content-Type: text/plain\n"
50              "Status: %d\n\n"
51              "ucgi: error:\n"
52              "%s\n",
53              st, m)==EOF || fflush(stdout)) outerror();
54   exit(0);
55 }
56
57 void *xmalloc(size_t sz) {
58   void *r;
59
60   r= malloc(sz);
61   if (!r) syserror("malloc failed");
62   return r;
63 }
64
65 void *xrealloc(void *ptr, size_t sz) {
66   void *r;
67
68   r= realloc(ptr,sz);
69   if (!r) syserror("realloc failed");
70   return r;
71 }
72
73 void xsetenv(const char *en, const char *ev, int overwrite) {
74   if (setenv(en,ev,overwrite)) syserror("setenv");
75 }
76
77 const char **load_filters(unsigned flags, const char *first, ...) {
78   va_list ap;
79   const char *name, *p, *q, **v;
80   char *pp;
81   size_t l, n, sz;
82   FILE *fp;
83   char buf[MAX_ENVVAR_NAME];
84
85   D( if (debugmode) printf(";; load_filters...\n"); )
86   va_start(ap, first);
87   for (name= first; name; name= va_arg(ap, const char *)) {
88     fp= fopen(name, "r"); if (fp) goto opened;
89     D( if (debugmode)
90          printf(";;   file `%s': %s\n", name, strerror(errno)); )
91     if (errno != ENOENT) syserror("failed to open environment filters");
92   }
93   va_end(ap);
94   if (flags & LOADF_MUST) syserror("failed to open environment filters");
95   D( if (debugmode) printf(";;   using default filters\n"); )
96   return 0;
97
98 opened:
99   va_end(ap);
100   D( if (debugmode) printf(";;   file `%s': OK\n", name); )
101
102   n= 0; sz= 128; v= xmalloc(sz * sizeof(*v));
103   for (;;) {
104     if (!fgets(buf, sizeof(buf), fp)) break;
105     l= strlen(buf);
106     if (buf[l - 1] == '\n') buf[--l]= 0;
107     if (l + 1 == sizeof(buf))
108       error("line too long in environment filter file", 500);
109     p= buf; q= p + l;
110     while (isspace((unsigned char)*p)) p++;
111     while (q > p && isspace((unsigned char)q[-1])) q--;
112     if (*p == '#' || p == q) continue;
113     l= q - p;
114     pp= xmalloc(l + 1);
115     memcpy(pp, p, l);
116     pp[l]= 0;
117     v[n++]= pp;
118     D( if (debugmode) printf(";;   filter: `%s'\n", pp); )
119     if (n >= sz) {
120       sz *= 2;
121       v= xrealloc(v, sz * sizeof(*v));
122     }
123   }
124   if (ferror(fp)) syserror("failed to read environment filters");
125   fclose(fp);
126   return v;
127 }
128
129 static int envvar_match(unsigned flags, const char *en,
130                         const char *const *patv,
131                         const char *const *defaults,
132                         const char **ev) {
133   const char *const *patp;
134   const char *q, *pat;
135   int acceptp;
136   int rc;
137
138   if (!patv) { patv= defaults; defaults= 0; }
139   for (patp= patv; (pat= *patp); patp++) {
140     q= en;
141     acceptp= 1;
142     if (*pat == '!' && (flags & FILTF_WILDCARD)) { acceptp= 0; pat++; }
143     else if (*pat == '?') {
144       if (strcmp(pat + 1, "DEFAULTS") == 0) {
145         assert(defaults);
146         rc= envvar_match(flags, en, defaults, 0, ev);
147         if (rc) return rc;
148       } else
149         error("unknown pattern directive", 500);
150       continue;
151     }
152
153     for (;;) {
154       if (!*pat) {
155         if (*q != '=') {
156           D( if (debugmode)
157                printf(";;     mismatch `%s' (prefix)\n", *patp); )
158           break;
159         }
160         D( if (debugmode) printf(";;     matched pattern `%s'\n", *patp); )
161         goto match;
162       } else if (*pat == '*' && (flags & FILTF_WILDCARD)) {
163         q = strchr(q, '=');
164         if (!q) {
165           D( if (debugmode)
166                printf(";;     mismatch `%s' (discard: no `=')\n", *patp); )
167           return -1;
168         }
169         D( if (debugmode)
170              printf(";;     wildcard match for `%s'\n", *patp); )
171         goto match;
172       } else {
173         if (*pat++ != *q++) {
174           D( if (debugmode) printf(";;     mismatch `%s'\n", *patp); )
175           break;
176         }
177       }
178     }
179   }
180   return 0;
181
182 match:
183   if (!acceptp) return -1;
184   *ev= q + 1;
185   return +1;
186 }
187
188 void filter_environment(unsigned flags, const char *prefix_in,
189                         const char *const *patv,
190                         const char *const *defaults,
191                         void (*foundone)(const char *fulln,
192                                          const char *en, const char *ev,
193                                          void *p),
194                         void *p) {
195   char *const *ep;
196   const char *en, *ev;
197   char enbuf[MAX_ENVVAR_NAME];
198   size_t n, pn = strlen(prefix_in);
199
200   D( if (debugmode) printf(";; filter_environment...\n"); )
201   for (ep= environ; (en= *ep); ep++) {
202     D( if (debugmode) printf(";;   consider env-var `%s'\n", en); )
203     if (strncmp(en, prefix_in, pn) != 0 || !en[pn]) {
204       D( if (debugmode) printf(";;     doesn't match prefix\n"); )
205       continue;
206     }
207     if (envvar_match(flags, en + pn, patv, defaults, &ev) > 0) {
208       n= strcspn(en, "=");
209       if (n >= sizeof(enbuf))
210         error("environment variable name too long", 500);
211       memcpy(enbuf, en, n);
212       enbuf[n]= 0;
213       D( if (debugmode)
214            printf(";;     full = `%s'; tail = `%s'; value = `%s'\n",
215                   enbuf, enbuf + pn, ev); )
216       foundone(enbuf, enbuf + pn, ev, p);
217     }
218   }
219 }