~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/generators/mod_status.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
 
2
 * contributor license agreements.  See the NOTICE file distributed with
 
3
 * this work for additional information regarding copyright ownership.
 
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
5
 * (the "License"); you may not use this file except in compliance with
 
6
 * the License.  You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
/* Status Module.  Display lots of internal data about how Apache is
 
18
 * performing and the state of all children processes.
 
19
 *
 
20
 * To enable this, add the following lines into any config file:
 
21
 *
 
22
 * <Location /server-status>
 
23
 * SetHandler server-status
 
24
 * </Location>
 
25
 *
 
26
 * You may want to protect this location by password or domain so no one
 
27
 * else can look at it.  Then you can access the statistics with a URL like:
 
28
 *
 
29
 * http://your_server_name/server-status
 
30
 *
 
31
 * /server-status - Returns page using tables
 
32
 * /server-status?notable - Returns page for browsers without table support
 
33
 * /server-status?refresh - Returns page with 1 second refresh
 
34
 * /server-status?refresh=6 - Returns page with refresh every 6 seconds
 
35
 * /server-status?auto - Returns page with data for automatic parsing
 
36
 *
 
37
 * Mark Cox, mark@ukweb.com, November 1995
 
38
 *
 
39
 * 12.11.95 Initial version for www.telescope.org
 
40
 * 13.3.96  Updated to remove rprintf's [Mark]
 
41
 * 18.3.96  Added CPU usage, process information, and tidied [Ben Laurie]
 
42
 * 18.3.96  Make extra Scoreboard variables #definable
 
43
 * 25.3.96  Make short report have full precision [Ben Laurie suggested]
 
44
 * 25.3.96  Show uptime better [Mark/Ben Laurie]
 
45
 * 29.3.96  Better HTML and explanation [Mark/Rob Hartill suggested]
 
46
 * 09.4.96  Added message for non-STATUS compiled version
 
47
 * 18.4.96  Added per child and per slot counters [Jim Jagielski]
 
48
 * 01.5.96  Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.]
 
49
 * 18.5.96  Adapted to use new rprintf() routine, incidentally fixing a missing
 
50
 *          piece in short reports [Ben Laurie]
 
51
 * 21.5.96  Additional Status codes (DNS and LOGGING only enabled if
 
52
 *          extended STATUS is enabled) [George Burgyan/Jim J.]
 
53
 * 10.8.98  Allow for extended status info at runtime (no more STATUS)
 
54
 *          [Jim J.]
 
55
 */
 
56
 
 
57
#define CORE_PRIVATE
 
58
#include "httpd.h"
 
59
#include "http_config.h"
 
60
#include "http_core.h"
 
61
#include "http_protocol.h"
 
62
#include "http_main.h"
 
63
#include "ap_mpm.h"
 
64
#include "util_script.h"
 
65
#include <time.h>
 
66
#include "scoreboard.h"
 
67
#include "http_log.h"
 
68
#include "mod_status.h"
 
69
#if APR_HAVE_UNISTD_H
 
70
#include <unistd.h>
 
71
#endif
 
72
#define APR_WANT_STRFUNC
 
73
#include "apr_want.h"
 
74
 
 
75
#ifdef NEXT
 
76
#if (NX_CURRENT_COMPILER_RELEASE == 410)
 
77
#ifdef m68k
 
78
#define HZ 64
 
79
#else
 
80
#define HZ 100
 
81
#endif
 
82
#else
 
83
#include <machine/param.h>
 
84
#endif
 
85
#endif /* NEXT */
 
86
 
 
87
#define STATUS_MAXLINE 64
 
88
 
 
89
#define KBYTE 1024
 
90
#define MBYTE 1048576L
 
91
#define GBYTE 1073741824L
 
92
 
 
93
#ifndef DEFAULT_TIME_FORMAT
 
94
#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
 
95
#endif
 
96
 
 
97
#define STATUS_MAGIC_TYPE "application/x-httpd-status"
 
98
 
 
99
module AP_MODULE_DECLARE_DATA status_module;
 
100
 
 
101
static int server_limit, thread_limit;
 
102
 
 
103
/* Implement 'ap_run_status_hook'. */
 
104
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap, STATUS, int, status_hook,
 
105
                                    (request_rec *r, int flags),
 
106
                                    (r, flags),
 
107
                                    OK, DECLINED)
 
108
 
 
109
#ifdef HAVE_TIMES
 
110
/* ugh... need to know if we're running with a pthread implementation
 
111
 * such as linuxthreads that treats individual threads as distinct
 
112
 * processes; that affects how we add up CPU time in a process
 
113
 */
 
114
static pid_t child_pid;
 
115
#endif
 
116
 
 
117
/*
 
118
 * command-related code. This is here to prevent use of ExtendedStatus
 
119
 * without status_module included.
 
120
 */
 
121
static const char *set_extended_status(cmd_parms *cmd, void *dummy, int arg)
 
122
{
 
123
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
124
    if (err != NULL) {
 
125
        return err;
 
126
    }
 
127
    ap_extended_status = arg;
 
128
    return NULL;
 
129
}
 
130
 
 
131
static const command_rec status_module_cmds[] =
 
132
{
 
133
    AP_INIT_FLAG("ExtendedStatus", set_extended_status, NULL, RSRC_CONF,
 
134
      "\"On\" to enable extended status information, \"Off\" to disable"),
 
135
    {NULL}
 
136
};
 
137
 
 
138
/* Format the number of bytes nicely */
 
139
static void format_byte_out(request_rec *r, apr_off_t bytes)
 
140
{
 
141
    if (bytes < (5 * KBYTE))
 
142
        ap_rprintf(r, "%d B", (int) bytes);
 
143
    else if (bytes < (MBYTE / 2))
 
144
        ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE);
 
145
    else if (bytes < (GBYTE / 2))
 
146
        ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE);
 
147
    else
 
148
        ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE);
 
149
}
 
150
 
 
151
static void format_kbyte_out(request_rec *r, apr_off_t kbytes)
 
152
{
 
153
    if (kbytes < KBYTE)
 
154
        ap_rprintf(r, "%d kB", (int) kbytes);
 
155
    else if (kbytes < MBYTE)
 
156
        ap_rprintf(r, "%.1f MB", (float) kbytes / KBYTE);
 
157
    else
 
158
        ap_rprintf(r, "%.1f GB", (float) kbytes / MBYTE);
 
159
}
 
160
 
 
161
static void show_time(request_rec *r, apr_interval_time_t tsecs)
 
162
{
 
163
    int days, hrs, mins, secs;
 
164
 
 
165
    secs = (int)(tsecs % 60);
 
166
    tsecs /= 60;
 
167
    mins = (int)(tsecs % 60);
 
168
    tsecs /= 60;
 
169
    hrs = (int)(tsecs % 24);
 
170
    days = (int)(tsecs / 24);
 
171
 
 
172
    if (days)
 
173
        ap_rprintf(r, " %d day%s", days, days == 1 ? "" : "s");
 
174
 
 
175
    if (hrs)
 
176
        ap_rprintf(r, " %d hour%s", hrs, hrs == 1 ? "" : "s");
 
177
 
 
178
    if (mins)
 
179
        ap_rprintf(r, " %d minute%s", mins, mins == 1 ? "" : "s");
 
180
 
 
181
    if (secs)
 
182
        ap_rprintf(r, " %d second%s", secs, secs == 1 ? "" : "s");
 
183
}
 
184
 
 
185
/* Main handler for x-httpd-status requests */
 
186
 
 
187
/* ID values for command table */
 
188
 
 
189
#define STAT_OPT_END     -1
 
190
#define STAT_OPT_REFRESH  0
 
191
#define STAT_OPT_NOTABLE  1
 
192
#define STAT_OPT_AUTO     2
 
193
 
 
194
struct stat_opt {
 
195
    int id;
 
196
    const char *form_data_str;
 
197
    const char *hdr_out_str;
 
198
};
 
199
 
 
200
static const struct stat_opt status_options[] = /* see #defines above */
 
201
{
 
202
    {STAT_OPT_REFRESH, "refresh", "Refresh"},
 
203
    {STAT_OPT_NOTABLE, "notable", NULL},
 
204
    {STAT_OPT_AUTO, "auto", NULL},
 
205
    {STAT_OPT_END, NULL, NULL}
 
206
};
 
207
 
 
208
static char status_flags[SERVER_NUM_STATUS];
 
209
 
 
210
static int status_handler(request_rec *r)
 
211
{
 
212
    const char *loc;
 
213
    apr_time_t nowtime;
 
214
    apr_interval_time_t up_time;
 
215
    int j, i, res;
 
216
    int ready;
 
217
    int busy;
 
218
    unsigned long count;
 
219
    unsigned long lres, my_lres, conn_lres;
 
220
    apr_off_t bytes, my_bytes, conn_bytes;
 
221
    apr_off_t bcount, kbcount;
 
222
    long req_time;
 
223
#ifdef HAVE_TIMES
 
224
    float tick;
 
225
    int times_per_thread = getpid() != child_pid;
 
226
#endif
 
227
    int short_report;
 
228
    int no_table_report;
 
229
    worker_score *ws_record;
 
230
    process_score *ps_record;
 
231
    char *stat_buffer;
 
232
    pid_t *pid_buffer, worker_pid;
 
233
    clock_t tu, ts, tcu, tcs;
 
234
    ap_generation_t worker_generation;
 
235
 
 
236
    if (strcmp(r->handler, STATUS_MAGIC_TYPE) &&
 
237
        strcmp(r->handler, "server-status")) {
 
238
        return DECLINED;
 
239
    }
 
240
 
 
241
#ifdef HAVE_TIMES
 
242
#ifdef _SC_CLK_TCK
 
243
    tick = sysconf(_SC_CLK_TCK);
 
244
#else
 
245
    tick = HZ;
 
246
#endif
 
247
#endif
 
248
 
 
249
    ready = 0;
 
250
    busy = 0;
 
251
    count = 0;
 
252
    bcount = 0;
 
253
    kbcount = 0;
 
254
    short_report = 0;
 
255
    no_table_report = 0;
 
256
 
 
257
    pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t));
 
258
    stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
 
259
 
 
260
    nowtime = apr_time_now();
 
261
    tu = ts = tcu = tcs = 0;
 
262
 
 
263
    if (!ap_exists_scoreboard_image()) {
 
264
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
265
                      "Server status unavailable in inetd mode");
 
266
        return HTTP_INTERNAL_SERVER_ERROR;
 
267
    }
 
268
 
 
269
    r->allowed = (AP_METHOD_BIT << M_GET);
 
270
    if (r->method_number != M_GET)
 
271
        return DECLINED;
 
272
 
 
273
    ap_set_content_type(r, "text/html");
 
274
 
 
275
    /*
 
276
     * Simple table-driven form data set parser that lets you alter the header
 
277
     */
 
278
 
 
279
    if (r->args) {
 
280
        i = 0;
 
281
        while (status_options[i].id != STAT_OPT_END) {
 
282
            if ((loc = ap_strstr_c(r->args,
 
283
                                   status_options[i].form_data_str)) != NULL) {
 
284
                switch (status_options[i].id) {
 
285
                case STAT_OPT_REFRESH:
 
286
                    if (*(loc + strlen(status_options[i].form_data_str)) == '='
 
287
                        && atol(loc + strlen(status_options[i].form_data_str)
 
288
                                + 1) > 0)
 
289
                        apr_table_set(r->headers_out,
 
290
                                      status_options[i].hdr_out_str,
 
291
                                      loc +
 
292
                                      strlen(status_options[i].hdr_out_str) +
 
293
                                      1);
 
294
                    else
 
295
                        apr_table_set(r->headers_out,
 
296
                                      status_options[i].hdr_out_str, "1");
 
297
                    break;
 
298
                case STAT_OPT_NOTABLE:
 
299
                    no_table_report = 1;
 
300
                    break;
 
301
                case STAT_OPT_AUTO:
 
302
                    ap_set_content_type(r, "text/plain");
 
303
                    short_report = 1;
 
304
                    break;
 
305
                }
 
306
            }
 
307
 
 
308
            i++;
 
309
        }
 
310
    }
 
311
 
 
312
    for (i = 0; i < server_limit; ++i) {
 
313
#ifdef HAVE_TIMES
 
314
        clock_t proc_tu = 0, proc_ts = 0, proc_tcu = 0, proc_tcs = 0;
 
315
        clock_t tmp_tu, tmp_ts, tmp_tcu, tmp_tcs;
 
316
#endif
 
317
 
 
318
        ps_record = ap_get_scoreboard_process(i);
 
319
        for (j = 0; j < thread_limit; ++j) {
 
320
            int indx = (i * thread_limit) + j;
 
321
 
 
322
            ws_record = ap_get_scoreboard_worker(i, j);
 
323
            res = ws_record->status;
 
324
            stat_buffer[indx] = status_flags[res];
 
325
 
 
326
            if (!ps_record->quiescing
 
327
                && ps_record->pid) {
 
328
                if (res == SERVER_READY
 
329
                    && ps_record->generation == ap_my_generation)
 
330
                    ready++;
 
331
                else if (res != SERVER_DEAD &&
 
332
                         res != SERVER_STARTING &&
 
333
                         res != SERVER_IDLE_KILL)
 
334
                    busy++;
 
335
            }
 
336
 
 
337
            /* XXX what about the counters for quiescing/seg faulted
 
338
             * processes?  should they be counted or not?  GLA
 
339
             */
 
340
            if (ap_extended_status) {
 
341
                lres = ws_record->access_count;
 
342
                bytes = ws_record->bytes_served;
 
343
 
 
344
                if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) {
 
345
#ifdef HAVE_TIMES
 
346
                    tmp_tu = ws_record->times.tms_utime;
 
347
                    tmp_ts = ws_record->times.tms_stime;
 
348
                    tmp_tcu = ws_record->times.tms_cutime;
 
349
                    tmp_tcs = ws_record->times.tms_cstime;
 
350
 
 
351
                    if (times_per_thread) {
 
352
                        proc_tu += tmp_tu;
 
353
                        proc_ts += tmp_ts;
 
354
                        proc_tcu += tmp_tcu;
 
355
                        proc_tcs += proc_tcs;
 
356
                    }
 
357
                    else {
 
358
                        if (tmp_tu > proc_tu ||
 
359
                            tmp_ts > proc_ts ||
 
360
                            tmp_tcu > proc_tcu ||
 
361
                            tmp_tcs > proc_tcs) {
 
362
                            proc_tu = tmp_tu;
 
363
                            proc_ts = tmp_ts;
 
364
                            proc_tcu = tmp_tcu;
 
365
                            proc_tcs = proc_tcs;
 
366
                        }
 
367
                    }
 
368
#endif /* HAVE_TIMES */
 
369
 
 
370
                    count += lres;
 
371
                    bcount += bytes;
 
372
 
 
373
                    if (bcount >= KBYTE) {
 
374
                        kbcount += (bcount >> 10);
 
375
                        bcount = bcount & 0x3ff;
 
376
                    }
 
377
                }
 
378
            }
 
379
        }
 
380
#ifdef HAVE_TIMES
 
381
        tu += proc_tu;
 
382
        ts += proc_ts;
 
383
        tcu += proc_tcu;
 
384
        tcs += proc_tcs;
 
385
#endif
 
386
        pid_buffer[i] = ps_record->pid;
 
387
    }
 
388
 
 
389
    /* up_time in seconds */
 
390
    up_time = (apr_uint32_t) apr_time_sec(nowtime -
 
391
                               ap_scoreboard_image->global->restart_time);
 
392
 
 
393
    if (!short_report) {
 
394
        ap_rputs(DOCTYPE_HTML_3_2
 
395
                 "<html><head>\n<title>Apache Status</title>\n</head><body>\n",
 
396
                 r);
 
397
        ap_rputs("<h1>Apache Server Status for ", r);
 
398
        ap_rvputs(r, ap_get_server_name(r), "</h1>\n\n", NULL);
 
399
        ap_rvputs(r, "<dl><dt>Server Version: ",
 
400
                  ap_get_server_version(), "</dt>\n", NULL);
 
401
        ap_rvputs(r, "<dt>Server Built: ",
 
402
                  ap_get_server_built(), "\n</dt></dl><hr /><dl>\n", NULL);
 
403
        ap_rvputs(r, "<dt>Current Time: ",
 
404
                  ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0),
 
405
                             "</dt>\n", NULL);
 
406
        ap_rvputs(r, "<dt>Restart Time: ",
 
407
                  ap_ht_time(r->pool,
 
408
                             ap_scoreboard_image->global->restart_time,
 
409
                             DEFAULT_TIME_FORMAT, 0),
 
410
                  "</dt>\n", NULL);
 
411
        ap_rprintf(r, "<dt>Parent Server Generation: %d</dt>\n",
 
412
                   (int)ap_my_generation);
 
413
        ap_rputs("<dt>Server uptime: ", r);
 
414
        show_time(r, up_time);
 
415
        ap_rputs("</dt>\n", r);
 
416
    }
 
417
 
 
418
    if (ap_extended_status) {
 
419
        if (short_report) {
 
420
            ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %"
 
421
                       APR_OFF_T_FMT "\n",
 
422
                       count, kbcount);
 
423
 
 
424
#ifdef HAVE_TIMES
 
425
            /* Allow for OS/2 not having CPU stats */
 
426
            if (ts || tu || tcu || tcs)
 
427
                ap_rprintf(r, "CPULoad: %g\n",
 
428
                           (tu + ts + tcu + tcs) / tick / up_time * 100.);
 
429
#endif
 
430
 
 
431
            ap_rprintf(r, "Uptime: %ld\n", (long) (up_time));
 
432
            if (up_time > 0)
 
433
                ap_rprintf(r, "ReqPerSec: %g\n",
 
434
                           (float) count / (float) up_time);
 
435
 
 
436
            if (up_time > 0)
 
437
                ap_rprintf(r, "BytesPerSec: %g\n",
 
438
                           KBYTE * (float) kbcount / (float) up_time);
 
439
 
 
440
            if (count > 0)
 
441
                ap_rprintf(r, "BytesPerReq: %g\n",
 
442
                           KBYTE * (float) kbcount / (float) count);
 
443
        }
 
444
        else { /* !short_report */
 
445
            ap_rprintf(r, "<dt>Total accesses: %lu - Total Traffic: ", count);
 
446
            format_kbyte_out(r, kbcount);
 
447
            ap_rputs("</dt>\n", r);
 
448
 
 
449
#ifdef HAVE_TIMES
 
450
            /* Allow for OS/2 not having CPU stats */
 
451
            ap_rprintf(r, "<dt>CPU Usage: u%g s%g cu%g cs%g",
 
452
                       tu / tick, ts / tick, tcu / tick, tcs / tick);
 
453
 
 
454
            if (ts || tu || tcu || tcs)
 
455
                ap_rprintf(r, " - %.3g%% CPU load</dt>\n",
 
456
                           (tu + ts + tcu + tcs) / tick / up_time * 100.);
 
457
#endif
 
458
 
 
459
            if (up_time > 0)
 
460
                ap_rprintf(r, "<dt>%.3g requests/sec - ",
 
461
                           (float) count / (float) up_time);
 
462
 
 
463
            if (up_time > 0) {
 
464
                format_byte_out(r, (unsigned long)(KBYTE * (float) kbcount
 
465
                                                   / (float) up_time));
 
466
                ap_rputs("/second - ", r);
 
467
            }
 
468
 
 
469
            if (count > 0) {
 
470
                format_byte_out(r, (unsigned long)(KBYTE * (float) kbcount
 
471
                                                   / (float) count));
 
472
                ap_rputs("/request", r);
 
473
            }
 
474
 
 
475
            ap_rputs("</dt>\n", r);
 
476
        } /* short_report */
 
477
    } /* ap_extended_status */
 
478
 
 
479
    if (!short_report)
 
480
        ap_rprintf(r, "<dt>%d requests currently being processed, "
 
481
                      "%d idle workers</dt>\n", busy, ready);
 
482
    else
 
483
        ap_rprintf(r, "BusyWorkers: %d\nIdleWorkers: %d\n", busy, ready);
 
484
 
 
485
    /* send the scoreboard 'table' out */
 
486
    if (!short_report)
 
487
        ap_rputs("</dl><pre>", r);
 
488
    else
 
489
        ap_rputs("Scoreboard: ", r);
 
490
 
 
491
    for (i = 0; i < server_limit; ++i) {
 
492
        for (j = 0; j < thread_limit; ++j) {
 
493
            int indx = (i * thread_limit) + j;
 
494
            ap_rputc(stat_buffer[indx], r);
 
495
            if ((indx % STATUS_MAXLINE == (STATUS_MAXLINE - 1))
 
496
                && !short_report)
 
497
                ap_rputs("\n", r);
 
498
        }
 
499
    }
 
500
 
 
501
    if (short_report)
 
502
        ap_rputs("\n", r);
 
503
    else {
 
504
        ap_rputs("</pre>\n", r);
 
505
        ap_rputs("<p>Scoreboard Key:<br />\n", r);
 
506
        ap_rputs("\"<b><code>_</code></b>\" Waiting for Connection, \n", r);
 
507
        ap_rputs("\"<b><code>S</code></b>\" Starting up, \n", r);
 
508
        ap_rputs("\"<b><code>R</code></b>\" Reading Request,<br />\n", r);
 
509
        ap_rputs("\"<b><code>W</code></b>\" Sending Reply, \n", r);
 
510
        ap_rputs("\"<b><code>K</code></b>\" Keepalive (read), \n", r);
 
511
        ap_rputs("\"<b><code>D</code></b>\" DNS Lookup,<br />\n", r);
 
512
        ap_rputs("\"<b><code>C</code></b>\" Closing connection, \n", r);
 
513
        ap_rputs("\"<b><code>L</code></b>\" Logging, \n", r);
 
514
        ap_rputs("\"<b><code>G</code></b>\" Gracefully finishing,<br /> \n", r);
 
515
        ap_rputs("\"<b><code>I</code></b>\" Idle cleanup of worker, \n", r);
 
516
        ap_rputs("\"<b><code>.</code></b>\" Open slot with no current process</p>\n", r);
 
517
        ap_rputs("<p />\n", r);
 
518
        if (!ap_extended_status) {
 
519
            int j;
 
520
            int k = 0;
 
521
            ap_rputs("PID Key: <br />\n", r);
 
522
            ap_rputs("<pre>\n", r);
 
523
            for (i = 0; i < server_limit; ++i) {
 
524
                for (j = 0; j < thread_limit; ++j) {
 
525
                    int indx = (i * thread_limit) + j;
 
526
 
 
527
                    if (stat_buffer[indx] != '.') {
 
528
                        ap_rprintf(r, "   %" APR_PID_T_FMT
 
529
                                   " in state: %c ", pid_buffer[i],
 
530
                                   stat_buffer[indx]);
 
531
 
 
532
                        if (++k >= 3) {
 
533
                            ap_rputs("\n", r);
 
534
                            k = 0;
 
535
                        } else
 
536
                            ap_rputs(",", r);
 
537
                    }
 
538
                }
 
539
            }
 
540
 
 
541
            ap_rputs("\n", r);
 
542
            ap_rputs("</pre>\n", r);
 
543
        }
 
544
    }
 
545
 
 
546
    if (ap_extended_status && !short_report) {
 
547
        if (no_table_report)
 
548
            ap_rputs("<hr /><h2>Server Details</h2>\n\n", r);
 
549
        else
 
550
            ap_rputs("\n\n<table border=\"0\"><tr>"
 
551
                     "<th>Srv</th><th>PID</th><th>Acc</th>"
 
552
                     "<th>M</th>"
 
553
#ifdef HAVE_TIMES
 
554
                     "<th>CPU\n</th>"
 
555
#endif
 
556
                     "<th>SS</th><th>Req</th>"
 
557
                     "<th>Conn</th><th>Child</th><th>Slot</th>"
 
558
                     "<th>Client</th><th>VHost</th>"
 
559
                     "<th>Request</th></tr>\n\n", r);
 
560
 
 
561
        for (i = 0; i < server_limit; ++i) {
 
562
            for (j = 0; j < thread_limit; ++j) {
 
563
                ws_record = ap_get_scoreboard_worker(i, j);
 
564
 
 
565
                if (ws_record->access_count == 0 &&
 
566
                    (ws_record->status == SERVER_READY ||
 
567
                     ws_record->status == SERVER_DEAD)) {
 
568
                    continue;
 
569
                }
 
570
 
 
571
                ps_record = ap_get_scoreboard_process(i);
 
572
 
 
573
                if (ws_record->start_time == 0L)
 
574
                    req_time = 0L;
 
575
                else
 
576
                    req_time = (long)
 
577
                        ((ws_record->stop_time -
 
578
                          ws_record->start_time) / 1000);
 
579
                if (req_time < 0L)
 
580
                    req_time = 0L;
 
581
 
 
582
                lres = ws_record->access_count;
 
583
                my_lres = ws_record->my_access_count;
 
584
                conn_lres = ws_record->conn_count;
 
585
                bytes = ws_record->bytes_served;
 
586
                my_bytes = ws_record->my_bytes_served;
 
587
                conn_bytes = ws_record->conn_bytes;
 
588
                if (ws_record->pid) { /* MPM sets per-worker pid and generation */
 
589
                    worker_pid = ws_record->pid;
 
590
                    worker_generation = ws_record->generation;
 
591
                }
 
592
                else {
 
593
                    worker_pid = ps_record->pid;
 
594
                    worker_generation = ps_record->generation;
 
595
                }
 
596
 
 
597
                if (no_table_report) {
 
598
                    if (ws_record->status == SERVER_DEAD)
 
599
                        ap_rprintf(r,
 
600
                                   "<b>Server %d-%d</b> (-): %d|%lu|%lu [",
 
601
                                   i, (int)worker_generation,
 
602
                                   (int)conn_lres, my_lres, lres);
 
603
                    else
 
604
                        ap_rprintf(r,
 
605
                                   "<b>Server %d-%d</b> (%"
 
606
                                   APR_PID_T_FMT "): %d|%lu|%lu [",
 
607
                                   i, (int) worker_generation,
 
608
                                   worker_pid,
 
609
                                   (int)conn_lres, my_lres, lres);
 
610
 
 
611
                    switch (ws_record->status) {
 
612
                    case SERVER_READY:
 
613
                        ap_rputs("Ready", r);
 
614
                        break;
 
615
                    case SERVER_STARTING:
 
616
                        ap_rputs("Starting", r);
 
617
                        break;
 
618
                    case SERVER_BUSY_READ:
 
619
                        ap_rputs("<b>Read</b>", r);
 
620
                        break;
 
621
                    case SERVER_BUSY_WRITE:
 
622
                        ap_rputs("<b>Write</b>", r);
 
623
                        break;
 
624
                    case SERVER_BUSY_KEEPALIVE:
 
625
                        ap_rputs("<b>Keepalive</b>", r);
 
626
                        break;
 
627
                    case SERVER_BUSY_LOG:
 
628
                        ap_rputs("<b>Logging</b>", r);
 
629
                        break;
 
630
                    case SERVER_BUSY_DNS:
 
631
                        ap_rputs("<b>DNS lookup</b>", r);
 
632
                        break;
 
633
                    case SERVER_CLOSING:
 
634
                        ap_rputs("<b>Closing</b>", r);
 
635
                        break;
 
636
                    case SERVER_DEAD:
 
637
                        ap_rputs("Dead", r);
 
638
                        break;
 
639
                    case SERVER_GRACEFUL:
 
640
                        ap_rputs("Graceful", r);
 
641
                        break;
 
642
                    case SERVER_IDLE_KILL:
 
643
                        ap_rputs("Dying", r);
 
644
                        break;
 
645
                    default:
 
646
                        ap_rputs("?STATE?", r);
 
647
                        break;
 
648
                    }
 
649
 
 
650
                    ap_rprintf(r, "] "
 
651
#ifdef HAVE_TIMES
 
652
                               "u%g s%g cu%g cs%g"
 
653
#endif
 
654
                               "\n %ld %ld (",
 
655
#ifdef HAVE_TIMES
 
656
                               ws_record->times.tms_utime / tick,
 
657
                               ws_record->times.tms_stime / tick,
 
658
                               ws_record->times.tms_cutime / tick,
 
659
                               ws_record->times.tms_cstime / tick,
 
660
#endif
 
661
                               (long)apr_time_sec(nowtime -
 
662
                                                  ws_record->last_used),
 
663
                               (long) req_time);
 
664
 
 
665
                    format_byte_out(r, conn_bytes);
 
666
                    ap_rputs("|", r);
 
667
                    format_byte_out(r, my_bytes);
 
668
                    ap_rputs("|", r);
 
669
                    format_byte_out(r, bytes);
 
670
                    ap_rputs(")\n", r);
 
671
                    ap_rprintf(r,
 
672
                               " <i>%s {%s}</i> <b>[%s]</b><br />\n\n",
 
673
                               ap_escape_html(r->pool,
 
674
                                              ws_record->client),
 
675
                               ap_escape_html(r->pool,
 
676
                                              ws_record->request),
 
677
                               ap_escape_html(r->pool,
 
678
                                              ws_record->vhost));
 
679
                }
 
680
                else { /* !no_table_report */
 
681
                    if (ws_record->status == SERVER_DEAD)
 
682
                        ap_rprintf(r,
 
683
                                   "<tr><td><b>%d-%d</b></td><td>-</td><td>%d/%lu/%lu",
 
684
                                   i, (int)worker_generation,
 
685
                                   (int)conn_lres, my_lres, lres);
 
686
                    else
 
687
                        ap_rprintf(r,
 
688
                                   "<tr><td><b>%d-%d</b></td><td>%"
 
689
                                   APR_PID_T_FMT
 
690
                                   "</td><td>%d/%lu/%lu",
 
691
                                   i, (int)worker_generation,
 
692
                                   worker_pid,
 
693
                                   (int)conn_lres,
 
694
                                   my_lres, lres);
 
695
 
 
696
                    switch (ws_record->status) {
 
697
                    case SERVER_READY:
 
698
                        ap_rputs("</td><td>_", r);
 
699
                        break;
 
700
                    case SERVER_STARTING:
 
701
                        ap_rputs("</td><td><b>S</b>", r);
 
702
                        break;
 
703
                    case SERVER_BUSY_READ:
 
704
                        ap_rputs("</td><td><b>R</b>", r);
 
705
                        break;
 
706
                    case SERVER_BUSY_WRITE:
 
707
                        ap_rputs("</td><td><b>W</b>", r);
 
708
                        break;
 
709
                    case SERVER_BUSY_KEEPALIVE:
 
710
                        ap_rputs("</td><td><b>K</b>", r);
 
711
                        break;
 
712
                    case SERVER_BUSY_LOG:
 
713
                        ap_rputs("</td><td><b>L</b>", r);
 
714
                        break;
 
715
                    case SERVER_BUSY_DNS:
 
716
                        ap_rputs("</td><td><b>D</b>", r);
 
717
                        break;
 
718
                    case SERVER_CLOSING:
 
719
                        ap_rputs("</td><td><b>C</b>", r);
 
720
                        break;
 
721
                    case SERVER_DEAD:
 
722
                        ap_rputs("</td><td>.", r);
 
723
                        break;
 
724
                    case SERVER_GRACEFUL:
 
725
                        ap_rputs("</td><td>G", r);
 
726
                        break;
 
727
                    case SERVER_IDLE_KILL:
 
728
                        ap_rputs("</td><td>I", r);
 
729
                        break;
 
730
                    default:
 
731
                        ap_rputs("</td><td>?", r);
 
732
                        break;
 
733
                    }
 
734
 
 
735
                    ap_rprintf(r,
 
736
                               "\n</td>"
 
737
#ifdef HAVE_TIMES
 
738
                               "<td>%.2f</td>"
 
739
#endif
 
740
                               "<td>%ld</td><td>%ld",
 
741
#ifdef HAVE_TIMES
 
742
                               (ws_record->times.tms_utime +
 
743
                                ws_record->times.tms_stime +
 
744
                                ws_record->times.tms_cutime +
 
745
                                ws_record->times.tms_cstime) / tick,
 
746
#endif
 
747
                               (long)apr_time_sec(nowtime -
 
748
                                                  ws_record->last_used),
 
749
                               (long)req_time);
 
750
 
 
751
                    ap_rprintf(r, "</td><td>%-1.1f</td><td>%-2.2f</td><td>%-2.2f\n",
 
752
                               (float)conn_bytes / KBYTE, (float) my_bytes / MBYTE,
 
753
                               (float)bytes / MBYTE);
 
754
 
 
755
                    if (ws_record->status == SERVER_BUSY_READ)
 
756
                        ap_rprintf(r,
 
757
                                   "</td><td>?</td><td nowrap>?</td><td nowrap>..reading.. </td></tr>\n\n");
 
758
                    else
 
759
                        ap_rprintf(r,
 
760
                                   "</td><td>%s</td><td nowrap>%s</td><td nowrap>%s</td></tr>\n\n",
 
761
                                   ap_escape_html(r->pool,
 
762
                                                  ws_record->client),
 
763
                                   ap_escape_html(r->pool,
 
764
                                                  ws_record->vhost),
 
765
                                   ap_escape_html(r->pool,
 
766
                                                  ws_record->request));
 
767
                } /* no_table_report */
 
768
            } /* for (j...) */
 
769
        } /* for (i...) */
 
770
 
 
771
        if (!no_table_report) {
 
772
            ap_rputs("</table>\n \
 
773
<hr /> \
 
774
<table>\n \
 
775
<tr><th>Srv</th><td>Child Server number - generation</td></tr>\n \
 
776
<tr><th>PID</th><td>OS process ID</td></tr>\n \
 
777
<tr><th>Acc</th><td>Number of accesses this connection / this child / this slot</td></tr>\n \
 
778
<tr><th>M</th><td>Mode of operation</td></tr>\n"
 
779
 
 
780
#ifdef HAVE_TIMES
 
781
"<tr><th>CPU</th><td>CPU usage, number of seconds</td></tr>\n"
 
782
#endif
 
783
 
 
784
"<tr><th>SS</th><td>Seconds since beginning of most recent request</td></tr>\n \
 
785
<tr><th>Req</th><td>Milliseconds required to process most recent request</td></tr>\n \
 
786
<tr><th>Conn</th><td>Kilobytes transferred this connection</td></tr>\n \
 
787
<tr><th>Child</th><td>Megabytes transferred this child</td></tr>\n \
 
788
<tr><th>Slot</th><td>Total megabytes transferred this slot</td></tr>\n \
 
789
</table>\n", r);
 
790
        }
 
791
    } /* if (ap_extended_status && !short_report) */
 
792
    else {
 
793
 
 
794
        if (!short_report) {
 
795
            ap_rputs("<hr />To obtain a full report with current status "
 
796
                     "information you need to use the "
 
797
                     "<code>ExtendedStatus On</code> directive.\n", r);
 
798
        }
 
799
    }
 
800
 
 
801
    {
 
802
        /* Run extension hooks to insert extra content. */
 
803
        int flags =
 
804
            (short_report ? AP_STATUS_SHORT : 0) |
 
805
            (no_table_report ? AP_STATUS_NOTABLE : 0) |
 
806
            (ap_extended_status ? AP_STATUS_EXTENDED : 0);
 
807
 
 
808
        ap_run_status_hook(r, flags);
 
809
    }
 
810
 
 
811
    if (!short_report) {
 
812
        ap_rputs(ap_psignature("<hr />\n",r), r);
 
813
        ap_rputs("</body></html>\n", r);
 
814
    }
 
815
 
 
816
    return 0;
 
817
}
 
818
 
 
819
 
 
820
static int status_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
 
821
                       server_rec *s)
 
822
{
 
823
    status_flags[SERVER_DEAD] = '.';  /* We don't want to assume these are in */
 
824
    status_flags[SERVER_READY] = '_'; /* any particular order in scoreboard.h */
 
825
    status_flags[SERVER_STARTING] = 'S';
 
826
    status_flags[SERVER_BUSY_READ] = 'R';
 
827
    status_flags[SERVER_BUSY_WRITE] = 'W';
 
828
    status_flags[SERVER_BUSY_KEEPALIVE] = 'K';
 
829
    status_flags[SERVER_BUSY_LOG] = 'L';
 
830
    status_flags[SERVER_BUSY_DNS] = 'D';
 
831
    status_flags[SERVER_CLOSING] = 'C';
 
832
    status_flags[SERVER_GRACEFUL] = 'G';
 
833
    status_flags[SERVER_IDLE_KILL] = 'I';
 
834
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
 
835
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
 
836
    return OK;
 
837
}
 
838
 
 
839
#ifdef HAVE_TIMES
 
840
static void status_child_init(apr_pool_t *p, server_rec *s)
 
841
{
 
842
    child_pid = getpid();
 
843
}
 
844
#endif
 
845
 
 
846
static void register_hooks(apr_pool_t *p)
 
847
{
 
848
    ap_hook_handler(status_handler, NULL, NULL, APR_HOOK_MIDDLE);
 
849
    ap_hook_post_config(status_init, NULL, NULL, APR_HOOK_MIDDLE);
 
850
#ifdef HAVE_TIMES
 
851
    ap_hook_child_init(status_child_init, NULL, NULL, APR_HOOK_MIDDLE);
 
852
#endif
 
853
}
 
854
 
 
855
module AP_MODULE_DECLARE_DATA status_module =
 
856
{
 
857
    STANDARD20_MODULE_STUFF,
 
858
    NULL,                       /* dir config creater */
 
859
    NULL,                       /* dir merger --- default is to override */
 
860
    NULL,                       /* server config */
 
861
    NULL,                       /* merge server config */
 
862
    status_module_cmds,         /* command table */
 
863
    register_hooks              /* register_hooks */
 
864
};
 
865