Ensure libdb handles are properly closed when terminating.
[statserve.git] / statserve.c
CommitLineData
34d725a5
FT
1#include <stdlib.h>
2#include <stdio.h>
3#include <unistd.h>
4#include <errno.h>
5#include <string.h>
a823d5b4 6#include <sys/socket.h>
34d725a5
FT
7#include <ashd/req.h>
8#include <ashd/resp.h>
9#include <ashd/log.h>
10#include <ashd/mt.h>
11#include <ashd/mtio.h>
12
13#include "statserve.h"
14
15static struct source *sources = NULL;
16
17static struct source *parsesource(char *arg)
18{
19 if(arg[strlen(arg) - 1] == '/') {
20 return(mkfssrc(arg));
21 } else {
22 return(mkdbsrc(arg, NULL));
23 }
24}
25
26static void serve(struct muth *muth, va_list args)
27{
28 vavar(struct hthead *, req);
29 vavar(int, fd);
30 FILE *out;
31 struct source *src;
32 struct fileinfo f;
33
34 out = NULL;
35 for(src = sources; src != NULL; src = src->next) {
36 f = src->serve(src, req->rest);
37 if(f.data != NULL)
38 break;
39 }
40 if(src == NULL) {
41 simpleerror(fd, 404, "Resource not found", "The resource %s was not found", htmlquote(req->rest));
42 goto out;
43 }
44 out = mtstdopen(fd, 1, 60, "r+");
45 fprintf(out, "HTTP/1.1 200 OK\n");
46 fprintf(out, "Content-Type: %s\n", f.ctype);
47 fprintf(out, "Content-Length: %zi\n", f.sz);
48 fprintf(out, "Last-Modified: %s\n", fmthttpdate(f.mtime));
49 fprintf(out, "\n");
50 fwrite(f.data, 1, f.sz, out);
51 free(f.data);
52
53out:
54 if(out != NULL)
55 fclose(out);
56 else
57 close(fd);
58 freehthead(req);
59}
60
61static void usage(FILE *out)
62{
ea4e0b71 63 fprintf(out, "usage: statserve [-h] [-P PAGESIZE] SOURCE...\n");
34d725a5
FT
64}
65
66static void listenloop(struct muth *muth, va_list args)
67{
68 vavar(int, lfd);
69 int fd;
70 struct hthead *req;
71 struct source *src;
72
73 while(1) {
74 block(0, EV_READ, 0);
75 if((fd = recvreq(lfd, &req)) < 0) {
76 if(errno != 0)
77 flog(LOG_ERR, "recvreq: %s", strerror(errno));
78 break;
79 }
80 mustart(serve, req, fd);
81 for(src = sources; src != NULL; src = src->next) {
82 if(src->idle)
83 src->idle(src);
84 }
85 }
86}
87
a823d5b4
FT
88static void sigterm(int sig)
89{
90 shutdown(0, SHUT_RDWR);
91}
92
93static void closeall(void)
94{
95 struct source *src;
96
97 for(src = sources; src != NULL; src = src->next) {
98 if(src->close)
99 src->close(src);
100 }
101}
102
34d725a5
FT
103int main(int argc, char **argv)
104{
105 int c;
106 struct source *last, *src;
107
ea4e0b71 108 while((c = getopt(argc, argv, "+hP:")) >= 0) {
34d725a5 109 switch(c) {
ea4e0b71
FT
110 case 'P':
111 dbpagesize = atoi(optarg);
112 break;
34d725a5
FT
113 case 'h':
114 usage(stdout);
115 return(0);
116 default:
117 usage(stderr);
118 return(1);
119 }
120 }
121 last = NULL;
122 while(optind < argc) {
a823d5b4
FT
123 if((src = parsesource(argv[optind++])) == NULL) {
124 closeall();
125 return(1);
126 }
34d725a5
FT
127 if(!sources)
128 sources = src;
129 if(last)
130 last->next = src;
131 last = src;
132 }
133 if(!sources) {
134 usage(stderr);
a823d5b4 135 closeall();
34d725a5
FT
136 return(1);
137 }
138 mustart(listenloop, 0);
a823d5b4
FT
139 signal(SIGINT, sigterm);
140 signal(SIGTERM, sigterm);
34d725a5 141 ioloop();
a823d5b4 142 closeall();
34d725a5
FT
143 return(0);
144}