X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fdirplex.c;h=01d87157319005e62bf3a75682995eb2ba4e9b80;hb=6373daf9d9fdd9e24d2c657abf0625337f9b3a24;hp=46342830c55b380499b8b068a431577f2e9287b9;hpb=d58ed97c97e7e9b58eec06c02254b35a22ab4969;p=ashd.git diff --git a/src/dirplex.c b/src/dirplex.c index 4634283..01d8715 100644 --- a/src/dirplex.c +++ b/src/dirplex.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include @@ -45,35 +46,43 @@ struct config { struct config *next, *prev; char *path; - time_t mtime; + time_t mtime, lastck; struct child *children; struct pattern *patterns; + char **index; }; struct rule { int type; - char *pattern; + char **patterns; }; struct pattern { struct pattern *next; 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 freerule(struct rule *rule) +{ + 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); } @@ -88,7 +97,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); @@ -97,6 +107,7 @@ static void freeconfig(struct config *cf) npat = pat->next; freepattern(pat); } + freeca(cf->index); free(cf); } @@ -132,6 +143,19 @@ static struct pattern *newpattern(void) return(pat); } +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) { struct pattern *pat; @@ -155,7 +179,7 @@ static struct pattern *parsepattern(struct cfstate *s) } rule = newrule(pat); rule->type = PAT_BASENAME; - rule->pattern = sstrdup(s->argv[1]); + 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); @@ -163,7 +187,7 @@ static struct pattern *parsepattern(struct cfstate *s) } rule = newrule(pat); rule->type = PAT_PATHNAME; - rule->pattern = sstrdup(s->argv[1]); + 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")) { @@ -176,6 +200,8 @@ static struct pattern *parsepattern(struct cfstate *s) 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 { @@ -188,7 +214,7 @@ static struct pattern *parsepattern(struct cfstate *s) freepattern(pat); return(NULL); } - if(pat->childnm == 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); @@ -196,27 +222,28 @@ static struct pattern *parsepattern(struct cfstate *s) return(pat); } -static struct config *readconfig(char *path) +static struct config *emptyconfig(void) +{ + struct config *cf; + + omalloc(cf); + return(cf); +} + +static struct config *readconfig(char *file) { struct cfstate *s; FILE *in; struct config *cf; struct child *child; struct pattern *pat; - struct stat sb; - char *p; - p = sprintf3("%s/.htrc", path); - if(stat(p, &sb)) - return(NULL); - if((in = fopen(p, "r")) == NULL) { - flog(LOG_WARNING, "%s: %s", p, strerror(errno)); + if((in = fopen(file, "r")) == NULL) { + flog(LOG_WARNING, "%s: %s", file, strerror(errno)); return(NULL); } - s = mkcfparser(in, p); - omalloc(cf); - cf->mtime = sb.st_mtime; - cf->path = sstrdup(path); + s = mkcfparser(in, file); + cf = emptyconfig(); while(1) { getcfline(s); @@ -226,6 +253,11 @@ static struct config *readconfig(char *path) } 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 { @@ -242,22 +274,35 @@ 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; + cflist = cf; return(cf); } @@ -285,6 +330,10 @@ static struct config **getconfigs(char *file) 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); } @@ -305,7 +354,7 @@ static struct child *findchild(char *file, char *name) static struct pattern *findmatch(char *file, int trydefault) { - int i, c; + int i, o, c; char *bn; struct config **cfs; struct pattern *pat; @@ -320,10 +369,18 @@ static struct pattern *findmatch(char *file, int trydefault) for(pat = cfs[c]->patterns; pat != NULL; pat = pat->next) { 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) { @@ -348,20 +405,69 @@ static void handlefile(struct hthead *req, int fd, char *path) simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); 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); - return; + 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; + } + if(childhandle(ch, req, fd)) + simpleerror(fd, 500, "Server Error", "The request handler crashed."); } - - if(childhandle(ch, req, fd)) - simpleerror(fd, 500, "Server Error", "The request handler crashed."); } static void handledir(struct hthead *req, int fd, char *path) { - /* XXX: Todo */ - simpleerror(fd, 403, "Not Authorized", "Will not send directory listings or indices yet."); + struct config **cfs; + int i, o; + struct stat sb; + char *inm, *ipath, *p; + DIR *dir; + struct dirent *dent; + + cfs = getconfigs(sprintf3("%s/", path)); + 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); + return; + } + free(ipath); + + ipath = NULL; + if(!strchr(inm, '.') && ((dir = opendir(path)) != NULL)) { + while((dent = readdir(dir)) != NULL) { + if((p = strchr(dent->d_name, '.')) == NULL) + continue; + if(strncmp(dent->d_name, inm, p - dent->d_name)) + continue; + ipath = sprintf2("%s/%s", path, dent->d_name); + if(stat(ipath, &sb) || !S_ISREG(sb.st_mode)) { + free(ipath); + ipath = NULL; + continue; + } + break; + } + closedir(dir); + } + if(ipath != NULL) { + handlefile(req, fd, ipath); + free(ipath); + return; + } + } + break; + } + } + /* XXX: Directory listings */ + simpleerror(fd, 403, "Not Authorized", "Will not send listings for this directory."); } static int checkdir(struct hthead *req, int fd, char *path) @@ -376,6 +482,7 @@ static void serve(struct hthead *req, int fd) DIR *dir; struct dirent *dent; + now = time(NULL); nm = req->rest; path = sstrdup("."); p = nm; @@ -489,17 +596,53 @@ out: free(path); } +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; 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((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);