home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / modules / standard / mod_status.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-01  |  22.9 KB  |  760 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  */
  57.  
  58. /* Status Module.  Display lots of internal data about how Apache is
  59.  * performing and the state of all children processes.
  60.  *
  61.  * To enable this, add the following lines into any config file:
  62.  *
  63.  * <Location /server-status>
  64.  * SetHandler server-status
  65.  * </Location>
  66.  *
  67.  * You may want to protect this location by password or domain so no one
  68.  * else can look at it.  Then you can access the statistics with a URL like:
  69.  *
  70.  * http://your_server_name/server-status
  71.  *
  72.  * /server-status - Returns page using tables
  73.  * /server-status?notable - Returns page for browsers without table support
  74.  * /server-status?refresh - Returns page with 1 second refresh
  75.  * /server-status?refresh=6 - Returns page with refresh every 6 seconds
  76.  * /server-status?auto - Returns page with data for automatic parsing
  77.  *
  78.  * Mark Cox, mark@ukweb.com, November 1995
  79.  *
  80.  * 12.11.95 Initial version for www.telescope.org
  81.  * 13.3.96  Updated to remove rprintf's [Mark]
  82.  * 18.3.96  Added CPU usage, process information, and tidied [Ben Laurie]
  83.  * 18.3.96  Make extra Scoreboard variables #definable
  84.  * 25.3.96  Make short report have full precision [Ben Laurie suggested]
  85.  * 25.3.96  Show uptime better [Mark/Ben Laurie]
  86.  * 29.3.96  Better HTML and explanation [Mark/Rob Hartill suggested]
  87.  * 09.4.96  Added message for non-STATUS compiled version
  88.  * 18.4.96  Added per child and per slot counters [Jim Jagielski]
  89.  * 01.5.96  Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.]
  90.  * 18.5.96  Adapted to use new rprintf() routine, incidentally fixing a missing
  91.  *          piece in short reports [Ben Laurie]
  92.  * 21.5.96  Additional Status codes (DNS and LOGGING only enabled if
  93.  *          extended STATUS is enabled) [George Burgyan/Jim J.]
  94.  * 10.8.98  Allow for extended status info at runtime (no more STATUS)
  95.  *          [Jim J.]
  96.  */
  97.  
  98. #define CORE_PRIVATE
  99. #include "httpd.h"
  100. #include "http_config.h"
  101. #include "http_core.h"
  102. #include "http_protocol.h"
  103. #include "http_conf_globals.h"    /* for ap_extended_status */
  104. #include "http_main.h"
  105. #include "util_script.h"
  106. #include <time.h>
  107. #include "scoreboard.h"
  108. #include "http_log.h"
  109.  
  110. #ifdef NEXT
  111. #if (NX_CURRENT_COMPILER_RELEASE == 410)
  112. #ifdef m68k
  113. #define HZ 64
  114. #else
  115. #define HZ 100
  116. #endif
  117. #else
  118. #include <machine/param.h>
  119. #endif
  120. #endif /* NEXT */
  121.  
  122. #define STATUS_MAXLINE        64
  123.  
  124. #define KBYTE            1024
  125. #define    MBYTE            1048576L
  126. #define    GBYTE            1073741824L
  127.  
  128. #ifndef DEFAULT_TIME_FORMAT 
  129. #define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
  130. #endif
  131.  
  132. module MODULE_VAR_EXPORT status_module;
  133.  
  134. /*
  135.  *command-related code. This is here to prevent use of ExtendedStatus
  136.  * without status_module included.
  137.  */
  138. static const char *set_extended_status(cmd_parms *cmd, void *dummy, char *arg) 
  139. {
  140.     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
  141.     if (err != NULL) {
  142.         return err;
  143.     }
  144.     if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
  145.     ap_extended_status = 0;
  146.     }
  147.     else {
  148.     ap_extended_status = 1;
  149.     }
  150.     return NULL;
  151. }
  152.  
  153. static const command_rec status_module_cmds[] =
  154. {
  155.     { "ExtendedStatus", set_extended_status, NULL, RSRC_CONF, TAKE1,
  156.       "\"On\" to enable extended status information, \"Off\" to disable" },
  157.     {NULL}
  158. };
  159.  
  160. /* Format the number of bytes nicely */
  161. static void format_byte_out(request_rec *r, unsigned long bytes)
  162. {
  163.     if (bytes < (5 * KBYTE))
  164.     ap_rprintf(r, "%d B", (int) bytes);
  165.     else if (bytes < (MBYTE / 2))
  166.     ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE);
  167.     else if (bytes < (GBYTE / 2))
  168.     ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE);
  169.     else
  170.     ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE);
  171. }
  172.  
  173. static void format_kbyte_out(request_rec *r, unsigned long kbytes)
  174. {
  175.     if (kbytes < KBYTE)
  176.     ap_rprintf(r, "%d kB", (int) kbytes);
  177.     else if (kbytes < MBYTE)
  178.     ap_rprintf(r, "%.1f MB", (float) kbytes / KBYTE);
  179.     else
  180.     ap_rprintf(r, "%.1f GB", (float) kbytes / MBYTE);
  181. }
  182.  
  183. static void show_time(request_rec *r, time_t tsecs)
  184. {
  185.     long days, hrs, mins, secs;
  186.  
  187.     secs = tsecs % 60;
  188.     tsecs /= 60;
  189.     mins = tsecs % 60;
  190.     tsecs /= 60;
  191.     hrs = tsecs % 24;
  192.     days = tsecs / 24;
  193.     if (days)
  194.     ap_rprintf(r, " %ld day%s", days, days == 1 ? "" : "s");
  195.     if (hrs)
  196.     ap_rprintf(r, " %ld hour%s", hrs, hrs == 1 ? "" : "s");
  197.     if (mins)
  198.     ap_rprintf(r, " %ld minute%s", mins, mins == 1 ? "" : "s");
  199.     if (secs)
  200.     ap_rprintf(r, " %ld second%s", secs, secs == 1 ? "" : "s");
  201. }
  202.  
  203. /* Main handler for x-httpd-status requests */
  204.  
  205. /* ID values for command table */
  206.  
  207. #define STAT_OPT_END        -1
  208. #define STAT_OPT_REFRESH    0
  209. #define STAT_OPT_NOTABLE    1
  210. #define STAT_OPT_AUTO        2
  211.  
  212. struct stat_opt {
  213.     int id;
  214.     const char *form_data_str;
  215.     const char *hdr_out_str;
  216. };
  217.  
  218. static const struct stat_opt status_options[] =    /* see #defines above */
  219. {
  220.     {STAT_OPT_REFRESH, "refresh", "Refresh"},
  221.     {STAT_OPT_NOTABLE, "notable", NULL},
  222.     {STAT_OPT_AUTO, "auto", NULL},
  223.     {STAT_OPT_END, NULL, NULL}
  224. };
  225.  
  226. static char status_flags[SERVER_NUM_STATUS];
  227.  
  228. static int status_handler(request_rec *r)
  229. {
  230.     char *loc;
  231.     time_t nowtime = time(NULL);
  232.     time_t up_time;
  233.     int i, res;
  234.     int ready = 0;
  235.     int busy = 0;
  236.     unsigned long count = 0;
  237.     unsigned long lres, bytes;
  238.     unsigned long my_lres, my_bytes, conn_bytes;
  239.     unsigned short conn_lres;
  240.     unsigned long bcount = 0;
  241.     unsigned long kbcount = 0;
  242.     long req_time;
  243. #ifndef NO_TIMES
  244. #ifdef _SC_CLK_TCK
  245.     float tick = sysconf(_SC_CLK_TCK);
  246. #else
  247.     float tick = HZ;
  248. #endif
  249. #endif
  250.     int short_report = 0;
  251.     int no_table_report = 0;
  252.     short_score score_record;
  253.     parent_score ps_record;
  254.     char stat_buffer[HARD_SERVER_LIMIT];
  255.     int pid_buffer[HARD_SERVER_LIMIT];
  256.     clock_t tu, ts, tcu, tcs;
  257.     server_rec *vhost;
  258.  
  259.     tu = ts = tcu = tcs = 0;
  260.  
  261.     if (!ap_exists_scoreboard_image()) {
  262.     ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  263.             "Server status unavailable in inetd mode");
  264.     return HTTP_INTERNAL_SERVER_ERROR;
  265.     }
  266.     r->allowed = (1 << M_GET);
  267.     if (r->method_number != M_GET)
  268.     return DECLINED;
  269.  
  270.     r->content_type = "text/html";
  271.  
  272.     /*
  273.      * Simple table-driven form data set parser that lets you alter the header
  274.      */
  275.  
  276.     if (r->args) {
  277.     i = 0;
  278.     while (status_options[i].id != STAT_OPT_END) {
  279.         if ((loc = strstr(r->args, status_options[i].form_data_str)) != NULL) {
  280.         switch (status_options[i].id) {
  281.         case STAT_OPT_REFRESH:
  282.             if (*(loc + strlen(status_options[i].form_data_str)) == '=')
  283.             ap_table_set(r->headers_out,
  284.                   status_options[i].hdr_out_str,
  285.                   loc + strlen(status_options[i].hdr_out_str) + 1);
  286.             else
  287.             ap_table_set(r->headers_out,
  288.                   status_options[i].hdr_out_str, "1");
  289.             break;
  290.         case STAT_OPT_NOTABLE:
  291.             no_table_report = 1;
  292.             break;
  293.         case STAT_OPT_AUTO:
  294.             r->content_type = "text/plain";
  295.             short_report = 1;
  296.             break;
  297.         }
  298.         }
  299.         i++;
  300.     }
  301.     }
  302.  
  303.     ap_send_http_header(r);
  304.  
  305.     if (r->header_only)
  306.     return 0;
  307.  
  308.     ap_sync_scoreboard_image();
  309.     for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
  310.     score_record = ap_scoreboard_image->servers[i];
  311.     ps_record = ap_scoreboard_image->parent[i];
  312.     res = score_record.status;
  313.     stat_buffer[i] = status_flags[res];
  314.     pid_buffer[i] = (int) ps_record.pid;
  315.     if (res == SERVER_READY)
  316.         ready++;
  317.     else if (res != SERVER_DEAD)
  318.         busy++;
  319.     if (ap_extended_status) {
  320.         lres = score_record.access_count;
  321.         bytes = score_record.bytes_served;
  322.         if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) {
  323. #ifndef NO_TIMES
  324.         tu += score_record.times.tms_utime;
  325.         ts += score_record.times.tms_stime;
  326.         tcu += score_record.times.tms_cutime;
  327.         tcs += score_record.times.tms_cstime;
  328. #endif /* NO_TIMES */
  329.         count += lres;
  330.         bcount += bytes;
  331.         if (bcount >= KBYTE) {
  332.             kbcount += (bcount >> 10);
  333.             bcount = bcount & 0x3ff;
  334.         }
  335.         }
  336.     }
  337.     }
  338.  
  339.     up_time = nowtime - ap_restart_time;
  340.  
  341.     ap_hard_timeout("send status info", r);
  342.  
  343.     if (!short_report) {
  344.     ap_rputs("<HTML><HEAD>\n<TITLE>Apache Status</TITLE>\n</HEAD><BODY>\n", r);
  345.     ap_rputs("<H1>Apache Server Status for ", r);
  346.     ap_rvputs(r, ap_get_server_name(r), "</H1>\n\n", NULL);
  347.     ap_rvputs(r, "Server Version: ",
  348.       ap_get_server_version(), "<br>\n", NULL);
  349.     ap_rvputs(r, "Server Built: ",
  350.       ap_get_server_built(), "<br>\n<hr>\n", NULL);
  351.     ap_rvputs(r, "Current Time: ",
  352.       ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0), "<br>\n", NULL);
  353.     ap_rvputs(r, "Restart Time: ",
  354.       ap_ht_time(r->pool, ap_restart_time, DEFAULT_TIME_FORMAT, 0), 
  355.       "<br>\n", NULL);
  356.     ap_rputs("Server uptime: ", r);
  357.     show_time(r, up_time);
  358.     ap_rputs("<br>\n", r);
  359.     }
  360.  
  361.     if (ap_extended_status) {
  362.     if (short_report) {
  363.         ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %lu\n",
  364.         count, kbcount);
  365.  
  366. #ifndef NO_TIMES
  367.         /* Allow for OS/2 not having CPU stats */
  368.         if (ts || tu || tcu || tcs)
  369.         ap_rprintf(r, "CPULoad: %g\n",
  370.             (tu + ts + tcu + tcs) / tick / up_time * 100.);
  371. #endif
  372.  
  373.         ap_rprintf(r, "Uptime: %ld\n", (long) (up_time));
  374.         if (up_time > 0)
  375.         ap_rprintf(r, "ReqPerSec: %g\n",
  376.             (float) count / (float) up_time);
  377.  
  378.         if (up_time > 0)
  379.         ap_rprintf(r, "BytesPerSec: %g\n",
  380.             KBYTE * (float) kbcount / (float) up_time);
  381.  
  382.         if (count > 0)
  383.         ap_rprintf(r, "BytesPerReq: %g\n",
  384.             KBYTE * (float) kbcount / (float) count);
  385.     }
  386.     else {            /* !short_report */
  387.         ap_rprintf(r, "Total accesses: %lu - Total Traffic: ", count);
  388.         format_kbyte_out(r, kbcount);
  389.  
  390. #ifndef NO_TIMES
  391.         /* Allow for OS/2 not having CPU stats */
  392.         ap_rputs("<br>\n", r);
  393.         ap_rprintf(r, "CPU Usage: u%g s%g cu%g cs%g",
  394.             tu / tick, ts / tick, tcu / tick, tcs / tick);
  395.  
  396.         if (ts || tu || tcu || tcs)
  397.         ap_rprintf(r, " - %.3g%% CPU load",
  398.             (tu + ts + tcu + tcs) / tick / up_time * 100.);
  399. #endif
  400.  
  401.         ap_rputs("<br>\n", r);
  402.  
  403.         if (up_time > 0)
  404.         ap_rprintf(r, "%.3g requests/sec - ",
  405.             (float) count / (float) up_time);
  406.  
  407.         if (up_time > 0) {
  408.         format_byte_out(r, KBYTE * (float) kbcount / (float) up_time);
  409.         ap_rputs("/second - ", r);
  410.         }
  411.  
  412.         if (count > 0) {
  413.         format_byte_out(r, KBYTE * (float) kbcount / (float) count);
  414.         ap_rputs("/request", r);
  415.         }
  416.  
  417.         ap_rputs("<br>\n", r);
  418.     }                /* short_report */
  419.     }                    /* ap_extended_status */
  420.  
  421.     if (!short_report)
  422.     ap_rprintf(r, "\n%d requests currently being processed, %d idle servers\n"
  423.         ,busy, ready);
  424.     else
  425.     ap_rprintf(r, "BusyServers: %d\nIdleServers: %d\n", busy, ready);
  426.  
  427.     /* send the scoreboard 'table' out */
  428.  
  429.     if (!short_report)
  430.     ap_rputs("<PRE>", r);
  431.     else
  432.     ap_rputs("Scoreboard: ", r);
  433.  
  434.     for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
  435.     ap_rputc(stat_buffer[i], r);
  436.     if ((i % STATUS_MAXLINE == (STATUS_MAXLINE - 1)) && !short_report)
  437.         ap_rputs("\n", r);
  438.     }
  439.  
  440.     if (short_report)
  441.     ap_rputs("\n", r);
  442.     else {
  443.     ap_rputs("</PRE>\n", r);
  444.     ap_rputs("Scoreboard Key: <br>\n", r);
  445.     ap_rputs("\"<B><code>_</code></B>\" Waiting for Connection, \n", r);
  446.     ap_rputs("\"<B><code>S</code></B>\" Starting up, \n", r);
  447.     ap_rputs("\"<B><code>R</code></B>\" Reading Request,<BR>\n", r);
  448.     ap_rputs("\"<B><code>W</code></B>\" Sending Reply, \n", r);
  449.     ap_rputs("\"<B><code>K</code></B>\" Keepalive (read), \n", r);
  450.     ap_rputs("\"<B><code>D</code></B>\" DNS Lookup,<BR>\n", r);
  451.     ap_rputs("\"<B><code>L</code></B>\" Logging, \n", r);
  452.     ap_rputs("\"<B><code>G</code></B>\" Gracefully finishing, \n", r);
  453.     ap_rputs("\"<B><code>.</code></B>\" Open slot with no current process<P>\n", r);
  454.     ap_rputs("<P>\n", r);
  455.     if (!ap_extended_status) {
  456.         int j = 0;
  457.         ap_rputs("PID Key: <br>\n", r);
  458.         ap_rputs("<PRE>\n", r);
  459.         for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
  460.         if (stat_buffer[i] != '.') {
  461.             ap_rprintf(r, "   %d in state: %c ", pid_buffer[i],
  462.              stat_buffer[i]);
  463.             if (++j >= 3) {
  464.                 ap_rputs("\n", r);
  465.             j = 0;
  466.             } else
  467.                 ap_rputs(",", r);
  468.         }
  469.         }
  470.         ap_rputs("\n", r);
  471.         ap_rputs("</PRE>\n", r);
  472.     }
  473.     }
  474.  
  475.     if (ap_extended_status) {
  476.     if (!short_report) {
  477.         if (no_table_report)
  478.         ap_rputs("<p><hr><h2>Server Details</h2>\n\n", r);
  479.         else
  480. #ifdef NO_TIMES
  481.         /* Allow for OS/2 not having CPU stats */
  482.         ap_rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M\n<th>SS<th>Req<th>Conn<th>Child<th>Slot<th>Client<th>VHost<th>Request</tr>\n\n", r);
  483. #else
  484.         ap_rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M<th>CPU\n<th>SS<th>Req<th>Conn<th>Child<th>Slot<th>Client<th>VHost<th>Request</tr>\n\n", r);
  485. #endif
  486.     }
  487.  
  488.     for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
  489.         score_record = ap_scoreboard_image->servers[i];
  490.         ps_record = ap_scoreboard_image->parent[i];
  491.         vhost = score_record.vhostrec;
  492.         if (ps_record.generation != ap_my_generation) {
  493.         vhost = NULL;
  494.         }
  495.  
  496. #if defined(NO_GETTIMEOFDAY)
  497. #ifndef NO_TIMES
  498.         if (score_record.start_time == (clock_t) 0)
  499. #endif /* NO_TIMES */
  500.         req_time = 0L;
  501. #ifndef NO_TIMES
  502.         else {
  503.         req_time = score_record.stop_time - score_record.start_time;
  504.         req_time = (req_time * 1000) / (int) tick;
  505.         }
  506. #endif /* NO_TIMES */
  507. #else
  508.         if (score_record.start_time.tv_sec == 0L &&
  509.         score_record.start_time.tv_usec == 0L)
  510.         req_time = 0L;
  511.         else
  512.         req_time =
  513.             ((score_record.stop_time.tv_sec - score_record.start_time.tv_sec) * 1000) +
  514.             ((score_record.stop_time.tv_usec - score_record.start_time.tv_usec) / 1000);
  515. #endif
  516.         if (req_time < 0L)
  517.         req_time = 0L;
  518.  
  519.         lres = score_record.access_count;
  520.         my_lres = score_record.my_access_count;
  521.         conn_lres = score_record.conn_count;
  522.         bytes = score_record.bytes_served;
  523.         my_bytes = score_record.my_bytes_served;
  524.         conn_bytes = score_record.conn_bytes;
  525.         if (lres != 0 || (score_record.status != SERVER_READY
  526.                   && score_record.status != SERVER_DEAD)) {
  527.         if (!short_report) {
  528.             if (no_table_report) {
  529.             if (score_record.status == SERVER_DEAD)
  530.                 ap_rprintf(r, "<b>Server %d</b> (-): %d|%lu|%lu [",
  531.                     i, (int) conn_lres, my_lres, lres);
  532.             else
  533.                 ap_rprintf(r, "<b>Server %d</b> (%d): %d|%lu|%lu [",
  534.                     i, (int) ps_record.pid, (int) conn_lres, my_lres, lres);
  535.  
  536.             switch (score_record.status) {
  537.             case SERVER_READY:
  538.                 ap_rputs("Ready", r);
  539.                 break;
  540.             case SERVER_STARTING:
  541.                 ap_rputs("Starting", r);
  542.                 break;
  543.             case SERVER_BUSY_READ:
  544.                 ap_rputs("<b>Read</b>", r);
  545.                 break;
  546.             case SERVER_BUSY_WRITE:
  547.                 ap_rputs("<b>Write</b>", r);
  548.                 break;
  549.             case SERVER_BUSY_KEEPALIVE:
  550.                 ap_rputs("<b>Keepalive</b>", r);
  551.                 break;
  552.             case SERVER_BUSY_LOG:
  553.                 ap_rputs("<b>Logging</b>", r);
  554.                 break;
  555.             case SERVER_BUSY_DNS:
  556.                 ap_rputs("<b>DNS lookup</b>", r);
  557.                 break;
  558.             case SERVER_DEAD:
  559.                 ap_rputs("Dead", r);
  560.                 break;
  561.             case SERVER_GRACEFUL:
  562.                 ap_rputs("Graceful", r);
  563.                 break;
  564.             default:
  565.                 ap_rputs("?STATE?", r);
  566.                 break;
  567.             }
  568. #ifdef NO_TIMES
  569.             /* Allow for OS/2 not having CPU stats */
  570.             ap_rprintf(r, "]\n %.0f %ld (",
  571. #else
  572.  
  573.             ap_rprintf(r, "] u%g s%g cu%g cs%g\n %.0f %ld (",
  574.                 score_record.times.tms_utime / tick,
  575.                 score_record.times.tms_stime / tick,
  576.                 score_record.times.tms_cutime / tick,
  577.                 score_record.times.tms_cstime / tick,
  578. #endif
  579. #ifdef OPTIMIZE_TIMEOUTS
  580.                 difftime(nowtime, ps_record.last_rtime),
  581. #else
  582.                 difftime(nowtime, score_record.last_used),
  583. #endif
  584.                 (long) req_time);
  585.             format_byte_out(r, conn_bytes);
  586.             ap_rputs("|", r);
  587.             format_byte_out(r, my_bytes);
  588.             ap_rputs("|", r);
  589.             format_byte_out(r, bytes);
  590.             ap_rputs(")\n", r);
  591.             ap_rprintf(r, " <i>%s {%s}</i><br>\n\n",
  592.                 score_record.client,
  593.                 ap_escape_html(r->pool, score_record.request));
  594.             }
  595.             else {        /* !no_table_report */
  596.             if (score_record.status == SERVER_DEAD)
  597.                 ap_rprintf(r, "<tr><td><b>%d</b><td>-<td>%d/%lu/%lu",
  598.                     i, (int) conn_lres, my_lres, lres);
  599.             else
  600.                 ap_rprintf(r, "<tr><td><b>%d</b><td>%d<td>%d/%lu/%lu",
  601.                     i, (int) ps_record.pid, (int) conn_lres, my_lres, lres);
  602.  
  603.             switch (score_record.status) {
  604.             case SERVER_READY:
  605.                 ap_rputs("<td>_", r);
  606.                 break;
  607.             case SERVER_STARTING:
  608.                 ap_rputs("<td><b>S</b>", r);
  609.                 break;
  610.             case SERVER_BUSY_READ:
  611.                 ap_rputs("<td><b>R</b>", r);
  612.                 break;
  613.             case SERVER_BUSY_WRITE:
  614.                 ap_rputs("<td><b>W</b>", r);
  615.                 break;
  616.             case SERVER_BUSY_KEEPALIVE:
  617.                 ap_rputs("<td><b>K</b>", r);
  618.                 break;
  619.             case SERVER_BUSY_LOG:
  620.                 ap_rputs("<td><b>L</b>", r);
  621.                 break;
  622.             case SERVER_BUSY_DNS:
  623.                 ap_rputs("<td><b>D</b>", r);
  624.                 break;
  625.             case SERVER_DEAD:
  626.                 ap_rputs("<td>.", r);
  627.                 break;
  628.             case SERVER_GRACEFUL:
  629.                 ap_rputs("<td>G", r);
  630.                 break;
  631.             default:
  632.                 ap_rputs("<td>?", r);
  633.                 break;
  634.             }
  635. #ifdef NO_TIMES
  636.             /* Allow for OS/2 not having CPU stats */
  637.             ap_rprintf(r, "\n<td>%.0f<td>%ld",
  638. #else
  639.             ap_rprintf(r, "\n<td>%.2f<td>%.0f<td>%ld",
  640.                 (score_record.times.tms_utime +
  641.                  score_record.times.tms_stime +
  642.                  score_record.times.tms_cutime +
  643.                  score_record.times.tms_cstime) / tick,
  644. #endif
  645. #ifdef OPTIMIZE_TIMEOUTS
  646.                 difftime(nowtime, ps_record.last_rtime),
  647. #else
  648.                 difftime(nowtime, score_record.last_used),
  649. #endif
  650.                 (long) req_time);
  651.             ap_rprintf(r, "<td>%-1.1f<td>%-2.2f<td>%-2.2f\n",
  652.                (float) conn_bytes / KBYTE, (float) my_bytes / MBYTE,
  653.                 (float) bytes / MBYTE);
  654.             if (score_record.status == SERVER_BUSY_READ)
  655.                 ap_rprintf(r,
  656.                  "<td>?<td nowrap>?<td nowrap>..reading.. </tr>\n\n");
  657.             else
  658.                 ap_rprintf(r,
  659.                  "<td>%s<td nowrap>%s<td nowrap>%s</tr>\n\n",
  660.                  score_record.client,
  661.                  vhost ? vhost->server_hostname : "(unavailable)",
  662.                  ap_escape_html(r->pool, score_record.request));
  663.             }        /* no_table_report */
  664.         }            /* !short_report */
  665.         }            /* if (<active child>) */
  666.     }                /* for () */
  667.  
  668.     if (!(short_report || no_table_report)) {
  669. #ifdef NO_TIMES
  670.         ap_rputs("</table>\n \
  671. <hr> \
  672. <table>\n \
  673. <tr><th>Srv<td>Server number\n \
  674. <tr><th>PID<td>OS process ID\n \
  675. <tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \
  676. <tr><th>M<td>Mode of operation\n \
  677. <tr><th>SS<td>Seconds since beginning of most recent request\n \
  678. <tr><th>Req<td>Milliseconds required to process most recent request\n \
  679. <tr><th>Conn<td>Kilobytes transferred this connection\n \
  680. <tr><th>Child<td>Megabytes transferred this child\n \
  681. <tr><th>Slot<td>Total megabytes transferred this slot\n \
  682. </table>\n", r);
  683. #else
  684.         ap_rputs("</table>\n \
  685. <hr> \
  686. <table>\n \
  687. <tr><th>Srv<td>Server number\n \
  688. <tr><th>PID<td>OS process ID\n \
  689. <tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \
  690. <tr><th>M<td>Mode of operation\n \
  691. <tr><th>CPU<td>CPU usage, number of seconds\n \
  692. <tr><th>SS<td>Seconds since beginning of most recent request\n \
  693. <tr><th>Req<td>Milliseconds required to process most recent request\n \
  694. <tr><th>Conn<td>Kilobytes transferred this connection\n \
  695. <tr><th>Child<td>Megabytes transferred this child\n \
  696. <tr><th>Slot<td>Total megabytes transferred this slot\n \
  697. </table>\n", r);
  698. #endif
  699.     }
  700.  
  701.     } else {
  702.  
  703.     ap_rputs("<hr>To obtain a full report with current status information ", r);
  704.     ap_rputs("you need to use the <code>ExtendedStatus On</code> directive. \n", r);
  705.  
  706.     }
  707.  
  708.     if (!short_report) {
  709.     ap_rputs(ap_psignature("<HR>\n",r), r);
  710.     ap_rputs("</BODY></HTML>\n", r);
  711.     }
  712.  
  713.     ap_kill_timeout(r);
  714.     return 0;
  715. }
  716.  
  717.  
  718. static void status_init(server_rec *s, pool *p)
  719. {
  720.     status_flags[SERVER_DEAD] = '.';    /* We don't want to assume these are in */
  721.     status_flags[SERVER_READY] = '_';    /* any particular order in scoreboard.h */
  722.     status_flags[SERVER_STARTING] = 'S';
  723.     status_flags[SERVER_BUSY_READ] = 'R';
  724.     status_flags[SERVER_BUSY_WRITE] = 'W';
  725.     status_flags[SERVER_BUSY_KEEPALIVE] = 'K';
  726.     status_flags[SERVER_BUSY_LOG] = 'L';
  727.     status_flags[SERVER_BUSY_DNS] = 'D';
  728.     status_flags[SERVER_GRACEFUL] = 'G';
  729. }
  730.  
  731. static const handler_rec status_handlers[] =
  732. {
  733.     {STATUS_MAGIC_TYPE, status_handler},
  734.     {"server-status", status_handler},
  735.     {NULL}
  736. };
  737.  
  738. module MODULE_VAR_EXPORT status_module =
  739. {
  740.     STANDARD_MODULE_STUFF,
  741.     status_init,        /* initializer */
  742.     NULL,            /* dir config creater */
  743.     NULL,            /* dir merger --- default is to override */
  744.     NULL,            /* server config */
  745.     NULL,            /* merge server config */
  746.     status_module_cmds,        /* command table */
  747.     status_handlers,        /* handlers */
  748.     NULL,            /* filename translation */
  749.     NULL,            /* check_user_id */
  750.     NULL,            /* check auth */
  751.     NULL,            /* check access */
  752.     NULL,            /* type_checker */
  753.     NULL,            /* fixups */
  754.     NULL,            /* logger */
  755.     NULL,            /* header parser */
  756.     NULL,            /* child_init */
  757.     NULL,            /* child_exit */
  758.     NULL            /* post read-request */
  759. };
  760.