diff options
author | rsc <devnull@localhost> | 2005-07-12 15:23:36 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-07-12 15:23:36 +0000 |
commit | a0d146edd7a7de6236a0d60baafeeb59f8452aae (patch) | |
tree | b55baa526d9f5adfc73246e6ee2fadf455e0b7a2 /src/cmd/venti/srv/httpd.c | |
parent | 88bb285e3d87ec2508840af33f7e0af53ec3c13c (diff) | |
download | plan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.tar.gz plan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.tar.bz2 plan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.zip |
return of venti
Diffstat (limited to 'src/cmd/venti/srv/httpd.c')
-rw-r--r-- | src/cmd/venti/srv/httpd.c | 988 |
1 files changed, 988 insertions, 0 deletions
diff --git a/src/cmd/venti/srv/httpd.c b/src/cmd/venti/srv/httpd.c new file mode 100644 index 00000000..5f1a00e1 --- /dev/null +++ b/src/cmd/venti/srv/httpd.c @@ -0,0 +1,988 @@ +#include "stdinc.h" +#include "dat.h" +#include "fns.h" +#include "xml.h" + +typedef struct HttpObj HttpObj; +extern QLock memdrawlock; + +enum +{ + ObjNameSize = 64, + MaxObjs = 16 +}; + +struct HttpObj +{ + char name[ObjNameSize]; + int (*f)(HConnect*); +}; + +static HttpObj objs[MaxObjs]; + +static char *webroot; + +static void listenproc(void*); +static int estats(HConnect *c); +static int dindex(HConnect *c); +static int xindex(HConnect *c); +static int xlog(HConnect *c); +static int sindex(HConnect *c); +static int hicacheflush(HConnect *c); +static int hdcacheflush(HConnect *c); +static int notfound(HConnect *c); +static int httpdobj(char *name, int (*f)(HConnect*)); +static int xgraph(HConnect *c); +static int xset(HConnect *c); +static int fromwebdir(HConnect *c); + +int +httpdinit(char *address, char *dir) +{ + fmtinstall('D', hdatefmt); +/* fmtinstall('H', httpfmt); */ + fmtinstall('U', hurlfmt); + + if(address == nil) + address = "tcp!*!http"; + webroot = dir; + + httpdobj("/stats", estats); + httpdobj("/index", dindex); + httpdobj("/storage", sindex); + httpdobj("/xindex", xindex); + httpdobj("/flushicache", hicacheflush); + httpdobj("/flushdcache", hdcacheflush); + httpdobj("/graph/", xgraph); + httpdobj("/set/", xset); + httpdobj("/log", xlog); + httpdobj("/log/", xlog); + + if(vtproc(listenproc, address) < 0) + return -1; + return 0; +} + +static int +httpdobj(char *name, int (*f)(HConnect*)) +{ + int i; + + if(name == nil || strlen(name) >= ObjNameSize) + return -1; + for(i = 0; i < MaxObjs; i++){ + if(objs[i].name[0] == '\0'){ + strcpy(objs[i].name, name); + objs[i].f = f; + return 0; + } + if(strcmp(objs[i].name, name) == 0) + return -1; + } + return -1; +} + +static HConnect* +mkconnect(void) +{ + HConnect *c; + + c = mallocz(sizeof(HConnect), 1); + if(c == nil) + sysfatal("out of memory"); + c->replog = nil; + c->hpos = c->header; + c->hstop = c->header; + return c; +} + +void httpproc(void*); + +static void +listenproc(void *vaddress) +{ + HConnect *c; + char *address, ndir[NETPATHLEN], dir[NETPATHLEN]; + int ctl, nctl, data; + +//sleep(1000); /* let strace find us */ + + address = vaddress; + ctl = announce(address, dir); + if(ctl < 0){ + fprint(2, "venti: httpd can't announce on %s: %r\n", address); + return; + } + + if(0) print("announce ctl %d dir %s\n", ctl, dir); + for(;;){ + /* + * wait for a call (or an error) + */ + nctl = listen(dir, ndir); + if(0) print("httpd listen %d %s...\n", nctl, ndir); + if(nctl < 0){ + fprint(2, "venti: httpd can't listen on %s: %r\n", address); + return; + } + + data = accept(ctl, ndir); + if(0) print("httpd accept %d...\n", data); + if(data < 0){ + fprint(2, "venti: httpd accept: %r\n"); + close(nctl); + continue; + } + if(0) print("httpd close nctl %d\n", nctl); + close(nctl); + c = mkconnect(); + hinit(&c->hin, data, Hread); + hinit(&c->hout, data, Hwrite); + vtproc(httpproc, c); + } +} + +void +httpproc(void *v) +{ + HConnect *c; + int ok, i, n; + +//sleep(1000); /* let strace find us */ + c = v; + + for(;;){ + /* + * No timeout because the signal appears to hit every + * proc, not just us. + */ + if(hparsereq(c, 0) < 0) + break; + + ok = -1; + for(i = 0; i < MaxObjs && objs[i].name[0]; i++){ + n = strlen(objs[i].name); + if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0) + || (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){ + ok = (*objs[i].f)(c); + goto found; + } + } + ok = fromwebdir(c); + found: + if(c->head.closeit) + ok = -1; + hreqcleanup(c); + + if(ok < 0) + break; + } + hreqcleanup(c); + close(c->hin.fd); + free(c); +} + +static int +percent(long v, long total) +{ + if(total == 0) + total = 1; + if(v < 1000*1000) + return (v * 100) / total; + total /= 100; + if(total == 0) + total = 1; + return v / total; +} + +static int +preq(HConnect *c) +{ + if(hparseheaders(c, 0) < 0) + return -1; + if(strcmp(c->req.meth, "GET") != 0 + && strcmp(c->req.meth, "HEAD") != 0) + return hunallowed(c, "GET, HEAD"); + if(c->head.expectother || c->head.expectcont) + return hfail(c, HExpectFail, nil); + return 0; +} + +static int +preqtype(HConnect *c, char *type) +{ + Hio *hout; + int r; + + r = preq(c); + if(r < 0) + return r; + + hout = &c->hout; + if(c->req.vermaj){ + hokheaders(c); + hprint(hout, "Content-type: %s\r\n", type); + if(http11(c)) + hprint(hout, "Transfer-Encoding: chunked\r\n"); + hprint(hout, "\r\n"); + } + + if(http11(c)) + hxferenc(hout, 1); + else + c->head.closeit = 1; + return 0; +} + +static int +preqtext(HConnect *c) +{ + return preqtype(c, "text/plain"); +} + +static int +notfound(HConnect *c) +{ + int r; + + r = preq(c); + if(r < 0) + return r; + return hfail(c, HNotFound, c->req.uri); +} + +struct { + char *ext; + char *type; +} exttab[] = { + ".html", "text/html", + ".txt", "text/plain", + ".xml", "text/xml", + ".png", "image/png", + ".gif", "image/gif", + 0 +}; + +static int +fromwebdir(HConnect *c) +{ + char buf[4096], *p, *ext, *type; + int i, fd, n, defaulted; + Dir *d; + + if(webroot == nil || strstr(c->req.uri, "..")) + return notfound(c); + snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1); + defaulted = 0; +reopen: + if((fd = open(buf, OREAD)) < 0) + return notfound(c); + d = dirfstat(fd); + if(d == nil){ + close(fd); + return notfound(c); + } + if(d->mode&DMDIR){ + if(!defaulted){ + defaulted = 1; + strcat(buf, "/index.html"); + free(d); + close(fd); + goto reopen; + } + free(d); + return notfound(c); + } + free(d); + p = buf+strlen(buf); + type = "application/octet-stream"; + for(i=0; exttab[i].ext; i++){ + ext = exttab[i].ext; + if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){ + type = exttab[i].type; + break; + } + } + if(preqtype(c, type) < 0){ + close(fd); + return 0; + } + while((n = read(fd, buf, sizeof buf)) > 0) + if(hwrite(&c->hout, buf, n) < 0) + break; + close(fd); + hflush(&c->hout); + return 0; +} + +static struct +{ + char *name; + int *p; +} namedints[] = +{ + "compress", &compressblocks, + "devnull", &writestodevnull, + "logging", &ventilogging, + "stats", &collectstats, + "icachesleeptime", &icachesleeptime, + "arenasumsleeptime", &arenasumsleeptime, + 0 +}; + +static int +xset(HConnect *c) +{ + int i, nf, r; + char *f[10], *s; + + s = estrdup(c->req.uri); + nf = getfields(s+strlen("/set/"), f, nelem(f), 1, "/"); + + if(nf < 1) + return notfound(c); + for(i=0; namedints[i].name; i++){ + if(strcmp(f[0], namedints[i].name) == 0){ + if(nf >= 2) + *namedints[i].p = atoi(f[1]); + r = preqtext(c); + if(r < 0) + return r; + hprint(&c->hout, "%s = %d\n", f[0], *namedints[i].p); + hflush(&c->hout); + return 0; + } + } + return notfound(c); +} + +static int +estats(HConnect *c) +{ + Hio *hout; + int r; + + r = preqtext(c); + if(r < 0) + return r; + + + hout = &c->hout; +/* + hprint(hout, "lump writes=%,ld\n", stats.lumpwrites); + hprint(hout, "lump reads=%,ld\n", stats.lumpreads); + hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit); + hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss); + + hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites); + hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites); + hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp); + hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads); + hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads); + hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp); + + hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites); + hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads); + + hprint(hout, "index disk writes=%,ld\n", stats.indexwrites); + hprint(hout, "index disk reads=%,ld\n", stats.indexreads); + hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n", + stats.indexbloomhits, + percent(stats.indexbloomhits, stats.indexreads), + stats.indexbloomfalsemisses, + percent(stats.indexbloomfalsemisses, stats.indexreads)); + hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n", + stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits)); + hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads); + hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads); + hprint(hout, "index block splits=%,ld\n", stats.indexsplits); + + hprint(hout, "index cache lookups=%,ld\n", stats.iclookups); + hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits, + percent(stats.ichits, stats.iclookups)); + hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills, + percent(stats.icfills, stats.iclookups)); + hprint(hout, "index cache inserts=%,ld\n", stats.icinserts); + + hprint(hout, "disk cache hits=%,ld\n", stats.pchit); + hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss); + hprint(hout, "disk cache reads=%,ld\n", stats.pcreads); + hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads); + + hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks); + hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites, + percent(stats.absorbedwrites, stats.dirtydblocks)); + + hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes); + hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n", + stats.dcacheflushwrites, + stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1)); + + hprint(hout, "disk writes=%,ld\n", stats.diskwrites); + hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites); + hprint(hout, "disk reads=%,ld\n", stats.diskreads); + hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads); +*/ + + hflush(hout); + return 0; +} + +static int +sindex(HConnect *c) +{ + Hio *hout; + Index *ix; + Arena *arena; + vlong clumps, cclumps, uncsize, used, size; + int i, r, active; + + r = preqtext(c); + if(r < 0) + return r; + hout = &c->hout; + + ix = mainindex; + + hprint(hout, "index=%s\n", ix->name); + + active = 0; + clumps = 0; + cclumps = 0; + uncsize = 0; + used = 0; + size = 0; + for(i = 0; i < ix->narenas; i++){ + arena = ix->arenas[i]; + if(arena != nil && arena->memstats.clumps != 0){ + active++; + clumps += arena->memstats.clumps; + cclumps += arena->memstats.cclumps; + uncsize += arena->memstats.uncsize; + used += arena->memstats.used; + } + size += arena->size; + } + hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active); + hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize); + hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n", + clumps, cclumps, uncsize, used - clumps * ClumpSize); + hflush(hout); + return 0; +} + +static void +darena(Hio *hout, Arena *arena) +{ + hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d", + arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize, + arena->version, arena->ctime, arena->wtime); + if(arena->memstats.sealed) + hprint(hout, " mem=sealed"); + if(arena->diskstats.sealed) + hprint(hout, " disk=sealed"); + hprint(hout, "\n"); + if(scorecmp(zeroscore, arena->score) != 0) + hprint(hout, "\tscore=%V\n", arena->score); + + hprint(hout, "\tmem: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n", + arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize, + arena->memstats.used - arena->memstats.clumps * ClumpSize, + arena->memstats.used + arena->memstats.clumps * ClumpInfoSize); + hprint(hout, "\tdisk: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n", + arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize, + arena->diskstats.used - arena->diskstats.clumps * ClumpSize, + arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize); +} + +static int +hicacheflush(HConnect *c) +{ + Hio *hout; + int r; + + r = preqtext(c); + if(r < 0) + return r; + hout = &c->hout; + + flushicache(); + hprint(hout, "flushed icache\n"); + hflush(hout); + return 0; +} + +static int +hdcacheflush(HConnect *c) +{ + Hio *hout; + int r; + + r = preqtext(c); + if(r < 0) + return r; + hout = &c->hout; + + flushdcache(); + hprint(hout, "flushed dcache\n"); + hflush(hout); + return 0; +} + +static int +dindex(HConnect *c) +{ + Hio *hout; + Index *ix; + int i, r; + + r = preqtext(c); + if(r < 0) + return r; + hout = &c->hout; + + + ix = mainindex; + hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n", + ix->name, ix->version, ix->blocksize, ix->tabsize); + hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div); + for(i = 0; i < ix->nsects; i++) + 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); + for(i = 0; i < ix->narenas; i++){ + if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){ + hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop); + darena(hout, ix->arenas[i]); + } + } + hflush(hout); + return 0; +} + +typedef struct Arg Arg; +struct Arg +{ + int index; + int index2; +}; + +static long +rawgraph(Stats *s, Stats *t, void *va) +{ + Arg *a; + + a = va; + return t->n[a->index]; +} + +static long +diffgraph(Stats *s, Stats *t, void *va) +{ + Arg *a; + + a = va; + return t->n[a->index] - s->n[a->index]; +} + +static long +pctgraph(Stats *s, Stats *t, void *va) +{ + Arg *a; + + a = va; + return percent(t->n[a->index], t->n[a->index2]); +} + +static long +pctdiffgraph(Stats *s, Stats *t, void *va) +{ + Arg *a; + + a = va; + return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]); +} + +static long +netbw(Stats *s) +{ + ulong *n; + + n = s->n; + return n[StatRpcReadBytes]+n[StatRpcWriteBytes]; /* not exactly right */ +} + +static long +diskbw(Stats *s) +{ + ulong *n; + + n = s->n; + return n[StatApartReadBytes]+n[StatApartWriteBytes] + + n[StatIsectReadBytes]+n[StatIsectWriteBytes] + + n[StatSumReadBytes]; +} + +static long +iobw(Stats *s) +{ + return netbw(s)+diskbw(s); +} + +static long +diskgraph(Stats *s, Stats *t, void *va) +{ + USED(va); + return diskbw(t)-diskbw(s); +} + +static long +netgraph(Stats *s, Stats *t, void *va) +{ + USED(va); + return netbw(t)-netbw(s); +} + +static long +iograph(Stats *s, Stats *t, void *va) +{ + USED(va); + return iobw(t)-iobw(s); +} + + +static char* graphname[] = +{ + "rpctotal", + "rpcread", + "rpcreadok", + "rpcreadfail", + "rpcreadbyte", + "rpcreadtime", + "rpcreadcached", + "rpcreadcachedtime", + "rpcreaduncached", + "rpcreaduncachedtime", + "rpcwrite", + "rpcwritenew", + "rpcwriteold", + "rpcwritefail", + "rpcwritebyte", + "rpcwritetime", + "rpcwritenewtime", + "rpcwriteoldtime", + + "lcachehit", + "lcachemiss", + "lcachelookup", + "lcachewrite", + "lcachesize", + "lcachestall", + "lcachelookuptime", + + "dcachehit", + "dcachemiss", + "dcachelookup", + "dcacheread", + "dcachewrite", + "dcachedirty", + "dcachesize", + "dcacheflush", + "dcachestall", + "dcachelookuptime", + + "dblockstall", + "lumpstall", + + "icachehit", + "icachemiss", + "icachelookup", + "icachewrite", + "icachefill", + "icacheprefetch", + "icachedirty", + "icachesize", + "icacheflush", + "icachestall", + "icachelookuptime", + + "bloomhit", + "bloommiss", + "bloomfalsemiss", + "bloomlookup", + "bloomones", + "bloombits", + "bloomlookuptime", + + "apartread", + "apartreadbyte", + "apartwrite", + "apartwritebyte", + + "isectread", + "isectreadbyte", + "isectwrite", + "isectwritebyte", + + "sumread", + "sumreadbyte", +}; + +static int +findname(char *s) +{ + int i; + + for(i=0; i<nelem(graphname); i++) + if(strcmp(graphname[i], s) == 0) + return i; +fprint(2, "no name '%s'\n", s); + return -1; +} + +static void +dotextbin(Hio *io, Graph *g) +{ + int i, nbin; + Statbin *b, bin[2000]; /* 32 kB, but whack is worse */ + + needstack(8192); /* double check that bin didn't kill us */ + nbin = 100; + binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin); + + hprint(io, "stats\n\n"); + for(i=0; i<nbin; i++){ + b = &bin[i]; + hprint(io, "%d: nsamp=%d min=%d max=%d avg=%d\n", + i, b->nsamp, b->min, b->max, b->avg); + } +} + +static int +xgraph(HConnect *c) +{ + char *f[20], *s; + Hio *hout; + Memimage *m; + int i, nf, dotext; + Graph g; + Arg arg; + + s = estrdup(c->req.uri); +if(0) fprint(2, "graph %s\n" ,s); + memset(&g, 0, sizeof g); + nf = getfields(s+strlen("/graph/"), f, nelem(f), 1, "/"); + if(nf < 1) + goto notfound; + if((arg.index = findname(f[0])) == -1 && strcmp(f[0], "*") != 0) + goto notfound; + g.arg = &arg; + g.t0 = -120; + g.t1 = 0; + g.min = -1; + g.max = -1; + g.fn = rawgraph; + g.wid = -1; + g.ht = -1; + dotext = 0; + g.fill = -1; + for(i=1; i<nf; i++){ + if(strncmp(f[i], "t0=", 3) == 0) + g.t0 = atoi(f[i]+3); + else if(strncmp(f[i], "t1=", 3) == 0) + g.t1 = atoi(f[i]+3); + else if(strncmp(f[i], "min=", 4) == 0) + g.min = atoi(f[i]+4); + else if(strncmp(f[i], "max=", 4) == 0) + g.max = atoi(f[i]+4); + else if(strncmp(f[i], "pct=", 4) == 0){ + if((arg.index2 = findname(f[i]+4)) == -1) + goto notfound; + g.fn = pctgraph; + g.min = 0; + g.max = 100; + }else if(strncmp(f[i], "pctdiff=", 8) == 0){ + if((arg.index2 = findname(f[i]+8)) == -1) + goto notfound; + g.fn = pctdiffgraph; + g.min = 0; + g.max = 100; + }else if(strcmp(f[i], "diff") == 0) + g.fn = diffgraph; + else if(strcmp(f[i], "text") == 0) + dotext = 1; + else if(strncmp(f[i], "wid=", 4) == 0) + g.wid = atoi(f[i]+4); + else if(strncmp(f[i], "ht=", 3) == 0) + g.ht = atoi(f[i]+3); + else if(strncmp(f[i], "fill=", 5) == 0) + g.fill = atoi(f[i]+5); + else if(strcmp(f[i], "diskbw") == 0) + g.fn = diskgraph; + else if(strcmp(f[i], "iobw") == 0) + g.fn = iograph; + else if(strcmp(f[i], "netbw") == 0) + g.fn = netgraph; + } + if(dotext){ + preqtype(c, "text/plain"); + dotextbin(&c->hout, &g); + hflush(&c->hout); + return 0; + } + + m = statgraph(&g); + if(m == nil) + goto notfound; + + if(preqtype(c, "image/png") < 0) + return -1; + hout = &c->hout; + writepng(hout, m); + qlock(&memdrawlock); + freememimage(m); + qunlock(&memdrawlock); + hflush(hout); + free(s); + return 0; + +notfound: + free(s); + return notfound(c); +} + +static int +xloglist(HConnect *c) +{ + if(preqtype(c, "text/html") < 0) + return -1; + vtloghlist(&c->hout); + hflush(&c->hout); + return 0; +} + +static int +xlog(HConnect *c) +{ + char *name; + VtLog *l; + + if(strcmp(c->req.uri, "/log") == 0 || strcmp(c->req.uri, "/log/") == 0) + return xloglist(c); + if(strncmp(c->req.uri, "/log/", 5) != 0) + return notfound(c); + name = c->req.uri + strlen("/log/"); + l = vtlogopen(name, 0); + if(l == nil) + return notfound(c); + if(preqtype(c, "text/html") < 0){ + vtlogclose(l); + return -1; + } + vtloghdump(&c->hout, l); + vtlogclose(l); + hflush(&c->hout); + return 0; +} + +static int +xindex(HConnect *c) +{ + if(preqtype(c, "text/xml") < 0) + return -1; + xmlindex(&c->hout, mainindex, "index", 0); + hflush(&c->hout); + return 0; +} + +void +xmlindent(Hio *hout, int indent) +{ + int i; + + for(i = 0; i < indent; i++) + hputc(hout, '\t'); +} + +void +xmlaname(Hio *hout, char *v, char *tag) +{ + hprint(hout, " %s=\"%s\"", tag, v); +} + +void +xmlscore(Hio *hout, u8int *v, char *tag) +{ + if(scorecmp(zeroscore, v) == 0) + return; + hprint(hout, " %s=\"%V\"", tag, v); +} + +void +xmlsealed(Hio *hout, int v, char *tag) +{ + if(!v) + return; + hprint(hout, " %s=\"yes\"", tag); +} + +void +xmlu32int(Hio *hout, u32int v, char *tag) +{ + hprint(hout, " %s=\"%ud\"", tag, v); +} + +void +xmlu64int(Hio *hout, u64int v, char *tag) +{ + hprint(hout, " %s=\"%llud\"", tag, v); +} + +void +vtloghdump(Hio *h, VtLog *l) +{ + int i; + VtLogChunk *c; + char *name; + + name = l ? l->name : "<nil>"; + +fprint(2, "hdump xfer %d\n", h->xferenc); + hprint(h, "<html><head>\n"); + hprint(h, "<title>Venti Server Log: %s</title>\n", name); + hprint(h, "</head><body>\n"); + hprint(h, "<b>Venti Server Log: %s</b>\n<p>\n", name); + + if(l){ + c = l->w; + for(i=0; i<l->nchunk; i++){ + if(++c == l->chunk+l->nchunk) + c = l->chunk; + hwrite(h, c->p, c->wp-c->p); + } + } + hprint(h, "</body></html>\n"); +} + +static int +strpcmp(const void *va, const void *vb) +{ + return strcmp(*(char**)va, *(char**)vb); +} + +void +vtloghlist(Hio *h) +{ + char **p; + int i, n; + + hprint(h, "<html><head>\n"); + hprint(h, "<title>Venti Server Logs</title>\n"); + hprint(h, "</head><body>\n"); + hprint(h, "<b>Venti Server Logs</b>\n<p>\n"); + + p = vtlognames(&n); + qsort(p, n, sizeof(p[0]), strpcmp); + for(i=0; i<n; i++) + hprint(h, "<a href=\"/log/%s\">%s</a><br>\n", p[i], p[i]); + vtfree(p); + hprint(h, "</body></html>\n"); +} |