Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/venti/srv/httpd.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "stdinc.h"
2
#include "dat.h"
3
#include "fns.h"
4
#include "xml.h"
5
 
6
typedef struct HttpObj	HttpObj;
7
extern QLock memdrawlock;
8
 
9
enum
10
{
11
	ObjNameSize	= 64,
12
	MaxObjs		= 64
13
};
14
 
15
struct HttpObj
16
{
17
	char	name[ObjNameSize];
18
	int	(*f)(HConnect*);
19
};
20
 
21
static HttpObj	objs[MaxObjs];
22
 
23
static char *webroot;
24
 
25
static	void		listenproc(void*);
26
static	int		estats(HConnect *c);
27
static	int		dindex(HConnect *c);
28
static	int		xindex(HConnect *c);
29
static	int		xlog(HConnect *c);
30
static	int		sindex(HConnect *c);
31
static	int		hempty(HConnect *c);
32
static	int		hlcacheempty(HConnect *c);
33
static	int		hdcacheempty(HConnect *c);
34
static	int		hicacheempty(HConnect *c);
35
static	int		hicachekick(HConnect *c);
36
static	int		hdcachekick(HConnect *c);
37
static	int		hicacheflush(HConnect *c);
38
static	int		hdcacheflush(HConnect *c);
39
static	int		httpdobj(char *name, int (*f)(HConnect*));
40
static	int		xgraph(HConnect *c);
41
static	int		xset(HConnect *c);
42
static	int		fromwebdir(HConnect *c);
43
 
44
int
45
httpdinit(char *address, char *dir)
46
{
47
	fmtinstall('D', hdatefmt);
48
/*	fmtinstall('H', httpfmt); */
49
	fmtinstall('U', hurlfmt);
50
 
51
	if(address == nil)
52
		address = "tcp!*!http";
53
	webroot = dir;
54
 
55
	httpdobj("/stats", estats);
56
	httpdobj("/index", dindex);
57
	httpdobj("/storage", sindex);
58
	httpdobj("/xindex", xindex);
59
	httpdobj("/flushicache", hicacheflush);
60
	httpdobj("/flushdcache", hdcacheflush);
61
	httpdobj("/kickicache", hicachekick);
62
	httpdobj("/kickdcache", hdcachekick);
63
	httpdobj("/graph", xgraph);
64
	httpdobj("/set", xset);
65
	httpdobj("/log", xlog);
66
	httpdobj("/empty", hempty);
67
	httpdobj("/emptyicache", hicacheempty);
68
	httpdobj("/emptylumpcache", hlcacheempty);
69
	httpdobj("/emptydcache", hdcacheempty);
70
	httpdobj("/disk", hdisk);
71
	httpdobj("/debug", hdebug);
72
	httpdobj("/proc/", hproc);
73
 
74
	if(vtproc(listenproc, address) < 0)
75
		return -1;
76
	return 0;
77
}
78
 
79
static int
80
httpdobj(char *name, int (*f)(HConnect*))
81
{
82
	int i;
83
 
84
	if(name == nil || strlen(name) >= ObjNameSize)
85
		return -1;
86
	for(i = 0; i < MaxObjs; i++){
87
		if(objs[i].name[0] == '\0'){
88
			strcpy(objs[i].name, name);
89
			objs[i].f = f;
90
			return 0;
91
		}
92
		if(strcmp(objs[i].name, name) == 0)
93
			return -1;
94
	}
95
	return -1;
96
}
97
 
98
static HConnect*
99
mkconnect(void)
100
{
101
	HConnect *c;
102
 
103
	c = mallocz(sizeof(HConnect), 1);
104
	if(c == nil)
105
		sysfatal("out of memory");
106
	c->replog = nil;
107
	c->hpos = c->header;
108
	c->hstop = c->header;
109
	return c;
110
}
111
 
112
void httpproc(void*);
113
 
114
static void
115
listenproc(void *vaddress)
116
{
117
	HConnect *c;
118
	char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
119
	int ctl, nctl, data;
120
 
121
	address = vaddress;
122
	ctl = announce(address, dir);
123
	if(ctl < 0){
124
		fprint(2, "venti: httpd can't announce on %s: %r\n", address);
125
		return;
126
	}
127
 
128
	if(0) print("announce ctl %d dir %s\n", ctl, dir);
129
	for(;;){
130
		/*
131
		 *  wait for a call (or an error)
132
		 */
133
		nctl = listen(dir, ndir);
134
		if(0) print("httpd listen %d %s...\n", nctl, ndir);
135
		if(nctl < 0){
136
			fprint(2, "venti: httpd can't listen on %s: %r\n", address);
137
			return;
138
		}
139
 
140
		data = accept(ctl, ndir);
141
		if(0) print("httpd accept %d...\n", data);
142
		if(data < 0){
143
			fprint(2, "venti: httpd accept: %r\n");
144
			close(nctl);
145
			continue;
146
		}
147
		if(0) print("httpd close nctl %d\n", nctl);
148
		close(nctl);
149
		c = mkconnect();
150
		hinit(&c->hin, data, Hread);
151
		hinit(&c->hout, data, Hwrite);
152
		vtproc(httpproc, c);
153
	}
154
}
155
 
156
void
157
httpproc(void *v)
158
{
159
	HConnect *c;
160
	int ok, i, n;
161
 
162
	c = v;
163
 
164
	for(;;){
165
		/*
166
		 * No timeout because the signal appears to hit every
167
		 * proc, not just us.
168
		 */
169
		if(hparsereq(c, 0) < 0)
170
			break;
171
 
172
		for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
173
			n = strlen(objs[i].name);
174
			if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0)
175
			|| (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){
176
				ok = (*objs[i].f)(c);
177
				goto found;
178
			}
179
		}
180
		ok = fromwebdir(c);
181
	found:
182
		hflush(&c->hout);
183
		if(c->head.closeit)
184
			ok = -1;
185
		hreqcleanup(c);
186
 
187
		if(ok < 0)
188
			break;
189
	}
190
	hreqcleanup(c);
191
	close(c->hin.fd);
192
	free(c);
193
}
194
 
195
char*
196
hargstr(HConnect *c, char *name, char *def)
197
{
198
	HSPairs *p;
199
 
200
	for(p=c->req.searchpairs; p; p=p->next)
201
		if(strcmp(p->s, name) == 0)
202
			return p->t;
203
	return def;
204
}
205
 
206
vlong
207
hargint(HConnect *c, char *name, vlong def)
208
{
209
	char *a;
210
 
211
	if((a = hargstr(c, name, nil)) == nil)
212
		return def;
213
	return atoll(a);
214
}
215
 
216
static int
217
percent(ulong v, ulong total)
218
{
219
	if(total == 0)
220
		total = 1;
221
	if(v < 1000*1000)
222
		return (v * 100) / total;
223
	total /= 100;
224
	if(total == 0)
225
		total = 1;
226
	return v / total;
227
}
228
 
229
static int
230
preq(HConnect *c)
231
{
232
	if(hparseheaders(c, 0) < 0)
233
		return -1;
234
	if(strcmp(c->req.meth, "GET") != 0
235
	&& strcmp(c->req.meth, "HEAD") != 0)
236
		return hunallowed(c, "GET, HEAD");
237
	if(c->head.expectother || c->head.expectcont)
238
		return hfail(c, HExpectFail, nil);
239
	return 0;
240
}
241
 
242
int
243
hsettype(HConnect *c, char *type)
244
{
245
	Hio *hout;
246
	int r;
247
 
248
	r = preq(c);
249
	if(r < 0)
250
		return r;
251
 
252
	hout = &c->hout;
253
	if(c->req.vermaj){
254
		hokheaders(c);
255
		hprint(hout, "Content-type: %s\r\n", type);
256
		if(http11(c))
257
			hprint(hout, "Transfer-Encoding: chunked\r\n");
258
		hprint(hout, "\r\n");
259
	}
260
 
261
	if(http11(c))
262
		hxferenc(hout, 1);
263
	else
264
		c->head.closeit = 1;
265
	return 0;
266
}
267
 
268
int
269
hsethtml(HConnect *c)
270
{
271
	return hsettype(c, "text/html; charset=utf-8");
272
}
273
 
274
int
275
hsettext(HConnect *c)
276
{
277
	return hsettype(c, "text/plain; charset=utf-8");
278
}
279
 
280
static int
281
herror(HConnect *c)
282
{
283
	int n;
284
	Hio *hout;
285
 
286
	hout = &c->hout;
287
	n = snprint(c->xferbuf, HBufSize, "<html><head><title>Error</title></head>\n<body><h1>Error</h1>\n<pre>%r</pre>\n</body></html>");
288
	hprint(hout, "%s %s\r\n", hversion, "400 Bad Request");
289
	hprint(hout, "Date: %D\r\n", time(nil));
290
	hprint(hout, "Server: Venti\r\n");
291
	hprint(hout, "Content-Type: text/html\r\n");
292
	hprint(hout, "Content-Length: %d\r\n", n);
293
	if(c->head.closeit)
294
		hprint(hout, "Connection: close\r\n");
295
	else if(!http11(c))
296
		hprint(hout, "Connection: Keep-Alive\r\n");
297
	hprint(hout, "\r\n");
298
 
299
	if(c->req.meth == nil || strcmp(c->req.meth, "HEAD") != 0)
300
		hwrite(hout, c->xferbuf, n);
301
 
302
	return hflush(hout);
303
}
304
 
305
int
306
hnotfound(HConnect *c)
307
{
308
	int r;
309
 
310
	r = preq(c);
311
	if(r < 0)
312
		return r;
313
	return hfail(c, HNotFound, c->req.uri);
314
}
315
 
316
struct {
317
	char *ext;
318
	char *type;
319
} exttab[] = {
320
	".html",	"text/html",
321
	".txt",	"text/plain",
322
	".xml",	"text/xml",
323
	".png",	"image/png",
324
	".gif",	"image/gif",
325
 
326
};
327
 
328
static int
329
fromwebdir(HConnect *c)
330
{
331
	char buf[4096], *p, *ext, *type;
332
	int i, fd, n, defaulted;
333
	Dir *d;
334
 
335
	if(webroot == nil || strstr(c->req.uri, ".."))
336
		return hnotfound(c);
337
	snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1);
338
	defaulted = 0;
339
reopen:
340
	if((fd = open(buf, OREAD)) < 0)
341
		return hnotfound(c);
342
	d = dirfstat(fd);
343
	if(d == nil){
344
		close(fd);
345
		return hnotfound(c);
346
	}
347
	if(d->mode&DMDIR){
348
		if(!defaulted){
349
			defaulted = 1;
350
			strcat(buf, "/index.html");
351
			free(d);
352
			close(fd);
353
			goto reopen;
354
		}
355
		free(d);
356
		return hnotfound(c);
357
	}
358
	free(d);
359
	p = buf+strlen(buf);
360
	type = "application/octet-stream";
361
	for(i=0; exttab[i].ext; i++){
362
		ext = exttab[i].ext;
363
		if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){
364
			type = exttab[i].type;
365
			break;
366
		}
367
	}
368
	if(hsettype(c, type) < 0){
369
		close(fd);
370
		return 0;
371
	}
372
	while((n = read(fd, buf, sizeof buf)) > 0)
373
		if(hwrite(&c->hout, buf, n) < 0)
374
			break;
375
	close(fd);
376
	hflush(&c->hout);
377
	return 0;
378
}
379
 
380
static struct
381
{
382
	char *name;
383
	int *p;
384
} namedints[] =
385
{
386
	"compress",	&compressblocks,
387
	"devnull",	&writestodevnull,
388
	"logging",	&ventilogging,
389
	"stats",	&collectstats,
390
	"icachesleeptime",	&icachesleeptime,
391
	"minicachesleeptime",	&minicachesleeptime,
392
	"arenasumsleeptime",	&arenasumsleeptime,
393
	"l0quantum",	&l0quantum,
394
	"l1quantum",	&l1quantum,
395
	"manualscheduling",	&manualscheduling,
396
	"ignorebloom",	&ignorebloom,
397
	"syncwrites",	&syncwrites,
398
	"icacheprefetch",	&icacheprefetch,
399
 
400
};
401
 
402
static int
403
xset(HConnect *c)
404
{
405
	int i, old;
406
	char *name, *value;
407
 
408
	if(hsettext(c) < 0)
409
		return -1;
410
 
411
	if((name = hargstr(c, "name", nil)) == nil || name[0] == 0){
412
		for(i=0; namedints[i].name; i++)
413
			hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
414
		hflush(&c->hout);
415
		return 0;
416
	}
417
 
418
	for(i=0; namedints[i].name; i++)
419
		if(strcmp(name, namedints[i].name) == 0)
420
			break;
421
	if(!namedints[i].name){
422
		hprint(&c->hout, "%s not found\n", name);
423
		hflush(&c->hout);
424
		return 0;
425
	}
426
 
427
	if((value = hargstr(c, "value", nil)) == nil || value[0] == 0){
428
		hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
429
		hflush(&c->hout);
430
		return 0;
431
	}
432
 
433
	old = *namedints[i].p;
434
	*namedints[i].p = atoll(value);
435
	hprint(&c->hout, "%s = %d (was %d)\n", name, *namedints[i].p, old);
436
	hflush(&c->hout);
437
	return 0;
438
}
439
 
440
static int
441
estats(HConnect *c)
442
{
443
	Hio *hout;
444
	int r;
445
 
446
	r = hsettext(c);
447
	if(r < 0)
448
		return r;
449
 
450
 
451
	hout = &c->hout;
452
/*
453
	hprint(hout, "lump writes=%,ld\n", stats.lumpwrites);
454
	hprint(hout, "lump reads=%,ld\n", stats.lumpreads);
455
	hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit);
456
	hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss);
457
 
458
	hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites);
459
	hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites);
460
	hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp);
461
	hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads);
462
	hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads);
463
	hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp);
464
 
465
	hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
466
	hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
467
 
468
	hprint(hout, "index disk writes=%,ld\n", stats.indexwrites);
469
	hprint(hout, "index disk reads=%,ld\n", stats.indexreads);
470
	hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n",
471
		stats.indexbloomhits,
472
		percent(stats.indexbloomhits, stats.indexreads),
473
		stats.indexbloomfalsemisses,
474
		percent(stats.indexbloomfalsemisses, stats.indexreads));
475
	hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n",
476
		stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits));
477
	hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads);
478
	hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads);
479
	hprint(hout, "index block splits=%,ld\n", stats.indexsplits);
480
 
481
	hprint(hout, "index cache lookups=%,ld\n", stats.iclookups);
482
	hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits,
483
		percent(stats.ichits, stats.iclookups));
484
	hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills,
485
		percent(stats.icfills, stats.iclookups));
486
	hprint(hout, "index cache inserts=%,ld\n", stats.icinserts);
487
 
488
	hprint(hout, "disk cache hits=%,ld\n", stats.pchit);
489
	hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss);
490
	hprint(hout, "disk cache reads=%,ld\n", stats.pcreads);
491
	hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads);
492
 
493
	hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks);
494
	hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites,
495
		percent(stats.absorbedwrites, stats.dirtydblocks));
496
 
497
	hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes);
498
	hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n", 
499
		stats.dcacheflushwrites,
500
		stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1));
501
 
502
	hprint(hout, "disk writes=%,ld\n", stats.diskwrites);
503
	hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites);
504
	hprint(hout, "disk reads=%,ld\n", stats.diskreads);
505
	hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads);
506
*/
507
 
508
	hflush(hout);
509
	return 0;
510
}
511
 
512
static int
513
sindex(HConnect *c)
514
{
515
	Hio *hout;
516
	Index *ix;
517
	Arena *arena;
518
	vlong clumps, cclumps, uncsize, used, size;
519
	int i, r, active;
520
 
521
	r = hsettext(c);
522
	if(r < 0)
523
		return r;
524
	hout = &c->hout;
525
 
526
	ix = mainindex;
527
 
528
	hprint(hout, "index=%s\n", ix->name);
529
 
530
	active = 0;
531
	clumps = 0;
532
	cclumps = 0;
533
	uncsize = 0;
534
	used = 0;
535
	size = 0;
536
	for(i = 0; i < ix->narenas; i++){
537
		arena = ix->arenas[i];
538
		if(arena != nil && arena->memstats.clumps != 0){
539
			active++;
540
			clumps += arena->memstats.clumps;
541
			cclumps += arena->memstats.cclumps;
542
			uncsize += arena->memstats.uncsize;
543
			used += arena->memstats.used;
544
		}
545
		size += arena->size;
546
	}
547
	hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active);
548
	hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize);
549
	hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n",
550
		clumps, cclumps, uncsize, used - clumps * ClumpSize);
551
	hflush(hout);
552
	return 0;
553
}
554
 
555
static void
556
darena(Hio *hout, Arena *arena)
557
{
558
	hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
559
		arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize,
560
		arena->version, arena->ctime, arena->wtime);
561
	if(arena->memstats.sealed)
562
		hprint(hout, " mem=sealed");
563
	if(arena->diskstats.sealed)
564
		hprint(hout, " disk=sealed");
565
	hprint(hout, "\n");
566
	if(scorecmp(zeroscore, arena->score) != 0)
567
		hprint(hout, "\tscore=%V\n", arena->score);
568
 
569
	hprint(hout, "\twritten: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
570
		arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize,
571
		arena->memstats.used - arena->memstats.clumps * ClumpSize,
572
		arena->memstats.used + arena->memstats.clumps * ClumpInfoSize);
573
	hprint(hout, "\tindexed: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
574
		arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize,
575
		arena->diskstats.used - arena->diskstats.clumps * ClumpSize,
576
		arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize);
577
}
578
 
579
static int
580
hempty(HConnect *c)
581
{
582
	Hio *hout;
583
	int r;
584
 
585
	r = hsettext(c);
586
	if(r < 0)
587
		return r;
588
	hout = &c->hout;
589
 
590
	emptylumpcache();
591
	emptydcache();
592
	emptyicache();
593
	hprint(hout, "emptied all caches\n");
594
	hflush(hout);
595
	return 0;
596
}
597
 
598
static int
599
hlcacheempty(HConnect *c)
600
{
601
	Hio *hout;
602
	int r;
603
 
604
	r = hsettext(c);
605
	if(r < 0)
606
		return r;
607
	hout = &c->hout;
608
 
609
	emptylumpcache();
610
	hprint(hout, "emptied lumpcache\n");
611
	hflush(hout);
612
	return 0;
613
}
614
 
615
static int
616
hicacheempty(HConnect *c)
617
{
618
	Hio *hout;
619
	int r;
620
 
621
	r = hsettext(c);
622
	if(r < 0)
623
		return r;
624
	hout = &c->hout;
625
 
626
	emptyicache();
627
	hprint(hout, "emptied icache\n");
628
	hflush(hout);
629
	return 0;
630
}
631
 
632
static int
633
hdcacheempty(HConnect *c)
634
{
635
	Hio *hout;
636
	int r;
637
 
638
	r = hsettext(c);
639
	if(r < 0)
640
		return r;
641
	hout = &c->hout;
642
 
643
	emptydcache();
644
	hprint(hout, "emptied dcache\n");
645
	hflush(hout);
646
	return 0;
647
}
648
static int
649
hicachekick(HConnect *c)
650
{
651
	Hio *hout;
652
	int r;
653
 
654
	r = hsettext(c);
655
	if(r < 0)
656
		return r;
657
	hout = &c->hout;
658
 
659
	kickicache();
660
	hprint(hout, "kicked icache\n");
661
	hflush(hout);
662
	return 0;
663
}
664
 
665
static int
666
hdcachekick(HConnect *c)
667
{
668
	Hio *hout;
669
	int r;
670
 
671
	r = hsettext(c);
672
	if(r < 0)
673
		return r;
674
	hout = &c->hout;
675
 
676
	kickdcache();
677
	hprint(hout, "kicked dcache\n");
678
	hflush(hout);
679
	return 0;
680
}
681
static int
682
hicacheflush(HConnect *c)
683
{
684
	Hio *hout;
685
	int r;
686
 
687
	r = hsettext(c);
688
	if(r < 0)
689
		return r;
690
	hout = &c->hout;
691
 
692
	flushicache();
693
	hprint(hout, "flushed icache\n");
694
	hflush(hout);
695
	return 0;
696
}
697
 
698
static int
699
hdcacheflush(HConnect *c)
700
{
701
	Hio *hout;
702
	int r;
703
 
704
	r = hsettext(c);
705
	if(r < 0)
706
		return r;
707
	hout = &c->hout;
708
 
709
	flushdcache();
710
	hprint(hout, "flushed dcache\n");
711
	hflush(hout);
712
	return 0;
713
}
714
 
715
static int
716
dindex(HConnect *c)
717
{
718
	Hio *hout;
719
	Index *ix;
720
	int i, r;
721
 
722
	r = hsettext(c);
723
	if(r < 0)
724
		return r;
725
	hout = &c->hout;
726
 
727
 
728
	ix = mainindex;
729
	hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n",
730
		ix->name, ix->version, ix->blocksize, ix->tabsize);
731
	hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
732
	for(i = 0; i < ix->nsects; i++)
733
		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);
734
	for(i = 0; i < ix->narenas; i++){
735
		if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){
736
			hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
737
			darena(hout, ix->arenas[i]);
738
		}
739
	}
740
	hflush(hout);
741
	return 0;
742
}
743
 
744
typedef struct Arg Arg;
745
struct Arg
746
{
747
	int index;
748
	int index2;
749
};
750
 
751
static long
752
rawgraph(Stats *s, Stats *t, void *va)
753
{
754
	Arg *a;
755
 
756
	USED(s);
757
	a = va;
758
	return t->n[a->index];
759
}
760
 
761
static long
762
diffgraph(Stats *s, Stats *t, void *va)
763
{
764
	Arg *a;
765
 
766
	a = va;
767
	return t->n[a->index] - s->n[a->index];
768
}
769
 
770
static long
771
pctgraph(Stats *s, Stats *t, void *va)
772
{
773
	Arg *a;
774
 
775
	USED(s);
776
	a = va;
777
	return percent(t->n[a->index], t->n[a->index2]);
778
}
779
 
780
static long
781
pctdiffgraph(Stats *s, Stats *t, void *va)
782
{
783
	Arg *a;
784
 
785
	a = va;
786
	return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]);
787
}
788
 
789
static long
790
xdiv(long a, long b)
791
{
792
	if(b == 0)
793
		b++;
794
	return a/b;
795
}
796
 
797
static long
798
divdiffgraph(Stats *s, Stats *t, void *va)
799
{
800
	Arg *a;
801
 
802
	a = va;
803
	return xdiv(t->n[a->index] - s->n[a->index], t->n[a->index2] - s->n[a->index2]);
804
}
805
 
806
static long
807
netbw(Stats *s)
808
{
809
	ulong *n;
810
 
811
	n = s->n;
812
	return n[StatRpcReadBytes]+n[StatRpcWriteBytes];	/* not exactly right */
813
}
814
 
815
static long
816
diskbw(Stats *s)
817
{
818
	ulong *n;
819
 
820
	n = s->n;
821
	return n[StatApartReadBytes]+n[StatApartWriteBytes]	
822
		+ n[StatIsectReadBytes]+n[StatIsectWriteBytes]
823
		+ n[StatSumReadBytes];
824
}
825
 
826
static long
827
iobw(Stats *s)
828
{
829
	return netbw(s)+diskbw(s);
830
}
831
 
832
static long
833
diskgraph(Stats *s, Stats *t, void *va)
834
{
835
	USED(va);
836
	return diskbw(t)-diskbw(s);
837
}
838
 
839
static long
840
netgraph(Stats *s, Stats *t, void *va)
841
{
842
	USED(va);
843
	return netbw(t)-netbw(s);
844
}
845
 
846
static long
847
iograph(Stats *s, Stats *t, void *va)
848
{
849
	USED(va);
850
	return iobw(t)-iobw(s);
851
}
852
 
853
 
854
static char* graphname[] =
855
{
856
	"rpctotal",
857
	"rpcread",
858
	"rpcreadok",
859
	"rpcreadfail",
860
	"rpcreadbyte",
861
	"rpcreadtime",
862
	"rpcreadcached",
863
	"rpcreadcachedtime",
864
	"rpcreaduncached",
865
	"rpcreaduncachedtime",
866
	"rpcwrite",
867
	"rpcwritenew",
868
	"rpcwriteold",
869
	"rpcwritefail",
870
	"rpcwritebyte",
871
	"rpcwritetime",
872
	"rpcwritenewtime",
873
	"rpcwriteoldtime",
874
 
875
	"lcachehit",
876
	"lcachemiss",
877
	"lcachelookup",
878
	"lcachewrite",
879
	"lcachesize",
880
	"lcachestall",
881
	"lcachelookuptime",
882
 
883
	"dcachehit",
884
	"dcachemiss",
885
	"dcachelookup",
886
	"dcacheread",
887
	"dcachewrite",
888
	"dcachedirty",
889
	"dcachesize",
890
	"dcacheflush",
891
	"dcachestall",
892
	"dcachelookuptime",
893
 
894
	"dblockstall",
895
	"lumpstall",
896
 
897
	"icachehit",
898
	"icachemiss",
899
	"icacheread",
900
	"icachewrite",
901
	"icachefill",
902
	"icacheprefetch",
903
	"icachedirty",
904
	"icachesize",
905
	"icacheflush",
906
	"icachestall",
907
	"icachelookuptime",
908
	"icachelookup",
909
	"scachehit",
910
	"scacheprefetch",
911
 
912
	"bloomhit",
913
	"bloommiss",
914
	"bloomfalsemiss",
915
	"bloomlookup",
916
	"bloomones",
917
	"bloombits",
918
 
919
	"apartread",
920
	"apartreadbyte",
921
	"apartwrite",
922
	"apartwritebyte",
923
 
924
	"isectread",
925
	"isectreadbyte",
926
	"isectwrite",
927
	"isectwritebyte",
928
 
929
	"sumread",
930
	"sumreadbyte",
931
 
932
	"cigload",
933
	"cigloadtime",
934
};
935
 
936
static int
937
findname(char *s)
938
{
939
	int i;
940
 
941
	for(i=0; i<nelem(graphname); i++)
942
		if(strcmp(graphname[i], s) == 0)
943
			return i;
944
	return -1;
945
}
946
 
947
static void
948
dotextbin(Hio *io, Graph *g)
949
{
950
	int i, nbin;
951
	Statbin *b, bin[2000];	/* 32 kB, but whack is worse */
952
 
953
	needstack(8192);	/* double check that bin didn't kill us */
954
	nbin = 100;
955
	binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin);
956
 
957
	hprint(io, "stats\n\n");
958
	for(i=0; i<nbin; i++){
959
		b = &bin[i];
960
		hprint(io, "%d: nsamp=%d min=%d max=%d avg=%d\n",
961
			i, b->nsamp, b->min, b->max, b->avg);
962
	}
963
}
964
 
965
static int
966
xgraph(HConnect *c)
967
{
968
	char *name;
969
	Hio *hout;
970
	Memimage *m;
971
	int dotext;
972
	Graph g;
973
	Arg arg;
974
	char *graph, *a;
975
 
976
	name = hargstr(c, "arg", "");
977
	if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){
978
		werrstr("unknown name %s", name);
979
		goto error;
980
	}
981
	a = hargstr(c, "arg2", "");
982
	if(a[0] && (arg.index2 = findname(a)) == -1){
983
		werrstr("unknown name %s", a);
984
		goto error;
985
	}
986
 
987
	g.arg = &arg;
988
	g.t0 = hargint(c, "t0", -120);
989
	g.t1 = hargint(c, "t1", 0);
990
	g.min = hargint(c, "min", -1);
991
	g.max = hargint(c, "max", -1);
992
	g.wid = hargint(c, "wid", -1);
993
	g.ht = hargint(c, "ht", -1);
994
	dotext = hargstr(c, "text", "")[0] != 0;
995
	g.fill = hargint(c, "fill", -1);
996
 
997
	graph = hargstr(c, "graph", "raw");
998
	if(strcmp(graph, "raw") == 0)
999
		g.fn = rawgraph;
1000
	else if(strcmp(graph, "diskbw") == 0)
1001
		g.fn = diskgraph;
1002
	else if(strcmp(graph, "iobw") == 0)
1003
		g.fn = iograph;
1004
	else if(strcmp(graph, "netbw") == 0)
1005
		g.fn = netgraph;
1006
	else if(strcmp(graph, "diff") == 0)
1007
		g.fn = diffgraph;
1008
	else if(strcmp(graph, "pct") == 0)
1009
		g.fn = pctgraph;
1010
	else if(strcmp(graph, "pctdiff") == 0)
1011
		g.fn = pctdiffgraph;
1012
	else if(strcmp(graph, "divdiff") == 0)
1013
		g.fn = divdiffgraph;
1014
	else{
1015
		werrstr("unknown graph %s", graph);
1016
		goto error;
1017
	}
1018
 
1019
	if(dotext){
1020
		hsettype(c, "text/plain");
1021
		dotextbin(&c->hout, &g);
1022
		hflush(&c->hout);
1023
		return 0;
1024
	}
1025
 
1026
	m = statgraph(&g);
1027
	if(m == nil)
1028
		goto error;
1029
 
1030
	if(hsettype(c, "image/png") < 0)
1031
		return -1;
1032
	hout = &c->hout;
1033
	writepng(hout, m);
1034
	qlock(&memdrawlock);
1035
	freememimage(m);
1036
	qunlock(&memdrawlock);
1037
	hflush(hout);
1038
	return 0;
1039
 
1040
error:
1041
	return herror(c);
1042
}
1043
 
1044
static int
1045
xloglist(HConnect *c)
1046
{
1047
	if(hsettype(c, "text/html") < 0)
1048
		return -1;
1049
	vtloghlist(&c->hout);
1050
	hflush(&c->hout);
1051
	return 0;
1052
}
1053
 
1054
static int
1055
xlog(HConnect *c)
1056
{
1057
	char *name;
1058
	VtLog *l;
1059
 
1060
	name = hargstr(c, "log", "");
1061
	if(!name[0])
1062
		return xloglist(c);
1063
	l = vtlogopen(name, 0);
1064
	if(l == nil)
1065
		return hnotfound(c);
1066
	if(hsettype(c, "text/html") < 0){
1067
		vtlogclose(l);
1068
		return -1;
1069
	}
1070
	vtloghdump(&c->hout, l);
1071
	vtlogclose(l);
1072
	hflush(&c->hout);
1073
	return 0;
1074
}
1075
 
1076
static int
1077
xindex(HConnect *c)
1078
{
1079
	if(hsettype(c, "text/xml") < 0)
1080
		return -1;
1081
	xmlindex(&c->hout, mainindex, "index", 0);
1082
	hflush(&c->hout);
1083
	return 0;
1084
}
1085
 
1086
void
1087
xmlindent(Hio *hout, int indent)
1088
{
1089
	int i;
1090
 
1091
	for(i = 0; i < indent; i++)
1092
		hputc(hout, '\t');
1093
}
1094
 
1095
void
1096
xmlaname(Hio *hout, char *v, char *tag)
1097
{
1098
	hprint(hout, " %s=\"%s\"", tag, v);
1099
}
1100
 
1101
void
1102
xmlscore(Hio *hout, u8int *v, char *tag)
1103
{
1104
	if(scorecmp(zeroscore, v) == 0)
1105
		return;
1106
	hprint(hout, " %s=\"%V\"", tag, v);
1107
}
1108
 
1109
void
1110
xmlsealed(Hio *hout, int v, char *tag)
1111
{
1112
	if(!v)
1113
		return;
1114
	hprint(hout, " %s=\"yes\"", tag);
1115
}
1116
 
1117
void
1118
xmlu32int(Hio *hout, u32int v, char *tag)
1119
{
1120
	hprint(hout, " %s=\"%ud\"", tag, v);
1121
}
1122
 
1123
void
1124
xmlu64int(Hio *hout, u64int v, char *tag)
1125
{
1126
	hprint(hout, " %s=\"%llud\"", tag, v);
1127
}
1128
 
1129
void
1130
vtloghdump(Hio *h, VtLog *l)
1131
{
1132
	int i;
1133
	VtLogChunk *c;
1134
	char *name;
1135
 
1136
	name = l ? l->name : "&lt;nil&gt;";
1137
 
1138
	hprint(h, "<html><head>\n");
1139
	hprint(h, "<title>Venti Server Log: %s</title>\n", name);
1140
	hprint(h, "</head><body>\n");
1141
	hprint(h, "<b>Venti Server Log: %s</b>\n<p>\n", name);
1142
 
1143
	if(l){
1144
		c = l->w;
1145
		for(i=0; i<l->nchunk; i++){
1146
			if(++c == l->chunk+l->nchunk)
1147
				c = l->chunk;
1148
			hwrite(h, c->p, c->wp-c->p);
1149
		}
1150
	}
1151
	hprint(h, "</body></html>\n");
1152
}
1153
 
1154
static int
1155
strpcmp(const void *va, const void *vb)
1156
{
1157
	return strcmp(*(char**)va, *(char**)vb);
1158
}
1159
 
1160
void
1161
vtloghlist(Hio *h)
1162
{
1163
	char **p;
1164
	int i, n;
1165
 
1166
	hprint(h, "<html><head>\n");
1167
	hprint(h, "<title>Venti Server Logs</title>\n");
1168
	hprint(h, "</head><body>\n");
1169
	hprint(h, "<b>Venti Server Logs</b>\n<p>\n");
1170
 
1171
	p = vtlognames(&n);
1172
	qsort(p, n, sizeof(p[0]), strpcmp);
1173
	for(i=0; i<n; i++)
1174
		hprint(h, "<a href=\"/log?log=%s\">%s</a><br>\n", p[i], p[i]);
1175
	vtfree(p);
1176
	hprint(h, "</body></html>\n");
1177
}