home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / mod_stat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-02  |  19.7 KB  |  600 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995, 1996 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.
  24.  *
  25.  * 5. Redistributions of any form whatsoever must retain the following
  26.  *    acknowledgment:
  27.  *    "This product includes software developed by the Apache Group
  28.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  31.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  34.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  41.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  42.  * ====================================================================
  43.  *
  44.  * This software consists of voluntary contributions made by many
  45.  * individuals on behalf of the Apache Group and was originally based
  46.  * on public domain software written at the National Center for
  47.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  48.  * For more information on the Apache Group and the Apache HTTP server
  49.  * project, please see <http://www.apache.org/>.
  50.  *
  51.  */
  52.  
  53. /* Status Module.  Provide a way of getting at the internal Apache
  54.  * status information without having to worry where the scoreboard is
  55.  * held.
  56.  *
  57.  * AddType application/x-httpd-status .status
  58.  * You might like to do this in a .htaccess in a protected directory only
  59.  *
  60.  * GET /.status - Returns pretty page for system admin user
  61.  * GET /.status?refresh - Returns page with 1 second refresh
  62.  * GET /.status?refresh=6 - Returns page with refresh every 6 seconds
  63.  * GET /.status?auto - Returns page with data for automatic parsing
  64.  * GET /.status?notable - Returns page with no table niceties
  65.  *
  66.  * Mark Cox, mark@ukweb.com, November 1995
  67.  *
  68.  * 12.11.95 Initial version for telescope.org
  69.  * 13.3.96  Updated to remove rprintf's [Mark]
  70.  * 18.3.96  Added CPU usage, process information, and tidied [Ben Laurie]
  71.  * 18.3.96  Make extra Scoreboard variables #definable
  72.  * 25.3.96  Make short report have full precision [Ben Laurie suggested]
  73.  * 25.3.96  Show uptime better [Mark/Ben Laurie]
  74.  * 29.3.96  Better HTML and explanation [Mark/Rob Hartill suggested]
  75.  * 09.4.96  Added message for non-STATUS compiled version
  76.  * 18.4.96  Added per child and per slot counters [Jim Jagielski]
  77.  * 01.5.96  Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.]
  78.  * 18.5.96  Adapted to use new rprintf() routine, incidentally fixing a missing
  79.  *          piece in short reports [Ben Laurie]
  80.  * 21.5.96  Additional Status codes (DNS and LOGGING only enabled if
  81.              extended STATUS is enabled) [George Burgyan/Jim J.]
  82.  */
  83.  
  84. #include "httpd.h"
  85. #include "http_config.h"
  86. #include "http_core.h"
  87. #include "http_protocol.h"
  88. #include "http_main.h"
  89. #include "util_script.h"
  90. #include <time.h>
  91. #include "scoreboard.h"
  92.  
  93. #ifdef NEXT
  94. #include <machine/param.h>
  95. #endif
  96.  
  97. #define STATUS_MAXLINE      50
  98.  
  99. #define KBYTE           1024
  100. #define MBYTE           1048576L
  101. #define GBYTE           1073741824L
  102.  
  103. module status_module;
  104.  
  105. /* Format the number of bytes nicely */
  106.  
  107. void format_byte_out(request_rec *r,unsigned long bytes)
  108. {
  109.     if (bytes < (5 * KBYTE))
  110.     rprintf(r,"%d B",(int)bytes);
  111.     else if (bytes < (MBYTE / 2))
  112.     rprintf(r,"%.1f kB",(float)bytes/KBYTE);
  113.     else if (bytes < (GBYTE / 2))
  114.     rprintf(r,"%.1f MB",(float)bytes/MBYTE);
  115.     else
  116.     rprintf(r,"%.1f GB",(float)bytes/GBYTE);
  117. }
  118.  
  119. void show_time(request_rec *r,time_t tsecs)
  120. {
  121.     long days,hrs,mins,secs;
  122.     char buf[100];
  123.     char *s;
  124.  
  125.     secs=tsecs%60;
  126.     tsecs/=60;
  127.     mins=tsecs%60;
  128.     tsecs/=60;
  129.     hrs=tsecs%24;
  130.     days=tsecs/24;
  131.     s=buf;
  132.     *s='\0';
  133.     if(days)
  134.     rprintf(r," %ld day%s",days,days==1?"":"s");
  135.     if(hrs)
  136.     rprintf(r," %ld hour%s",hrs,hrs==1?"":"s");
  137.     if(mins)
  138.     rprintf(r," %ld minute%s",mins,mins==1?"":"s");
  139.     if(secs)
  140.     rprintf(r," %ld second%s",secs,secs==1?"":"s");
  141. }
  142.  
  143. #if defined(SUNOS4)
  144. double
  145. difftime(time1, time0)
  146.         time_t time1, time0;
  147. {
  148.         return(time1 - time0);
  149. }
  150. #endif
  151.  
  152. /* Main handler for x-httpd-status requests */
  153.  
  154. /* ID values for command table */
  155.  
  156. #define STAT_OPT_END        -1
  157. #define STAT_OPT_REFRESH    0
  158. #define STAT_OPT_NOTABLE    1
  159. #define STAT_OPT_AUTO       2
  160.  
  161. struct stat_opt
  162. {
  163.     int id;
  164.     char *form_data_str;
  165.     char *hdr_out_str;
  166. };
  167.  
  168. int status_handler (request_rec *r)
  169. {
  170.     struct stat_opt options[] =        /* see #defines above */
  171.     {
  172.     { STAT_OPT_REFRESH, "refresh", "Refresh" },
  173.         { STAT_OPT_NOTABLE, "notable", NULL },
  174.         { STAT_OPT_AUTO, "auto", NULL },
  175.     { STAT_OPT_END, NULL, NULL }
  176.     };
  177.     char *loc;
  178.     time_t nowtime=time(NULL);
  179.     time_t up_time;
  180.     int i,res;
  181.     int ready=0;
  182.     int busy=0;
  183. #if defined(STATUS)
  184.     unsigned long count=0;
  185.     unsigned long lres,bytes;
  186.     unsigned long my_lres,my_bytes,conn_bytes;
  187.     unsigned short conn_lres;
  188.     unsigned long bcount=0;
  189. #ifdef NEXT
  190.     float tick=HZ;
  191. #else
  192.     float tick=sysconf(_SC_CLK_TCK);
  193. #endif
  194. #endif /* STATUS */
  195.     int short_report=0;
  196.     int no_table_report=0;
  197.     server_rec *server = r->server;
  198.     short_score score_record;
  199.     char status[]="??????????";
  200.     char stat_buffer[HARD_SERVER_LIMIT];
  201.     clock_t tu,ts,tcu,tcs;
  202.  
  203.     tu=ts=tcu=tcs=0;
  204.  
  205.     status[SERVER_DEAD]='.';  /* We don't want to assume these are in */
  206.     status[SERVER_READY]='_'; /* any particular order in scoreboard.h */
  207.     status[SERVER_STARTING]='S';
  208.     status[SERVER_BUSY_READ]='R';
  209.     status[SERVER_BUSY_WRITE]='W';
  210.     status[SERVER_BUSY_KEEPALIVE]='K';
  211.     status[SERVER_BUSY_LOG]='L';
  212.     status[SERVER_BUSY_DNS]='D';
  213.  
  214.     if (r->method_number != M_GET) return NOT_IMPLEMENTED;
  215.     r->content_type = "text/html";
  216.  
  217.     /*
  218.      * Simple table-driven form data set parser that lets you alter the header
  219.      */
  220.  
  221.     if (r->args)
  222.     {
  223.     i = 0;
  224.         while (options[i].id != STAT_OPT_END)
  225.         {
  226.             if ((loc = strstr(r->args,options[i].form_data_str)) != NULL)
  227.         {
  228.                 switch (options[i].id)
  229.                 {
  230.                   case STAT_OPT_REFRESH:
  231.                       if(*(loc + strlen(options[i].form_data_str)) == '=')
  232.                           table_set(r->headers_out,options[i].hdr_out_str,
  233.                 loc+strlen(options[i].hdr_out_str)+1);
  234.                       else
  235.                           table_set(r->headers_out,options[i].hdr_out_str,"1");
  236.                       break;
  237.                   case STAT_OPT_NOTABLE:
  238.                       no_table_report = 1;
  239.                       break;
  240.                   case STAT_OPT_AUTO:
  241.                       r->content_type = "text/plain";
  242.                       short_report = 1;
  243.                       break;
  244.                 }
  245.         }
  246.         i++;
  247.         }
  248.     }
  249.  
  250.     soft_timeout ("send status info", r);
  251.     send_http_header(r);
  252.  
  253.     if (r->header_only)
  254.     return 0;
  255.  
  256.     sync_scoreboard_image();
  257.     for (i = 0; i<HARD_SERVER_LIMIT; ++i)
  258.     {
  259.         score_record = get_scoreboard_info(i);
  260.         res = score_record.status;
  261.     stat_buffer[i] = status[res];
  262.         if (res == SERVER_READY)
  263.         ready++;
  264.         else if (res == SERVER_BUSY_READ || res==SERVER_BUSY_WRITE ||
  265.          res == SERVER_STARTING || res==SERVER_BUSY_KEEPALIVE ||
  266.          res == SERVER_BUSY_LOG || res==SERVER_BUSY_DNS)
  267.         busy++;
  268. #if defined(STATUS)
  269.         lres = score_record.access_count;
  270.     bytes= score_record.bytes_served;
  271.         if (lres!=0 || (score_record.status != SERVER_READY
  272.       && score_record.status != SERVER_DEAD))
  273.     {
  274.         tu+=score_record.times.tms_utime;
  275.         ts+=score_record.times.tms_stime;
  276.         tcu+=score_record.times.tms_cutime;
  277.         tcs+=score_record.times.tms_cstime;
  278.             count+=lres;
  279.         bcount+=bytes;
  280.     }
  281. #endif /* STATUS */
  282.     }
  283.  
  284.     up_time=nowtime-restart_time;
  285.  
  286.     if (!short_report)
  287.     {
  288.         rputs("<html><head><title>Apache Status</title></head><body>\n",r);
  289.         rputs("<h1>Apache Server Status for ",r);
  290.         rvputs(r,server->server_hostname,"</h1>\n\n",NULL);
  291.         rvputs(r,"Current Time: ",asctime(localtime(&nowtime)),"<br>\n",NULL);
  292.         rvputs(r,"Restart Time: ",asctime(localtime(&restart_time)),"<br>\n",
  293.            NULL);
  294.         rputs("Server uptime: ",r);
  295.         show_time(r,up_time);
  296.         rputs("<br>\n",r);
  297.     }
  298.  
  299. #if defined(STATUS)
  300.     if (short_report)
  301.     {
  302.         rprintf(r,"Total Accesses: %lu\nTotal Bytes: %lu\n",count,bcount);
  303.  
  304. #ifndef __EMX__
  305.     /* Allow for OS/2 not having CPU stats */
  306.     if(ts || tu || tcu || tcs)
  307.         rprintf(r,"CPULoad: %g\n",(tu+ts+tcu+tcs)/tick/up_time*100.);
  308. #endif
  309.  
  310.     rprintf(r,"Uptime: %ld\n",(long)(up_time));
  311.     if (up_time>0)
  312.         rprintf(r,"ReqPerSec: %g\n",(float)count/(float)up_time);
  313.  
  314.     if (up_time>0)
  315.         rprintf(r,"BytesPerSec: %g\n",(float)bcount/(float)up_time);
  316.  
  317.     if (count>0)
  318.         rprintf(r,"BytesPerReq: %g\n",(float)bcount/(float)count);
  319.     } else /* !short_report */
  320.     {
  321.     rprintf(r,"Total accesses: %lu - Total Traffic: ", count);
  322.     format_byte_out(r,bcount);
  323.  
  324. #ifndef __EMX__
  325.     /* Allow for OS/2 not having CPU stats */
  326.     rputs("<br>\n",r);
  327.         rprintf(r,"CPU Usage: u%g s%g cu%g cs%g",
  328.         tu/tick,ts/tick,tcu/tick,tcs/tick);
  329.  
  330.     if(ts || tu || tcu || tcs)
  331.         rprintf(r," - %.3g%% CPU load",(tu+ts+tcu+tcs)/tick/up_time*100.);
  332. #endif
  333.  
  334.     rputs("<br>\n",r);
  335.  
  336.     if (up_time>0)
  337.         rprintf(r,"%.3g requests/sec - ",
  338.             (float)count/(float)up_time);
  339.  
  340.     if (up_time>0)
  341.     {
  342.         format_byte_out(r,(float)bcount/(float)up_time);
  343.         rputs("/second - ",r);
  344.     }
  345.  
  346.     if (count>0)
  347.     {
  348.         format_byte_out(r,(float)bcount/(float)count);
  349.         rputs("/request",r);
  350.     }
  351.  
  352.     rputs("<p>\n",r);
  353.     } /* short_report */
  354. #endif /* STATUS */
  355.  
  356.     /* send the scoreboard 'table' out */
  357.  
  358.     rputs("Scoreboard: \n",r);
  359.  
  360.     if(!short_report)
  361.     rputs("<PRE>",r);
  362.  
  363.     rputs("\n",r);
  364.  
  365.     for (i = 0; i<HARD_SERVER_LIMIT; ++i)
  366.     {
  367.     rputc(stat_buffer[i], r);
  368.     if(i%STATUS_MAXLINE == (STATUS_MAXLINE - 1))
  369.         rputs("\n",r);
  370.     }
  371.  
  372.     if (short_report)
  373.     {
  374.         rprintf(r,"\nBusyServers: %d\nIdleServers: %d\n",busy,ready);
  375.     }
  376.     else
  377.     {
  378.     rputs("</PRE>\n",r);
  379.     rputs("Key:<br> \n",r);
  380.     rputs("\"<code>_</code>\" Waiting for Connection, \n",r);
  381.     rputs("\"<code>S</code>\" Starting up,<br> \n",r);
  382.     rputs("\"<code>R</code>\" Reading Request, \n",r);
  383.     rputs("\"<code>W</code>\" Sending Reply,<br> \n",r);
  384.     rputs("\"<code>K</code>\" Keepalive (read), \n",r);
  385.     rputs("\"<code>D</code>\" DNS Lookup, \n",r);
  386.     rputs("\"<code>L</code>\" Logging<p>\n",r);
  387.         rprintf(r,"\n%d requests currently being processed, %d idle servers\n"
  388.         ,busy,ready);
  389.     }
  390.  
  391. #if defined(STATUS)
  392.     if (!short_report)
  393.         if(no_table_report)
  394.             rputs("<p><hr><h2>Server Details</h2>\n\n",r);
  395.     else
  396. #ifdef __EMX__
  397.             /* Allow for OS/2 not having CPU stats */
  398.             rputs("<p>\n\n<table border=3><tr><th>Srv<th>PID<th>Acc<th>M\n<th>SS<th>Conn<th>Child<th>Slot<th>Host<th>Request</tr>\n\n",r);
  399. #else
  400.             rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M<th>CPU\n<th>SS<th>Conn<th>Child<th>Slot<th>Host<th>Request</tr>\n\n",r);
  401. #endif
  402.  
  403.  
  404.     for (i = 0; i<HARD_SERVER_LIMIT; ++i)
  405.     {
  406.         score_record=get_scoreboard_info(i);
  407.         lres = score_record.access_count;
  408.         my_lres = score_record.my_access_count;
  409.         conn_lres = score_record.conn_count;
  410.         bytes= score_record.bytes_served;
  411.         my_bytes = score_record.my_bytes_served;
  412.         conn_bytes = score_record.conn_bytes;
  413.         if (lres!=0 || (score_record.status != SERVER_READY
  414.         && score_record.status != SERVER_DEAD))
  415.     {
  416.         if (!short_report)
  417.         {
  418.         if (no_table_report)
  419.         {
  420.                 rprintf(r,"<b>Server %d</b> (%d): %d|%lu|%lu [",
  421.              i,(int)score_record.pid,(int)conn_lres,my_lres,lres);
  422.  
  423.             switch (score_record.status)
  424.             {
  425.                 case SERVER_READY:
  426.                     rputs("Ready",r);
  427.                     break;
  428.                 case SERVER_STARTING:
  429.                     rputs("Starting",r);
  430.                     break;
  431.                 case SERVER_BUSY_READ:
  432.                     rputs("<b>Read</b>",r);
  433.                     break;
  434.                 case SERVER_BUSY_WRITE:
  435.                     rputs("<b>Write</b>",r);
  436.                     break;
  437.                 case SERVER_BUSY_KEEPALIVE:
  438.                     rputs("<b>Keepalive</b>",r);
  439.                     break;
  440.                 case SERVER_BUSY_LOG:
  441.                     rputs("<b>Logging</b>",r);
  442.                     break;
  443.                 case SERVER_BUSY_DNS:
  444.                     rputs("<b>DNS lookup</b>",r);
  445.                     break;
  446.                 case SERVER_DEAD:
  447.                     rputs("Dead",r);
  448.                     break;
  449.             }
  450. #ifdef __EMX__
  451.             /* Allow for OS/2 not having CPU stats */
  452.             rprintf(r,"]\n %s (",
  453.                 asctime(localtime(&score_record.last_used)));
  454. #else
  455.             rprintf(r,"] u%g s%g cu%g cs%g\n %s (",
  456.                 score_record.times.tms_utime/tick,
  457.                 score_record.times.tms_stime/tick,
  458.                 score_record.times.tms_cutime/tick,
  459.                 score_record.times.tms_cstime/tick,
  460.                 asctime(localtime(&score_record.last_used)));
  461. #endif
  462.             format_byte_out(r,conn_bytes);
  463.             rputs("|",r);
  464.             format_byte_out(r,my_bytes);
  465.             rputs("|",r);
  466.             format_byte_out(r,bytes);
  467.             rputs(")\n",r);
  468.             rprintf(r," <i>%s {%s}</i><br>\n\n",
  469.                 score_record.client, score_record.request);
  470.         }
  471.         else /* !no_table_report */
  472.         {
  473.                 rprintf(r,"<tr><td><b>%d</b><td>%d<td>%d/%lu/%lu",
  474.              i,(int)score_record.pid,(int)conn_lres,my_lres,lres);
  475.  
  476.             switch (score_record.status)
  477.             {
  478.                 case SERVER_READY:
  479.                     rputs("<td>_",r);
  480.                     break;
  481.                 case SERVER_STARTING:
  482.                     rputs("<td><b>S</b>",r);
  483.                     break;
  484.                 case SERVER_BUSY_READ:
  485.                     rputs("<td><b>R</b>",r);
  486.                     break;
  487.                 case SERVER_BUSY_WRITE:
  488.                     rputs("<td><b>W</b>",r);
  489.                     break;
  490.                 case SERVER_BUSY_KEEPALIVE:
  491.                     rputs("<td><b>K</b>",r);
  492.                     break;
  493.                 case SERVER_BUSY_LOG:
  494.                     rputs("<td><b>L</b>",r);
  495.                     break;
  496.                 case SERVER_BUSY_DNS:
  497.                     rputs("<td><b>D</b>",r);
  498.                     break;
  499.                 case SERVER_DEAD:
  500.                     rputs("<td>.",r);
  501.                     break;
  502.             }
  503. #ifdef __EMX__
  504.             /* Allow for OS/2 not having CPU stats */
  505.             rprintf(r,"\n<td>%.0f",
  506.                 difftime(nowtime, score_record.last_used));
  507. #else
  508.             rprintf(r,"\n<td>%.2f<td>%.0f",
  509.                 (score_record.times.tms_utime +
  510.                 score_record.times.tms_stime +
  511.                 score_record.times.tms_cutime +
  512.                 score_record.times.tms_cstime)/tick,
  513.                 difftime(nowtime, score_record.last_used));
  514. #endif
  515.             rprintf(r,"<td>%-1.1f<td>%-2.2f<td>%-2.2f\n",
  516.             (float)conn_bytes/KBYTE, (float)my_bytes/MBYTE,
  517.             (float)bytes/MBYTE);
  518.             rprintf(r,"<td>%s<td nowrap>%s</tr>\n\n",
  519.             score_record.client, score_record.request);
  520.         }   /* no_table_report */
  521.         }       /* !short_report */
  522.     }       /* if (<active child>) */
  523.     }           /* for () */
  524.  
  525.     if (!(short_report || no_table_report))
  526.     {
  527. #ifdef __EMX__
  528. /* Allow for OS/2 not having CPU stats */
  529.     rputs("</table>\n \
  530. <hr> \
  531. <table>\n \
  532. <tr><th>Srv<td>Server number\n \
  533. <tr><th>PID<td>OS process ID\n \
  534. <tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \
  535. <tr><th>M<td>Mode of operation\n \
  536. <tr><th>SS<td>Seconds since beginning of most recent request\n \
  537. <tr><th>Conn<td>Kilobytes transferred this connection\n \
  538. <tr><th>Child<td>Megabytes transferred this child\n \
  539. <tr><th>Slot<td>Total megabytes transferred this slot\n \
  540. </table>\n",r);
  541. #else
  542.     rputs("</table>\n \
  543. <hr> \
  544. <table>\n \
  545. <tr><th>Srv<td>Server number\n \
  546. <tr><th>PID<td>OS process ID\n \
  547. <tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \
  548. <tr><th>M<td>Mode of operation\n \
  549. <tr><th>CPU<td>CPU usage, number of seconds\n \
  550. <tr><th>SS<td>Seconds since beginning of most recent request\n \
  551. <tr><th>Conn<td>Kilobytes transferred this connection\n \
  552. <tr><th>Child<td>Megabytes transferred this child\n \
  553. <tr><th>Slot<td>Total megabytes transferred this slot\n \
  554. </table>\n",r);
  555. #endif
  556.     }
  557.  
  558. #else /* !defined(STATUS) */
  559.  
  560.     rputs("<hr>To obtain a full report with current status information \n",r);
  561.     rputs("you need to recompile Apache adding the <code>-DSTATUS</code> \n",r);
  562.     rputs("directive on the <code>CFLAGS</code> line in the \n",r);
  563.     rputs("<code>Configuration</code> file.\n",r);
  564.     rputs("<code>DNS</code> and <code>LOGGING</code> status \n",r);
  565.     rputs("also requires the <code>-DSTATUS</code> directive. \n",r);
  566.  
  567. #endif /* STATUS */
  568.  
  569.     if (!short_report)
  570.         rputs("</body></html>",r);
  571.     return 0;
  572. }
  573.  
  574. handler_rec status_handlers[] =
  575. {
  576. { STATUS_MAGIC_TYPE, status_handler },
  577. { "server-status", status_handler },
  578. { NULL }
  579. };
  580.  
  581. module status_module =
  582. {
  583.    STANDARD_MODULE_STUFF,
  584.    NULL,            /* initializer */
  585.    NULL,            /* dir config creater */
  586.    NULL,            /* dir merger --- default is to override */
  587.    NULL,            /* server config */
  588.    NULL,            /* merge server config */
  589.    NULL,            /* command table */
  590.    status_handlers,     /* handlers */
  591.    NULL,            /* filename translation */
  592.    NULL,            /* check_user_id */
  593.    NULL,            /* check auth */
  594.    NULL,            /* check access */
  595.    NULL,            /* type_checker */
  596.    NULL,            /* fixups */
  597.    NULL             /* logger */
  598. };
  599.  
  600.