xref: /plan9/sys/src/cmd/venti/srv/httpd.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
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
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);
72368c31abSDavid du Colombier 
73368c31abSDavid du Colombier 	if(vtproc(listenproc, address) < 0)
74368c31abSDavid du Colombier 		return -1;
75368c31abSDavid du Colombier 	return 0;
76368c31abSDavid du Colombier }
77368c31abSDavid du Colombier 
78368c31abSDavid du Colombier static int
79368c31abSDavid du Colombier httpdobj(char *name, int (*f)(HConnect*))
80368c31abSDavid du Colombier {
81368c31abSDavid du Colombier 	int i;
82368c31abSDavid du Colombier 
83368c31abSDavid du Colombier 	if(name == nil || strlen(name) >= ObjNameSize)
84368c31abSDavid du Colombier 		return -1;
85368c31abSDavid du Colombier 	for(i = 0; i < MaxObjs; i++){
86368c31abSDavid du Colombier 		if(objs[i].name[0] == '\0'){
87368c31abSDavid du Colombier 			strcpy(objs[i].name, name);
88368c31abSDavid du Colombier 			objs[i].f = f;
89368c31abSDavid du Colombier 			return 0;
90368c31abSDavid du Colombier 		}
91368c31abSDavid du Colombier 		if(strcmp(objs[i].name, name) == 0)
92368c31abSDavid du Colombier 			return -1;
93368c31abSDavid du Colombier 	}
94368c31abSDavid du Colombier 	return -1;
95368c31abSDavid du Colombier }
96368c31abSDavid du Colombier 
97368c31abSDavid du Colombier static HConnect*
98368c31abSDavid du Colombier mkconnect(void)
99368c31abSDavid du Colombier {
100368c31abSDavid du Colombier 	HConnect *c;
101368c31abSDavid du Colombier 
102368c31abSDavid du Colombier 	c = mallocz(sizeof(HConnect), 1);
103368c31abSDavid du Colombier 	if(c == nil)
104368c31abSDavid du Colombier 		sysfatal("out of memory");
105368c31abSDavid du Colombier 	c->replog = nil;
106368c31abSDavid du Colombier 	c->hpos = c->header;
107368c31abSDavid du Colombier 	c->hstop = c->header;
108368c31abSDavid du Colombier 	return c;
109368c31abSDavid du Colombier }
110368c31abSDavid du Colombier 
111368c31abSDavid du Colombier void httpproc(void*);
112368c31abSDavid du Colombier 
113368c31abSDavid du Colombier static void
114368c31abSDavid du Colombier listenproc(void *vaddress)
115368c31abSDavid du Colombier {
116368c31abSDavid du Colombier 	HConnect *c;
117368c31abSDavid du Colombier 	char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
118368c31abSDavid du Colombier 	int ctl, nctl, data;
119368c31abSDavid du Colombier 
120368c31abSDavid du Colombier 	address = vaddress;
121368c31abSDavid du Colombier 	ctl = announce(address, dir);
122368c31abSDavid du Colombier 	if(ctl < 0){
123368c31abSDavid du Colombier 		fprint(2, "venti: httpd can't announce on %s: %r\n", address);
124368c31abSDavid du Colombier 		return;
125368c31abSDavid du Colombier 	}
126368c31abSDavid du Colombier 
127368c31abSDavid du Colombier 	if(0) print("announce ctl %d dir %s\n", ctl, dir);
128368c31abSDavid du Colombier 	for(;;){
129368c31abSDavid du Colombier 		/*
130368c31abSDavid du Colombier 		 *  wait for a call (or an error)
131368c31abSDavid du Colombier 		 */
132368c31abSDavid du Colombier 		nctl = listen(dir, ndir);
133368c31abSDavid du Colombier 		if(0) print("httpd listen %d %s...\n", nctl, ndir);
134368c31abSDavid du Colombier 		if(nctl < 0){
135368c31abSDavid du Colombier 			fprint(2, "venti: httpd can't listen on %s: %r\n", address);
136368c31abSDavid du Colombier 			return;
137368c31abSDavid du Colombier 		}
138368c31abSDavid du Colombier 
139368c31abSDavid du Colombier 		data = accept(ctl, ndir);
140368c31abSDavid du Colombier 		if(0) print("httpd accept %d...\n", data);
141368c31abSDavid du Colombier 		if(data < 0){
142368c31abSDavid du Colombier 			fprint(2, "venti: httpd accept: %r\n");
143368c31abSDavid du Colombier 			close(nctl);
144368c31abSDavid du Colombier 			continue;
145368c31abSDavid du Colombier 		}
146368c31abSDavid du Colombier 		if(0) print("httpd close nctl %d\n", nctl);
147368c31abSDavid du Colombier 		close(nctl);
148368c31abSDavid du Colombier 		c = mkconnect();
149368c31abSDavid du Colombier 		hinit(&c->hin, data, Hread);
150368c31abSDavid du Colombier 		hinit(&c->hout, data, Hwrite);
151368c31abSDavid du Colombier 		vtproc(httpproc, c);
152368c31abSDavid du Colombier 	}
153368c31abSDavid du Colombier }
154368c31abSDavid du Colombier 
155368c31abSDavid du Colombier void
156368c31abSDavid du Colombier httpproc(void *v)
157368c31abSDavid du Colombier {
158368c31abSDavid du Colombier 	HConnect *c;
159368c31abSDavid du Colombier 	int ok, i, n;
160368c31abSDavid du Colombier 
161368c31abSDavid du Colombier 	c = v;
162368c31abSDavid du Colombier 
163368c31abSDavid du Colombier 	for(;;){
164368c31abSDavid du Colombier 		/*
165368c31abSDavid du Colombier 		 * No timeout because the signal appears to hit every
166368c31abSDavid du Colombier 		 * proc, not just us.
167368c31abSDavid du Colombier 		 */
168368c31abSDavid du Colombier 		if(hparsereq(c, 0) < 0)
169368c31abSDavid du Colombier 			break;
170368c31abSDavid du Colombier 
171368c31abSDavid du Colombier 		for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
172368c31abSDavid du Colombier 			n = strlen(objs[i].name);
173368c31abSDavid du Colombier 			if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0)
174368c31abSDavid du Colombier 			|| (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){
175368c31abSDavid du Colombier 				ok = (*objs[i].f)(c);
176368c31abSDavid du Colombier 				goto found;
177368c31abSDavid du Colombier 			}
178368c31abSDavid du Colombier 		}
179368c31abSDavid du Colombier 		ok = fromwebdir(c);
180368c31abSDavid du Colombier 	found:
181368c31abSDavid du Colombier 		hflush(&c->hout);
182368c31abSDavid du Colombier 		if(c->head.closeit)
183368c31abSDavid du Colombier 			ok = -1;
184368c31abSDavid du Colombier 		hreqcleanup(c);
185368c31abSDavid du Colombier 
186368c31abSDavid du Colombier 		if(ok < 0)
187368c31abSDavid du Colombier 			break;
188368c31abSDavid du Colombier 	}
189368c31abSDavid du Colombier 	hreqcleanup(c);
190368c31abSDavid du Colombier 	close(c->hin.fd);
191368c31abSDavid du Colombier 	free(c);
192368c31abSDavid du Colombier }
193368c31abSDavid du Colombier 
194368c31abSDavid du Colombier char*
195368c31abSDavid du Colombier hargstr(HConnect *c, char *name, char *def)
196368c31abSDavid du Colombier {
197368c31abSDavid du Colombier 	HSPairs *p;
198368c31abSDavid du Colombier 
199368c31abSDavid du Colombier 	for(p=c->req.searchpairs; p; p=p->next)
200368c31abSDavid du Colombier 		if(strcmp(p->s, name) == 0)
201368c31abSDavid du Colombier 			return p->t;
202368c31abSDavid du Colombier 	return def;
203368c31abSDavid du Colombier }
204368c31abSDavid du Colombier 
205368c31abSDavid du Colombier vlong
206368c31abSDavid du Colombier hargint(HConnect *c, char *name, vlong def)
207368c31abSDavid du Colombier {
208368c31abSDavid du Colombier 	char *a;
209368c31abSDavid du Colombier 
210368c31abSDavid du Colombier 	if((a = hargstr(c, name, nil)) == nil)
211368c31abSDavid du Colombier 		return def;
212368c31abSDavid du Colombier 	return atoll(a);
213368c31abSDavid du Colombier }
214368c31abSDavid du Colombier 
215368c31abSDavid du Colombier static int
216368c31abSDavid du Colombier percent(ulong v, ulong total)
217368c31abSDavid du Colombier {
218368c31abSDavid du Colombier 	if(total == 0)
219368c31abSDavid du Colombier 		total = 1;
220368c31abSDavid du Colombier 	if(v < 1000*1000)
221368c31abSDavid du Colombier 		return (v * 100) / total;
222368c31abSDavid du Colombier 	total /= 100;
223368c31abSDavid du Colombier 	if(total == 0)
224368c31abSDavid du Colombier 		total = 1;
225368c31abSDavid du Colombier 	return v / total;
226368c31abSDavid du Colombier }
227368c31abSDavid du Colombier 
228368c31abSDavid du Colombier static int
229368c31abSDavid du Colombier preq(HConnect *c)
230368c31abSDavid du Colombier {
231368c31abSDavid du Colombier 	if(hparseheaders(c, 0) < 0)
232368c31abSDavid du Colombier 		return -1;
233368c31abSDavid du Colombier 	if(strcmp(c->req.meth, "GET") != 0
234368c31abSDavid du Colombier 	&& strcmp(c->req.meth, "HEAD") != 0)
235368c31abSDavid du Colombier 		return hunallowed(c, "GET, HEAD");
236368c31abSDavid du Colombier 	if(c->head.expectother || c->head.expectcont)
237368c31abSDavid du Colombier 		return hfail(c, HExpectFail, nil);
238368c31abSDavid du Colombier 	return 0;
239368c31abSDavid du Colombier }
240368c31abSDavid du Colombier 
241368c31abSDavid du Colombier int
242368c31abSDavid du Colombier hsettype(HConnect *c, char *type)
243368c31abSDavid du Colombier {
244368c31abSDavid du Colombier 	Hio *hout;
245368c31abSDavid du Colombier 	int r;
246368c31abSDavid du Colombier 
247368c31abSDavid du Colombier 	r = preq(c);
248368c31abSDavid du Colombier 	if(r < 0)
249368c31abSDavid du Colombier 		return r;
250368c31abSDavid du Colombier 
251368c31abSDavid du Colombier 	hout = &c->hout;
252368c31abSDavid du Colombier 	if(c->req.vermaj){
253368c31abSDavid du Colombier 		hokheaders(c);
254368c31abSDavid du Colombier 		hprint(hout, "Content-type: %s\r\n", type);
255368c31abSDavid du Colombier 		if(http11(c))
256368c31abSDavid du Colombier 			hprint(hout, "Transfer-Encoding: chunked\r\n");
257368c31abSDavid du Colombier 		hprint(hout, "\r\n");
258368c31abSDavid du Colombier 	}
259368c31abSDavid du Colombier 
260368c31abSDavid du Colombier 	if(http11(c))
261368c31abSDavid du Colombier 		hxferenc(hout, 1);
262368c31abSDavid du Colombier 	else
263368c31abSDavid du Colombier 		c->head.closeit = 1;
264368c31abSDavid du Colombier 	return 0;
265368c31abSDavid du Colombier }
266368c31abSDavid du Colombier 
267368c31abSDavid du Colombier int
268368c31abSDavid du Colombier hsethtml(HConnect *c)
269368c31abSDavid du Colombier {
270368c31abSDavid du Colombier 	return hsettype(c, "text/html; charset=utf-8");
271368c31abSDavid du Colombier }
272368c31abSDavid du Colombier 
273368c31abSDavid du Colombier int
274368c31abSDavid du Colombier hsettext(HConnect *c)
275368c31abSDavid du Colombier {
276368c31abSDavid du Colombier 	return hsettype(c, "text/plain; charset=utf-8");
277368c31abSDavid du Colombier }
278368c31abSDavid du Colombier 
279368c31abSDavid du Colombier static int
280368c31abSDavid du Colombier herror(HConnect *c)
281368c31abSDavid du Colombier {
282368c31abSDavid du Colombier 	int n;
283368c31abSDavid du Colombier 	Hio *hout;
284368c31abSDavid du Colombier 
285368c31abSDavid du Colombier 	hout = &c->hout;
286368c31abSDavid 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>");
287368c31abSDavid du Colombier 	hprint(hout, "%s %s\r\n", hversion, "400 Bad Request");
288368c31abSDavid du Colombier 	hprint(hout, "Date: %D\r\n", time(nil));
289368c31abSDavid du Colombier 	hprint(hout, "Server: Venti\r\n");
290368c31abSDavid du Colombier 	hprint(hout, "Content-Type: text/html\r\n");
291368c31abSDavid du Colombier 	hprint(hout, "Content-Length: %d\r\n", n);
292368c31abSDavid du Colombier 	if(c->head.closeit)
293368c31abSDavid du Colombier 		hprint(hout, "Connection: close\r\n");
294368c31abSDavid du Colombier 	else if(!http11(c))
295368c31abSDavid du Colombier 		hprint(hout, "Connection: Keep-Alive\r\n");
296368c31abSDavid du Colombier 	hprint(hout, "\r\n");
297368c31abSDavid du Colombier 
298368c31abSDavid du Colombier 	if(c->req.meth == nil || strcmp(c->req.meth, "HEAD") != 0)
299368c31abSDavid du Colombier 		hwrite(hout, c->xferbuf, n);
300368c31abSDavid du Colombier 
301368c31abSDavid du Colombier 	return hflush(hout);
302368c31abSDavid du Colombier }
303368c31abSDavid du Colombier 
304368c31abSDavid du Colombier int
305368c31abSDavid du Colombier hnotfound(HConnect *c)
306368c31abSDavid du Colombier {
307368c31abSDavid du Colombier 	int r;
308368c31abSDavid du Colombier 
309368c31abSDavid du Colombier 	r = preq(c);
310368c31abSDavid du Colombier 	if(r < 0)
311368c31abSDavid du Colombier 		return r;
312368c31abSDavid du Colombier 	return hfail(c, HNotFound, c->req.uri);
313368c31abSDavid du Colombier }
314368c31abSDavid du Colombier 
315368c31abSDavid du Colombier struct {
316368c31abSDavid du Colombier 	char *ext;
317368c31abSDavid du Colombier 	char *type;
318368c31abSDavid du Colombier } exttab[] = {
319368c31abSDavid du Colombier 	".html",	"text/html",
320368c31abSDavid du Colombier 	".txt",	"text/plain",
321368c31abSDavid du Colombier 	".xml",	"text/xml",
322368c31abSDavid du Colombier 	".png",	"image/png",
323368c31abSDavid du Colombier 	".gif",	"image/gif",
324368c31abSDavid du Colombier 	0
325368c31abSDavid du Colombier };
326368c31abSDavid du Colombier 
327368c31abSDavid du Colombier static int
328368c31abSDavid du Colombier fromwebdir(HConnect *c)
329368c31abSDavid du Colombier {
330368c31abSDavid du Colombier 	char buf[4096], *p, *ext, *type;
331368c31abSDavid du Colombier 	int i, fd, n, defaulted;
332368c31abSDavid du Colombier 	Dir *d;
333368c31abSDavid du Colombier 
334368c31abSDavid du Colombier 	if(webroot == nil || strstr(c->req.uri, ".."))
335368c31abSDavid du Colombier 		return hnotfound(c);
336368c31abSDavid du Colombier 	snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1);
337368c31abSDavid du Colombier 	defaulted = 0;
338368c31abSDavid du Colombier reopen:
339368c31abSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0)
340368c31abSDavid du Colombier 		return hnotfound(c);
341368c31abSDavid du Colombier 	d = dirfstat(fd);
342368c31abSDavid du Colombier 	if(d == nil){
343368c31abSDavid du Colombier 		close(fd);
344368c31abSDavid du Colombier 		return hnotfound(c);
345368c31abSDavid du Colombier 	}
346368c31abSDavid du Colombier 	if(d->mode&DMDIR){
347368c31abSDavid du Colombier 		if(!defaulted){
348368c31abSDavid du Colombier 			defaulted = 1;
349368c31abSDavid du Colombier 			strcat(buf, "/index.html");
350368c31abSDavid du Colombier 			free(d);
351368c31abSDavid du Colombier 			close(fd);
352368c31abSDavid du Colombier 			goto reopen;
353368c31abSDavid du Colombier 		}
354368c31abSDavid du Colombier 		free(d);
355368c31abSDavid du Colombier 		return hnotfound(c);
356368c31abSDavid du Colombier 	}
357368c31abSDavid du Colombier 	free(d);
358368c31abSDavid du Colombier 	p = buf+strlen(buf);
359368c31abSDavid du Colombier 	type = "application/octet-stream";
360368c31abSDavid du Colombier 	for(i=0; exttab[i].ext; i++){
361368c31abSDavid du Colombier 		ext = exttab[i].ext;
362368c31abSDavid du Colombier 		if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){
363368c31abSDavid du Colombier 			type = exttab[i].type;
364368c31abSDavid du Colombier 			break;
365368c31abSDavid du Colombier 		}
366368c31abSDavid du Colombier 	}
367368c31abSDavid du Colombier 	if(hsettype(c, type) < 0){
368368c31abSDavid du Colombier 		close(fd);
369368c31abSDavid du Colombier 		return 0;
370368c31abSDavid du Colombier 	}
371368c31abSDavid du Colombier 	while((n = read(fd, buf, sizeof buf)) > 0)
372368c31abSDavid du Colombier 		if(hwrite(&c->hout, buf, n) < 0)
373368c31abSDavid du Colombier 			break;
374368c31abSDavid du Colombier 	close(fd);
375368c31abSDavid du Colombier 	hflush(&c->hout);
376368c31abSDavid du Colombier 	return 0;
377368c31abSDavid du Colombier }
378368c31abSDavid du Colombier 
379368c31abSDavid du Colombier static struct
380368c31abSDavid du Colombier {
381368c31abSDavid du Colombier 	char *name;
382368c31abSDavid du Colombier 	int *p;
383368c31abSDavid du Colombier } namedints[] =
384368c31abSDavid du Colombier {
385368c31abSDavid du Colombier 	"compress",	&compressblocks,
386368c31abSDavid du Colombier 	"devnull",	&writestodevnull,
387368c31abSDavid du Colombier 	"logging",	&ventilogging,
388368c31abSDavid du Colombier 	"stats",	&collectstats,
389368c31abSDavid du Colombier 	"icachesleeptime",	&icachesleeptime,
390368c31abSDavid du Colombier 	"minicachesleeptime",	&minicachesleeptime,
391368c31abSDavid du Colombier 	"arenasumsleeptime",	&arenasumsleeptime,
392368c31abSDavid du Colombier 	"l0quantum",	&l0quantum,
393368c31abSDavid du Colombier 	"l1quantum",	&l1quantum,
394368c31abSDavid du Colombier 	"manualscheduling",	&manualscheduling,
395368c31abSDavid du Colombier 	"ignorebloom",	&ignorebloom,
396368c31abSDavid du Colombier 	"syncwrites",	&syncwrites,
397368c31abSDavid du Colombier 	"icacheprefetch",	&icacheprefetch,
398368c31abSDavid du Colombier 	0
399368c31abSDavid du Colombier };
400368c31abSDavid du Colombier 
401368c31abSDavid du Colombier static int
402368c31abSDavid du Colombier xset(HConnect *c)
403368c31abSDavid du Colombier {
404368c31abSDavid du Colombier 	int i, old;
405368c31abSDavid du Colombier 	char *name, *value;
406368c31abSDavid du Colombier 
407368c31abSDavid du Colombier 	if(hsettext(c) < 0)
408368c31abSDavid du Colombier 		return -1;
409368c31abSDavid du Colombier 
410368c31abSDavid du Colombier 	if((name = hargstr(c, "name", nil)) == nil || name[0] == 0){
411368c31abSDavid du Colombier 		for(i=0; namedints[i].name; i++)
412368c31abSDavid du Colombier 			hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
413368c31abSDavid du Colombier 		hflush(&c->hout);
414368c31abSDavid du Colombier 		return 0;
415368c31abSDavid du Colombier 	}
416368c31abSDavid du Colombier 
417368c31abSDavid du Colombier 	for(i=0; namedints[i].name; i++)
418368c31abSDavid du Colombier 		if(strcmp(name, namedints[i].name) == 0)
419368c31abSDavid du Colombier 			break;
420368c31abSDavid du Colombier 	if(!namedints[i].name){
421368c31abSDavid du Colombier 		hprint(&c->hout, "%s not found\n", name);
422368c31abSDavid du Colombier 		hflush(&c->hout);
423368c31abSDavid du Colombier 		return 0;
424368c31abSDavid du Colombier 	}
425368c31abSDavid du Colombier 
426368c31abSDavid du Colombier 	if((value = hargstr(c, "value", nil)) == nil || value[0] == 0){
427368c31abSDavid du Colombier 		hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
428368c31abSDavid du Colombier 		hflush(&c->hout);
429368c31abSDavid du Colombier 		return 0;
430368c31abSDavid du Colombier 	}
431368c31abSDavid du Colombier 
432368c31abSDavid du Colombier 	old = *namedints[i].p;
433368c31abSDavid du Colombier 	*namedints[i].p = atoll(value);
434368c31abSDavid du Colombier 	hprint(&c->hout, "%s = %d (was %d)\n", name, *namedints[i].p, old);
435368c31abSDavid du Colombier 	hflush(&c->hout);
436368c31abSDavid du Colombier 	return 0;
437368c31abSDavid du Colombier }
438368c31abSDavid du Colombier 
439368c31abSDavid du Colombier static int
440368c31abSDavid du Colombier estats(HConnect *c)
441368c31abSDavid du Colombier {
442368c31abSDavid du Colombier 	Hio *hout;
443368c31abSDavid du Colombier 	int r;
444368c31abSDavid du Colombier 
445368c31abSDavid du Colombier 	r = hsettext(c);
446368c31abSDavid du Colombier 	if(r < 0)
447368c31abSDavid du Colombier 		return r;
448368c31abSDavid du Colombier 
449368c31abSDavid du Colombier 
450368c31abSDavid du Colombier 	hout = &c->hout;
451368c31abSDavid du Colombier /*
452368c31abSDavid du Colombier 	hprint(hout, "lump writes=%,ld\n", stats.lumpwrites);
453368c31abSDavid du Colombier 	hprint(hout, "lump reads=%,ld\n", stats.lumpreads);
454368c31abSDavid du Colombier 	hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit);
455368c31abSDavid du Colombier 	hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss);
456368c31abSDavid du Colombier 
457368c31abSDavid du Colombier 	hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites);
458368c31abSDavid du Colombier 	hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites);
459368c31abSDavid du Colombier 	hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp);
460368c31abSDavid du Colombier 	hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads);
461368c31abSDavid du Colombier 	hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads);
462368c31abSDavid du Colombier 	hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp);
463368c31abSDavid du Colombier 
464368c31abSDavid du Colombier 	hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
465368c31abSDavid du Colombier 	hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
466368c31abSDavid du Colombier 
467368c31abSDavid du Colombier 	hprint(hout, "index disk writes=%,ld\n", stats.indexwrites);
468368c31abSDavid du Colombier 	hprint(hout, "index disk reads=%,ld\n", stats.indexreads);
469368c31abSDavid du Colombier 	hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n",
470368c31abSDavid du Colombier 		stats.indexbloomhits,
471368c31abSDavid du Colombier 		percent(stats.indexbloomhits, stats.indexreads),
472368c31abSDavid du Colombier 		stats.indexbloomfalsemisses,
473368c31abSDavid du Colombier 		percent(stats.indexbloomfalsemisses, stats.indexreads));
474368c31abSDavid du Colombier 	hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n",
475368c31abSDavid du Colombier 		stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits));
476368c31abSDavid du Colombier 	hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads);
477368c31abSDavid du Colombier 	hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads);
478368c31abSDavid du Colombier 	hprint(hout, "index block splits=%,ld\n", stats.indexsplits);
479368c31abSDavid du Colombier 
480368c31abSDavid du Colombier 	hprint(hout, "index cache lookups=%,ld\n", stats.iclookups);
481368c31abSDavid du Colombier 	hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits,
482368c31abSDavid du Colombier 		percent(stats.ichits, stats.iclookups));
483368c31abSDavid du Colombier 	hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills,
484368c31abSDavid du Colombier 		percent(stats.icfills, stats.iclookups));
485368c31abSDavid du Colombier 	hprint(hout, "index cache inserts=%,ld\n", stats.icinserts);
486368c31abSDavid du Colombier 
487368c31abSDavid du Colombier 	hprint(hout, "disk cache hits=%,ld\n", stats.pchit);
488368c31abSDavid du Colombier 	hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss);
489368c31abSDavid du Colombier 	hprint(hout, "disk cache reads=%,ld\n", stats.pcreads);
490368c31abSDavid du Colombier 	hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads);
491368c31abSDavid du Colombier 
492368c31abSDavid du Colombier 	hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks);
493368c31abSDavid du Colombier 	hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites,
494368c31abSDavid du Colombier 		percent(stats.absorbedwrites, stats.dirtydblocks));
495368c31abSDavid du Colombier 
496368c31abSDavid du Colombier 	hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes);
497368c31abSDavid du Colombier 	hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n",
498368c31abSDavid du Colombier 		stats.dcacheflushwrites,
499368c31abSDavid du Colombier 		stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1));
500368c31abSDavid du Colombier 
501368c31abSDavid du Colombier 	hprint(hout, "disk writes=%,ld\n", stats.diskwrites);
502368c31abSDavid du Colombier 	hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites);
503368c31abSDavid du Colombier 	hprint(hout, "disk reads=%,ld\n", stats.diskreads);
504368c31abSDavid du Colombier 	hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads);
505368c31abSDavid du Colombier */
506368c31abSDavid du Colombier 
507368c31abSDavid du Colombier 	hflush(hout);
508368c31abSDavid du Colombier 	return 0;
509368c31abSDavid du Colombier }
510368c31abSDavid du Colombier 
511368c31abSDavid du Colombier static int
512368c31abSDavid du Colombier sindex(HConnect *c)
513368c31abSDavid du Colombier {
514368c31abSDavid du Colombier 	Hio *hout;
515368c31abSDavid du Colombier 	Index *ix;
516368c31abSDavid du Colombier 	Arena *arena;
517368c31abSDavid du Colombier 	vlong clumps, cclumps, uncsize, used, size;
518368c31abSDavid du Colombier 	int i, r, active;
519368c31abSDavid du Colombier 
520368c31abSDavid du Colombier 	r = hsettext(c);
521368c31abSDavid du Colombier 	if(r < 0)
522368c31abSDavid du Colombier 		return r;
523368c31abSDavid du Colombier 	hout = &c->hout;
524368c31abSDavid du Colombier 
525368c31abSDavid du Colombier 	ix = mainindex;
526368c31abSDavid du Colombier 
527368c31abSDavid du Colombier 	hprint(hout, "index=%s\n", ix->name);
528368c31abSDavid du Colombier 
529368c31abSDavid du Colombier 	active = 0;
530368c31abSDavid du Colombier 	clumps = 0;
531368c31abSDavid du Colombier 	cclumps = 0;
532368c31abSDavid du Colombier 	uncsize = 0;
533368c31abSDavid du Colombier 	used = 0;
534368c31abSDavid du Colombier 	size = 0;
535368c31abSDavid du Colombier 	for(i = 0; i < ix->narenas; i++){
536368c31abSDavid du Colombier 		arena = ix->arenas[i];
537368c31abSDavid du Colombier 		if(arena != nil && arena->memstats.clumps != 0){
538368c31abSDavid du Colombier 			active++;
539368c31abSDavid du Colombier 			clumps += arena->memstats.clumps;
540368c31abSDavid du Colombier 			cclumps += arena->memstats.cclumps;
541368c31abSDavid du Colombier 			uncsize += arena->memstats.uncsize;
542368c31abSDavid du Colombier 			used += arena->memstats.used;
543368c31abSDavid du Colombier 		}
544368c31abSDavid du Colombier 		size += arena->size;
545368c31abSDavid du Colombier 	}
546368c31abSDavid du Colombier 	hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active);
547368c31abSDavid du Colombier 	hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize);
548368c31abSDavid du Colombier 	hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n",
549368c31abSDavid du Colombier 		clumps, cclumps, uncsize, used - clumps * ClumpSize);
550368c31abSDavid du Colombier 	hflush(hout);
551368c31abSDavid du Colombier 	return 0;
552368c31abSDavid du Colombier }
553368c31abSDavid du Colombier 
554368c31abSDavid du Colombier static void
555368c31abSDavid du Colombier darena(Hio *hout, Arena *arena)
556368c31abSDavid du Colombier {
557368c31abSDavid du Colombier 	hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
558368c31abSDavid du Colombier 		arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize,
559368c31abSDavid du Colombier 		arena->version, arena->ctime, arena->wtime);
560368c31abSDavid du Colombier 	if(arena->memstats.sealed)
561368c31abSDavid du Colombier 		hprint(hout, " mem=sealed");
562368c31abSDavid du Colombier 	if(arena->diskstats.sealed)
563368c31abSDavid du Colombier 		hprint(hout, " disk=sealed");
564368c31abSDavid du Colombier 	hprint(hout, "\n");
565368c31abSDavid du Colombier 	if(scorecmp(zeroscore, arena->score) != 0)
566368c31abSDavid du Colombier 		hprint(hout, "\tscore=%V\n", arena->score);
567368c31abSDavid du Colombier 
568*f9e1cf08SDavid du Colombier 	hprint(hout, "\twritten: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
569368c31abSDavid du Colombier 		arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize,
570368c31abSDavid du Colombier 		arena->memstats.used - arena->memstats.clumps * ClumpSize,
571368c31abSDavid du Colombier 		arena->memstats.used + arena->memstats.clumps * ClumpInfoSize);
572*f9e1cf08SDavid du Colombier 	hprint(hout, "\tindexed: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
573368c31abSDavid du Colombier 		arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize,
574368c31abSDavid du Colombier 		arena->diskstats.used - arena->diskstats.clumps * ClumpSize,
575368c31abSDavid du Colombier 		arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize);
576368c31abSDavid du Colombier }
577368c31abSDavid du Colombier 
578368c31abSDavid du Colombier static int
579368c31abSDavid du Colombier hempty(HConnect *c)
580368c31abSDavid du Colombier {
581368c31abSDavid du Colombier 	Hio *hout;
582368c31abSDavid du Colombier 	int r;
583368c31abSDavid du Colombier 
584368c31abSDavid du Colombier 	r = hsettext(c);
585368c31abSDavid du Colombier 	if(r < 0)
586368c31abSDavid du Colombier 		return r;
587368c31abSDavid du Colombier 	hout = &c->hout;
588368c31abSDavid du Colombier 
589368c31abSDavid du Colombier 	emptylumpcache();
590368c31abSDavid du Colombier 	emptydcache();
591368c31abSDavid du Colombier 	emptyicache();
592368c31abSDavid du Colombier 	hprint(hout, "emptied all caches\n");
593368c31abSDavid du Colombier 	hflush(hout);
594368c31abSDavid du Colombier 	return 0;
595368c31abSDavid du Colombier }
596368c31abSDavid du Colombier 
597368c31abSDavid du Colombier static int
598368c31abSDavid du Colombier hlcacheempty(HConnect *c)
599368c31abSDavid du Colombier {
600368c31abSDavid du Colombier 	Hio *hout;
601368c31abSDavid du Colombier 	int r;
602368c31abSDavid du Colombier 
603368c31abSDavid du Colombier 	r = hsettext(c);
604368c31abSDavid du Colombier 	if(r < 0)
605368c31abSDavid du Colombier 		return r;
606368c31abSDavid du Colombier 	hout = &c->hout;
607368c31abSDavid du Colombier 
608368c31abSDavid du Colombier 	emptylumpcache();
609368c31abSDavid du Colombier 	hprint(hout, "emptied lumpcache\n");
610368c31abSDavid du Colombier 	hflush(hout);
611368c31abSDavid du Colombier 	return 0;
612368c31abSDavid du Colombier }
613368c31abSDavid du Colombier 
614368c31abSDavid du Colombier static int
615368c31abSDavid du Colombier hicacheempty(HConnect *c)
616368c31abSDavid du Colombier {
617368c31abSDavid du Colombier 	Hio *hout;
618368c31abSDavid du Colombier 	int r;
619368c31abSDavid du Colombier 
620368c31abSDavid du Colombier 	r = hsettext(c);
621368c31abSDavid du Colombier 	if(r < 0)
622368c31abSDavid du Colombier 		return r;
623368c31abSDavid du Colombier 	hout = &c->hout;
624368c31abSDavid du Colombier 
625368c31abSDavid du Colombier 	emptyicache();
626368c31abSDavid du Colombier 	hprint(hout, "emptied icache\n");
627368c31abSDavid du Colombier 	hflush(hout);
628368c31abSDavid du Colombier 	return 0;
629368c31abSDavid du Colombier }
630368c31abSDavid du Colombier 
631368c31abSDavid du Colombier static int
632368c31abSDavid du Colombier hdcacheempty(HConnect *c)
633368c31abSDavid du Colombier {
634368c31abSDavid du Colombier 	Hio *hout;
635368c31abSDavid du Colombier 	int r;
636368c31abSDavid du Colombier 
637368c31abSDavid du Colombier 	r = hsettext(c);
638368c31abSDavid du Colombier 	if(r < 0)
639368c31abSDavid du Colombier 		return r;
640368c31abSDavid du Colombier 	hout = &c->hout;
641368c31abSDavid du Colombier 
642368c31abSDavid du Colombier 	emptydcache();
643368c31abSDavid du Colombier 	hprint(hout, "emptied dcache\n");
644368c31abSDavid du Colombier 	hflush(hout);
645368c31abSDavid du Colombier 	return 0;
646368c31abSDavid du Colombier }
647368c31abSDavid du Colombier static int
648368c31abSDavid du Colombier hicachekick(HConnect *c)
649368c31abSDavid du Colombier {
650368c31abSDavid du Colombier 	Hio *hout;
651368c31abSDavid du Colombier 	int r;
652368c31abSDavid du Colombier 
653368c31abSDavid du Colombier 	r = hsettext(c);
654368c31abSDavid du Colombier 	if(r < 0)
655368c31abSDavid du Colombier 		return r;
656368c31abSDavid du Colombier 	hout = &c->hout;
657368c31abSDavid du Colombier 
658368c31abSDavid du Colombier 	kickicache();
659368c31abSDavid du Colombier 	hprint(hout, "kicked icache\n");
660368c31abSDavid du Colombier 	hflush(hout);
661368c31abSDavid du Colombier 	return 0;
662368c31abSDavid du Colombier }
663368c31abSDavid du Colombier 
664368c31abSDavid du Colombier static int
665368c31abSDavid du Colombier hdcachekick(HConnect *c)
666368c31abSDavid du Colombier {
667368c31abSDavid du Colombier 	Hio *hout;
668368c31abSDavid du Colombier 	int r;
669368c31abSDavid du Colombier 
670368c31abSDavid du Colombier 	r = hsettext(c);
671368c31abSDavid du Colombier 	if(r < 0)
672368c31abSDavid du Colombier 		return r;
673368c31abSDavid du Colombier 	hout = &c->hout;
674368c31abSDavid du Colombier 
675368c31abSDavid du Colombier 	kickdcache();
676368c31abSDavid du Colombier 	hprint(hout, "kicked dcache\n");
677368c31abSDavid du Colombier 	hflush(hout);
678368c31abSDavid du Colombier 	return 0;
679368c31abSDavid du Colombier }
680368c31abSDavid du Colombier static int
681368c31abSDavid du Colombier hicacheflush(HConnect *c)
682368c31abSDavid du Colombier {
683368c31abSDavid du Colombier 	Hio *hout;
684368c31abSDavid du Colombier 	int r;
685368c31abSDavid du Colombier 
686368c31abSDavid du Colombier 	r = hsettext(c);
687368c31abSDavid du Colombier 	if(r < 0)
688368c31abSDavid du Colombier 		return r;
689368c31abSDavid du Colombier 	hout = &c->hout;
690368c31abSDavid du Colombier 
691368c31abSDavid du Colombier 	flushicache();
692368c31abSDavid du Colombier 	hprint(hout, "flushed icache\n");
693368c31abSDavid du Colombier 	hflush(hout);
694368c31abSDavid du Colombier 	return 0;
695368c31abSDavid du Colombier }
696368c31abSDavid du Colombier 
697368c31abSDavid du Colombier static int
698368c31abSDavid du Colombier hdcacheflush(HConnect *c)
699368c31abSDavid du Colombier {
700368c31abSDavid du Colombier 	Hio *hout;
701368c31abSDavid du Colombier 	int r;
702368c31abSDavid du Colombier 
703368c31abSDavid du Colombier 	r = hsettext(c);
704368c31abSDavid du Colombier 	if(r < 0)
705368c31abSDavid du Colombier 		return r;
706368c31abSDavid du Colombier 	hout = &c->hout;
707368c31abSDavid du Colombier 
708368c31abSDavid du Colombier 	flushdcache();
709368c31abSDavid du Colombier 	hprint(hout, "flushed dcache\n");
710368c31abSDavid du Colombier 	hflush(hout);
711368c31abSDavid du Colombier 	return 0;
712368c31abSDavid du Colombier }
713368c31abSDavid du Colombier 
714368c31abSDavid du Colombier static int
715368c31abSDavid du Colombier dindex(HConnect *c)
716368c31abSDavid du Colombier {
717368c31abSDavid du Colombier 	Hio *hout;
718368c31abSDavid du Colombier 	Index *ix;
719368c31abSDavid du Colombier 	int i, r;
720368c31abSDavid du Colombier 
721368c31abSDavid du Colombier 	r = hsettext(c);
722368c31abSDavid du Colombier 	if(r < 0)
723368c31abSDavid du Colombier 		return r;
724368c31abSDavid du Colombier 	hout = &c->hout;
725368c31abSDavid du Colombier 
726368c31abSDavid du Colombier 
727368c31abSDavid du Colombier 	ix = mainindex;
728368c31abSDavid du Colombier 	hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n",
729368c31abSDavid du Colombier 		ix->name, ix->version, ix->blocksize, ix->tabsize);
730368c31abSDavid du Colombier 	hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
731368c31abSDavid du Colombier 	for(i = 0; i < ix->nsects; i++)
732368c31abSDavid 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);
733368c31abSDavid du Colombier 	for(i = 0; i < ix->narenas; i++){
734368c31abSDavid du Colombier 		if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){
735368c31abSDavid du Colombier 			hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
736368c31abSDavid du Colombier 			darena(hout, ix->arenas[i]);
737368c31abSDavid du Colombier 		}
738368c31abSDavid du Colombier 	}
739368c31abSDavid du Colombier 	hflush(hout);
740368c31abSDavid du Colombier 	return 0;
741368c31abSDavid du Colombier }
742368c31abSDavid du Colombier 
743368c31abSDavid du Colombier typedef struct Arg Arg;
744368c31abSDavid du Colombier struct Arg
745368c31abSDavid du Colombier {
746368c31abSDavid du Colombier 	int index;
747368c31abSDavid du Colombier 	int index2;
748368c31abSDavid du Colombier };
749368c31abSDavid du Colombier 
750368c31abSDavid du Colombier static long
751368c31abSDavid du Colombier rawgraph(Stats *s, Stats *t, void *va)
752368c31abSDavid du Colombier {
753368c31abSDavid du Colombier 	Arg *a;
754368c31abSDavid du Colombier 
755368c31abSDavid du Colombier 	USED(s);
756368c31abSDavid du Colombier 	a = va;
757368c31abSDavid du Colombier 	return t->n[a->index];
758368c31abSDavid du Colombier }
759368c31abSDavid du Colombier 
760368c31abSDavid du Colombier static long
761368c31abSDavid du Colombier diffgraph(Stats *s, Stats *t, void *va)
762368c31abSDavid du Colombier {
763368c31abSDavid du Colombier 	Arg *a;
764368c31abSDavid du Colombier 
765368c31abSDavid du Colombier 	a = va;
766368c31abSDavid du Colombier 	return t->n[a->index] - s->n[a->index];
767368c31abSDavid du Colombier }
768368c31abSDavid du Colombier 
769368c31abSDavid du Colombier static long
770368c31abSDavid du Colombier pctgraph(Stats *s, Stats *t, void *va)
771368c31abSDavid du Colombier {
772368c31abSDavid du Colombier 	Arg *a;
773368c31abSDavid du Colombier 
774368c31abSDavid du Colombier 	USED(s);
775368c31abSDavid du Colombier 	a = va;
776368c31abSDavid du Colombier 	return percent(t->n[a->index], t->n[a->index2]);
777368c31abSDavid du Colombier }
778368c31abSDavid du Colombier 
779368c31abSDavid du Colombier static long
780368c31abSDavid du Colombier pctdiffgraph(Stats *s, Stats *t, void *va)
781368c31abSDavid du Colombier {
782368c31abSDavid du Colombier 	Arg *a;
783368c31abSDavid du Colombier 
784368c31abSDavid du Colombier 	a = va;
785368c31abSDavid du Colombier 	return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]);
786368c31abSDavid du Colombier }
787368c31abSDavid du Colombier 
788368c31abSDavid du Colombier static long
789368c31abSDavid du Colombier xdiv(long a, long b)
790368c31abSDavid du Colombier {
791368c31abSDavid du Colombier 	if(b == 0)
792368c31abSDavid du Colombier 		b++;
793368c31abSDavid du Colombier 	return a/b;
794368c31abSDavid du Colombier }
795368c31abSDavid du Colombier 
796368c31abSDavid du Colombier static long
797368c31abSDavid du Colombier divdiffgraph(Stats *s, Stats *t, void *va)
798368c31abSDavid du Colombier {
799368c31abSDavid du Colombier 	Arg *a;
800368c31abSDavid du Colombier 
801368c31abSDavid du Colombier 	a = va;
802368c31abSDavid du Colombier 	return xdiv(t->n[a->index] - s->n[a->index], t->n[a->index2] - s->n[a->index2]);
803368c31abSDavid du Colombier }
804368c31abSDavid du Colombier 
805368c31abSDavid du Colombier static long
806368c31abSDavid du Colombier netbw(Stats *s)
807368c31abSDavid du Colombier {
808368c31abSDavid du Colombier 	ulong *n;
809368c31abSDavid du Colombier 
810368c31abSDavid du Colombier 	n = s->n;
811368c31abSDavid du Colombier 	return n[StatRpcReadBytes]+n[StatRpcWriteBytes];	/* not exactly right */
812368c31abSDavid du Colombier }
813368c31abSDavid du Colombier 
814368c31abSDavid du Colombier static long
815368c31abSDavid du Colombier diskbw(Stats *s)
816368c31abSDavid du Colombier {
817368c31abSDavid du Colombier 	ulong *n;
818368c31abSDavid du Colombier 
819368c31abSDavid du Colombier 	n = s->n;
820368c31abSDavid du Colombier 	return n[StatApartReadBytes]+n[StatApartWriteBytes]
821368c31abSDavid du Colombier 		+ n[StatIsectReadBytes]+n[StatIsectWriteBytes]
822368c31abSDavid du Colombier 		+ n[StatSumReadBytes];
823368c31abSDavid du Colombier }
824368c31abSDavid du Colombier 
825368c31abSDavid du Colombier static long
826368c31abSDavid du Colombier iobw(Stats *s)
827368c31abSDavid du Colombier {
828368c31abSDavid du Colombier 	return netbw(s)+diskbw(s);
829368c31abSDavid du Colombier }
830368c31abSDavid du Colombier 
831368c31abSDavid du Colombier static long
832368c31abSDavid du Colombier diskgraph(Stats *s, Stats *t, void *va)
833368c31abSDavid du Colombier {
834368c31abSDavid du Colombier 	USED(va);
835368c31abSDavid du Colombier 	return diskbw(t)-diskbw(s);
836368c31abSDavid du Colombier }
837368c31abSDavid du Colombier 
838368c31abSDavid du Colombier static long
839368c31abSDavid du Colombier netgraph(Stats *s, Stats *t, void *va)
840368c31abSDavid du Colombier {
841368c31abSDavid du Colombier 	USED(va);
842368c31abSDavid du Colombier 	return netbw(t)-netbw(s);
843368c31abSDavid du Colombier }
844368c31abSDavid du Colombier 
845368c31abSDavid du Colombier static long
846368c31abSDavid du Colombier iograph(Stats *s, Stats *t, void *va)
847368c31abSDavid du Colombier {
848368c31abSDavid du Colombier 	USED(va);
849368c31abSDavid du Colombier 	return iobw(t)-iobw(s);
850368c31abSDavid du Colombier }
851368c31abSDavid du Colombier 
852368c31abSDavid du Colombier 
853368c31abSDavid du Colombier static char* graphname[] =
854368c31abSDavid du Colombier {
855368c31abSDavid du Colombier 	"rpctotal",
856368c31abSDavid du Colombier 	"rpcread",
857368c31abSDavid du Colombier 	"rpcreadok",
858368c31abSDavid du Colombier 	"rpcreadfail",
859368c31abSDavid du Colombier 	"rpcreadbyte",
860368c31abSDavid du Colombier 	"rpcreadtime",
861368c31abSDavid du Colombier 	"rpcreadcached",
862368c31abSDavid du Colombier 	"rpcreadcachedtime",
863368c31abSDavid du Colombier 	"rpcreaduncached",
864368c31abSDavid du Colombier 	"rpcreaduncachedtime",
865368c31abSDavid du Colombier 	"rpcwrite",
866368c31abSDavid du Colombier 	"rpcwritenew",
867368c31abSDavid du Colombier 	"rpcwriteold",
868368c31abSDavid du Colombier 	"rpcwritefail",
869368c31abSDavid du Colombier 	"rpcwritebyte",
870368c31abSDavid du Colombier 	"rpcwritetime",
871368c31abSDavid du Colombier 	"rpcwritenewtime",
872368c31abSDavid du Colombier 	"rpcwriteoldtime",
873368c31abSDavid du Colombier 
874368c31abSDavid du Colombier 	"lcachehit",
875368c31abSDavid du Colombier 	"lcachemiss",
876368c31abSDavid du Colombier 	"lcachelookup",
877368c31abSDavid du Colombier 	"lcachewrite",
878368c31abSDavid du Colombier 	"lcachesize",
879368c31abSDavid du Colombier 	"lcachestall",
880368c31abSDavid du Colombier 	"lcachelookuptime",
881368c31abSDavid du Colombier 
882368c31abSDavid du Colombier 	"dcachehit",
883368c31abSDavid du Colombier 	"dcachemiss",
884368c31abSDavid du Colombier 	"dcachelookup",
885368c31abSDavid du Colombier 	"dcacheread",
886368c31abSDavid du Colombier 	"dcachewrite",
887368c31abSDavid du Colombier 	"dcachedirty",
888368c31abSDavid du Colombier 	"dcachesize",
889368c31abSDavid du Colombier 	"dcacheflush",
890368c31abSDavid du Colombier 	"dcachestall",
891368c31abSDavid du Colombier 	"dcachelookuptime",
892368c31abSDavid du Colombier 
893368c31abSDavid du Colombier 	"dblockstall",
894368c31abSDavid du Colombier 	"lumpstall",
895368c31abSDavid du Colombier 
896368c31abSDavid du Colombier 	"icachehit",
897368c31abSDavid du Colombier 	"icachemiss",
898*f9e1cf08SDavid du Colombier 	"icacheread",
899368c31abSDavid du Colombier 	"icachewrite",
900368c31abSDavid du Colombier 	"icachefill",
901368c31abSDavid du Colombier 	"icacheprefetch",
902368c31abSDavid du Colombier 	"icachedirty",
903368c31abSDavid du Colombier 	"icachesize",
904368c31abSDavid du Colombier 	"icacheflush",
905368c31abSDavid du Colombier 	"icachestall",
906368c31abSDavid du Colombier 	"icachelookuptime",
907*f9e1cf08SDavid du Colombier 	"icachelookup",
908*f9e1cf08SDavid du Colombier 	"scachehit",
909*f9e1cf08SDavid du Colombier 	"scacheprefetch",
910368c31abSDavid du Colombier 
911368c31abSDavid du Colombier 	"bloomhit",
912368c31abSDavid du Colombier 	"bloommiss",
913368c31abSDavid du Colombier 	"bloomfalsemiss",
914368c31abSDavid du Colombier 	"bloomlookup",
915368c31abSDavid du Colombier 	"bloomones",
916368c31abSDavid du Colombier 	"bloombits",
917368c31abSDavid du Colombier 	"bloomlookuptime",
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",
931*f9e1cf08SDavid du Colombier 
932*f9e1cf08SDavid du Colombier 	"cigload",
933*f9e1cf08SDavid du Colombier 	"cigloadtime",
934368c31abSDavid du Colombier };
935368c31abSDavid du Colombier 
936368c31abSDavid du Colombier static int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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