URI: 
       thttpd.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       thttpd.c (22933B)
       ---
            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         0
          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         "bootstrap",        &bootstrap,
          400         0
          401 };
          402 
          403 static int
          404 xset(HConnect *c)
          405 {
          406         int i, old;
          407         char *name, *value;
          408 
          409         if(hsettext(c) < 0)
          410                 return -1;
          411 
          412         if((name = hargstr(c, "name", nil)) == nil || name[0] == 0){
          413                 for(i=0; namedints[i].name; i++)
          414                         hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
          415                 hflush(&c->hout);
          416                 return 0;
          417         }
          418 
          419         for(i=0; namedints[i].name; i++)
          420                 if(strcmp(name, namedints[i].name) == 0)
          421                         break;
          422         if(!namedints[i].name){
          423                 hprint(&c->hout, "%s not found\n", name);
          424                 hflush(&c->hout);
          425                 return 0;
          426         }
          427 
          428         if((value = hargstr(c, "value", nil)) == nil || value[0] == 0){
          429                 hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
          430                 hflush(&c->hout);
          431                 return 0;
          432         }
          433 
          434         old = *namedints[i].p;
          435         *namedints[i].p = atoll(value);
          436         hprint(&c->hout, "%s = %d (was %d)\n", name, *namedints[i].p, old);
          437         hflush(&c->hout);
          438         return 0;
          439 }
          440 
          441 static int
          442 estats(HConnect *c)
          443 {
          444         Hio *hout;
          445         int r;
          446 
          447         r = hsettext(c);
          448         if(r < 0)
          449                 return r;
          450 
          451 
          452         hout = &c->hout;
          453 /*
          454         hprint(hout, "lump writes=%,ld\n", stats.lumpwrites);
          455         hprint(hout, "lump reads=%,ld\n", stats.lumpreads);
          456         hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit);
          457         hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss);
          458 
          459         hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites);
          460         hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites);
          461         hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp);
          462         hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads);
          463         hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads);
          464         hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp);
          465 
          466         hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
          467         hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
          468 
          469         hprint(hout, "index disk writes=%,ld\n", stats.indexwrites);
          470         hprint(hout, "index disk reads=%,ld\n", stats.indexreads);
          471         hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n",
          472                 stats.indexbloomhits,
          473                 percent(stats.indexbloomhits, stats.indexreads),
          474                 stats.indexbloomfalsemisses,
          475                 percent(stats.indexbloomfalsemisses, stats.indexreads));
          476         hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n",
          477                 stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits));
          478         hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads);
          479         hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads);
          480         hprint(hout, "index block splits=%,ld\n", stats.indexsplits);
          481 
          482         hprint(hout, "index cache lookups=%,ld\n", stats.iclookups);
          483         hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits,
          484                 percent(stats.ichits, stats.iclookups));
          485         hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills,
          486                 percent(stats.icfills, stats.iclookups));
          487         hprint(hout, "index cache inserts=%,ld\n", stats.icinserts);
          488 
          489         hprint(hout, "disk cache hits=%,ld\n", stats.pchit);
          490         hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss);
          491         hprint(hout, "disk cache reads=%,ld\n", stats.pcreads);
          492         hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads);
          493 
          494         hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks);
          495         hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites,
          496                 percent(stats.absorbedwrites, stats.dirtydblocks));
          497 
          498         hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes);
          499         hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n",
          500                 stats.dcacheflushwrites,
          501                 stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1));
          502 
          503         hprint(hout, "disk writes=%,ld\n", stats.diskwrites);
          504         hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites);
          505         hprint(hout, "disk reads=%,ld\n", stats.diskreads);
          506         hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads);
          507 */
          508 
          509         hflush(hout);
          510         return 0;
          511 }
          512 
          513 static int
          514 sindex(HConnect *c)
          515 {
          516         Hio *hout;
          517         Index *ix;
          518         Arena *arena;
          519         vlong clumps, cclumps, uncsize, used, size;
          520         int i, r, active;
          521 
          522         r = hsettext(c);
          523         if(r < 0)
          524                 return r;
          525         hout = &c->hout;
          526 
          527         ix = mainindex;
          528 
          529         hprint(hout, "index=%s\n", ix->name);
          530 
          531         active = 0;
          532         clumps = 0;
          533         cclumps = 0;
          534         uncsize = 0;
          535         used = 0;
          536         size = 0;
          537         for(i = 0; i < ix->narenas; i++){
          538                 arena = ix->arenas[i];
          539                 if(arena != nil && arena->memstats.clumps != 0){
          540                         active++;
          541                         clumps += arena->memstats.clumps;
          542                         cclumps += arena->memstats.cclumps;
          543                         uncsize += arena->memstats.uncsize;
          544                         used += arena->memstats.used;
          545                 }
          546                 size += arena->size;
          547         }
          548         hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active);
          549         hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize);
          550         hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n",
          551                 clumps, cclumps, uncsize, used - clumps * ClumpSize);
          552         hflush(hout);
          553         return 0;
          554 }
          555 
          556 static void
          557 darena(Hio *hout, Arena *arena)
          558 {
          559         hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
          560                 arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize,
          561                 arena->version, arena->ctime, arena->wtime);
          562         if(arena->memstats.sealed)
          563                 hprint(hout, " mem=sealed");
          564         if(arena->diskstats.sealed)
          565                 hprint(hout, " disk=sealed");
          566         if(arena->inqueue)
          567                 hprint(hout, " inqueue");
          568         hprint(hout, "\n");
          569         if(scorecmp(zeroscore, arena->score) != 0)
          570                 hprint(hout, "\tscore=%V\n", arena->score);
          571 
          572         hprint(hout, "\twritten: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
          573                 arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize,
          574                 arena->memstats.used - arena->memstats.clumps * ClumpSize,
          575                 arena->memstats.used + arena->memstats.clumps * ClumpInfoSize);
          576         hprint(hout, "\tindexed: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
          577                 arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize,
          578                 arena->diskstats.used - arena->diskstats.clumps * ClumpSize,
          579                 arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize);
          580 }
          581 
          582 static int
          583 hempty(HConnect *c)
          584 {
          585         Hio *hout;
          586         int r;
          587 
          588         r = hsettext(c);
          589         if(r < 0)
          590                 return r;
          591         hout = &c->hout;
          592 
          593         emptylumpcache();
          594         emptydcache();
          595         emptyicache();
          596         hprint(hout, "emptied all caches\n");
          597         hflush(hout);
          598         return 0;
          599 }
          600 
          601 static int
          602 hlcacheempty(HConnect *c)
          603 {
          604         Hio *hout;
          605         int r;
          606 
          607         r = hsettext(c);
          608         if(r < 0)
          609                 return r;
          610         hout = &c->hout;
          611 
          612         emptylumpcache();
          613         hprint(hout, "emptied lumpcache\n");
          614         hflush(hout);
          615         return 0;
          616 }
          617 
          618 static int
          619 hicacheempty(HConnect *c)
          620 {
          621         Hio *hout;
          622         int r;
          623 
          624         r = hsettext(c);
          625         if(r < 0)
          626                 return r;
          627         hout = &c->hout;
          628 
          629         emptyicache();
          630         hprint(hout, "emptied icache\n");
          631         hflush(hout);
          632         return 0;
          633 }
          634 
          635 static int
          636 hdcacheempty(HConnect *c)
          637 {
          638         Hio *hout;
          639         int r;
          640 
          641         r = hsettext(c);
          642         if(r < 0)
          643                 return r;
          644         hout = &c->hout;
          645 
          646         emptydcache();
          647         hprint(hout, "emptied dcache\n");
          648         hflush(hout);
          649         return 0;
          650 }
          651 static int
          652 hicachekick(HConnect *c)
          653 {
          654         Hio *hout;
          655         int r;
          656 
          657         r = hsettext(c);
          658         if(r < 0)
          659                 return r;
          660         hout = &c->hout;
          661 
          662         kickicache();
          663         hprint(hout, "kicked icache\n");
          664         hflush(hout);
          665         return 0;
          666 }
          667 
          668 static int
          669 hdcachekick(HConnect *c)
          670 {
          671         Hio *hout;
          672         int r;
          673 
          674         r = hsettext(c);
          675         if(r < 0)
          676                 return r;
          677         hout = &c->hout;
          678 
          679         kickdcache();
          680         hprint(hout, "kicked dcache\n");
          681         hflush(hout);
          682         return 0;
          683 }
          684 static int
          685 hicacheflush(HConnect *c)
          686 {
          687         Hio *hout;
          688         int r;
          689 
          690         r = hsettext(c);
          691         if(r < 0)
          692                 return r;
          693         hout = &c->hout;
          694 
          695         flushicache();
          696         hprint(hout, "flushed icache\n");
          697         hflush(hout);
          698         return 0;
          699 }
          700 
          701 static int
          702 hdcacheflush(HConnect *c)
          703 {
          704         Hio *hout;
          705         int r;
          706 
          707         r = hsettext(c);
          708         if(r < 0)
          709                 return r;
          710         hout = &c->hout;
          711 
          712         flushdcache();
          713         hprint(hout, "flushed dcache\n");
          714         hflush(hout);
          715         return 0;
          716 }
          717 
          718 static int
          719 dindex(HConnect *c)
          720 {
          721         Hio *hout;
          722         Index *ix;
          723         int i, r;
          724 
          725         r = hsettext(c);
          726         if(r < 0)
          727                 return r;
          728         hout = &c->hout;
          729 
          730 
          731         ix = mainindex;
          732         hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n",
          733                 ix->name, ix->version, ix->blocksize, ix->tabsize);
          734         hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
          735         for(i = 0; i < ix->nsects; i++)
          736                 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);
          737         for(i = 0; i < ix->narenas; i++){
          738                 if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){
          739                         hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
          740                         darena(hout, ix->arenas[i]);
          741                 }
          742         }
          743         hflush(hout);
          744         return 0;
          745 }
          746 
          747 typedef struct Arg Arg;
          748 struct Arg
          749 {
          750         int index;
          751         int index2;
          752 };
          753 
          754 static long
          755 rawgraph(Stats *s, Stats *t, void *va)
          756 {
          757         Arg *a;
          758 
          759         USED(s);
          760         a = va;
          761         return t->n[a->index];
          762 }
          763 
          764 static long
          765 diffgraph(Stats *s, Stats *t, void *va)
          766 {
          767         Arg *a;
          768 
          769         a = va;
          770         return t->n[a->index] - s->n[a->index];
          771 }
          772 
          773 static long
          774 pctgraph(Stats *s, Stats *t, void *va)
          775 {
          776         Arg *a;
          777 
          778         USED(s);
          779         a = va;
          780         return percent(t->n[a->index], t->n[a->index2]);
          781 }
          782 
          783 static long
          784 pctdiffgraph(Stats *s, Stats *t, void *va)
          785 {
          786         Arg *a;
          787 
          788         a = va;
          789         return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]);
          790 }
          791 
          792 static long
          793 xdiv(long a, long b)
          794 {
          795         if(b == 0)
          796                 b++;
          797         return a/b;
          798 }
          799 
          800 static long
          801 divdiffgraph(Stats *s, Stats *t, void *va)
          802 {
          803         Arg *a;
          804 
          805         a = va;
          806         return xdiv(t->n[a->index] - s->n[a->index], t->n[a->index2] - s->n[a->index2]);
          807 }
          808 
          809 static long
          810 netbw(Stats *s)
          811 {
          812         ulong *n;
          813 
          814         n = s->n;
          815         return n[StatRpcReadBytes]+n[StatRpcWriteBytes];        /* not exactly right */
          816 }
          817 
          818 static long
          819 diskbw(Stats *s)
          820 {
          821         ulong *n;
          822 
          823         n = s->n;
          824         return n[StatApartReadBytes]+n[StatApartWriteBytes]
          825                 + n[StatIsectReadBytes]+n[StatIsectWriteBytes]
          826                 + n[StatSumReadBytes];
          827 }
          828 
          829 static long
          830 iobw(Stats *s)
          831 {
          832         return netbw(s)+diskbw(s);
          833 }
          834 
          835 static long
          836 diskgraph(Stats *s, Stats *t, void *va)
          837 {
          838         USED(va);
          839         return diskbw(t)-diskbw(s);
          840 }
          841 
          842 static long
          843 netgraph(Stats *s, Stats *t, void *va)
          844 {
          845         USED(va);
          846         return netbw(t)-netbw(s);
          847 }
          848 
          849 static long
          850 iograph(Stats *s, Stats *t, void *va)
          851 {
          852         USED(va);
          853         return iobw(t)-iobw(s);
          854 }
          855 
          856 
          857 static char* graphname[] =
          858 {
          859         "rpctotal",
          860         "rpcread",
          861         "rpcreadok",
          862         "rpcreadfail",
          863         "rpcreadbyte",
          864         "rpcreadtime",
          865         "rpcreadcached",
          866         "rpcreadcachedtime",
          867         "rpcreaduncached",
          868         "rpcreaduncachedtime",
          869         "rpcwrite",
          870         "rpcwritenew",
          871         "rpcwriteold",
          872         "rpcwritefail",
          873         "rpcwritebyte",
          874         "rpcwritetime",
          875         "rpcwritenewtime",
          876         "rpcwriteoldtime",
          877 
          878         "lcachehit",
          879         "lcachemiss",
          880         "lcachelookup",
          881         "lcachewrite",
          882         "lcachesize",
          883         "lcachestall",
          884         "lcachelookuptime",
          885 
          886         "dcachehit",
          887         "dcachemiss",
          888         "dcachelookup",
          889         "dcacheread",
          890         "dcachewrite",
          891         "dcachedirty",
          892         "dcachesize",
          893         "dcacheflush",
          894         "dcachestall",
          895         "dcachelookuptime",
          896 
          897         "dblockstall",
          898         "lumpstall",
          899 
          900         "icachehit",
          901         "icachemiss",
          902         "icacheread",
          903         "icachewrite",
          904         "icachefill",
          905         "icacheprefetch",
          906         "icachedirty",
          907         "icachesize",
          908         "icacheflush",
          909         "icachestall",
          910         "icachelookuptime",
          911         "icachelookup",
          912         "scachehit",
          913         "scacheprefetch",
          914 
          915         "bloomhit",
          916         "bloommiss",
          917         "bloomfalsemiss",
          918         "bloomlookup",
          919         "bloomones",
          920         "bloombits",
          921 
          922         "apartread",
          923         "apartreadbyte",
          924         "apartwrite",
          925         "apartwritebyte",
          926 
          927         "isectread",
          928         "isectreadbyte",
          929         "isectwrite",
          930         "isectwritebyte",
          931 
          932         "sumread",
          933         "sumreadbyte",
          934 
          935         "cigload",
          936         "cigloadtime",
          937 };
          938 
          939 static int
          940 findname(char *s)
          941 {
          942         int i;
          943 
          944         for(i=0; i<nelem(graphname); i++)
          945                 if(strcmp(graphname[i], s) == 0)
          946                         return i;
          947         return -1;
          948 }
          949 
          950 static void
          951 dotextbin(Hio *io, Graph *g)
          952 {
          953         int i, nbin;
          954         Statbin *b, bin[2000];        /* 32 kB, but whack is worse */
          955 
          956         needstack(8192);        /* double check that bin didn't kill us */
          957         nbin = 100;
          958         binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin);
          959 
          960         hprint(io, "stats\n\n");
          961         for(i=0; i<nbin; i++){
          962                 b = &bin[i];
          963                 hprint(io, "%d: nsamp=%d min=%d max=%d avg=%d\n",
          964                         i, b->nsamp, b->min, b->max, b->avg);
          965         }
          966 }
          967 
          968 static int
          969 xgraph(HConnect *c)
          970 {
          971         char *name;
          972         Hio *hout;
          973         Memimage *m;
          974         int dotext;
          975         Graph g;
          976         Arg arg;
          977         char *graph, *a;
          978 
          979         name = hargstr(c, "arg", "");
          980         if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){
          981                 werrstr("unknown name %s", name);
          982                 goto error;
          983         }
          984         a = hargstr(c, "arg2", "");
          985         if(a[0] && (arg.index2 = findname(a)) == -1){
          986                 werrstr("unknown name %s", a);
          987                 goto error;
          988         }
          989 
          990         g.arg = &arg;
          991         g.t0 = hargint(c, "t0", -120);
          992         g.t1 = hargint(c, "t1", 0);
          993         g.min = hargint(c, "min", -1);
          994         g.max = hargint(c, "max", -1);
          995         g.wid = hargint(c, "wid", -1);
          996         g.ht = hargint(c, "ht", -1);
          997         dotext = hargstr(c, "text", "")[0] != 0;
          998         g.fill = hargint(c, "fill", -1);
          999 
         1000         graph = hargstr(c, "graph", "raw");
         1001         if(strcmp(graph, "raw") == 0)
         1002                 g.fn = rawgraph;
         1003         else if(strcmp(graph, "diskbw") == 0)
         1004                 g.fn = diskgraph;
         1005         else if(strcmp(graph, "iobw") == 0)
         1006                 g.fn = iograph;
         1007         else if(strcmp(graph, "netbw") == 0)
         1008                 g.fn = netgraph;
         1009         else if(strcmp(graph, "diff") == 0)
         1010                 g.fn = diffgraph;
         1011         else if(strcmp(graph, "pct") == 0)
         1012                 g.fn = pctgraph;
         1013         else if(strcmp(graph, "pctdiff") == 0)
         1014                 g.fn = pctdiffgraph;
         1015         else if(strcmp(graph, "divdiff") == 0)
         1016                 g.fn = divdiffgraph;
         1017         else{
         1018                 werrstr("unknown graph %s", graph);
         1019                 goto error;
         1020         }
         1021 
         1022         if(dotext){
         1023                 hsettype(c, "text/plain");
         1024                 dotextbin(&c->hout, &g);
         1025                 hflush(&c->hout);
         1026                 return 0;
         1027         }
         1028 
         1029         m = statgraph(&g);
         1030         if(m == nil)
         1031                 goto error;
         1032 
         1033         if(hsettype(c, "image/png") < 0)
         1034                 return -1;
         1035         hout = &c->hout;
         1036         writepng(hout, m);
         1037         qlock(&memdrawlock);
         1038         freememimage(m);
         1039         qunlock(&memdrawlock);
         1040         hflush(hout);
         1041         return 0;
         1042 
         1043 error:
         1044         return herror(c);
         1045 }
         1046 
         1047 static int
         1048 xloglist(HConnect *c)
         1049 {
         1050         if(hsettype(c, "text/html") < 0)
         1051                 return -1;
         1052         vtloghlist(&c->hout);
         1053         hflush(&c->hout);
         1054         return 0;
         1055 }
         1056 
         1057 static int
         1058 xlog(HConnect *c)
         1059 {
         1060         char *name;
         1061         VtLog *l;
         1062 
         1063         name = hargstr(c, "log", "");
         1064         if(!name[0])
         1065                 return xloglist(c);
         1066         l = vtlogopen(name, 0);
         1067         if(l == nil)
         1068                 return hnotfound(c);
         1069         if(hsettype(c, "text/html") < 0){
         1070                 vtlogclose(l);
         1071                 return -1;
         1072         }
         1073         vtloghdump(&c->hout, l);
         1074         vtlogclose(l);
         1075         hflush(&c->hout);
         1076         return 0;
         1077 }
         1078 
         1079 static int
         1080 xindex(HConnect *c)
         1081 {
         1082         if(hsettype(c, "text/xml") < 0)
         1083                 return -1;
         1084         xmlindex(&c->hout, mainindex, "index", 0);
         1085         hflush(&c->hout);
         1086         return 0;
         1087 }
         1088 
         1089 void
         1090 xmlindent(Hio *hout, int indent)
         1091 {
         1092         int i;
         1093 
         1094         for(i = 0; i < indent; i++)
         1095                 hputc(hout, '\t');
         1096 }
         1097 
         1098 void
         1099 xmlaname(Hio *hout, char *v, char *tag)
         1100 {
         1101         hprint(hout, " %s=\"%s\"", tag, v);
         1102 }
         1103 
         1104 void
         1105 xmlscore(Hio *hout, u8int *v, char *tag)
         1106 {
         1107         if(scorecmp(zeroscore, v) == 0)
         1108                 return;
         1109         hprint(hout, " %s=\"%V\"", tag, v);
         1110 }
         1111 
         1112 void
         1113 xmlsealed(Hio *hout, int v, char *tag)
         1114 {
         1115         if(!v)
         1116                 return;
         1117         hprint(hout, " %s=\"yes\"", tag);
         1118 }
         1119 
         1120 void
         1121 xmlu32int(Hio *hout, u32int v, char *tag)
         1122 {
         1123         hprint(hout, " %s=\"%ud\"", tag, v);
         1124 }
         1125 
         1126 void
         1127 xmlu64int(Hio *hout, u64int v, char *tag)
         1128 {
         1129         hprint(hout, " %s=\"%llud\"", tag, v);
         1130 }
         1131 
         1132 void
         1133 vtloghdump(Hio *h, VtLog *l)
         1134 {
         1135         int i;
         1136         VtLogChunk *c;
         1137         char *name;
         1138 
         1139         name = l ? l->name : "&lt;nil&gt;";
         1140 
         1141         hprint(h, "<html><head>\n");
         1142         hprint(h, "<title>Venti Server Log: %s</title>\n", name);
         1143         hprint(h, "</head><body>\n");
         1144         hprint(h, "<b>Venti Server Log: %s</b>\n<p>\n", name);
         1145 
         1146         if(l){
         1147                 c = l->w;
         1148                 for(i=0; i<l->nchunk; i++){
         1149                         if(++c == l->chunk+l->nchunk)
         1150                                 c = l->chunk;
         1151                         hwrite(h, c->p, c->wp-c->p);
         1152                 }
         1153         }
         1154         hprint(h, "</body></html>\n");
         1155 }
         1156 
         1157 static int
         1158 strpcmp(const void *va, const void *vb)
         1159 {
         1160         return strcmp(*(char**)va, *(char**)vb);
         1161 }
         1162 
         1163 void
         1164 vtloghlist(Hio *h)
         1165 {
         1166         char **p;
         1167         int i, n;
         1168 
         1169         hprint(h, "<html><head>\n");
         1170         hprint(h, "<title>Venti Server Logs</title>\n");
         1171         hprint(h, "</head><body>\n");
         1172         hprint(h, "<b>Venti Server Logs</b>\n<p>\n");
         1173 
         1174         p = vtlognames(&n);
         1175         qsort(p, n, sizeof(p[0]), strpcmp);
         1176         for(i=0; i<n; i++)
         1177                 hprint(h, "<a href=\"/log?log=%s\">%s</a><br>\n", p[i], p[i]);
         1178         vtfree(p);
         1179         hprint(h, "</body></html>\n");
         1180 }