thttpd.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
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, "Error\n

Error

\n
%r
\n"); 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; ifn, g->arg, g->t0, g->t1, bin, nbin); 959 960 hprint(io, "stats\n\n"); 961 for(i=0; insamp, 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 : "<nil>"; 1140 1141 hprint(h, "\n"); 1142 hprint(h, "Venti Server Log: %s\n", name); 1143 hprint(h, "\n"); 1144 hprint(h, "Venti Server Log: %s\n

\n", name); 1145 1146 if(l){ 1147 c = l->w; 1148 for(i=0; inchunk; 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, "\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, "\n"); 1170 hprint(h, "Venti Server Logs\n"); 1171 hprint(h, "\n"); 1172 hprint(h, "Venti Server Logs\n

\n"); 1173 1174 p = vtlognames(&n); 1175 qsort(p, n, sizeof(p[0]), strpcmp); 1176 for(i=0; i%s
\n", p[i], p[i]); 1178 vtfree(p); 1179 hprint(h, "\n"); 1180 }