xref: /plan9/sys/src/cmd/venti/srv/httpd.c (revision 23566e0c4b9b5ce80121325d240a2f6e83a70a8f)
1368c31abSDavid du Colombier #include "stdinc.h"
2368c31abSDavid du Colombier #include "dat.h"
3368c31abSDavid du Colombier #include "fns.h"
4368c31abSDavid du Colombier #include "xml.h"
5368c31abSDavid du Colombier 
6368c31abSDavid du Colombier typedef struct HttpObj	HttpObj;
7368c31abSDavid du Colombier extern QLock memdrawlock;
8368c31abSDavid du Colombier 
9368c31abSDavid du Colombier enum
10368c31abSDavid du Colombier {
11368c31abSDavid du Colombier 	ObjNameSize	= 64,
12368c31abSDavid du Colombier 	MaxObjs		= 64
13368c31abSDavid du Colombier };
14368c31abSDavid du Colombier 
15368c31abSDavid du Colombier struct HttpObj
16368c31abSDavid du Colombier {
17368c31abSDavid du Colombier 	char	name[ObjNameSize];
18368c31abSDavid du Colombier 	int	(*f)(HConnect*);
19368c31abSDavid du Colombier };
20368c31abSDavid du Colombier 
21368c31abSDavid du Colombier static HttpObj	objs[MaxObjs];
22368c31abSDavid du Colombier 
23368c31abSDavid du Colombier static char *webroot;
24368c31abSDavid du Colombier 
25368c31abSDavid du Colombier static	void		listenproc(void*);
26368c31abSDavid du Colombier static	int		estats(HConnect *c);
27368c31abSDavid du Colombier static	int		dindex(HConnect *c);
28368c31abSDavid du Colombier static	int		xindex(HConnect *c);
29368c31abSDavid du Colombier static	int		xlog(HConnect *c);
30368c31abSDavid du Colombier static	int		sindex(HConnect *c);
31368c31abSDavid du Colombier static	int		hempty(HConnect *c);
32368c31abSDavid du Colombier static	int		hlcacheempty(HConnect *c);
33368c31abSDavid du Colombier static	int		hdcacheempty(HConnect *c);
34368c31abSDavid du Colombier static	int		hicacheempty(HConnect *c);
35368c31abSDavid du Colombier static	int		hicachekick(HConnect *c);
36368c31abSDavid du Colombier static	int		hdcachekick(HConnect *c);
37368c31abSDavid du Colombier static	int		hicacheflush(HConnect *c);
38368c31abSDavid du Colombier static	int		hdcacheflush(HConnect *c);
39368c31abSDavid du Colombier static	int		httpdobj(char *name, int (*f)(HConnect*));
40368c31abSDavid du Colombier static	int		xgraph(HConnect *c);
41368c31abSDavid du Colombier static	int		xset(HConnect *c);
42368c31abSDavid du Colombier static	int		fromwebdir(HConnect *c);
43368c31abSDavid du Colombier 
44368c31abSDavid du Colombier int
httpdinit(char * address,char * dir)45368c31abSDavid du Colombier httpdinit(char *address, char *dir)
46368c31abSDavid du Colombier {
47368c31abSDavid du Colombier 	fmtinstall('D', hdatefmt);
48368c31abSDavid du Colombier /*	fmtinstall('H', httpfmt); */
49368c31abSDavid du Colombier 	fmtinstall('U', hurlfmt);
50368c31abSDavid du Colombier 
51368c31abSDavid du Colombier 	if(address == nil)
52368c31abSDavid du Colombier 		address = "tcp!*!http";
53368c31abSDavid du Colombier 	webroot = dir;
54368c31abSDavid du Colombier 
55368c31abSDavid du Colombier 	httpdobj("/stats", estats);
56368c31abSDavid du Colombier 	httpdobj("/index", dindex);
57368c31abSDavid du Colombier 	httpdobj("/storage", sindex);
58368c31abSDavid du Colombier 	httpdobj("/xindex", xindex);
59368c31abSDavid du Colombier 	httpdobj("/flushicache", hicacheflush);
60368c31abSDavid du Colombier 	httpdobj("/flushdcache", hdcacheflush);
61368c31abSDavid du Colombier 	httpdobj("/kickicache", hicachekick);
62368c31abSDavid du Colombier 	httpdobj("/kickdcache", hdcachekick);
63368c31abSDavid du Colombier 	httpdobj("/graph", xgraph);
64368c31abSDavid du Colombier 	httpdobj("/set", xset);
65368c31abSDavid du Colombier 	httpdobj("/log", xlog);
66368c31abSDavid du Colombier 	httpdobj("/empty", hempty);
67368c31abSDavid du Colombier 	httpdobj("/emptyicache", hicacheempty);
68368c31abSDavid du Colombier 	httpdobj("/emptylumpcache", hlcacheempty);
69368c31abSDavid du Colombier 	httpdobj("/emptydcache", hdcacheempty);
70368c31abSDavid du Colombier 	httpdobj("/disk", hdisk);
71368c31abSDavid du Colombier 	httpdobj("/debug", hdebug);
72*c65cf52cSDavid du Colombier 	httpdobj("/proc/", hproc);
73368c31abSDavid du Colombier 
74368c31abSDavid du Colombier 	if(vtproc(listenproc, address) < 0)
75368c31abSDavid du Colombier 		return -1;
76368c31abSDavid du Colombier 	return 0;
77368c31abSDavid du Colombier }
78368c31abSDavid du Colombier 
79368c31abSDavid du Colombier static int
httpdobj(char * name,int (* f)(HConnect *))80368c31abSDavid du Colombier httpdobj(char *name, int (*f)(HConnect*))
81368c31abSDavid du Colombier {
82368c31abSDavid du Colombier 	int i;
83368c31abSDavid du Colombier 
84368c31abSDavid du Colombier 	if(name == nil || strlen(name) >= ObjNameSize)
85368c31abSDavid du Colombier 		return -1;
86368c31abSDavid du Colombier 	for(i = 0; i < MaxObjs; i++){
87368c31abSDavid du Colombier 		if(objs[i].name[0] == '\0'){
88368c31abSDavid du Colombier 			strcpy(objs[i].name, name);
89368c31abSDavid du Colombier 			objs[i].f = f;
90368c31abSDavid du Colombier 			return 0;
91368c31abSDavid du Colombier 		}
92368c31abSDavid du Colombier 		if(strcmp(objs[i].name, name) == 0)
93368c31abSDavid du Colombier 			return -1;
94368c31abSDavid du Colombier 	}
95368c31abSDavid du Colombier 	return -1;
96368c31abSDavid du Colombier }
97368c31abSDavid du Colombier 
98368c31abSDavid du Colombier static HConnect*
mkconnect(void)99368c31abSDavid du Colombier mkconnect(void)
100368c31abSDavid du Colombier {
101368c31abSDavid du Colombier 	HConnect *c;
102368c31abSDavid du Colombier 
103368c31abSDavid du Colombier 	c = mallocz(sizeof(HConnect), 1);
104368c31abSDavid du Colombier 	if(c == nil)
105368c31abSDavid du Colombier 		sysfatal("out of memory");
106368c31abSDavid du Colombier 	c->replog = nil;
107368c31abSDavid du Colombier 	c->hpos = c->header;
108368c31abSDavid du Colombier 	c->hstop = c->header;
109368c31abSDavid du Colombier 	return c;
110368c31abSDavid du Colombier }
111368c31abSDavid du Colombier 
112368c31abSDavid du Colombier void httpproc(void*);
113368c31abSDavid du Colombier 
114368c31abSDavid du Colombier static void
listenproc(void * vaddress)115368c31abSDavid du Colombier listenproc(void *vaddress)
116368c31abSDavid du Colombier {
117368c31abSDavid du Colombier 	HConnect *c;
118368c31abSDavid du Colombier 	char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
119368c31abSDavid du Colombier 	int ctl, nctl, data;
120368c31abSDavid du Colombier 
121368c31abSDavid du Colombier 	address = vaddress;
122368c31abSDavid du Colombier 	ctl = announce(address, dir);
123368c31abSDavid du Colombier 	if(ctl < 0){
124368c31abSDavid du Colombier 		fprint(2, "venti: httpd can't announce on %s: %r\n", address);
125368c31abSDavid du Colombier 		return;
126368c31abSDavid du Colombier 	}
127368c31abSDavid du Colombier 
128368c31abSDavid du Colombier 	if(0) print("announce ctl %d dir %s\n", ctl, dir);
129368c31abSDavid du Colombier 	for(;;){
130368c31abSDavid du Colombier 		/*
131368c31abSDavid du Colombier 		 *  wait for a call (or an error)
132368c31abSDavid du Colombier 		 */
133368c31abSDavid du Colombier 		nctl = listen(dir, ndir);
134368c31abSDavid du Colombier 		if(0) print("httpd listen %d %s...\n", nctl, ndir);
135368c31abSDavid du Colombier 		if(nctl < 0){
136368c31abSDavid du Colombier 			fprint(2, "venti: httpd can't listen on %s: %r\n", address);
137368c31abSDavid du Colombier 			return;
138368c31abSDavid du Colombier 		}
139368c31abSDavid du Colombier 
140368c31abSDavid du Colombier 		data = accept(ctl, ndir);
141368c31abSDavid du Colombier 		if(0) print("httpd accept %d...\n", data);
142368c31abSDavid du Colombier 		if(data < 0){
143368c31abSDavid du Colombier 			fprint(2, "venti: httpd accept: %r\n");
144368c31abSDavid du Colombier 			close(nctl);
145368c31abSDavid du Colombier 			continue;
146368c31abSDavid du Colombier 		}
147368c31abSDavid du Colombier 		if(0) print("httpd close nctl %d\n", nctl);
148368c31abSDavid du Colombier 		close(nctl);
149368c31abSDavid du Colombier 		c = mkconnect();
150368c31abSDavid du Colombier 		hinit(&c->hin, data, Hread);
151368c31abSDavid du Colombier 		hinit(&c->hout, data, Hwrite);
152368c31abSDavid du Colombier 		vtproc(httpproc, c);
153368c31abSDavid du Colombier 	}
154368c31abSDavid du Colombier }
155368c31abSDavid du Colombier 
156368c31abSDavid du Colombier void
httpproc(void * v)157368c31abSDavid du Colombier httpproc(void *v)
158368c31abSDavid du Colombier {
159368c31abSDavid du Colombier 	HConnect *c;
160368c31abSDavid du Colombier 	int ok, i, n;
161368c31abSDavid du Colombier 
162368c31abSDavid du Colombier 	c = v;
163368c31abSDavid du Colombier 
164368c31abSDavid du Colombier 	for(;;){
165368c31abSDavid du Colombier 		/*
166368c31abSDavid du Colombier 		 * No timeout because the signal appears to hit every
167368c31abSDavid du Colombier 		 * proc, not just us.
168368c31abSDavid du Colombier 		 */
169368c31abSDavid du Colombier 		if(hparsereq(c, 0) < 0)
170368c31abSDavid du Colombier 			break;
171368c31abSDavid du Colombier 
172368c31abSDavid du Colombier 		for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
173368c31abSDavid du Colombier 			n = strlen(objs[i].name);
174368c31abSDavid du Colombier 			if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0)
175368c31abSDavid du Colombier 			|| (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){
176368c31abSDavid du Colombier 				ok = (*objs[i].f)(c);
177368c31abSDavid du Colombier 				goto found;
178368c31abSDavid du Colombier 			}
179368c31abSDavid du Colombier 		}
180368c31abSDavid du Colombier 		ok = fromwebdir(c);
181368c31abSDavid du Colombier 	found:
182368c31abSDavid du Colombier 		hflush(&c->hout);
183368c31abSDavid du Colombier 		if(c->head.closeit)
184368c31abSDavid du Colombier 			ok = -1;
185368c31abSDavid du Colombier 		hreqcleanup(c);
186368c31abSDavid du Colombier 
187368c31abSDavid du Colombier 		if(ok < 0)
188368c31abSDavid du Colombier 			break;
189368c31abSDavid du Colombier 	}
190368c31abSDavid du Colombier 	hreqcleanup(c);
191368c31abSDavid du Colombier 	close(c->hin.fd);
192368c31abSDavid du Colombier 	free(c);
193368c31abSDavid du Colombier }
194368c31abSDavid du Colombier 
195368c31abSDavid du Colombier char*
hargstr(HConnect * c,char * name,char * def)196368c31abSDavid du Colombier hargstr(HConnect *c, char *name, char *def)
197368c31abSDavid du Colombier {
198368c31abSDavid du Colombier 	HSPairs *p;
199368c31abSDavid du Colombier 
200368c31abSDavid du Colombier 	for(p=c->req.searchpairs; p; p=p->next)
201368c31abSDavid du Colombier 		if(strcmp(p->s, name) == 0)
202368c31abSDavid du Colombier 			return p->t;
203368c31abSDavid du Colombier 	return def;
204368c31abSDavid du Colombier }
205368c31abSDavid du Colombier 
206368c31abSDavid du Colombier vlong
hargint(HConnect * c,char * name,vlong def)207368c31abSDavid du Colombier hargint(HConnect *c, char *name, vlong def)
208368c31abSDavid du Colombier {
209368c31abSDavid du Colombier 	char *a;
210368c31abSDavid du Colombier 
211368c31abSDavid du Colombier 	if((a = hargstr(c, name, nil)) == nil)
212368c31abSDavid du Colombier 		return def;
213368c31abSDavid du Colombier 	return atoll(a);
214368c31abSDavid du Colombier }
215368c31abSDavid du Colombier 
216368c31abSDavid du Colombier static int
percent(ulong v,ulong total)217368c31abSDavid du Colombier percent(ulong v, ulong total)
218368c31abSDavid du Colombier {
219368c31abSDavid du Colombier 	if(total == 0)
220368c31abSDavid du Colombier 		total = 1;
221368c31abSDavid du Colombier 	if(v < 1000*1000)
222368c31abSDavid du Colombier 		return (v * 100) / total;
223368c31abSDavid du Colombier 	total /= 100;
224368c31abSDavid du Colombier 	if(total == 0)
225368c31abSDavid du Colombier 		total = 1;
226368c31abSDavid du Colombier 	return v / total;
227368c31abSDavid du Colombier }
228368c31abSDavid du Colombier 
229368c31abSDavid du Colombier static int
preq(HConnect * c)230368c31abSDavid du Colombier preq(HConnect *c)
231368c31abSDavid du Colombier {
232368c31abSDavid du Colombier 	if(hparseheaders(c, 0) < 0)
233368c31abSDavid du Colombier 		return -1;
234368c31abSDavid du Colombier 	if(strcmp(c->req.meth, "GET") != 0
235368c31abSDavid du Colombier 	&& strcmp(c->req.meth, "HEAD") != 0)
236368c31abSDavid du Colombier 		return hunallowed(c, "GET, HEAD");
237368c31abSDavid du Colombier 	if(c->head.expectother || c->head.expectcont)
238368c31abSDavid du Colombier 		return hfail(c, HExpectFail, nil);
239368c31abSDavid du Colombier 	return 0;
240368c31abSDavid du Colombier }
241368c31abSDavid du Colombier 
242368c31abSDavid du Colombier int
hsettype(HConnect * c,char * type)243368c31abSDavid du Colombier hsettype(HConnect *c, char *type)
244368c31abSDavid du Colombier {
245368c31abSDavid du Colombier 	Hio *hout;
246368c31abSDavid du Colombier 	int r;
247368c31abSDavid du Colombier 
248368c31abSDavid du Colombier 	r = preq(c);
249368c31abSDavid du Colombier 	if(r < 0)
250368c31abSDavid du Colombier 		return r;
251368c31abSDavid du Colombier 
252368c31abSDavid du Colombier 	hout = &c->hout;
253368c31abSDavid du Colombier 	if(c->req.vermaj){
254368c31abSDavid du Colombier 		hokheaders(c);
255368c31abSDavid du Colombier 		hprint(hout, "Content-type: %s\r\n", type);
256368c31abSDavid du Colombier 		if(http11(c))
257368c31abSDavid du Colombier 			hprint(hout, "Transfer-Encoding: chunked\r\n");
258368c31abSDavid du Colombier 		hprint(hout, "\r\n");
259368c31abSDavid du Colombier 	}
260368c31abSDavid du Colombier 
261368c31abSDavid du Colombier 	if(http11(c))
262368c31abSDavid du Colombier 		hxferenc(hout, 1);
263368c31abSDavid du Colombier 	else
264368c31abSDavid du Colombier 		c->head.closeit = 1;
265368c31abSDavid du Colombier 	return 0;
266368c31abSDavid du Colombier }
267368c31abSDavid du Colombier 
268368c31abSDavid du Colombier int
hsethtml(HConnect * c)269368c31abSDavid du Colombier hsethtml(HConnect *c)
270368c31abSDavid du Colombier {
271368c31abSDavid du Colombier 	return hsettype(c, "text/html; charset=utf-8");
272368c31abSDavid du Colombier }
273368c31abSDavid du Colombier 
274368c31abSDavid du Colombier int
hsettext(HConnect * c)275368c31abSDavid du Colombier hsettext(HConnect *c)
276368c31abSDavid du Colombier {
277368c31abSDavid du Colombier 	return hsettype(c, "text/plain; charset=utf-8");
278368c31abSDavid du Colombier }
279368c31abSDavid du Colombier 
280368c31abSDavid du Colombier static int
herror(HConnect * c)281368c31abSDavid du Colombier herror(HConnect *c)
282368c31abSDavid du Colombier {
283368c31abSDavid du Colombier 	int n;
284368c31abSDavid du Colombier 	Hio *hout;
285368c31abSDavid du Colombier 
286368c31abSDavid du Colombier 	hout = &c->hout;
287368c31abSDavid du Colombier 	n = snprint(c->xferbuf, HBufSize, "<html><head><title>Error</title></head>\n<body><h1>Error</h1>\n<pre>%r</pre>\n</body></html>");
288368c31abSDavid du Colombier 	hprint(hout, "%s %s\r\n", hversion, "400 Bad Request");
289368c31abSDavid du Colombier 	hprint(hout, "Date: %D\r\n", time(nil));
290368c31abSDavid du Colombier 	hprint(hout, "Server: Venti\r\n");
291368c31abSDavid du Colombier 	hprint(hout, "Content-Type: text/html\r\n");
292368c31abSDavid du Colombier 	hprint(hout, "Content-Length: %d\r\n", n);
293368c31abSDavid du Colombier 	if(c->head.closeit)
294368c31abSDavid du Colombier 		hprint(hout, "Connection: close\r\n");
295368c31abSDavid du Colombier 	else if(!http11(c))
296368c31abSDavid du Colombier 		hprint(hout, "Connection: Keep-Alive\r\n");
297368c31abSDavid du Colombier 	hprint(hout, "\r\n");
298368c31abSDavid du Colombier 
299368c31abSDavid du Colombier 	if(c->req.meth == nil || strcmp(c->req.meth, "HEAD") != 0)
300368c31abSDavid du Colombier 		hwrite(hout, c->xferbuf, n);
301368c31abSDavid du Colombier 
302368c31abSDavid du Colombier 	return hflush(hout);
303368c31abSDavid du Colombier }
304368c31abSDavid du Colombier 
305368c31abSDavid du Colombier int
hnotfound(HConnect * c)306368c31abSDavid du Colombier hnotfound(HConnect *c)
307368c31abSDavid du Colombier {
308368c31abSDavid du Colombier 	int r;
309368c31abSDavid du Colombier 
310368c31abSDavid du Colombier 	r = preq(c);
311368c31abSDavid du Colombier 	if(r < 0)
312368c31abSDavid du Colombier 		return r;
313368c31abSDavid du Colombier 	return hfail(c, HNotFound, c->req.uri);
314368c31abSDavid du Colombier }
315368c31abSDavid du Colombier 
316368c31abSDavid du Colombier struct {
317368c31abSDavid du Colombier 	char *ext;
318368c31abSDavid du Colombier 	char *type;
319368c31abSDavid du Colombier } exttab[] = {
320368c31abSDavid du Colombier 	".html",	"text/html",
321368c31abSDavid du Colombier 	".txt",	"text/plain",
322368c31abSDavid du Colombier 	".xml",	"text/xml",
323368c31abSDavid du Colombier 	".png",	"image/png",
324368c31abSDavid du Colombier 	".gif",	"image/gif",
325368c31abSDavid du Colombier 	0
326368c31abSDavid du Colombier };
327368c31abSDavid du Colombier 
328368c31abSDavid du Colombier static int
fromwebdir(HConnect * c)329368c31abSDavid du Colombier fromwebdir(HConnect *c)
330368c31abSDavid du Colombier {
331368c31abSDavid du Colombier 	char buf[4096], *p, *ext, *type;
332368c31abSDavid du Colombier 	int i, fd, n, defaulted;
333368c31abSDavid du Colombier 	Dir *d;
334368c31abSDavid du Colombier 
335368c31abSDavid du Colombier 	if(webroot == nil || strstr(c->req.uri, ".."))
336368c31abSDavid du Colombier 		return hnotfound(c);
337368c31abSDavid du Colombier 	snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1);
338368c31abSDavid du Colombier 	defaulted = 0;
339368c31abSDavid du Colombier reopen:
340368c31abSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0)
341368c31abSDavid du Colombier 		return hnotfound(c);
342368c31abSDavid du Colombier 	d = dirfstat(fd);
343368c31abSDavid du Colombier 	if(d == nil){
344368c31abSDavid du Colombier 		close(fd);
345368c31abSDavid du Colombier 		return hnotfound(c);
346368c31abSDavid du Colombier 	}
347368c31abSDavid du Colombier 	if(d->mode&DMDIR){
348368c31abSDavid du Colombier 		if(!defaulted){
349368c31abSDavid du Colombier 			defaulted = 1;
350368c31abSDavid du Colombier 			strcat(buf, "/index.html");
351368c31abSDavid du Colombier 			free(d);
352368c31abSDavid du Colombier 			close(fd);
353368c31abSDavid du Colombier 			goto reopen;
354368c31abSDavid du Colombier 		}
355368c31abSDavid du Colombier 		free(d);
356368c31abSDavid du Colombier 		return hnotfound(c);
357368c31abSDavid du Colombier 	}
358368c31abSDavid du Colombier 	free(d);
359368c31abSDavid du Colombier 	p = buf+strlen(buf);
360368c31abSDavid du Colombier 	type = "application/octet-stream";
361368c31abSDavid du Colombier 	for(i=0; exttab[i].ext; i++){
362368c31abSDavid du Colombier 		ext = exttab[i].ext;
363368c31abSDavid du Colombier 		if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){
364368c31abSDavid du Colombier 			type = exttab[i].type;
365368c31abSDavid du Colombier 			break;
366368c31abSDavid du Colombier 		}
367368c31abSDavid du Colombier 	}
368368c31abSDavid du Colombier 	if(hsettype(c, type) < 0){
369368c31abSDavid du Colombier 		close(fd);
370368c31abSDavid du Colombier 		return 0;
371368c31abSDavid du Colombier 	}
372368c31abSDavid du Colombier 	while((n = read(fd, buf, sizeof buf)) > 0)
373368c31abSDavid du Colombier 		if(hwrite(&c->hout, buf, n) < 0)
374368c31abSDavid du Colombier 			break;
375368c31abSDavid du Colombier 	close(fd);
376368c31abSDavid du Colombier 	hflush(&c->hout);
377368c31abSDavid du Colombier 	return 0;
378368c31abSDavid du Colombier }
379368c31abSDavid du Colombier 
380368c31abSDavid du Colombier static struct
381368c31abSDavid du Colombier {
382368c31abSDavid du Colombier 	char *name;
383368c31abSDavid du Colombier 	int *p;
384368c31abSDavid du Colombier } namedints[] =
385368c31abSDavid du Colombier {
386368c31abSDavid du Colombier 	"compress",	&compressblocks,
387368c31abSDavid du Colombier 	"devnull",	&writestodevnull,
388368c31abSDavid du Colombier 	"logging",	&ventilogging,
389368c31abSDavid du Colombier 	"stats",	&collectstats,
390368c31abSDavid du Colombier 	"icachesleeptime",	&icachesleeptime,
391368c31abSDavid du Colombier 	"minicachesleeptime",	&minicachesleeptime,
392368c31abSDavid du Colombier 	"arenasumsleeptime",	&arenasumsleeptime,
393368c31abSDavid du Colombier 	"l0quantum",	&l0quantum,
394368c31abSDavid du Colombier 	"l1quantum",	&l1quantum,
395368c31abSDavid du Colombier 	"manualscheduling",	&manualscheduling,
396368c31abSDavid du Colombier 	"ignorebloom",	&ignorebloom,
397368c31abSDavid du Colombier 	"syncwrites",	&syncwrites,
398368c31abSDavid du Colombier 	"icacheprefetch",	&icacheprefetch,
399368c31abSDavid du Colombier 	0
400368c31abSDavid du Colombier };
401368c31abSDavid du Colombier 
402368c31abSDavid du Colombier static int
xset(HConnect * c)403368c31abSDavid du Colombier xset(HConnect *c)
404368c31abSDavid du Colombier {
405368c31abSDavid du Colombier 	int i, old;
406368c31abSDavid du Colombier 	char *name, *value;
407368c31abSDavid du Colombier 
408368c31abSDavid du Colombier 	if(hsettext(c) < 0)
409368c31abSDavid du Colombier 		return -1;
410368c31abSDavid du Colombier 
411368c31abSDavid du Colombier 	if((name = hargstr(c, "name", nil)) == nil || name[0] == 0){
412368c31abSDavid du Colombier 		for(i=0; namedints[i].name; i++)
413368c31abSDavid du Colombier 			hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
414368c31abSDavid du Colombier 		hflush(&c->hout);
415368c31abSDavid du Colombier 		return 0;
416368c31abSDavid du Colombier 	}
417368c31abSDavid du Colombier 
418368c31abSDavid du Colombier 	for(i=0; namedints[i].name; i++)
419368c31abSDavid du Colombier 		if(strcmp(name, namedints[i].name) == 0)
420368c31abSDavid du Colombier 			break;
421368c31abSDavid du Colombier 	if(!namedints[i].name){
422368c31abSDavid du Colombier 		hprint(&c->hout, "%s not found\n", name);
423368c31abSDavid du Colombier 		hflush(&c->hout);
424368c31abSDavid du Colombier 		return 0;
425368c31abSDavid du Colombier 	}
426368c31abSDavid du Colombier 
427368c31abSDavid du Colombier 	if((value = hargstr(c, "value", nil)) == nil || value[0] == 0){
428368c31abSDavid du Colombier 		hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
429368c31abSDavid du Colombier 		hflush(&c->hout);
430368c31abSDavid du Colombier 		return 0;
431368c31abSDavid du Colombier 	}
432368c31abSDavid du Colombier 
433368c31abSDavid du Colombier 	old = *namedints[i].p;
434368c31abSDavid du Colombier 	*namedints[i].p = atoll(value);
435368c31abSDavid du Colombier 	hprint(&c->hout, "%s = %d (was %d)\n", name, *namedints[i].p, old);
436368c31abSDavid du Colombier 	hflush(&c->hout);
437368c31abSDavid du Colombier 	return 0;
438368c31abSDavid du Colombier }
439368c31abSDavid du Colombier 
440368c31abSDavid du Colombier static int
estats(HConnect * c)441368c31abSDavid du Colombier estats(HConnect *c)
442368c31abSDavid du Colombier {
443368c31abSDavid du Colombier 	Hio *hout;
444368c31abSDavid du Colombier 	int r;
445368c31abSDavid du Colombier 
446368c31abSDavid du Colombier 	r = hsettext(c);
447368c31abSDavid du Colombier 	if(r < 0)
448368c31abSDavid du Colombier 		return r;
449368c31abSDavid du Colombier 
450368c31abSDavid du Colombier 
451368c31abSDavid du Colombier 	hout = &c->hout;
452368c31abSDavid du Colombier /*
453368c31abSDavid du Colombier 	hprint(hout, "lump writes=%,ld\n", stats.lumpwrites);
454368c31abSDavid du Colombier 	hprint(hout, "lump reads=%,ld\n", stats.lumpreads);
455368c31abSDavid du Colombier 	hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit);
456368c31abSDavid du Colombier 	hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss);
457368c31abSDavid du Colombier 
458368c31abSDavid du Colombier 	hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites);
459368c31abSDavid du Colombier 	hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites);
460368c31abSDavid du Colombier 	hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp);
461368c31abSDavid du Colombier 	hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads);
462368c31abSDavid du Colombier 	hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads);
463368c31abSDavid du Colombier 	hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp);
464368c31abSDavid du Colombier 
465368c31abSDavid du Colombier 	hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
466368c31abSDavid du Colombier 	hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
467368c31abSDavid du Colombier 
468368c31abSDavid du Colombier 	hprint(hout, "index disk writes=%,ld\n", stats.indexwrites);
469368c31abSDavid du Colombier 	hprint(hout, "index disk reads=%,ld\n", stats.indexreads);
470368c31abSDavid du Colombier 	hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n",
471368c31abSDavid du Colombier 		stats.indexbloomhits,
472368c31abSDavid du Colombier 		percent(stats.indexbloomhits, stats.indexreads),
473368c31abSDavid du Colombier 		stats.indexbloomfalsemisses,
474368c31abSDavid du Colombier 		percent(stats.indexbloomfalsemisses, stats.indexreads));
475368c31abSDavid du Colombier 	hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n",
476368c31abSDavid du Colombier 		stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits));
477368c31abSDavid du Colombier 	hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads);
478368c31abSDavid du Colombier 	hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads);
479368c31abSDavid du Colombier 	hprint(hout, "index block splits=%,ld\n", stats.indexsplits);
480368c31abSDavid du Colombier 
481368c31abSDavid du Colombier 	hprint(hout, "index cache lookups=%,ld\n", stats.iclookups);
482368c31abSDavid du Colombier 	hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits,
483368c31abSDavid du Colombier 		percent(stats.ichits, stats.iclookups));
484368c31abSDavid du Colombier 	hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills,
485368c31abSDavid du Colombier 		percent(stats.icfills, stats.iclookups));
486368c31abSDavid du Colombier 	hprint(hout, "index cache inserts=%,ld\n", stats.icinserts);
487368c31abSDavid du Colombier 
488368c31abSDavid du Colombier 	hprint(hout, "disk cache hits=%,ld\n", stats.pchit);
489368c31abSDavid du Colombier 	hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss);
490368c31abSDavid du Colombier 	hprint(hout, "disk cache reads=%,ld\n", stats.pcreads);
491368c31abSDavid du Colombier 	hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads);
492368c31abSDavid du Colombier 
493368c31abSDavid du Colombier 	hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks);
494368c31abSDavid du Colombier 	hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites,
495368c31abSDavid du Colombier 		percent(stats.absorbedwrites, stats.dirtydblocks));
496368c31abSDavid du Colombier 
497368c31abSDavid du Colombier 	hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes);
498368c31abSDavid du Colombier 	hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n",
499368c31abSDavid du Colombier 		stats.dcacheflushwrites,
500368c31abSDavid du Colombier 		stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1));
501368c31abSDavid du Colombier 
502368c31abSDavid du Colombier 	hprint(hout, "disk writes=%,ld\n", stats.diskwrites);
503368c31abSDavid du Colombier 	hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites);
504368c31abSDavid du Colombier 	hprint(hout, "disk reads=%,ld\n", stats.diskreads);
505368c31abSDavid du Colombier 	hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads);
506368c31abSDavid du Colombier */
507368c31abSDavid du Colombier 
508368c31abSDavid du Colombier 	hflush(hout);
509368c31abSDavid du Colombier 	return 0;
510368c31abSDavid du Colombier }
511368c31abSDavid du Colombier 
512368c31abSDavid du Colombier static int
sindex(HConnect * c)513368c31abSDavid du Colombier sindex(HConnect *c)
514368c31abSDavid du Colombier {
515368c31abSDavid du Colombier 	Hio *hout;
516368c31abSDavid du Colombier 	Index *ix;
517368c31abSDavid du Colombier 	Arena *arena;
518368c31abSDavid du Colombier 	vlong clumps, cclumps, uncsize, used, size;
519368c31abSDavid du Colombier 	int i, r, active;
520368c31abSDavid du Colombier 
521368c31abSDavid du Colombier 	r = hsettext(c);
522368c31abSDavid du Colombier 	if(r < 0)
523368c31abSDavid du Colombier 		return r;
524368c31abSDavid du Colombier 	hout = &c->hout;
525368c31abSDavid du Colombier 
526368c31abSDavid du Colombier 	ix = mainindex;
527368c31abSDavid du Colombier 
528368c31abSDavid du Colombier 	hprint(hout, "index=%s\n", ix->name);
529368c31abSDavid du Colombier 
530368c31abSDavid du Colombier 	active = 0;
531368c31abSDavid du Colombier 	clumps = 0;
532368c31abSDavid du Colombier 	cclumps = 0;
533368c31abSDavid du Colombier 	uncsize = 0;
534368c31abSDavid du Colombier 	used = 0;
535368c31abSDavid du Colombier 	size = 0;
536368c31abSDavid du Colombier 	for(i = 0; i < ix->narenas; i++){
537368c31abSDavid du Colombier 		arena = ix->arenas[i];
538368c31abSDavid du Colombier 		if(arena != nil && arena->memstats.clumps != 0){
539368c31abSDavid du Colombier 			active++;
540368c31abSDavid du Colombier 			clumps += arena->memstats.clumps;
541368c31abSDavid du Colombier 			cclumps += arena->memstats.cclumps;
542368c31abSDavid du Colombier 			uncsize += arena->memstats.uncsize;
543368c31abSDavid du Colombier 			used += arena->memstats.used;
544368c31abSDavid du Colombier 		}
545368c31abSDavid du Colombier 		size += arena->size;
546368c31abSDavid du Colombier 	}
547368c31abSDavid du Colombier 	hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active);
548368c31abSDavid du Colombier 	hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize);
549368c31abSDavid du Colombier 	hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n",
550368c31abSDavid du Colombier 		clumps, cclumps, uncsize, used - clumps * ClumpSize);
551368c31abSDavid du Colombier 	hflush(hout);
552368c31abSDavid du Colombier 	return 0;
553368c31abSDavid du Colombier }
554368c31abSDavid du Colombier 
555368c31abSDavid du Colombier static void
darena(Hio * hout,Arena * arena)556368c31abSDavid du Colombier darena(Hio *hout, Arena *arena)
557368c31abSDavid du Colombier {
558368c31abSDavid du Colombier 	hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
559368c31abSDavid du Colombier 		arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize,
560368c31abSDavid du Colombier 		arena->version, arena->ctime, arena->wtime);
561368c31abSDavid du Colombier 	if(arena->memstats.sealed)
562368c31abSDavid du Colombier 		hprint(hout, " mem=sealed");
563368c31abSDavid du Colombier 	if(arena->diskstats.sealed)
564368c31abSDavid du Colombier 		hprint(hout, " disk=sealed");
565368c31abSDavid du Colombier 	hprint(hout, "\n");
566368c31abSDavid du Colombier 	if(scorecmp(zeroscore, arena->score) != 0)
567368c31abSDavid du Colombier 		hprint(hout, "\tscore=%V\n", arena->score);
568368c31abSDavid du Colombier 
569f9e1cf08SDavid du Colombier 	hprint(hout, "\twritten: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
570368c31abSDavid du Colombier 		arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize,
571368c31abSDavid du Colombier 		arena->memstats.used - arena->memstats.clumps * ClumpSize,
572368c31abSDavid du Colombier 		arena->memstats.used + arena->memstats.clumps * ClumpInfoSize);
573f9e1cf08SDavid du Colombier 	hprint(hout, "\tindexed: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
574368c31abSDavid du Colombier 		arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize,
575368c31abSDavid du Colombier 		arena->diskstats.used - arena->diskstats.clumps * ClumpSize,
576368c31abSDavid du Colombier 		arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize);
577368c31abSDavid du Colombier }
578368c31abSDavid du Colombier 
579368c31abSDavid du Colombier static int
hempty(HConnect * c)580368c31abSDavid du Colombier hempty(HConnect *c)
581368c31abSDavid du Colombier {
582368c31abSDavid du Colombier 	Hio *hout;
583368c31abSDavid du Colombier 	int r;
584368c31abSDavid du Colombier 
585368c31abSDavid du Colombier 	r = hsettext(c);
586368c31abSDavid du Colombier 	if(r < 0)
587368c31abSDavid du Colombier 		return r;
588368c31abSDavid du Colombier 	hout = &c->hout;
589368c31abSDavid du Colombier 
590368c31abSDavid du Colombier 	emptylumpcache();
591368c31abSDavid du Colombier 	emptydcache();
592368c31abSDavid du Colombier 	emptyicache();
593368c31abSDavid du Colombier 	hprint(hout, "emptied all caches\n");
594368c31abSDavid du Colombier 	hflush(hout);
595368c31abSDavid du Colombier 	return 0;
596368c31abSDavid du Colombier }
597368c31abSDavid du Colombier 
598368c31abSDavid du Colombier static int
hlcacheempty(HConnect * c)599368c31abSDavid du Colombier hlcacheempty(HConnect *c)
600368c31abSDavid du Colombier {
601368c31abSDavid du Colombier 	Hio *hout;
602368c31abSDavid du Colombier 	int r;
603368c31abSDavid du Colombier 
604368c31abSDavid du Colombier 	r = hsettext(c);
605368c31abSDavid du Colombier 	if(r < 0)
606368c31abSDavid du Colombier 		return r;
607368c31abSDavid du Colombier 	hout = &c->hout;
608368c31abSDavid du Colombier 
609368c31abSDavid du Colombier 	emptylumpcache();
610368c31abSDavid du Colombier 	hprint(hout, "emptied lumpcache\n");
611368c31abSDavid du Colombier 	hflush(hout);
612368c31abSDavid du Colombier 	return 0;
613368c31abSDavid du Colombier }
614368c31abSDavid du Colombier 
615368c31abSDavid du Colombier static int
hicacheempty(HConnect * c)616368c31abSDavid du Colombier hicacheempty(HConnect *c)
617368c31abSDavid du Colombier {
618368c31abSDavid du Colombier 	Hio *hout;
619368c31abSDavid du Colombier 	int r;
620368c31abSDavid du Colombier 
621368c31abSDavid du Colombier 	r = hsettext(c);
622368c31abSDavid du Colombier 	if(r < 0)
623368c31abSDavid du Colombier 		return r;
624368c31abSDavid du Colombier 	hout = &c->hout;
625368c31abSDavid du Colombier 
626368c31abSDavid du Colombier 	emptyicache();
627368c31abSDavid du Colombier 	hprint(hout, "emptied icache\n");
628368c31abSDavid du Colombier 	hflush(hout);
629368c31abSDavid du Colombier 	return 0;
630368c31abSDavid du Colombier }
631368c31abSDavid du Colombier 
632368c31abSDavid du Colombier static int
hdcacheempty(HConnect * c)633368c31abSDavid du Colombier hdcacheempty(HConnect *c)
634368c31abSDavid du Colombier {
635368c31abSDavid du Colombier 	Hio *hout;
636368c31abSDavid du Colombier 	int r;
637368c31abSDavid du Colombier 
638368c31abSDavid du Colombier 	r = hsettext(c);
639368c31abSDavid du Colombier 	if(r < 0)
640368c31abSDavid du Colombier 		return r;
641368c31abSDavid du Colombier 	hout = &c->hout;
642368c31abSDavid du Colombier 
643368c31abSDavid du Colombier 	emptydcache();
644368c31abSDavid du Colombier 	hprint(hout, "emptied dcache\n");
645368c31abSDavid du Colombier 	hflush(hout);
646368c31abSDavid du Colombier 	return 0;
647368c31abSDavid du Colombier }
648368c31abSDavid du Colombier static int
hicachekick(HConnect * c)649368c31abSDavid du Colombier hicachekick(HConnect *c)
650368c31abSDavid du Colombier {
651368c31abSDavid du Colombier 	Hio *hout;
652368c31abSDavid du Colombier 	int r;
653368c31abSDavid du Colombier 
654368c31abSDavid du Colombier 	r = hsettext(c);
655368c31abSDavid du Colombier 	if(r < 0)
656368c31abSDavid du Colombier 		return r;
657368c31abSDavid du Colombier 	hout = &c->hout;
658368c31abSDavid du Colombier 
659368c31abSDavid du Colombier 	kickicache();
660368c31abSDavid du Colombier 	hprint(hout, "kicked icache\n");
661368c31abSDavid du Colombier 	hflush(hout);
662368c31abSDavid du Colombier 	return 0;
663368c31abSDavid du Colombier }
664368c31abSDavid du Colombier 
665368c31abSDavid du Colombier static int
hdcachekick(HConnect * c)666368c31abSDavid du Colombier hdcachekick(HConnect *c)
667368c31abSDavid du Colombier {
668368c31abSDavid du Colombier 	Hio *hout;
669368c31abSDavid du Colombier 	int r;
670368c31abSDavid du Colombier 
671368c31abSDavid du Colombier 	r = hsettext(c);
672368c31abSDavid du Colombier 	if(r < 0)
673368c31abSDavid du Colombier 		return r;
674368c31abSDavid du Colombier 	hout = &c->hout;
675368c31abSDavid du Colombier 
676368c31abSDavid du Colombier 	kickdcache();
677368c31abSDavid du Colombier 	hprint(hout, "kicked dcache\n");
678368c31abSDavid du Colombier 	hflush(hout);
679368c31abSDavid du Colombier 	return 0;
680368c31abSDavid du Colombier }
681368c31abSDavid du Colombier static int
hicacheflush(HConnect * c)682368c31abSDavid du Colombier hicacheflush(HConnect *c)
683368c31abSDavid du Colombier {
684368c31abSDavid du Colombier 	Hio *hout;
685368c31abSDavid du Colombier 	int r;
686368c31abSDavid du Colombier 
687368c31abSDavid du Colombier 	r = hsettext(c);
688368c31abSDavid du Colombier 	if(r < 0)
689368c31abSDavid du Colombier 		return r;
690368c31abSDavid du Colombier 	hout = &c->hout;
691368c31abSDavid du Colombier 
692368c31abSDavid du Colombier 	flushicache();
693368c31abSDavid du Colombier 	hprint(hout, "flushed icache\n");
694368c31abSDavid du Colombier 	hflush(hout);
695368c31abSDavid du Colombier 	return 0;
696368c31abSDavid du Colombier }
697368c31abSDavid du Colombier 
698368c31abSDavid du Colombier static int
hdcacheflush(HConnect * c)699368c31abSDavid du Colombier hdcacheflush(HConnect *c)
700368c31abSDavid du Colombier {
701368c31abSDavid du Colombier 	Hio *hout;
702368c31abSDavid du Colombier 	int r;
703368c31abSDavid du Colombier 
704368c31abSDavid du Colombier 	r = hsettext(c);
705368c31abSDavid du Colombier 	if(r < 0)
706368c31abSDavid du Colombier 		return r;
707368c31abSDavid du Colombier 	hout = &c->hout;
708368c31abSDavid du Colombier 
709368c31abSDavid du Colombier 	flushdcache();
710368c31abSDavid du Colombier 	hprint(hout, "flushed dcache\n");
711368c31abSDavid du Colombier 	hflush(hout);
712368c31abSDavid du Colombier 	return 0;
713368c31abSDavid du Colombier }
714368c31abSDavid du Colombier 
715368c31abSDavid du Colombier static int
dindex(HConnect * c)716368c31abSDavid du Colombier dindex(HConnect *c)
717368c31abSDavid du Colombier {
718368c31abSDavid du Colombier 	Hio *hout;
719368c31abSDavid du Colombier 	Index *ix;
720368c31abSDavid du Colombier 	int i, r;
721368c31abSDavid du Colombier 
722368c31abSDavid du Colombier 	r = hsettext(c);
723368c31abSDavid du Colombier 	if(r < 0)
724368c31abSDavid du Colombier 		return r;
725368c31abSDavid du Colombier 	hout = &c->hout;
726368c31abSDavid du Colombier 
727368c31abSDavid du Colombier 
728368c31abSDavid du Colombier 	ix = mainindex;
729368c31abSDavid du Colombier 	hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n",
730368c31abSDavid du Colombier 		ix->name, ix->version, ix->blocksize, ix->tabsize);
731368c31abSDavid du Colombier 	hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
732368c31abSDavid du Colombier 	for(i = 0; i < ix->nsects; i++)
733368c31abSDavid du Colombier 		hprint(hout, "\tsect=%s for buckets [%lld,%lld) buckmax=%d\n", ix->smap[i].name, ix->smap[i].start, ix->smap[i].stop, ix->sects[i]->buckmax);
734368c31abSDavid du Colombier 	for(i = 0; i < ix->narenas; i++){
735368c31abSDavid du Colombier 		if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){
736368c31abSDavid du Colombier 			hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
737368c31abSDavid du Colombier 			darena(hout, ix->arenas[i]);
738368c31abSDavid du Colombier 		}
739368c31abSDavid du Colombier 	}
740368c31abSDavid du Colombier 	hflush(hout);
741368c31abSDavid du Colombier 	return 0;
742368c31abSDavid du Colombier }
743368c31abSDavid du Colombier 
744368c31abSDavid du Colombier typedef struct Arg Arg;
745368c31abSDavid du Colombier struct Arg
746368c31abSDavid du Colombier {
747368c31abSDavid du Colombier 	int index;
748368c31abSDavid du Colombier 	int index2;
749368c31abSDavid du Colombier };
750368c31abSDavid du Colombier 
751368c31abSDavid du Colombier static long
rawgraph(Stats * s,Stats * t,void * va)752368c31abSDavid du Colombier rawgraph(Stats *s, Stats *t, void *va)
753368c31abSDavid du Colombier {
754368c31abSDavid du Colombier 	Arg *a;
755368c31abSDavid du Colombier 
756368c31abSDavid du Colombier 	USED(s);
757368c31abSDavid du Colombier 	a = va;
758368c31abSDavid du Colombier 	return t->n[a->index];
759368c31abSDavid du Colombier }
760368c31abSDavid du Colombier 
761368c31abSDavid du Colombier static long
diffgraph(Stats * s,Stats * t,void * va)762368c31abSDavid du Colombier diffgraph(Stats *s, Stats *t, void *va)
763368c31abSDavid du Colombier {
764368c31abSDavid du Colombier 	Arg *a;
765368c31abSDavid du Colombier 
766368c31abSDavid du Colombier 	a = va;
767368c31abSDavid du Colombier 	return t->n[a->index] - s->n[a->index];
768368c31abSDavid du Colombier }
769368c31abSDavid du Colombier 
770368c31abSDavid du Colombier static long
pctgraph(Stats * s,Stats * t,void * va)771368c31abSDavid du Colombier pctgraph(Stats *s, Stats *t, void *va)
772368c31abSDavid du Colombier {
773368c31abSDavid du Colombier 	Arg *a;
774368c31abSDavid du Colombier 
775368c31abSDavid du Colombier 	USED(s);
776368c31abSDavid du Colombier 	a = va;
777368c31abSDavid du Colombier 	return percent(t->n[a->index], t->n[a->index2]);
778368c31abSDavid du Colombier }
779368c31abSDavid du Colombier 
780368c31abSDavid du Colombier static long
pctdiffgraph(Stats * s,Stats * t,void * va)781368c31abSDavid du Colombier pctdiffgraph(Stats *s, Stats *t, void *va)
782368c31abSDavid du Colombier {
783368c31abSDavid du Colombier 	Arg *a;
784368c31abSDavid du Colombier 
785368c31abSDavid du Colombier 	a = va;
786368c31abSDavid du Colombier 	return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]);
787368c31abSDavid du Colombier }
788368c31abSDavid du Colombier 
789368c31abSDavid du Colombier static long
xdiv(long a,long b)790368c31abSDavid du Colombier xdiv(long a, long b)
791368c31abSDavid du Colombier {
792368c31abSDavid du Colombier 	if(b == 0)
793368c31abSDavid du Colombier 		b++;
794368c31abSDavid du Colombier 	return a/b;
795368c31abSDavid du Colombier }
796368c31abSDavid du Colombier 
797368c31abSDavid du Colombier static long
divdiffgraph(Stats * s,Stats * t,void * va)798368c31abSDavid du Colombier divdiffgraph(Stats *s, Stats *t, void *va)
799368c31abSDavid du Colombier {
800368c31abSDavid du Colombier 	Arg *a;
801368c31abSDavid du Colombier 
802368c31abSDavid du Colombier 	a = va;
803368c31abSDavid du Colombier 	return xdiv(t->n[a->index] - s->n[a->index], t->n[a->index2] - s->n[a->index2]);
804368c31abSDavid du Colombier }
805368c31abSDavid du Colombier 
806368c31abSDavid du Colombier static long
netbw(Stats * s)807368c31abSDavid du Colombier netbw(Stats *s)
808368c31abSDavid du Colombier {
809368c31abSDavid du Colombier 	ulong *n;
810368c31abSDavid du Colombier 
811368c31abSDavid du Colombier 	n = s->n;
812368c31abSDavid du Colombier 	return n[StatRpcReadBytes]+n[StatRpcWriteBytes];	/* not exactly right */
813368c31abSDavid du Colombier }
814368c31abSDavid du Colombier 
815368c31abSDavid du Colombier static long
diskbw(Stats * s)816368c31abSDavid du Colombier diskbw(Stats *s)
817368c31abSDavid du Colombier {
818368c31abSDavid du Colombier 	ulong *n;
819368c31abSDavid du Colombier 
820368c31abSDavid du Colombier 	n = s->n;
821368c31abSDavid du Colombier 	return n[StatApartReadBytes]+n[StatApartWriteBytes]
822368c31abSDavid du Colombier 		+ n[StatIsectReadBytes]+n[StatIsectWriteBytes]
823368c31abSDavid du Colombier 		+ n[StatSumReadBytes];
824368c31abSDavid du Colombier }
825368c31abSDavid du Colombier 
826368c31abSDavid du Colombier static long
iobw(Stats * s)827368c31abSDavid du Colombier iobw(Stats *s)
828368c31abSDavid du Colombier {
829368c31abSDavid du Colombier 	return netbw(s)+diskbw(s);
830368c31abSDavid du Colombier }
831368c31abSDavid du Colombier 
832368c31abSDavid du Colombier static long
diskgraph(Stats * s,Stats * t,void * va)833368c31abSDavid du Colombier diskgraph(Stats *s, Stats *t, void *va)
834368c31abSDavid du Colombier {
835368c31abSDavid du Colombier 	USED(va);
836368c31abSDavid du Colombier 	return diskbw(t)-diskbw(s);
837368c31abSDavid du Colombier }
838368c31abSDavid du Colombier 
839368c31abSDavid du Colombier static long
netgraph(Stats * s,Stats * t,void * va)840368c31abSDavid du Colombier netgraph(Stats *s, Stats *t, void *va)
841368c31abSDavid du Colombier {
842368c31abSDavid du Colombier 	USED(va);
843368c31abSDavid du Colombier 	return netbw(t)-netbw(s);
844368c31abSDavid du Colombier }
845368c31abSDavid du Colombier 
846368c31abSDavid du Colombier static long
iograph(Stats * s,Stats * t,void * va)847368c31abSDavid du Colombier iograph(Stats *s, Stats *t, void *va)
848368c31abSDavid du Colombier {
849368c31abSDavid du Colombier 	USED(va);
850368c31abSDavid du Colombier 	return iobw(t)-iobw(s);
851368c31abSDavid du Colombier }
852368c31abSDavid du Colombier 
853368c31abSDavid du Colombier 
854368c31abSDavid du Colombier static char* graphname[] =
855368c31abSDavid du Colombier {
856368c31abSDavid du Colombier 	"rpctotal",
857368c31abSDavid du Colombier 	"rpcread",
858368c31abSDavid du Colombier 	"rpcreadok",
859368c31abSDavid du Colombier 	"rpcreadfail",
860368c31abSDavid du Colombier 	"rpcreadbyte",
861368c31abSDavid du Colombier 	"rpcreadtime",
862368c31abSDavid du Colombier 	"rpcreadcached",
863368c31abSDavid du Colombier 	"rpcreadcachedtime",
864368c31abSDavid du Colombier 	"rpcreaduncached",
865368c31abSDavid du Colombier 	"rpcreaduncachedtime",
866368c31abSDavid du Colombier 	"rpcwrite",
867368c31abSDavid du Colombier 	"rpcwritenew",
868368c31abSDavid du Colombier 	"rpcwriteold",
869368c31abSDavid du Colombier 	"rpcwritefail",
870368c31abSDavid du Colombier 	"rpcwritebyte",
871368c31abSDavid du Colombier 	"rpcwritetime",
872368c31abSDavid du Colombier 	"rpcwritenewtime",
873368c31abSDavid du Colombier 	"rpcwriteoldtime",
874368c31abSDavid du Colombier 
875368c31abSDavid du Colombier 	"lcachehit",
876368c31abSDavid du Colombier 	"lcachemiss",
877368c31abSDavid du Colombier 	"lcachelookup",
878368c31abSDavid du Colombier 	"lcachewrite",
879368c31abSDavid du Colombier 	"lcachesize",
880368c31abSDavid du Colombier 	"lcachestall",
881368c31abSDavid du Colombier 	"lcachelookuptime",
882368c31abSDavid du Colombier 
883368c31abSDavid du Colombier 	"dcachehit",
884368c31abSDavid du Colombier 	"dcachemiss",
885368c31abSDavid du Colombier 	"dcachelookup",
886368c31abSDavid du Colombier 	"dcacheread",
887368c31abSDavid du Colombier 	"dcachewrite",
888368c31abSDavid du Colombier 	"dcachedirty",
889368c31abSDavid du Colombier 	"dcachesize",
890368c31abSDavid du Colombier 	"dcacheflush",
891368c31abSDavid du Colombier 	"dcachestall",
892368c31abSDavid du Colombier 	"dcachelookuptime",
893368c31abSDavid du Colombier 
894368c31abSDavid du Colombier 	"dblockstall",
895368c31abSDavid du Colombier 	"lumpstall",
896368c31abSDavid du Colombier 
897368c31abSDavid du Colombier 	"icachehit",
898368c31abSDavid du Colombier 	"icachemiss",
899f9e1cf08SDavid du Colombier 	"icacheread",
900368c31abSDavid du Colombier 	"icachewrite",
901368c31abSDavid du Colombier 	"icachefill",
902368c31abSDavid du Colombier 	"icacheprefetch",
903368c31abSDavid du Colombier 	"icachedirty",
904368c31abSDavid du Colombier 	"icachesize",
905368c31abSDavid du Colombier 	"icacheflush",
906368c31abSDavid du Colombier 	"icachestall",
907368c31abSDavid du Colombier 	"icachelookuptime",
908f9e1cf08SDavid du Colombier 	"icachelookup",
909f9e1cf08SDavid du Colombier 	"scachehit",
910f9e1cf08SDavid du Colombier 	"scacheprefetch",
911368c31abSDavid du Colombier 
912368c31abSDavid du Colombier 	"bloomhit",
913368c31abSDavid du Colombier 	"bloommiss",
914368c31abSDavid du Colombier 	"bloomfalsemiss",
915368c31abSDavid du Colombier 	"bloomlookup",
916368c31abSDavid du Colombier 	"bloomones",
917368c31abSDavid du Colombier 	"bloombits",
918368c31abSDavid du Colombier 
919368c31abSDavid du Colombier 	"apartread",
920368c31abSDavid du Colombier 	"apartreadbyte",
921368c31abSDavid du Colombier 	"apartwrite",
922368c31abSDavid du Colombier 	"apartwritebyte",
923368c31abSDavid du Colombier 
924368c31abSDavid du Colombier 	"isectread",
925368c31abSDavid du Colombier 	"isectreadbyte",
926368c31abSDavid du Colombier 	"isectwrite",
927368c31abSDavid du Colombier 	"isectwritebyte",
928368c31abSDavid du Colombier 
929368c31abSDavid du Colombier 	"sumread",
930368c31abSDavid du Colombier 	"sumreadbyte",
931f9e1cf08SDavid du Colombier 
932f9e1cf08SDavid du Colombier 	"cigload",
933f9e1cf08SDavid du Colombier 	"cigloadtime",
934368c31abSDavid du Colombier };
935368c31abSDavid du Colombier 
936368c31abSDavid du Colombier static int
findname(char * s)937368c31abSDavid du Colombier findname(char *s)
938368c31abSDavid du Colombier {
939368c31abSDavid du Colombier 	int i;
940368c31abSDavid du Colombier 
941368c31abSDavid du Colombier 	for(i=0; i<nelem(graphname); i++)
942368c31abSDavid du Colombier 		if(strcmp(graphname[i], s) == 0)
943368c31abSDavid du Colombier 			return i;
944368c31abSDavid du Colombier 	return -1;
945368c31abSDavid du Colombier }
946368c31abSDavid du Colombier 
947368c31abSDavid du Colombier static void
dotextbin(Hio * io,Graph * g)948368c31abSDavid du Colombier dotextbin(Hio *io, Graph *g)
949368c31abSDavid du Colombier {
950368c31abSDavid du Colombier 	int i, nbin;
951368c31abSDavid du Colombier 	Statbin *b, bin[2000];	/* 32 kB, but whack is worse */
952368c31abSDavid du Colombier 
953368c31abSDavid du Colombier 	needstack(8192);	/* double check that bin didn't kill us */
954368c31abSDavid du Colombier 	nbin = 100;
955368c31abSDavid du Colombier 	binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin);
956368c31abSDavid du Colombier 
957368c31abSDavid du Colombier 	hprint(io, "stats\n\n");
958368c31abSDavid du Colombier 	for(i=0; i<nbin; i++){
959368c31abSDavid du Colombier 		b = &bin[i];
960368c31abSDavid du Colombier 		hprint(io, "%d: nsamp=%d min=%d max=%d avg=%d\n",
961368c31abSDavid du Colombier 			i, b->nsamp, b->min, b->max, b->avg);
962368c31abSDavid du Colombier 	}
963368c31abSDavid du Colombier }
964368c31abSDavid du Colombier 
965368c31abSDavid du Colombier static int
xgraph(HConnect * c)966368c31abSDavid du Colombier xgraph(HConnect *c)
967368c31abSDavid du Colombier {
968368c31abSDavid du Colombier 	char *name;
969368c31abSDavid du Colombier 	Hio *hout;
970368c31abSDavid du Colombier 	Memimage *m;
971368c31abSDavid du Colombier 	int dotext;
972368c31abSDavid du Colombier 	Graph g;
973368c31abSDavid du Colombier 	Arg arg;
974368c31abSDavid du Colombier 	char *graph, *a;
975368c31abSDavid du Colombier 
976368c31abSDavid du Colombier 	name = hargstr(c, "arg", "");
977368c31abSDavid du Colombier 	if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){
978368c31abSDavid du Colombier 		werrstr("unknown name %s", name);
979368c31abSDavid du Colombier 		goto error;
980368c31abSDavid du Colombier 	}
981368c31abSDavid du Colombier 	a = hargstr(c, "arg2", "");
982368c31abSDavid du Colombier 	if(a[0] && (arg.index2 = findname(a)) == -1){
983368c31abSDavid du Colombier 		werrstr("unknown name %s", a);
984368c31abSDavid du Colombier 		goto error;
985368c31abSDavid du Colombier 	}
986368c31abSDavid du Colombier 
987368c31abSDavid du Colombier 	g.arg = &arg;
988368c31abSDavid du Colombier 	g.t0 = hargint(c, "t0", -120);
989368c31abSDavid du Colombier 	g.t1 = hargint(c, "t1", 0);
990368c31abSDavid du Colombier 	g.min = hargint(c, "min", -1);
991368c31abSDavid du Colombier 	g.max = hargint(c, "max", -1);
992368c31abSDavid du Colombier 	g.wid = hargint(c, "wid", -1);
993368c31abSDavid du Colombier 	g.ht = hargint(c, "ht", -1);
994368c31abSDavid du Colombier 	dotext = hargstr(c, "text", "")[0] != 0;
995368c31abSDavid du Colombier 	g.fill = hargint(c, "fill", -1);
996368c31abSDavid du Colombier 
997368c31abSDavid du Colombier 	graph = hargstr(c, "graph", "raw");
998368c31abSDavid du Colombier 	if(strcmp(graph, "raw") == 0)
999368c31abSDavid du Colombier 		g.fn = rawgraph;
1000368c31abSDavid du Colombier 	else if(strcmp(graph, "diskbw") == 0)
1001368c31abSDavid du Colombier 		g.fn = diskgraph;
1002368c31abSDavid du Colombier 	else if(strcmp(graph, "iobw") == 0)
1003368c31abSDavid du Colombier 		g.fn = iograph;
1004368c31abSDavid du Colombier 	else if(strcmp(graph, "netbw") == 0)
1005368c31abSDavid du Colombier 		g.fn = netgraph;
1006368c31abSDavid du Colombier 	else if(strcmp(graph, "diff") == 0)
1007368c31abSDavid du Colombier 		g.fn = diffgraph;
1008368c31abSDavid du Colombier 	else if(strcmp(graph, "pct") == 0)
1009368c31abSDavid du Colombier 		g.fn = pctgraph;
1010368c31abSDavid du Colombier 	else if(strcmp(graph, "pctdiff") == 0)
1011368c31abSDavid du Colombier 		g.fn = pctdiffgraph;
1012368c31abSDavid du Colombier 	else if(strcmp(graph, "divdiff") == 0)
1013368c31abSDavid du Colombier 		g.fn = divdiffgraph;
1014368c31abSDavid du Colombier 	else{
1015368c31abSDavid du Colombier 		werrstr("unknown graph %s", graph);
1016368c31abSDavid du Colombier 		goto error;
1017368c31abSDavid du Colombier 	}
1018368c31abSDavid du Colombier 
1019368c31abSDavid du Colombier 	if(dotext){
1020368c31abSDavid du Colombier 		hsettype(c, "text/plain");
1021368c31abSDavid du Colombier 		dotextbin(&c->hout, &g);
1022368c31abSDavid du Colombier 		hflush(&c->hout);
1023368c31abSDavid du Colombier 		return 0;
1024368c31abSDavid du Colombier 	}
1025368c31abSDavid du Colombier 
1026368c31abSDavid du Colombier 	m = statgraph(&g);
1027368c31abSDavid du Colombier 	if(m == nil)
1028368c31abSDavid du Colombier 		goto error;
1029368c31abSDavid du Colombier 
1030368c31abSDavid du Colombier 	if(hsettype(c, "image/png") < 0)
1031368c31abSDavid du Colombier 		return -1;
1032368c31abSDavid du Colombier 	hout = &c->hout;
1033368c31abSDavid du Colombier 	writepng(hout, m);
1034368c31abSDavid du Colombier 	qlock(&memdrawlock);
1035368c31abSDavid du Colombier 	freememimage(m);
1036368c31abSDavid du Colombier 	qunlock(&memdrawlock);
1037368c31abSDavid du Colombier 	hflush(hout);
1038368c31abSDavid du Colombier 	return 0;
1039368c31abSDavid du Colombier 
1040368c31abSDavid du Colombier error:
1041368c31abSDavid du Colombier 	return herror(c);
1042368c31abSDavid du Colombier }
1043368c31abSDavid du Colombier 
1044368c31abSDavid du Colombier static int
xloglist(HConnect * c)1045368c31abSDavid du Colombier xloglist(HConnect *c)
1046368c31abSDavid du Colombier {
1047368c31abSDavid du Colombier 	if(hsettype(c, "text/html") < 0)
1048368c31abSDavid du Colombier 		return -1;
1049368c31abSDavid du Colombier 	vtloghlist(&c->hout);
1050368c31abSDavid du Colombier 	hflush(&c->hout);
1051368c31abSDavid du Colombier 	return 0;
1052368c31abSDavid du Colombier }
1053368c31abSDavid du Colombier 
1054368c31abSDavid du Colombier static int
xlog(HConnect * c)1055368c31abSDavid du Colombier xlog(HConnect *c)
1056368c31abSDavid du Colombier {
1057368c31abSDavid du Colombier 	char *name;
1058368c31abSDavid du Colombier 	VtLog *l;
1059368c31abSDavid du Colombier 
1060368c31abSDavid du Colombier 	name = hargstr(c, "log", "");
1061368c31abSDavid du Colombier 	if(!name[0])
1062368c31abSDavid du Colombier 		return xloglist(c);
1063368c31abSDavid du Colombier 	l = vtlogopen(name, 0);
1064368c31abSDavid du Colombier 	if(l == nil)
1065368c31abSDavid du Colombier 		return hnotfound(c);
1066368c31abSDavid du Colombier 	if(hsettype(c, "text/html") < 0){
1067368c31abSDavid du Colombier 		vtlogclose(l);
1068368c31abSDavid du Colombier 		return -1;
1069368c31abSDavid du Colombier 	}
1070368c31abSDavid du Colombier 	vtloghdump(&c->hout, l);
1071368c31abSDavid du Colombier 	vtlogclose(l);
1072368c31abSDavid du Colombier 	hflush(&c->hout);
1073368c31abSDavid du Colombier 	return 0;
1074368c31abSDavid du Colombier }
1075368c31abSDavid du Colombier 
1076368c31abSDavid du Colombier static int
xindex(HConnect * c)1077368c31abSDavid du Colombier xindex(HConnect *c)
1078368c31abSDavid du Colombier {
1079368c31abSDavid du Colombier 	if(hsettype(c, "text/xml") < 0)
1080368c31abSDavid du Colombier 		return -1;
1081368c31abSDavid du Colombier 	xmlindex(&c->hout, mainindex, "index", 0);
1082368c31abSDavid du Colombier 	hflush(&c->hout);
1083368c31abSDavid du Colombier 	return 0;
1084368c31abSDavid du Colombier }
1085368c31abSDavid du Colombier 
1086368c31abSDavid du Colombier void
xmlindent(Hio * hout,int indent)1087368c31abSDavid du Colombier xmlindent(Hio *hout, int indent)
1088368c31abSDavid du Colombier {
1089368c31abSDavid du Colombier 	int i;
1090368c31abSDavid du Colombier 
1091368c31abSDavid du Colombier 	for(i = 0; i < indent; i++)
1092368c31abSDavid du Colombier 		hputc(hout, '\t');
1093368c31abSDavid du Colombier }
1094368c31abSDavid du Colombier 
1095368c31abSDavid du Colombier void
xmlaname(Hio * hout,char * v,char * tag)1096368c31abSDavid du Colombier xmlaname(Hio *hout, char *v, char *tag)
1097368c31abSDavid du Colombier {
1098368c31abSDavid du Colombier 	hprint(hout, " %s=\"%s\"", tag, v);
1099368c31abSDavid du Colombier }
1100368c31abSDavid du Colombier 
1101368c31abSDavid du Colombier void
xmlscore(Hio * hout,u8int * v,char * tag)1102368c31abSDavid du Colombier xmlscore(Hio *hout, u8int *v, char *tag)
1103368c31abSDavid du Colombier {
1104368c31abSDavid du Colombier 	if(scorecmp(zeroscore, v) == 0)
1105368c31abSDavid du Colombier 		return;
1106368c31abSDavid du Colombier 	hprint(hout, " %s=\"%V\"", tag, v);
1107368c31abSDavid du Colombier }
1108368c31abSDavid du Colombier 
1109368c31abSDavid du Colombier void
xmlsealed(Hio * hout,int v,char * tag)1110368c31abSDavid du Colombier xmlsealed(Hio *hout, int v, char *tag)
1111368c31abSDavid du Colombier {
1112368c31abSDavid du Colombier 	if(!v)
1113368c31abSDavid du Colombier 		return;
1114368c31abSDavid du Colombier 	hprint(hout, " %s=\"yes\"", tag);
1115368c31abSDavid du Colombier }
1116368c31abSDavid du Colombier 
1117368c31abSDavid du Colombier void
xmlu32int(Hio * hout,u32int v,char * tag)1118368c31abSDavid du Colombier xmlu32int(Hio *hout, u32int v, char *tag)
1119368c31abSDavid du Colombier {
1120368c31abSDavid du Colombier 	hprint(hout, " %s=\"%ud\"", tag, v);
1121368c31abSDavid du Colombier }
1122368c31abSDavid du Colombier 
1123368c31abSDavid du Colombier void
xmlu64int(Hio * hout,u64int v,char * tag)1124368c31abSDavid du Colombier xmlu64int(Hio *hout, u64int v, char *tag)
1125368c31abSDavid du Colombier {
1126368c31abSDavid du Colombier 	hprint(hout, " %s=\"%llud\"", tag, v);
1127368c31abSDavid du Colombier }
1128368c31abSDavid du Colombier 
1129368c31abSDavid du Colombier void
vtloghdump(Hio * h,VtLog * l)1130368c31abSDavid du Colombier vtloghdump(Hio *h, VtLog *l)
1131368c31abSDavid du Colombier {
1132368c31abSDavid du Colombier 	int i;
1133368c31abSDavid du Colombier 	VtLogChunk *c;
1134368c31abSDavid du Colombier 	char *name;
1135368c31abSDavid du Colombier 
1136368c31abSDavid du Colombier 	name = l ? l->name : "&lt;nil&gt;";
1137368c31abSDavid du Colombier 
1138368c31abSDavid du Colombier 	hprint(h, "<html><head>\n");
1139368c31abSDavid du Colombier 	hprint(h, "<title>Venti Server Log: %s</title>\n", name);
1140368c31abSDavid du Colombier 	hprint(h, "</head><body>\n");
1141368c31abSDavid du Colombier 	hprint(h, "<b>Venti Server Log: %s</b>\n<p>\n", name);
1142368c31abSDavid du Colombier 
1143368c31abSDavid du Colombier 	if(l){
1144368c31abSDavid du Colombier 		c = l->w;
1145368c31abSDavid du Colombier 		for(i=0; i<l->nchunk; i++){
1146368c31abSDavid du Colombier 			if(++c == l->chunk+l->nchunk)
1147368c31abSDavid du Colombier 				c = l->chunk;
1148368c31abSDavid du Colombier 			hwrite(h, c->p, c->wp-c->p);
1149368c31abSDavid du Colombier 		}
1150368c31abSDavid du Colombier 	}
1151368c31abSDavid du Colombier 	hprint(h, "</body></html>\n");
1152368c31abSDavid du Colombier }
1153368c31abSDavid du Colombier 
1154368c31abSDavid du Colombier static int
strpcmp(const void * va,const void * vb)1155368c31abSDavid du Colombier strpcmp(const void *va, const void *vb)
1156368c31abSDavid du Colombier {
1157368c31abSDavid du Colombier 	return strcmp(*(char**)va, *(char**)vb);
1158368c31abSDavid du Colombier }
1159368c31abSDavid du Colombier 
1160368c31abSDavid du Colombier void
vtloghlist(Hio * h)1161368c31abSDavid du Colombier vtloghlist(Hio *h)
1162368c31abSDavid du Colombier {
1163368c31abSDavid du Colombier 	char **p;
1164368c31abSDavid du Colombier 	int i, n;
1165368c31abSDavid du Colombier 
1166368c31abSDavid du Colombier 	hprint(h, "<html><head>\n");
1167368c31abSDavid du Colombier 	hprint(h, "<title>Venti Server Logs</title>\n");
1168368c31abSDavid du Colombier 	hprint(h, "</head><body>\n");
1169368c31abSDavid du Colombier 	hprint(h, "<b>Venti Server Logs</b>\n<p>\n");
1170368c31abSDavid du Colombier 
1171368c31abSDavid du Colombier 	p = vtlognames(&n);
1172368c31abSDavid du Colombier 	qsort(p, n, sizeof(p[0]), strpcmp);
1173368c31abSDavid du Colombier 	for(i=0; i<n; i++)
1174368c31abSDavid du Colombier 		hprint(h, "<a href=\"/log?log=%s\">%s</a><br>\n", p[i], p[i]);
1175368c31abSDavid du Colombier 	vtfree(p);
1176368c31abSDavid du Colombier 	hprint(h, "</body></html>\n");
1177368c31abSDavid du Colombier }
1178