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 : "<nil>";
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