Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 #include "xml.h"
6 typedef struct HttpObj HttpObj;
7 extern QLock memdrawlock;
9 enum
10 {
11 ObjNameSize = 64,
12 MaxObjs = 16
13 };
15 struct HttpObj
16 {
17 char name[ObjNameSize];
18 int (*f)(HConnect*);
19 };
21 static HttpObj objs[MaxObjs];
23 static char *webroot;
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 hicacheflush(HConnect *c);
32 static int hdcacheflush(HConnect *c);
33 static int notfound(HConnect *c);
34 static int httpdobj(char *name, int (*f)(HConnect*));
35 static int xgraph(HConnect *c);
36 static int xset(HConnect *c);
37 static int fromwebdir(HConnect *c);
39 int
40 httpdinit(char *address, char *dir)
41 {
42 fmtinstall('D', hdatefmt);
43 /* fmtinstall('H', httpfmt); */
44 fmtinstall('U', hurlfmt);
46 if(address == nil)
47 address = "tcp!*!http";
48 webroot = dir;
50 httpdobj("/stats", estats);
51 httpdobj("/index", dindex);
52 httpdobj("/storage", sindex);
53 httpdobj("/xindex", xindex);
54 httpdobj("/flushicache", hicacheflush);
55 httpdobj("/flushdcache", hdcacheflush);
56 httpdobj("/graph/", xgraph);
57 httpdobj("/set/", xset);
58 httpdobj("/log", xlog);
59 httpdobj("/log/", xlog);
61 if(vtproc(listenproc, address) < 0)
62 return -1;
63 return 0;
64 }
66 static int
67 httpdobj(char *name, int (*f)(HConnect*))
68 {
69 int i;
71 if(name == nil || strlen(name) >= ObjNameSize)
72 return -1;
73 for(i = 0; i < MaxObjs; i++){
74 if(objs[i].name[0] == '\0'){
75 strcpy(objs[i].name, name);
76 objs[i].f = f;
77 return 0;
78 }
79 if(strcmp(objs[i].name, name) == 0)
80 return -1;
81 }
82 return -1;
83 }
85 static HConnect*
86 mkconnect(void)
87 {
88 HConnect *c;
90 c = mallocz(sizeof(HConnect), 1);
91 if(c == nil)
92 sysfatal("out of memory");
93 c->replog = nil;
94 c->hpos = c->header;
95 c->hstop = c->header;
96 return c;
97 }
99 void httpproc(void*);
101 static void
102 listenproc(void *vaddress)
104 HConnect *c;
105 char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
106 int ctl, nctl, data;
108 //sleep(1000); /* let strace find us */
110 address = vaddress;
111 ctl = announce(address, dir);
112 if(ctl < 0){
113 fprint(2, "venti: httpd can't announce on %s: %r\n", address);
114 return;
117 if(0) print("announce ctl %d dir %s\n", ctl, dir);
118 for(;;){
119 /*
120 * wait for a call (or an error)
121 */
122 nctl = listen(dir, ndir);
123 if(0) print("httpd listen %d %s...\n", nctl, ndir);
124 if(nctl < 0){
125 fprint(2, "venti: httpd can't listen on %s: %r\n", address);
126 return;
129 data = accept(ctl, ndir);
130 if(0) print("httpd accept %d...\n", data);
131 if(data < 0){
132 fprint(2, "venti: httpd accept: %r\n");
133 close(nctl);
134 continue;
136 if(0) print("httpd close nctl %d\n", nctl);
137 close(nctl);
138 c = mkconnect();
139 hinit(&c->hin, data, Hread);
140 hinit(&c->hout, data, Hwrite);
141 vtproc(httpproc, c);
145 void
146 httpproc(void *v)
148 HConnect *c;
149 int ok, i, n;
151 //sleep(1000); /* let strace find us */
152 c = v;
154 for(;;){
155 /*
156 * No timeout because the signal appears to hit every
157 * proc, not just us.
158 */
159 if(hparsereq(c, 0) < 0)
160 break;
162 for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
163 n = strlen(objs[i].name);
164 if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0)
165 || (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){
166 ok = (*objs[i].f)(c);
167 goto found;
170 ok = fromwebdir(c);
171 found:
172 if(c->head.closeit)
173 ok = -1;
174 hreqcleanup(c);
176 if(ok < 0)
177 break;
179 hreqcleanup(c);
180 close(c->hin.fd);
181 free(c);
184 static int
185 percent(long v, long total)
187 if(total == 0)
188 total = 1;
189 if(v < 1000*1000)
190 return (v * 100) / total;
191 total /= 100;
192 if(total == 0)
193 total = 1;
194 return v / total;
197 static int
198 preq(HConnect *c)
200 if(hparseheaders(c, 0) < 0)
201 return -1;
202 if(strcmp(c->req.meth, "GET") != 0
203 && strcmp(c->req.meth, "HEAD") != 0)
204 return hunallowed(c, "GET, HEAD");
205 if(c->head.expectother || c->head.expectcont)
206 return hfail(c, HExpectFail, nil);
207 return 0;
210 static int
211 preqtype(HConnect *c, char *type)
213 Hio *hout;
214 int r;
216 r = preq(c);
217 if(r < 0)
218 return r;
220 hout = &c->hout;
221 if(c->req.vermaj){
222 hokheaders(c);
223 hprint(hout, "Content-type: %s\r\n", type);
224 if(http11(c))
225 hprint(hout, "Transfer-Encoding: chunked\r\n");
226 hprint(hout, "\r\n");
229 if(http11(c))
230 hxferenc(hout, 1);
231 else
232 c->head.closeit = 1;
233 return 0;
236 static int
237 preqtext(HConnect *c)
239 return preqtype(c, "text/plain");
242 static int
243 notfound(HConnect *c)
245 int r;
247 r = preq(c);
248 if(r < 0)
249 return r;
250 return hfail(c, HNotFound, c->req.uri);
253 struct {
254 char *ext;
255 char *type;
256 } exttab[] = {
257 ".html", "text/html",
258 ".txt", "text/plain",
259 ".xml", "text/xml",
260 ".png", "image/png",
261 ".gif", "image/gif",
263 };
265 static int
266 fromwebdir(HConnect *c)
268 char buf[4096], *p, *ext, *type;
269 int i, fd, n, defaulted;
270 Dir *d;
272 if(webroot == nil || strstr(c->req.uri, ".."))
273 return notfound(c);
274 snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1);
275 defaulted = 0;
276 reopen:
277 if((fd = open(buf, OREAD)) < 0)
278 return notfound(c);
279 d = dirfstat(fd);
280 if(d == nil){
281 close(fd);
282 return notfound(c);
284 if(d->mode&DMDIR){
285 if(!defaulted){
286 defaulted = 1;
287 strcat(buf, "/index.html");
288 free(d);
289 close(fd);
290 goto reopen;
292 free(d);
293 return notfound(c);
295 free(d);
296 p = buf+strlen(buf);
297 type = "application/octet-stream";
298 for(i=0; exttab[i].ext; i++){
299 ext = exttab[i].ext;
300 if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){
301 type = exttab[i].type;
302 break;
305 if(preqtype(c, type) < 0){
306 close(fd);
307 return 0;
309 while((n = read(fd, buf, sizeof buf)) > 0)
310 if(hwrite(&c->hout, buf, n) < 0)
311 break;
312 close(fd);
313 hflush(&c->hout);
314 return 0;
317 static struct
319 char *name;
320 int *p;
321 } namedints[] =
323 "compress", &compressblocks,
324 "devnull", &writestodevnull,
325 "logging", &ventilogging,
326 "stats", &collectstats,
327 "icachesleeptime", &icachesleeptime,
328 "arenasumsleeptime", &arenasumsleeptime,
330 };
332 static int
333 xset(HConnect *c)
335 int i, nf, r;
336 char *f[10], *s;
338 s = estrdup(c->req.uri);
339 nf = getfields(s+strlen("/set/"), f, nelem(f), 1, "/");
341 if(nf < 1)
342 return notfound(c);
343 for(i=0; namedints[i].name; i++){
344 if(strcmp(f[0], namedints[i].name) == 0){
345 if(nf >= 2)
346 *namedints[i].p = atoi(f[1]);
347 r = preqtext(c);
348 if(r < 0)
349 return r;
350 hprint(&c->hout, "%s = %d\n", f[0], *namedints[i].p);
351 hflush(&c->hout);
352 return 0;
355 return notfound(c);
358 static int
359 estats(HConnect *c)
361 Hio *hout;
362 int r;
364 r = preqtext(c);
365 if(r < 0)
366 return r;
369 hout = &c->hout;
370 /*
371 hprint(hout, "lump writes=%,ld\n", stats.lumpwrites);
372 hprint(hout, "lump reads=%,ld\n", stats.lumpreads);
373 hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit);
374 hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss);
376 hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites);
377 hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites);
378 hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp);
379 hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads);
380 hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads);
381 hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp);
383 hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
384 hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
386 hprint(hout, "index disk writes=%,ld\n", stats.indexwrites);
387 hprint(hout, "index disk reads=%,ld\n", stats.indexreads);
388 hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n",
389 stats.indexbloomhits,
390 percent(stats.indexbloomhits, stats.indexreads),
391 stats.indexbloomfalsemisses,
392 percent(stats.indexbloomfalsemisses, stats.indexreads));
393 hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n",
394 stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits));
395 hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads);
396 hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads);
397 hprint(hout, "index block splits=%,ld\n", stats.indexsplits);
399 hprint(hout, "index cache lookups=%,ld\n", stats.iclookups);
400 hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits,
401 percent(stats.ichits, stats.iclookups));
402 hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills,
403 percent(stats.icfills, stats.iclookups));
404 hprint(hout, "index cache inserts=%,ld\n", stats.icinserts);
406 hprint(hout, "disk cache hits=%,ld\n", stats.pchit);
407 hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss);
408 hprint(hout, "disk cache reads=%,ld\n", stats.pcreads);
409 hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads);
411 hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks);
412 hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites,
413 percent(stats.absorbedwrites, stats.dirtydblocks));
415 hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes);
416 hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n",
417 stats.dcacheflushwrites,
418 stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1));
420 hprint(hout, "disk writes=%,ld\n", stats.diskwrites);
421 hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites);
422 hprint(hout, "disk reads=%,ld\n", stats.diskreads);
423 hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads);
424 */
426 hflush(hout);
427 return 0;
430 static int
431 sindex(HConnect *c)
433 Hio *hout;
434 Index *ix;
435 Arena *arena;
436 vlong clumps, cclumps, uncsize, used, size;
437 int i, r, active;
439 r = preqtext(c);
440 if(r < 0)
441 return r;
442 hout = &c->hout;
444 ix = mainindex;
446 hprint(hout, "index=%s\n", ix->name);
448 active = 0;
449 clumps = 0;
450 cclumps = 0;
451 uncsize = 0;
452 used = 0;
453 size = 0;
454 for(i = 0; i < ix->narenas; i++){
455 arena = ix->arenas[i];
456 if(arena != nil && arena->memstats.clumps != 0){
457 active++;
458 clumps += arena->memstats.clumps;
459 cclumps += arena->memstats.cclumps;
460 uncsize += arena->memstats.uncsize;
461 used += arena->memstats.used;
463 size += arena->size;
465 hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active);
466 hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize);
467 hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n",
468 clumps, cclumps, uncsize, used - clumps * ClumpSize);
469 hflush(hout);
470 return 0;
473 static void
474 darena(Hio *hout, Arena *arena)
476 hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
477 arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize,
478 arena->version, arena->ctime, arena->wtime);
479 if(arena->memstats.sealed)
480 hprint(hout, " mem=sealed");
481 if(arena->diskstats.sealed)
482 hprint(hout, " disk=sealed");
483 hprint(hout, "\n");
484 if(scorecmp(zeroscore, arena->score) != 0)
485 hprint(hout, "\tscore=%V\n", arena->score);
487 hprint(hout, "\tmem: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
488 arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize,
489 arena->memstats.used - arena->memstats.clumps * ClumpSize,
490 arena->memstats.used + arena->memstats.clumps * ClumpInfoSize);
491 hprint(hout, "\tdisk: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
492 arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize,
493 arena->diskstats.used - arena->diskstats.clumps * ClumpSize,
494 arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize);
497 static int
498 hicacheflush(HConnect *c)
500 Hio *hout;
501 int r;
503 r = preqtext(c);
504 if(r < 0)
505 return r;
506 hout = &c->hout;
508 flushicache();
509 hprint(hout, "flushed icache\n");
510 hflush(hout);
511 return 0;
514 static int
515 hdcacheflush(HConnect *c)
517 Hio *hout;
518 int r;
520 r = preqtext(c);
521 if(r < 0)
522 return r;
523 hout = &c->hout;
525 flushdcache();
526 hprint(hout, "flushed dcache\n");
527 hflush(hout);
528 return 0;
531 static int
532 dindex(HConnect *c)
534 Hio *hout;
535 Index *ix;
536 int i, r;
538 r = preqtext(c);
539 if(r < 0)
540 return r;
541 hout = &c->hout;
544 ix = mainindex;
545 hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n",
546 ix->name, ix->version, ix->blocksize, ix->tabsize);
547 hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
548 for(i = 0; i < ix->nsects; i++)
549 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);
550 for(i = 0; i < ix->narenas; i++){
551 if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){
552 hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
553 darena(hout, ix->arenas[i]);
556 hflush(hout);
557 return 0;
560 typedef struct Arg Arg;
561 struct Arg
563 int index;
564 int index2;
565 };
567 static long
568 rawgraph(Stats *s, Stats *t, void *va)
570 Arg *a;
572 a = va;
573 return t->n[a->index];
576 static long
577 diffgraph(Stats *s, Stats *t, void *va)
579 Arg *a;
581 a = va;
582 return t->n[a->index] - s->n[a->index];
585 static long
586 pctgraph(Stats *s, Stats *t, void *va)
588 Arg *a;
590 a = va;
591 return percent(t->n[a->index], t->n[a->index2]);
594 static long
595 pctdiffgraph(Stats *s, Stats *t, void *va)
597 Arg *a;
599 a = va;
600 return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]);
603 static long
604 netbw(Stats *s)
606 ulong *n;
608 n = s->n;
609 return n[StatRpcReadBytes]+n[StatRpcWriteBytes]; /* not exactly right */
612 static long
613 diskbw(Stats *s)
615 ulong *n;
617 n = s->n;
618 return n[StatApartReadBytes]+n[StatApartWriteBytes]
619 + n[StatIsectReadBytes]+n[StatIsectWriteBytes]
620 + n[StatSumReadBytes];
623 static long
624 iobw(Stats *s)
626 return netbw(s)+diskbw(s);
629 static long
630 diskgraph(Stats *s, Stats *t, void *va)
632 USED(va);
633 return diskbw(t)-diskbw(s);
636 static long
637 netgraph(Stats *s, Stats *t, void *va)
639 USED(va);
640 return netbw(t)-netbw(s);
643 static long
644 iograph(Stats *s, Stats *t, void *va)
646 USED(va);
647 return iobw(t)-iobw(s);
651 static char* graphname[] =
653 "rpctotal",
654 "rpcread",
655 "rpcreadok",
656 "rpcreadfail",
657 "rpcreadbyte",
658 "rpcreadtime",
659 "rpcreadcached",
660 "rpcreadcachedtime",
661 "rpcreaduncached",
662 "rpcreaduncachedtime",
663 "rpcwrite",
664 "rpcwritenew",
665 "rpcwriteold",
666 "rpcwritefail",
667 "rpcwritebyte",
668 "rpcwritetime",
669 "rpcwritenewtime",
670 "rpcwriteoldtime",
672 "lcachehit",
673 "lcachemiss",
674 "lcachelookup",
675 "lcachewrite",
676 "lcachesize",
677 "lcachestall",
678 "lcachelookuptime",
680 "dcachehit",
681 "dcachemiss",
682 "dcachelookup",
683 "dcacheread",
684 "dcachewrite",
685 "dcachedirty",
686 "dcachesize",
687 "dcacheflush",
688 "dcachestall",
689 "dcachelookuptime",
691 "dblockstall",
692 "lumpstall",
694 "icachehit",
695 "icachemiss",
696 "icachelookup",
697 "icachewrite",
698 "icachefill",
699 "icacheprefetch",
700 "icachedirty",
701 "icachesize",
702 "icacheflush",
703 "icachestall",
704 "icachelookuptime",
706 "bloomhit",
707 "bloommiss",
708 "bloomfalsemiss",
709 "bloomlookup",
710 "bloomones",
711 "bloombits",
712 "bloomlookuptime",
714 "apartread",
715 "apartreadbyte",
716 "apartwrite",
717 "apartwritebyte",
719 "isectread",
720 "isectreadbyte",
721 "isectwrite",
722 "isectwritebyte",
724 "sumread",
725 "sumreadbyte",
726 };
728 static int
729 findname(char *s)
731 int i;
733 for(i=0; i<nelem(graphname); i++)
734 if(strcmp(graphname[i], s) == 0)
735 return i;
736 fprint(2, "no name '%s'\n", s);
737 return -1;
740 static void
741 dotextbin(Hio *io, Graph *g)
743 int i, nbin;
744 Statbin *b, bin[2000]; /* 32 kB, but whack is worse */
746 needstack(8192); /* double check that bin didn't kill us */
747 nbin = 100;
748 binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin);
750 hprint(io, "stats\n\n");
751 for(i=0; i<nbin; i++){
752 b = &bin[i];
753 hprint(io, "%d: nsamp=%d min=%d max=%d avg=%d\n",
754 i, b->nsamp, b->min, b->max, b->avg);
758 static int
759 xgraph(HConnect *c)
761 char *f[20], *s;
762 Hio *hout;
763 Memimage *m;
764 int i, nf, dotext;
765 Graph g;
766 Arg arg;
768 s = estrdup(c->req.uri);
769 if(0) fprint(2, "graph %s\n" ,s);
770 memset(&g, 0, sizeof g);
771 nf = getfields(s+strlen("/graph/"), f, nelem(f), 1, "/");
772 if(nf < 1)
773 goto notfound;
774 if((arg.index = findname(f[0])) == -1 && strcmp(f[0], "*") != 0)
775 goto notfound;
776 g.arg = &arg;
777 g.t0 = -120;
778 g.t1 = 0;
779 g.min = -1;
780 g.max = -1;
781 g.fn = rawgraph;
782 g.wid = -1;
783 g.ht = -1;
784 dotext = 0;
785 g.fill = -1;
786 for(i=1; i<nf; i++){
787 if(strncmp(f[i], "t0=", 3) == 0)
788 g.t0 = atoi(f[i]+3);
789 else if(strncmp(f[i], "t1=", 3) == 0)
790 g.t1 = atoi(f[i]+3);
791 else if(strncmp(f[i], "min=", 4) == 0)
792 g.min = atoi(f[i]+4);
793 else if(strncmp(f[i], "max=", 4) == 0)
794 g.max = atoi(f[i]+4);
795 else if(strncmp(f[i], "pct=", 4) == 0){
796 if((arg.index2 = findname(f[i]+4)) == -1)
797 goto notfound;
798 g.fn = pctgraph;
799 g.min = 0;
800 g.max = 100;
801 }else if(strncmp(f[i], "pctdiff=", 8) == 0){
802 if((arg.index2 = findname(f[i]+8)) == -1)
803 goto notfound;
804 g.fn = pctdiffgraph;
805 g.min = 0;
806 g.max = 100;
807 }else if(strcmp(f[i], "diff") == 0)
808 g.fn = diffgraph;
809 else if(strcmp(f[i], "text") == 0)
810 dotext = 1;
811 else if(strncmp(f[i], "wid=", 4) == 0)
812 g.wid = atoi(f[i]+4);
813 else if(strncmp(f[i], "ht=", 3) == 0)
814 g.ht = atoi(f[i]+3);
815 else if(strncmp(f[i], "fill=", 5) == 0)
816 g.fill = atoi(f[i]+5);
817 else if(strcmp(f[i], "diskbw") == 0)
818 g.fn = diskgraph;
819 else if(strcmp(f[i], "iobw") == 0)
820 g.fn = iograph;
821 else if(strcmp(f[i], "netbw") == 0)
822 g.fn = netgraph;
824 if(dotext){
825 preqtype(c, "text/plain");
826 dotextbin(&c->hout, &g);
827 hflush(&c->hout);
828 return 0;
831 m = statgraph(&g);
832 if(m == nil)
833 goto notfound;
835 if(preqtype(c, "image/png") < 0)
836 return -1;
837 hout = &c->hout;
838 writepng(hout, m);
839 qlock(&memdrawlock);
840 freememimage(m);
841 qunlock(&memdrawlock);
842 hflush(hout);
843 free(s);
844 return 0;
846 notfound:
847 free(s);
848 return notfound(c);
851 static int
852 xloglist(HConnect *c)
854 if(preqtype(c, "text/html") < 0)
855 return -1;
856 vtloghlist(&c->hout);
857 hflush(&c->hout);
858 return 0;
861 static int
862 xlog(HConnect *c)
864 char *name;
865 VtLog *l;
867 if(strcmp(c->req.uri, "/log") == 0 || strcmp(c->req.uri, "/log/") == 0)
868 return xloglist(c);
869 if(strncmp(c->req.uri, "/log/", 5) != 0)
870 return notfound(c);
871 name = c->req.uri + strlen("/log/");
872 l = vtlogopen(name, 0);
873 if(l == nil)
874 return notfound(c);
875 if(preqtype(c, "text/html") < 0){
876 vtlogclose(l);
877 return -1;
879 vtloghdump(&c->hout, l);
880 vtlogclose(l);
881 hflush(&c->hout);
882 return 0;
885 static int
886 xindex(HConnect *c)
888 if(preqtype(c, "text/xml") < 0)
889 return -1;
890 xmlindex(&c->hout, mainindex, "index", 0);
891 hflush(&c->hout);
892 return 0;
895 void
896 xmlindent(Hio *hout, int indent)
898 int i;
900 for(i = 0; i < indent; i++)
901 hputc(hout, '\t');
904 void
905 xmlaname(Hio *hout, char *v, char *tag)
907 hprint(hout, " %s=\"%s\"", tag, v);
910 void
911 xmlscore(Hio *hout, u8int *v, char *tag)
913 if(scorecmp(zeroscore, v) == 0)
914 return;
915 hprint(hout, " %s=\"%V\"", tag, v);
918 void
919 xmlsealed(Hio *hout, int v, char *tag)
921 if(!v)
922 return;
923 hprint(hout, " %s=\"yes\"", tag);
926 void
927 xmlu32int(Hio *hout, u32int v, char *tag)
929 hprint(hout, " %s=\"%ud\"", tag, v);
932 void
933 xmlu64int(Hio *hout, u64int v, char *tag)
935 hprint(hout, " %s=\"%llud\"", tag, v);
938 void
939 vtloghdump(Hio *h, VtLog *l)
941 int i;
942 VtLogChunk *c;
943 char *name;
945 name = l ? l->name : "&lt;nil&gt;";
947 fprint(2, "hdump xfer %d\n", h->xferenc);
948 hprint(h, "<html><head>\n");
949 hprint(h, "<title>Venti Server Log: %s</title>\n", name);
950 hprint(h, "</head><body>\n");
951 hprint(h, "<b>Venti Server Log: %s</b>\n<p>\n", name);
953 if(l){
954 c = l->w;
955 for(i=0; i<l->nchunk; i++){
956 if(++c == l->chunk+l->nchunk)
957 c = l->chunk;
958 hwrite(h, c->p, c->wp-c->p);
961 hprint(h, "</body></html>\n");
964 static int
965 strpcmp(const void *va, const void *vb)
967 return strcmp(*(char**)va, *(char**)vb);
970 void
971 vtloghlist(Hio *h)
973 char **p;
974 int i, n;
976 hprint(h, "<html><head>\n");
977 hprint(h, "<title>Venti Server Logs</title>\n");
978 hprint(h, "</head><body>\n");
979 hprint(h, "<b>Venti Server Logs</b>\n<p>\n");
981 p = vtlognames(&n);
982 qsort(p, n, sizeof(p[0]), strpcmp);
983 for(i=0; i<n; i++)
984 hprint(h, "<a href=\"/log/%s\">%s</a><br>\n", p[i], p[i]);
985 vtfree(p);
986 hprint(h, "</body></html>\n");