2 ashd - A Sane HTTP Daemon
3 Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
40 static int parsefile(struct cfstate *s, FILE *in);
42 static int doinclude(struct cfstate *s, char *spec)
47 char *fbk, *dir, *fspec;
55 fspec = sprintf3("%s/%s", dirname(dir), spec);
58 if(glob(fspec, 0, NULL, &globm))
60 for(i = 0; i < globm.gl_pathc; i++) {
61 if((inc = fopen(globm.gl_pathv[i], "r")) != NULL) {
62 s->file = globm.gl_pathv[i];
63 if(parsefile(s, inc)) {
79 static int parsefile(struct cfstate *s, FILE *in)
84 int ind, indst[80], indl;
91 if(fgets(line, sizeof(line), in) == NULL) {
96 for(p = line + strlen(line) - 1; p >= line; p--) {
102 for(ind = 0, p = line; *p; p++) {
105 } else if(*p == '\t') {
106 ind = ind - (ind % 8) + 8;
111 if(!eof && (!*p || (*p == '#')))
115 if(ind > indst[indl]) {
118 s->res = tokenize("start");
126 s->res = tokenize("end");
131 while(ind < indst[indl]) {
133 s->res = tokenize("end");
137 if(ind > indst[indl]) {
138 flog(LOG_WARNING, "%s:%i: unexpected indentation level", s->file, s->lno);
146 argc = calen(w = tokenize(line));
148 /* Shouldn't happen, but... */
154 if(!strcmp(w[0], "include")) {
155 for(i = 1; i < argc; i++) {
156 if(doinclude(s, w[i])) {
166 if(!strcmp(w[0], "start") ||
167 !strcmp(w[0], "end") ||
168 !strcmp(w[0], "eof")) {
169 flog(LOG_WARNING, "%s:%i: illegal directive: %s", s->file, s->lno, w[0]);
178 static void parsefn(struct muth *mt, va_list args)
180 vavar(struct cfstate *, s);
184 s->file = sstrdup(file);
188 s->res = tokenize("eof");
195 char **getcfline(struct cfstate *s)
200 s->argc = calen(s->argv = s->res);
205 struct cfstate *mkcfparser(FILE *in, char *name)
210 s->pf = mustart(parsefn, s, in, name);
214 void freecfparser(struct cfstate *s)
222 static struct child *newchild(char *name, int type)
227 ch->name = sstrdup(name);
233 void freechild(struct child *ch)
244 void skipcfblock(struct cfstate *s)
250 if(!strcmp(w[0], "end") || !strcmp(w[0], "eof"))
255 struct child *parsechild(struct cfstate *s)
262 if(!strcmp(s->argv[0], "child")) {
265 flog(LOG_WARNING, "%s:%i: missing name in child declaration", s->file, s->lno);
269 ch = newchild(s->argv[1], CH_SOCKET);
270 } else if(!strcmp(s->argv[0], "fchild")) {
273 flog(LOG_WARNING, "%s:%i: missing name in child declaration", s->file, s->lno);
277 ch = newchild(s->argv[1], CH_FORK);
284 if(!strcmp(s->argv[0], "exec")) {
286 flog(LOG_WARNING, "%s:%i: too few parameters to `exec'", s->file, s->lno);
289 ch->argv = szmalloc(sizeof(*ch->argv) * s->argc);
290 for(i = 0; i < s->argc - 1; i++)
291 ch->argv[i] = sstrdup(s->argv[i + 1]);
292 } else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) {
295 flog(LOG_WARNING, "%s:%i: unknown directive `%s' in child declaration", s->file, s->lno, s->argv[0]);
298 if(ch->argv == NULL) {
299 flog(LOG_WARNING, "%s:%i: missing `exec' in child declaration %s", s->file, sl, ch->name);
306 int childhandle(struct child *ch, struct hthead *req, int fd)
308 if(ch->type == CH_SOCKET) {
310 ch->fd = stdmkchild(ch->argv);
311 if(sendreq(ch->fd, req, fd)) {
313 /* Assume that the child has crashed and restart it. */
315 ch->fd = stdmkchild(ch->argv);
316 if(!sendreq(ch->fd, req, fd))
319 flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(errno));
324 } else if(ch->type == CH_FORK) {
325 if(stdforkserve(ch->argv, req, fd) < 0)