X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=blobdiff_plain;f=src%2Fdirplex.c;h=86d2d9cfac1d451b4e39f3d16056eeec26493b7d;hp=063fbb4135812c8a95e8ca1474fd0682d397e73f;hb=c703cd40b144284a46eb4a59294b4b1757b8faa6;hpb=cceb36110d6caa3a44827652d836ac6862d17ff9 diff --git a/src/dirplex.c b/src/dirplex.c index 063fbb4..86d2d9c 100644 --- a/src/dirplex.c +++ b/src/dirplex.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include @@ -35,66 +36,57 @@ #include #include #include - -#define CH_SOCKET 0 -#define CH_FORK 1 +#include #define PAT_BASENAME 0 #define PAT_PATHNAME 1 #define PAT_ALL 2 #define PAT_DEFAULT 3 +#define PT_FILE 0 +#define PT_DIR 1 + struct config { struct config *next, *prev; char *path; - time_t mtime; + time_t mtime, lastck; struct child *children; struct pattern *patterns; -}; - -struct child { - struct child *next; - char *name; - int type; - char **argv; - int fd; + char **index; }; struct rule { int type; - char *pattern; + char **patterns; }; struct pattern { struct pattern *next; + int type; char *childnm; + char **fchild; struct rule **rules; }; -struct config *cflist; +static struct config *cflist; +static struct config *gconfig, *lconfig; +static time_t now; -static void freechild(struct child *ch) +static void freerule(struct rule *rule) { - if(ch->fd != -1) - close(ch->fd); - if(ch->name != NULL) - free(ch->name); - if(ch->argv != NULL) - freeca(ch->argv); - free(ch); + freeca(rule->patterns); + free(rule); } static void freepattern(struct pattern *pat) { struct rule **rule; - for(rule = pat->rules; *rule; rule++) { - if((*rule)->pattern != NULL) - free((*rule)->pattern); - free(*rule); - } + for(rule = pat->rules; *rule; rule++) + freerule(*rule); if(pat->childnm != NULL) free(pat->childnm); + freeca(pat->fchild); free(pat); } @@ -109,7 +101,8 @@ static void freeconfig(struct config *cf) cf->next->prev = cf->prev; if(cf == cflist) cflist = cf->next; - free(cf->path); + if(cf->path != NULL) + free(cf->path); for(ch = cf->children; ch != NULL; ch = nch) { nch = ch->next; freechild(ch); @@ -118,20 +111,10 @@ static void freeconfig(struct config *cf) npat = pat->next; freepattern(pat); } + freeca(cf->index); free(cf); } -static struct child *newchild(char *name, int type) -{ - struct child *ch; - - omalloc(ch); - ch->name = sstrdup(name); - ch->type = type; - ch->fd = -1; - return(ch); -} - static struct child *getchild(struct config *cf, char *name) { struct child *ch; @@ -164,165 +147,132 @@ static struct pattern *newpattern(void) return(pat); } -static struct config *readconfig(char *path) +static char **cadup(char **w) +{ + char **ret; + int i, l; + + l = calen(w); + ret = smalloc(sizeof(*ret) * (l + 1)); + for(i = 0; i < l; i++) + ret[i] = sstrdup(w[i]); + ret[i] = NULL; + return(ret); +} + +static struct pattern *parsepattern(struct cfstate *s) { - int i; - struct config *cf; - FILE *s; - char line[1024]; - char *p, **w; - int ind, eof; - int lno; - int state; - int rv; - int argc; - struct child *child; struct pattern *pat; struct rule *rule; - struct stat sb; - - p = sprintf3("%s/.htrc", path); - if(stat(p, &sb)) - return(NULL); - if((s = fopen(p, "r")) == NULL) + int sl; + + if(!strcmp(s->argv[0], "match")) { + s->expstart = 1; + pat = newpattern(); + } else { return(NULL); - omalloc(cf); - cf->mtime = sb.st_mtime; - cf->path = sstrdup(path); - eof = 0; - state = 0; - w = NULL; - lno = 0; - do { - if(fgets(line, sizeof(line), s) == NULL) { - eof = 1; - line[0] = 0; - } - lno++; - for(p = line; *p; p++) { - if(*p == '#') + } + + if((s->argc > 1) && !strcmp(s->argv[1], "directory")) + pat->type = PT_DIR; + sl = s->lno; + while(1) { + getcfline(s); + if(!strcmp(s->argv[0], "filename")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing pattern for `filename' match", s->file, s->lno); continue; - if(!isspace(*p)) - break; - } - ind = isspace(line[0]); - w = tokenize(line); - argc = calen(w); - - retry: - if(state == 0) { - if(ind) { - flog(LOG_WARNING, "%s%i: unexpected line indentation in global scope", path, lno); - goto next; - } else { - if(!w[0]) { - } else if(!strcmp(w[0], "child")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing name in child declaration", path, lno); - goto next; - } - child = newchild(w[1], CH_SOCKET); - state = 1; - } else if(!strcmp(w[0], "fchild")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing name in child declaration", path, lno); - goto next; - } - child = newchild(w[1], CH_FORK); - state = 1; - } else if(!strcmp(w[0], "match")) { - pat = newpattern(); - state = 2; - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", path, lno, w[0]); - } } - } else if(state == 1) { - if(ind) { - if(!w[0]) { - } else if(!strcmp(w[0], "exec")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: too few parameters to `exec'", path, lno); - goto next; - } - child->argv = szmalloc(sizeof(*child->argv) * argc); - for(i = 0; i < argc - 1; i++) - child->argv[i] = sstrdup(w[i + 1]); - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", path, lno, w[0]); - } - } else { - state = 0; - if(child->argv == NULL) { - flog(LOG_WARNING, "%s:%i: missing `exec' in child declaration %s", path, lno, child->name); - freechild(child); - goto retry; - } - child->next = cf->children; - cf->children = child; - goto retry; + rule = newrule(pat); + rule->type = PAT_BASENAME; + rule->patterns = cadup(s->argv + 1); + } else if(!strcmp(s->argv[0], "pathname")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing pattern for `pathname' match", s->file, s->lno); + continue; } - } else if(state == 2) { - if(ind) { - if(!w[0]) { - } else if(!strcmp(w[0], "filename")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing pattern for `filename' match", path, lno); - goto next; - } - rule = newrule(pat); - rule->type = PAT_BASENAME; - rule->pattern = sstrdup(w[1]); - } else if(!strcmp(w[0], "pathname")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing pattern for `pathname' match", path, lno); - goto next; - } - rule = newrule(pat); - rule->type = PAT_PATHNAME; - rule->pattern = sstrdup(w[1]); - } else if(!strcmp(w[0], "all")) { - newrule(pat)->type = PAT_ALL; - } else if(!strcmp(w[0], "default")) { - newrule(pat)->type = PAT_DEFAULT; - } else if(!strcmp(w[0], "handler")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing child name for `handler' directive", path, lno); - goto next; - } - if(pat->childnm != NULL) - free(pat->childnm); - pat->childnm = sstrdup(w[1]); - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", path, lno, w[0]); - } - } else { - state = 0; - if(pat->rules[0] == NULL) { - flog(LOG_WARNING, "%s:%i: missing rules in match declaration", path, lno); - freepattern(pat); - goto retry; - } - if(pat->childnm == NULL) { - flog(LOG_WARNING, "%s:%i: missing handler in match declaration", path, lno); - freepattern(pat); - goto retry; - } - pat->next = cf->patterns; - cf->patterns = pat; - goto retry; + rule = newrule(pat); + rule->type = PAT_PATHNAME; + rule->patterns = cadup(s->argv + 1); + } else if(!strcmp(s->argv[0], "all")) { + newrule(pat)->type = PAT_ALL; + } else if(!strcmp(s->argv[0], "default")) { + newrule(pat)->type = PAT_DEFAULT; + } else if(!strcmp(s->argv[0], "handler")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing child name for `handler' directive", s->file, s->lno); + continue; } + if(pat->childnm != NULL) + free(pat->childnm); + pat->childnm = sstrdup(s->argv[1]); + } else if(!strcmp(s->argv[0], "fork")) { + pat->fchild = cadup(s->argv + 1); + } else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) { + break; + } else { + flog(LOG_WARNING, "%s:%i: unknown directive `%s' in pattern declaration", s->file, s->lno, s->argv[0]); } - - next: - freeca(w); - w = NULL; - } while(!eof); - rv = 0; + } + + if(pat->rules[0] == NULL) { + flog(LOG_WARNING, "%s:%i: missing rules in match declaration", s->file, sl); + freepattern(pat); + return(NULL); + } + if((pat->childnm == NULL) && (pat->fchild == NULL)) { + flog(LOG_WARNING, "%s:%i: missing handler in match declaration", s->file, sl); + freepattern(pat); + return(NULL); + } + return(pat); +} + +static struct config *emptyconfig(void) +{ + struct config *cf; - if(w != NULL) - freeca(w); - fclose(s); + omalloc(cf); + return(cf); +} + +static struct config *readconfig(char *file) +{ + struct cfstate *s; + FILE *in; + struct config *cf; + struct child *child; + struct pattern *pat; + + if((in = fopen(file, "r")) == NULL) { + flog(LOG_WARNING, "%s: %s", file, strerror(errno)); + return(NULL); + } + s = mkcfparser(in, file); + cf = emptyconfig(); + + while(1) { + getcfline(s); + if((child = parsechild(s)) != NULL) { + child->next = cf->children; + cf->children = child; + } else if((pat = parsepattern(s)) != NULL) { + pat->next = cf->patterns; + cf->patterns = pat; + } else if(!strcmp(s->argv[0], "index-file")) { + freeca(cf->index); + cf->index = NULL; + if(s->argc > 1) + cf->index = cadup(s->argv + 1); + } else if(!strcmp(s->argv[0], "eof")) { + break; + } else { + flog(LOG_WARNING, "%s:%i: unknown directive `%s'", s->file, s->lno, s->argv[0]); + } + } + + freecfparser(s); + fclose(in); return(cf); } @@ -330,55 +280,92 @@ static struct config *getconfig(char *path) { struct config *cf; struct stat sb; + char *fn; + time_t mtime; + fn = sprintf3("%s/.htrc", path); for(cf = cflist; cf != NULL; cf = cf->next) { if(!strcmp(cf->path, path)) { - if(stat(sprintf3("%s/.htrc", path), &sb)) - return(NULL); - if(sb.st_mtime != cf->mtime) { - freeconfig(cf); - break; + if(now - cf->lastck > 5) { + if(stat(fn, &sb) || (sb.st_mtime != cf->mtime)) { + freeconfig(cf); + break; + } } + cf->lastck = now; return(cf); } } - if((cf = readconfig(path)) != NULL) { - cf->next = cflist; - cflist = cf; + if(access(fn, R_OK) || stat(fn, &sb)) { + cf = emptyconfig(); + mtime = 0; + } else { + if((cf = readconfig(fn)) == NULL) + return(NULL); + mtime = sb.st_mtime; } + cf->path = sstrdup(path); + cf->mtime = mtime; + cf->lastck = now; + cf->next = cflist; + cf->prev = NULL; + if(cflist != NULL) + cflist->prev = cf; + cflist = cf; return(cf); } -static struct child *findchild(char *file, char *name) +static struct config **getconfigs(char *file) { - char *buf, *p; + static struct config **ret = NULL; + struct { + struct config **b; + size_t s, d; + } buf; struct config *cf; - struct child *ch; - - buf = sstrdup(file); + char *tmp, *p; + + if(ret != NULL) + free(ret); + bufinit(buf); + tmp = sstrdup(file); while(1) { - ch = NULL; - if(!strcmp(buf, ".")) + if((p = strrchr(tmp, '/')) == NULL) break; - if((p = strrchr(buf, '/')) != NULL) - *p = 0; - else - strcpy(buf, "."); - cf = getconfig(buf); - if(cf == NULL) - continue; - if((ch = getchild(cf, name)) != NULL) + *p = 0; + if((cf = getconfig(tmp)) != NULL) + bufadd(buf, cf); + } + free(tmp); + if((cf = getconfig(".")) != NULL) + bufadd(buf, cf); + if(lconfig != NULL) + bufadd(buf, lconfig); + if(gconfig != NULL) + bufadd(buf, gconfig); + bufadd(buf, NULL); + return(ret = buf.b); +} + +static struct child *findchild(char *file, char *name) +{ + int i; + struct config **cfs; + struct child *ch; + + cfs = getconfigs(file); + for(i = 0; cfs[i] != NULL; i++) { + if((ch = getchild(cfs[i], name)) != NULL) break; } - free(buf); return(ch); } -static struct pattern *findmatch(char *file, int trydefault) +static struct pattern *findmatch(char *file, int trydefault, int dir) { - int i; - char *buf, *p, *bn; - struct config *cf; + int i, o, c; + char *bn; + struct config **cfs; struct pattern *pat; struct rule *rule; @@ -386,25 +373,27 @@ static struct pattern *findmatch(char *file, int trydefault) bn++; else bn = file; - buf = sstrdup(file); - while(1) { - pat = NULL; - if(!strcmp(buf, ".")) - break; - if((p = strrchr(buf, '/')) != NULL) - *p = 0; - else - strcpy(buf, "."); - cf = getconfig(buf); - if(cf == NULL) - continue; - for(pat = cf->patterns; pat != NULL; pat = pat->next) { + cfs = getconfigs(file); + for(c = 0; cfs[c] != NULL; c++) { + for(pat = cfs[c]->patterns; pat != NULL; pat = pat->next) { + if(!dir && (pat->type == PT_DIR)) + continue; + if(dir && (pat->type != PT_DIR)) + continue; for(i = 0; (rule = pat->rules[i]) != NULL; i++) { if(rule->type == PAT_BASENAME) { - if(fnmatch(rule->pattern, bn, 0)) + for(o = 0; rule->patterns[o] != NULL; o++) { + if(!fnmatch(rule->patterns[o], bn, 0)) + break; + } + if(rule->patterns[o] == NULL) break; } else if(rule->type == PAT_PATHNAME) { - if(fnmatch(rule->pattern, file, FNM_PATHNAME)) + for(o = 0; rule->patterns[o] != NULL; o++) { + if(!fnmatch(rule->patterns[o], file, FNM_PATHNAME)) + break; + } + if(rule->patterns[o] == NULL) break; } else if(rule->type == PAT_ALL) { } else if(rule->type == PAT_DEFAULT) { @@ -413,198 +402,269 @@ static struct pattern *findmatch(char *file, int trydefault) } } if(!rule) - goto out; + return(pat); } } - -out: - free(buf); - return(pat); + if(!trydefault) + return(findmatch(file, 1, dir)); + return(NULL); } -static void forkchild(struct child *ch) +static void handle(struct hthead *req, int fd, char *path, struct pattern *pat) { - ch->fd = stdmkchild(ch->argv); -} + struct child *ch; -static void passreq(struct child *ch, struct hthead *req, int fd) -{ - if(ch->fd < 0) - forkchild(ch); - if(sendreq(ch->fd, req, fd)) { - if(errno == EPIPE) { - /* Assume that the child has crashed and restart it. */ - forkchild(ch); - if(!sendreq(ch->fd, req, fd)) - return; + headappheader(req, "X-Ash-File", path); + if(pat->fchild) { + stdforkserve(pat->fchild, req, fd); + } else { + if((ch = findchild(path, pat->childnm)) == NULL) { + flog(LOG_ERR, "child %s requested, but was not declared", pat->childnm); + simpleerror(fd, 500, "Configuration Error", "The server is erroneously configured. Handler %s was requested, but not declared.", pat->childnm); + return; } - flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(errno)); - close(ch->fd); - ch->fd = -1; + if(childhandle(ch, req, fd)) + simpleerror(fd, 500, "Server Error", "The request handler crashed."); } } static void handlefile(struct hthead *req, int fd, char *path) { struct pattern *pat; - struct child *ch; - headappheader(req, "X-Ash-File", path); - if(((pat = findmatch(path, 0)) == NULL) && ((pat = findmatch(path, 1)) == NULL)) { - /* XXX: Send a 500 error? 404? */ - return; - } - if((ch = findchild(path, pat->childnm)) == NULL) { - flog(LOG_ERR, "child %s requested, but was not declared", pat->childnm); - simpleerror(fd, 500, "Configuration Error", "The server is erroneously configured. Handler %s was requested, but not declared.", pat->childnm); + if((pat = findmatch(path, 0, 0)) == NULL) { + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); return; } - - if(ch->type == CH_SOCKET) { - passreq(ch, req, fd); - } else if(ch->type == CH_FORK) { - stdforkserve(ch->argv, req, fd); - } + handle(req, fd, path, pat); } -static void handledir(struct hthead *req, int fd, char *path) +static char *findfile(char *path, char *name, struct stat *sb) { - /* XXX: Todo */ - simpleerror(fd, 403, "Not Authorized", "Will not send directory listings or indices yet"); -} - -static int checkdir(struct hthead *req, int fd, char *path) -{ - return(0); + DIR *dir; + struct stat sbuf; + struct dirent *dent; + char *p, *fp, *ret; + + if(sb == NULL) + sb = &sbuf; + if((dir = opendir(path)) == NULL) + return(NULL); + ret = NULL; + while((dent = readdir(dir)) != NULL) { + /* Ignore backup files. + * XXX: There is probably a better and more extensible way to + * do this. */ + if(dent->d_name[strlen(dent->d_name) - 1] == '~') + continue; + if((p = strchr(dent->d_name, '.')) == NULL) + continue; + if(strncmp(dent->d_name, name, strlen(name))) + continue; + fp = sprintf3("%s/%s", path, dent->d_name); + if(stat(fp, sb)) + continue; + if(!S_ISREG(sb->st_mode)) + continue; + ret = sstrdup(fp); + break; + } + closedir(dir); + return(ret); } -static void serve(struct hthead *req, int fd) +static void handledir(struct hthead *req, int fd, char *path) { - char *p, *p2, *path, *tmp, *buf, *p3, *nm; + struct config **cfs; + int i, o; struct stat sb; - DIR *dir; - struct dirent *dent; + char *inm, *ipath, *cpath; + struct pattern *pat; - nm = req->rest; - path = sstrdup("."); - p = nm; - while(1) { - if((p2 = strchr(p, '/')) == NULL) { - } else { - *(p2++) = 0; - } - - if(!*p) { - if(p2 == NULL) { - if(stat(path, &sb)) { - flog(LOG_WARNING, "failed to stat previously stated directory %s: %s", path, strerror(errno)); - simpleerror(fd, 500, "Internal Server Error", "The server encountered an unexpected condition."); - goto fail; + cpath = sprintf2("%s/", path); + cfs = getconfigs(cpath); + for(i = 0; cfs[i] != NULL; i++) { + if(cfs[i]->index != NULL) { + for(o = 0; cfs[i]->index[o] != NULL; o++) { + inm = cfs[i]->index[o]; + ipath = sprintf2("%s/%s", path, inm); + if(!stat(ipath, &sb) && S_ISREG(sb.st_mode)) { + handlefile(req, fd, ipath); + free(ipath); + goto out; + } + free(ipath); + + if(!strchr(inm, '.') && ((ipath = findfile(path, inm, NULL)) != NULL)) { + handlefile(req, fd, ipath); + free(ipath); + goto out; } - break; - } else { - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - goto fail; - } - } - if(*p == '.') { - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - goto fail; - } - - getconfig(path); - - /* - * First, check the name verbatimely: - */ - buf = sprintf3("%s/%s", path, p); - if(!stat(buf, &sb)) { - if(S_ISDIR(sb.st_mode)) { - tmp = path; - if(!strcmp(path, ".")) - path = sstrdup(p); - else - path = sprintf2("%s/%s", path, p); - free(tmp); - if(checkdir(req, fd, path)) - break; - goto next; - } - if(S_ISREG(sb.st_mode)) { - tmp = path; - path = sprintf2("%s/%s", path, p); - free(tmp); - break; } - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - goto fail; + break; } + } + if((pat = findmatch(cpath, 0, 1)) != NULL) { + handle(req, fd, cpath, pat); + goto out; + } + simpleerror(fd, 403, "Not Authorized", "Will not send listings for this directory."); + +out: + free(cpath); +} - /* - * Check the file extensionlessly: - */ - if(!strchr(p, '.') && ((dir = opendir(path)) != NULL)) { - while((dent = readdir(dir)) != NULL) { - buf = sprintf3("%s/%s", path, dent->d_name); - if((p3 = strchr(dent->d_name, '.')) != NULL) - *p3 = 0; - if(strcmp(dent->d_name, p)) - continue; - if(stat(buf, &sb)) - continue; - if(!S_ISREG(sb.st_mode)) - continue; - tmp = path; - path = sstrdup(buf); - free(tmp); - break; +static int checkpath(struct hthead *req, int fd, char *path, char *rest); + +static int checkentry(struct hthead *req, int fd, char *path, char *rest, char *el) +{ + struct stat sb; + char *newpath; + int rv; + + if(!el == '.') { + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + return(1); + } + if(!stat(sprintf3("%s/%s", path, el), &sb)) { + if(S_ISDIR(sb.st_mode)) { + if(!*rest) { + stdredir(req, fd, 301, sprintf3("%s/", el)); + return(1); } - closedir(dir); - if(dent != NULL) - break; + newpath = sprintf2("%s/%s", path, el); + rv = checkpath(req, fd, newpath, rest + 1); + free(newpath); + return(rv); + } else if(S_ISREG(sb.st_mode)) { + newpath = sprintf2("%s/%s", path, el); + replrest(req, rest); + handlefile(req, fd, newpath); + free(newpath); + return(1); } - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - goto fail; - - next: - if(p2 == NULL) - break; - p = p2; + return(1); } - if(p2 == NULL) - replrest(req, ""); - else - replrest(req, p2); + if(!strchr(el, '.') && ((newpath = findfile(path, el, NULL)) != NULL)) { + replrest(req, rest); + handlefile(req, fd, newpath); + free(newpath); + return(1); + } + return(0); +} + +static int checkpath(struct hthead *req, int fd, char *path, char *rest) +{ + struct config *cf; + char *p, *el; + int rv; + + el = NULL; + rv = 0; + if(!strncmp(path, "./", 2)) - memmove(path, path + 2, strlen(path + 2) + 1); - if(S_ISDIR(sb.st_mode)) { - handledir(req, fd, path); - } else if(S_ISREG(sb.st_mode)) { - handlefile(req, fd, path); + path += 2; + cf = getconfig(path); + + if((p = strchr(rest, '/')) == NULL) { + el = unquoteurl(rest); + rest = ""; } else { + char buf[p - rest + 1]; + memcpy(buf, rest, p - rest); + buf[p - rest] = 0; + el = unquoteurl(buf); + rest = p; + } + if(el == NULL) { + simpleerror(fd, 400, "Bad Request", "The requested URL contains an invalid escape sequence."); + rv = 1; + goto out; + } + if(strchr(el, '/') || (!*el && *rest)) { simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - goto fail; + rv = 1; + goto out; + } + if(!*el) { + replrest(req, rest); + handledir(req, fd, path); + return(1); } - goto out; + rv = checkentry(req, fd, path, rest, el); -fail: - /* No special handling, for now at least. */ out: - free(path); + if(el != NULL) + free(el); + return(rv); +} + +static void serve(struct hthead *req, int fd) +{ + now = time(NULL); + if(!checkpath(req, fd, ".", req->rest)) + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); +} + +static void usage(FILE *out) +{ + fprintf(out, "usage: dirplex [-hN] [-c CONFIG] DIR\n"); } int main(int argc, char **argv) { + int c; + int nodef; + char *gcf, *lcf, *clcf; struct hthead *req; int fd; - if(argc < 2) { - flog(LOG_ERR, "usage: dirplex DIR"); + nodef = 0; + lcf = NULL; + while((c = getopt(argc, argv, "hNc:")) >= 0) { + switch(c) { + case 'h': + usage(stdout); + exit(0); + case 'N': + nodef = 1; + break; + case 'c': + lcf = optarg; + break; + default: + usage(stderr); + exit(1); + } + } + if(argc - optind < 1) { + usage(stderr); exit(1); } - if(chdir(argv[1])) { - flog(LOG_ERR, "could not change directory to %s: %s", argv[1], strerror(errno)); + if(!nodef) { + if((gcf = findstdconf("ashd/dirplex.rc")) != NULL) { + gconfig = readconfig(gcf); + free(gcf); + } + } + if(lcf != NULL) { + if(strchr(lcf, '/') == NULL) { + if((clcf = findstdconf(sprintf3("ashd/%s", lcf))) == NULL) { + flog(LOG_ERR, "could not find requested configuration `%s'", lcf); + exit(1); + } + if((lconfig = readconfig(clcf)) == NULL) + exit(1); + free(clcf); + } else { + if((lconfig = readconfig(lcf)) == NULL) + exit(1); + } + } + if(chdir(argv[optind])) { + flog(LOG_ERR, "could not change directory to %s: %s", argv[optind], strerror(errno)); exit(1); } signal(SIGCHLD, SIG_IGN);