#include <ctype.h>
#include <dirent.h>
#include <fnmatch.h>
+#include <time.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
struct config {
struct config *next, *prev;
char *path;
- time_t mtime;
+ time_t mtime, lastck;
struct child *children;
struct pattern *patterns;
};
struct rule **rules;
};
-struct config *cflist;
+static struct config *cflist;
+static struct config *gconfig, *lconfig;
+static time_t now;
static void freepattern(struct pattern *pat)
{
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);
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);
{
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);
}
-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)
{
- int i;
- char *buf, *p, *bn;
- struct config *cf;
+ int i, c;
+ char *bn;
+ struct config **cfs;
struct pattern *pat;
struct rule *rule;
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) {
for(i = 0; (rule = pat->rules[i]) != NULL; i++) {
if(rule->type == PAT_BASENAME) {
if(fnmatch(rule->pattern, bn, 0))
}
}
if(!rule)
- goto out;
+ return(pat);
}
}
-
-out:
- free(buf);
- return(pat);
+ return(NULL);
}
static void handlefile(struct hthead *req, int fd, char *path)
headappheader(req, "X-Ash-File", path);
if(((pat = findmatch(path, 0)) == NULL) && ((pat = findmatch(path, 1)) == NULL)) {
- /* XXX: Send a 500 error? 404? */
+ simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource.");
return;
}
if((ch = findchild(path, pat->childnm)) == NULL) {
DIR *dir;
struct dirent *dent;
+ now = time(NULL);
nm = req->rest;
path = sstrdup(".");
p = nm;
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);