View | Details | Raw Unified | Return to bug 54339
Collapse All | Expand All

(-)a/docs/manual/logs.xml (+20 lines)
Lines 614-619 CustomLog "|$/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" commo Link Here
614
    "<code>||</code>" is also supported and equivalent to using
614
    "<code>||</code>" is also supported and equivalent to using
615
    "<code>|</code>".</p>
615
    "<code>|</code>".</p>
616
616
617
    <p>Depending on your OS, there may be a pipe buffer size limit
618
    for safe, atomic writes to a pipe. Log records that exceed that
619
    buffer limit may be interleaved and corrupted.
620
    Use "<code>|&lt;</code>" (mnemonic, split pipe) to split log
621
    records across the pipe so they may be reassembled by the piped
622
    program to preserve their integrity. The program receiving the
623
    records must know how to reassemble the records, and currently,
624
    rotatelogs supports this. When used, a variable
625
    (AP_MOD_LOG_CONFIG_CHUNKED_MSG) is exported to the environment
626
    so the receiving program can take appropriate action. This option
627
    may be used in conjunction with the shell option
628
    <code>|&lt;$</code>" (or for compatibility "<code>||&lt;</code>").
629
    This option is not available for ErrorLog directives and if
630
    present, a warning will be emitted.</p>
631
632
    <highlight language="config">
633
# Invoke "rotatelogs" with a safe (atomic split) pipe
634
CustomLog "|&lt;/usr/local/apache/bin/rotatelogs   /var/log/access_log 86400" common
635
    </highlight>
636
617
    <note><title>Windows note</title>
637
    <note><title>Windows note</title>
618
    <p>Note that on Windows, you may run into problems when running many piped
638
    <p>Note that on Windows, you may run into problems when running many piped
619
    logger processes, especially when HTTPD is running as a service. This is
639
    logger processes, especially when HTTPD is running as a service. This is
(-)a/docs/manual/mod/mod_log_config.xml (-1 / +2 lines)
Lines 442-448 expr=<var>expression</var>]</syntax> Link Here
442
      >ServerRoot</directive>.</dd>
442
      >ServerRoot</directive>.</dd>
443
443
444
      <dt><var>pipe</var></dt>
444
      <dt><var>pipe</var></dt>
445
      <dd>The pipe character "<code>|</code>", followed by the path
445
      <dd>The pipe character "<code>|</code>" (or safe pipe
446
      "<code>|&lt;</code>"), followed by the path
446
      to a program to receive the log information on its standard
447
      to a program to receive the log information on its standard
447
      input. See the notes on <a href="../logs.html#piped">piped logs</a>
448
      input. See the notes on <a href="../logs.html#piped">piped logs</a>
448
      for more information.
449
      for more information.
(-)a/include/http_log.h (+19 lines)
Lines 282-287 AP_DECLARE_DATA extern int ap_default_loglevel; Link Here
282
 */
282
 */
283
#define APLOG_MARK     __FILE__,__LINE__,APLOG_MODULE_INDEX
283
#define APLOG_MARK     __FILE__,__LINE__,APLOG_MODULE_INDEX
284
284
285
/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
286
 * guaranteed to be atomic when writing a pipe.  And PIPE_BUF >= 512
287
 * is guaranteed.  So we'll just guess 512 in the event the system
288
 * doesn't have this.  Now, for file writes there is actually no limit,
289
 * the entire write is atomic.  Whether all systems implement this
290
 * correctly is another question entirely ... so we'll just use PIPE_BUF
291
 * because it's probably a good guess as to what is implemented correctly
292
 * everywhere.
293
 */
294
#ifdef PIPE_BUF
295
#define LOG_BUFSIZE     PIPE_BUF
296
#else
297
#define LOG_BUFSIZE     (512)
298
#endif
299
300
#define MSG_HEADER_ELT_CNT 5
301
#define MSG_HEADER_LEN (sizeof(uint32_t) * MSG_HEADER_ELT_CNT)
302
#define LOG_BUFSIZE_LESS_CHUNKHEAD (LOG_BUFSIZE - MSG_HEADER_LEN)
303
285
/**
304
/**
286
 * Set up for logging to stderr.
305
 * Set up for logging to stderr.
287
 * @param p The pool to allocate out of
306
 * @param p The pool to allocate out of
(-)a/include/scoreboard.h (+4 lines)
Lines 157-162 typedef struct { Link Here
157
} scoreboard;
157
} scoreboard;
158
158
159
typedef struct ap_sb_handle_t ap_sb_handle_t;
159
typedef struct ap_sb_handle_t ap_sb_handle_t;
160
struct ap_sb_handle_t {
161
    int child_num;
162
    int thread_num;
163
};
160
164
161
/*
165
/*
162
 * Creation and deletion (internal)
166
 * Creation and deletion (internal)
(-)a/modules/loggers/mod_log_config.c (-45 / +166 lines)
Lines 151-158 Link Here
151
#include "apr_hash.h"
151
#include "apr_hash.h"
152
#include "apr_optional.h"
152
#include "apr_optional.h"
153
#include "apr_anylock.h"
153
#include "apr_anylock.h"
154
#include "apr_env.h"
154
155
155
#define APR_WANT_STRFUNC
156
#define APR_WANT_STRFUNC
157
#define APR_WANT_BYTEFUNC   /* for htons() et al */
156
#include "apr_want.h"
158
#include "apr_want.h"
157
159
158
#include "ap_config.h"
160
#include "ap_config.h"
Lines 164-169 Link Here
164
#include "http_protocol.h"
166
#include "http_protocol.h"
165
#include "util_time.h"
167
#include "util_time.h"
166
#include "ap_mpm.h"
168
#include "ap_mpm.h"
169
#include "scoreboard.h"
167
170
168
#if APR_HAVE_UNISTD_H
171
#if APR_HAVE_UNISTD_H
169
#include <unistd.h>
172
#include <unistd.h>
Lines 177-201 Link Here
177
module AP_MODULE_DECLARE_DATA log_config_module;
180
module AP_MODULE_DECLARE_DATA log_config_module;
178
181
179
182
183
typedef struct {
184
    apr_file_t *handle;
185
    apr_size_t outcnt;
186
    char outbuf[LOG_BUFSIZE];
187
    apr_anylock_t mutex;
188
} buffered_log;
189
180
static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
190
static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
181
static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
191
static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
182
static apr_hash_t *log_hash;
192
static apr_hash_t *log_hash;
193
static apr_status_t write_atomic_pipe_chunks(request_rec *r,
194
                           void *handle,
195
                           const char *str,
196
                           apr_size_t len,
197
                           buffered_log *buf);
183
static apr_status_t ap_default_log_writer(request_rec *r,
198
static apr_status_t ap_default_log_writer(request_rec *r,
184
                           void *handle,
199
                           void *handle,
185
                           const char **strs,
200
                           const char **strs,
186
                           int *strl,
201
                           int *strl,
187
                           int nelts,
202
                           int nelts,
188
                           apr_size_t len);
203
                           apr_size_t len,
204
                           int chunk_msgs);
189
static apr_status_t ap_buffered_log_writer(request_rec *r,
205
static apr_status_t ap_buffered_log_writer(request_rec *r,
190
                           void *handle,
206
                           void *handle,
191
                           const char **strs,
207
                           const char **strs,
192
                           int *strl,
208
                           int *strl,
193
                           int nelts,
209
                           int nelts,
194
                           apr_size_t len);
210
                           apr_size_t len,
211
                           int chunk_msgs);
195
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
212
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
196
                                        const char* name);
213
                                        config_log_state* cls);
197
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
214
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
198
                                        const char* name);
215
                                         config_log_state* cls);
199
216
200
static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle);
217
static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle);
201
static ap_log_writer *ap_log_set_writer(ap_log_writer *handle);
218
static ap_log_writer *ap_log_set_writer(ap_log_writer *handle);
Lines 204-224 static ap_log_writer_init *log_writer_init = ap_default_log_writer_init; Link Here
204
static int buffered_logs = 0; /* default unbuffered */
221
static int buffered_logs = 0; /* default unbuffered */
205
static apr_array_header_t *all_buffered_logs = NULL;
222
static apr_array_header_t *all_buffered_logs = NULL;
206
223
207
/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
208
 * guaranteed to be atomic when writing a pipe.  And PIPE_BUF >= 512
209
 * is guaranteed.  So we'll just guess 512 in the event the system
210
 * doesn't have this.  Now, for file writes there is actually no limit,
211
 * the entire write is atomic.  Whether all systems implement this
212
 * correctly is another question entirely ... so we'll just use PIPE_BUF
213
 * because it's probably a good guess as to what is implemented correctly
214
 * everywhere.
215
 */
216
#ifdef PIPE_BUF
217
#define LOG_BUFSIZE     PIPE_BUF
218
#else
219
#define LOG_BUFSIZE     (512)
220
#endif
221
222
/*
224
/*
223
 * multi_log_state is our per-(virtual)-server configuration. We store
225
 * multi_log_state is our per-(virtual)-server configuration. We store
224
 * an array of the logs we are going to use, each of type config_log_state.
226
 * an array of the logs we are going to use, each of type config_log_state.
Lines 252-265 typedef struct { Link Here
252
 * set to a opaque structure (usually a fd) after it is opened.
254
 * set to a opaque structure (usually a fd) after it is opened.
253
255
254
 */
256
 */
255
typedef struct {
257
struct config_log_state {
256
    apr_file_t *handle;
257
    apr_size_t outcnt;
258
    char outbuf[LOG_BUFSIZE];
259
    apr_anylock_t mutex;
260
} buffered_log;
261
262
typedef struct {
263
    const char *fname;
258
    const char *fname;
264
    const char *format_string;
259
    const char *format_string;
265
    apr_array_header_t *format;
260
    apr_array_header_t *format;
Lines 269-275 typedef struct { Link Here
269
    ap_expr_info_t *condition_expr;
264
    ap_expr_info_t *condition_expr;
270
    /** place of definition or NULL if already checked */
265
    /** place of definition or NULL if already checked */
271
    const ap_directive_t *directive;
266
    const ap_directive_t *directive;
272
} config_log_state;
267
    int chunked;
268
};
273
269
274
/*
270
/*
275
 * log_request_state holds request specific log data that is not
271
 * log_request_state holds request specific log data that is not
Lines 1175-1181 static int config_log_transaction(request_rec *r, config_log_state *cls, Link Here
1175
                "log writer isn't correctly setup");
1171
                "log writer isn't correctly setup");
1176
        return HTTP_INTERNAL_SERVER_ERROR;
1172
        return HTTP_INTERNAL_SERVER_ERROR;
1177
    }
1173
    }
1178
    rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len);
1174
    rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len, cls->chunked);
1179
    if (rv != APR_SUCCESS) {
1175
    if (rv != APR_SUCCESS) {
1180
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646)
1176
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646)
1181
                      "Error writing to %s", cls->fname);
1177
                      "Error writing to %s", cls->fname);
Lines 1327-1332 static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn, Link Here
1327
    }
1323
    }
1328
1324
1329
    cls->fname = fn;
1325
    cls->fname = fn;
1326
    if (fn && (!strncmp(fn, "|<", 2) || !strncmp(fn, "||<", 3))) {
1327
        cls->chunked = 1;
1328
    }
1330
    cls->format_string = fmt;
1329
    cls->format_string = fmt;
1331
    cls->directive = cmd->directive;
1330
    cls->directive = cmd->directive;
1332
    if (fmt == NULL) {
1331
    if (fmt == NULL) {
Lines 1386-1391 static const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag) Link Here
1386
    }
1385
    }
1387
    return NULL;
1386
    return NULL;
1388
}
1387
}
1388
1389
static const command_rec config_log_cmds[] =
1389
static const command_rec config_log_cmds[] =
1390
{
1390
{
1391
AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
1391
AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
Lines 1414-1420 static config_log_state *open_config_log(server_rec *s, apr_pool_t *p, Link Here
1414
        return cls;             /* Leave it NULL to decline.  */
1414
        return cls;             /* Leave it NULL to decline.  */
1415
    }
1415
    }
1416
1416
1417
    cls->log_writer = log_writer_init(p, s, cls->fname);
1417
    cls->log_writer = log_writer_init(p, s, cls);
1418
    if (cls->log_writer == NULL)
1418
    if (cls->log_writer == NULL)
1419
        return NULL;
1419
        return NULL;
1420
1420
Lines 1603-1614 static ap_log_writer *ap_log_set_writer(ap_log_writer *handle) Link Here
1603
    return old;
1603
    return old;
1604
}
1604
}
1605
1605
1606
static apr_status_t write_atomic_pipe_chunks(request_rec *r,
1607
                           void *handle,
1608
                           const char *str,
1609
                           apr_size_t len,
1610
                           buffered_log *buf)
1611
{
1612
    apr_status_t rv;
1613
    apr_size_t chunk_body_len;
1614
    apr_size_t write_cnt;
1615
    apr_size_t msg_read_len = 0;
1616
    uint32_t proc_slot_xfer, thread_slot_xfer;
1617
    char msg_chunk[LOG_BUFSIZE];
1618
    uint32_t chunk_order = 1;
1619
    uint32_t chunk_order_xfer;
1620
    uint32_t total_chunk_cnt = (len / LOG_BUFSIZE_LESS_CHUNKHEAD) +
1621
        !!(len % LOG_BUFSIZE_LESS_CHUNKHEAD);
1622
    uint32_t total_chunk_cnt_xfer = htonl(total_chunk_cnt);
1623
    uint32_t chunk_body_len_xfer;
1624
    ap_sb_handle_t *sbh = r->connection->sbh;
1625
    uint32_t cpy_pos = 0;
1626
    char *msg_buf = msg_chunk;
1627
1628
    if (buf != NULL)
1629
        msg_buf = &buf->outbuf[buf->outcnt];
1630
1631
    proc_slot_xfer = htonl(sbh->child_num);
1632
    thread_slot_xfer = htonl(sbh->thread_num);
1633
1634
    /*
1635
     * Split the log line into PIPE_BUF chunks to avoid interleaving concurrent
1636
     * writes to the pipe that may corrupt the log data.
1637
     */
1638
    do {
1639
        if (buf == NULL)
1640
            cpy_pos = 0;
1641
        chunk_body_len = len - msg_read_len;
1642
        if (chunk_body_len > LOG_BUFSIZE_LESS_CHUNKHEAD)
1643
            chunk_body_len = LOG_BUFSIZE_LESS_CHUNKHEAD;
1644
        memcpy(msg_buf + cpy_pos, &proc_slot_xfer, sizeof(uint32_t));
1645
        cpy_pos += sizeof(uint32_t);
1646
        memcpy(msg_buf + cpy_pos, &thread_slot_xfer, sizeof(uint32_t));
1647
        cpy_pos += sizeof(uint32_t);
1648
        chunk_order_xfer = htonl(chunk_order);
1649
        memcpy(msg_buf + cpy_pos, &chunk_order_xfer, sizeof(uint32_t));
1650
        cpy_pos += sizeof(uint32_t);
1651
        memcpy(msg_buf + cpy_pos, &total_chunk_cnt_xfer, sizeof(uint32_t));
1652
        cpy_pos += sizeof(uint32_t);
1653
1654
        /* Convert potentially long int to message header uint32_t. */
1655
        chunk_body_len_xfer = htonl(chunk_body_len);
1656
        memcpy(msg_buf + cpy_pos, &chunk_body_len_xfer, sizeof(uint32_t));
1657
        cpy_pos += sizeof(uint32_t);
1658
        memcpy(msg_buf + cpy_pos, str + msg_read_len, chunk_body_len);
1659
        cpy_pos += chunk_body_len;
1660
1661
        if (buf == NULL) {
1662
            write_cnt = chunk_body_len + MSG_HEADER_LEN;
1663
            if ((rv = apr_file_write((apr_file_t*)handle, msg_buf, &write_cnt))
1664
                != APR_SUCCESS) {
1665
                return rv;
1666
            }
1667
        }
1668
1669
        msg_read_len += chunk_body_len;
1670
        chunk_order++;
1671
1672
    } while (msg_read_len < len);
1673
1674
    if (buf != NULL)
1675
        buf->outcnt += cpy_pos;
1676
1677
    return rv;
1678
}
1679
1606
static apr_status_t ap_default_log_writer( request_rec *r,
1680
static apr_status_t ap_default_log_writer( request_rec *r,
1607
                           void *handle,
1681
                           void *handle,
1608
                           const char **strs,
1682
                           const char **strs,
1609
                           int *strl,
1683
                           int *strl,
1610
                           int nelts,
1684
                           int nelts,
1611
                           apr_size_t len)
1685
                           apr_size_t len,
1686
                           int chunk_msgs)
1612
1687
1613
{
1688
{
1614
    char *str;
1689
    char *str;
Lines 1627-1642 static apr_status_t ap_default_log_writer( request_rec *r, Link Here
1627
        s += strl[i];
1702
        s += strl[i];
1628
    }
1703
    }
1629
1704
1630
    rv = apr_file_write((apr_file_t*)handle, str, &len);
1705
    if (chunk_msgs) {
1706
        rv = write_atomic_pipe_chunks(r, handle, str, len, NULL);
1707
    }
1708
    else {
1709
        rv = apr_file_write((apr_file_t*)handle, str, &len);
1710
    }
1631
1711
1632
    return rv;
1712
    return rv;
1633
}
1713
}
1634
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
1714
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
1635
                                        const char* name)
1715
                                        config_log_state* cls)
1636
{
1716
{
1717
    apr_status_t rv;
1718
    const char *name = cls->fname;
1719
1637
    if (*name == '|') {
1720
    if (*name == '|') {
1638
        piped_log *pl;
1721
        piped_log *pl;
1639
1722
1723
        if (cls->chunked) {
1724
            if ((rv = apr_env_set("AP_MOD_LOG_CONFIG_CHUNKED_MSG", "", p)) !=
1725
                APR_SUCCESS) {
1726
                ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(03474)
1727
                                "Unable to apr_env_set");
1728
                return NULL;
1729
            }
1730
            ++name;
1731
            if (*name == '|')
1732
                ++name;
1733
        }
1640
        pl = ap_open_piped_log(p, name + 1);
1734
        pl = ap_open_piped_log(p, name + 1);
1641
        if (pl == NULL) {
1735
        if (pl == NULL) {
1642
           return NULL;
1736
           return NULL;
Lines 1663-1673 static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, Link Here
1663
    }
1757
    }
1664
}
1758
}
1665
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
1759
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
1666
                                        const char* name)
1760
                                         config_log_state* cls)
1667
{
1761
{
1668
    buffered_log *b;
1762
    buffered_log *b;
1669
    b = apr_pcalloc(p, sizeof(buffered_log));
1763
    b = apr_pcalloc(p, sizeof(buffered_log));
1670
    b->handle = ap_default_log_writer_init(p, s, name);
1764
    b->handle = ap_default_log_writer_init(p, s, cls);
1671
1765
1672
    if (b->handle) {
1766
    if (b->handle) {
1673
        *(buffered_log **)apr_array_push(all_buffered_logs) = b;
1767
        *(buffered_log **)apr_array_push(all_buffered_logs) = b;
Lines 1681-1703 static apr_status_t ap_buffered_log_writer(request_rec *r, Link Here
1681
                                           const char **strs,
1775
                                           const char **strs,
1682
                                           int *strl,
1776
                                           int *strl,
1683
                                           int nelts,
1777
                                           int nelts,
1684
                                           apr_size_t len)
1778
                                           apr_size_t len,
1779
                                           int chunk_msgs)
1685
1780
1686
{
1781
{
1687
    char *str;
1782
    char *str;
1688
    char *s;
1783
    char *s;
1689
    int i;
1784
    int i;
1690
    apr_status_t rv;
1785
    apr_status_t rv;
1786
    apr_size_t buf_len_limit = LOG_BUFSIZE;
1691
    buffered_log *buf = (buffered_log*)handle;
1787
    buffered_log *buf = (buffered_log*)handle;
1692
1788
1693
    if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
1789
    if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
1694
        return rv;
1790
        return rv;
1695
    }
1791
    }
1696
1792
1697
    if (len + buf->outcnt > LOG_BUFSIZE) {
1793
    if (chunk_msgs) {
1794
        buf_len_limit = LOG_BUFSIZE_LESS_CHUNKHEAD;
1795
    }
1796
1797
    if (len + buf->outcnt > buf_len_limit) {
1698
        flush_log(buf);
1798
        flush_log(buf);
1699
    }
1799
    }
1700
    if (len >= LOG_BUFSIZE) {
1800
    if (len >= buf_len_limit) {
1701
        apr_size_t w;
1801
        apr_size_t w;
1702
1802
1703
        /*
1803
        /*
Lines 1709-1725 static apr_status_t ap_buffered_log_writer(request_rec *r, Link Here
1709
            memcpy(s, strs[i], strl[i]);
1809
            memcpy(s, strs[i], strl[i]);
1710
            s += strl[i];
1810
            s += strl[i];
1711
        }
1811
        }
1712
        w = len;
1812
1713
        rv = apr_file_write(buf->handle, str, &w);
1813
        if (chunk_msgs) {
1814
            rv = write_atomic_pipe_chunks(r, buf->handle, str, len, NULL);
1815
        }
1816
        else {
1817
            w = len;
1818
            rv = apr_file_write(buf->handle, str, &w);
1819
        }
1714
1820
1715
    }
1821
    }
1716
    else {
1822
    else {
1717
        for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
1823
        if (chunk_msgs) {
1718
            memcpy(s, strs[i], strl[i]);
1824
            /*
1719
            s += strl[i];
1825
             * We do this memcpy dance because write() is atomic for
1826
             * len < PIPE_BUF, while writev() need not be.
1827
             */
1828
            str = apr_palloc(r->pool, len + 1);
1829
            for (i = 0, s = str; i < nelts; ++i) {
1830
                memcpy(s, strs[i], strl[i]);
1831
                s += strl[i];
1832
            }
1833
1834
            rv = write_atomic_pipe_chunks(r, buf->handle, str, len, buf);
1835
        }
1836
        else {
1837
            for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
1838
                memcpy(s, strs[i], strl[i]);
1839
                s += strl[i];
1840
            }
1841
            buf->outcnt += len;
1842
            rv = APR_SUCCESS;
1720
        }
1843
        }
1721
        buf->outcnt += len;
1722
        rv = APR_SUCCESS;
1723
    }
1844
    }
1724
1845
1725
    APR_ANYLOCK_UNLOCK(&buf->mutex);
1846
    APR_ANYLOCK_UNLOCK(&buf->mutex);
(-)a/modules/loggers/mod_log_config.h (-2 / +5 lines)
Lines 30-35 Link Here
30
#ifndef _MOD_LOG_CONFIG_H
30
#ifndef _MOD_LOG_CONFIG_H
31
#define _MOD_LOG_CONFIG_H 1
31
#define _MOD_LOG_CONFIG_H 1
32
32
33
typedef struct config_log_state config_log_state;
34
33
/**
35
/**
34
 * callback function prototype for a external log handler
36
 * callback function prototype for a external log handler
35
 */
37
 */
Lines 39-45 typedef const char *ap_log_handler_fn_t(request_rec *r, char *a); Link Here
39
 * callback function prototype for external writer initialization.
41
 * callback function prototype for external writer initialization.
40
 */
42
 */
41
typedef void *ap_log_writer_init(apr_pool_t *p, server_rec *s,
43
typedef void *ap_log_writer_init(apr_pool_t *p, server_rec *s,
42
                                 const char *name);
44
                                 config_log_state* cls);
43
/**
45
/**
44
 * callback which gets called where there is a log line to write.
46
 * callback which gets called where there is a log line to write.
45
 */
47
 */
Lines 49-55 typedef apr_status_t ap_log_writer( Link Here
49
                            const char **portions,
51
                            const char **portions,
50
                            int *lengths,
52
                            int *lengths,
51
                            int nelts,
53
                            int nelts,
52
                            apr_size_t len);
54
                            apr_size_t len,
55
                            int chunk_msgs);
53
56
54
typedef struct ap_log_handler {
57
typedef struct ap_log_handler {
55
    ap_log_handler_fn_t *func;
58
    ap_log_handler_fn_t *func;
(-)a/server/log.c (+6 lines)
Lines 375-380 static int open_error_log(server_rec *s, int is_main, apr_pool_t *p) Link Here
375
         */
375
         */
376
        if (*fname == '|')
376
        if (*fname == '|')
377
            ++fname;
377
            ++fname;
378
        if (*fname == '<') {
379
            ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, APLOGNO(03473)
380
                         "Safe pipe '<' not supported for ErrorLog: '%s'.",
381
                         s->error_fname);
382
            ++fname;
383
        }
378
        if (*fname == '$') {
384
        if (*fname == '$') {
379
            cmdtype = APR_SHELLCMD_ENV;
385
            cmdtype = APR_SHELLCMD_ENV;
380
            ++fname;
386
            ++fname;
(-)a/server/scoreboard.c (-5 lines)
Lines 104-114 AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_mpm, Link Here
104
static APR_OPTIONAL_FN_TYPE(ap_logio_get_last_bytes)
104
static APR_OPTIONAL_FN_TYPE(ap_logio_get_last_bytes)
105
                                *pfn_ap_logio_get_last_bytes;
105
                                *pfn_ap_logio_get_last_bytes;
106
106
107
struct ap_sb_handle_t {
108
    int child_num;
109
    int thread_num;
110
};
111
112
static int server_limit, thread_limit;
107
static int server_limit, thread_limit;
113
static apr_size_t scoreboard_size;
108
static apr_size_t scoreboard_size;
114
109
(-)a/support/rotatelogs.c (-4 / +166 lines)
Lines 25-30 Link Here
25
#include "apr_getopt.h"
25
#include "apr_getopt.h"
26
#include "apr_thread_proc.h"
26
#include "apr_thread_proc.h"
27
#include "apr_signal.h"
27
#include "apr_signal.h"
28
#include "apr_env.h"
29
#include "apr_hash.h"
30
#include "apr_tables.h"
28
#if APR_FILES_AS_SOCKETS
31
#if APR_FILES_AS_SOCKETS
29
#include "apr_poll.h"
32
#include "apr_poll.h"
30
#endif
33
#endif
Lines 33-40 Link Here
33
#include <stdlib.h>
36
#include <stdlib.h>
34
#endif
37
#endif
35
#define APR_WANT_STRFUNC
38
#define APR_WANT_STRFUNC
39
#define APR_WANT_BYTEFUNC   /* for htons() et al */
36
#include "apr_want.h"
40
#include "apr_want.h"
37
41
42
#include "httpd.h"
43
#include "http_log.h"
44
38
#define BUFSIZE         65536
45
#define BUFSIZE         65536
39
#define ERRMSGSZ        256
46
#define ERRMSGSZ        256
40
47
Lines 540-545 static const char *get_time_or_size(rotate_config_t *config, Link Here
540
    return NULL;
547
    return NULL;
541
}
548
}
542
549
550
static apr_status_t read_chunk(apr_file_t *f_stdin, apr_pool_t *p, char *buf,
551
                               char **msg, apr_hash_t *thread_chunks,
552
                               apr_size_t *nRead)
553
{
554
    apr_status_t rv;
555
    uint32_t chunk_header[MSG_HEADER_ELT_CNT];
556
    uint32_t proc_slot, thd_slot, chunk_cnt, tot_chunk_cnt, chunk_body_len;
557
558
    /* Read just the chunk header, expected to be present in its entirety. */
559
    rv = apr_file_read_full(f_stdin, chunk_header, MSG_HEADER_LEN, nRead);
560
    if (APR_STATUS_IS_EOF(rv)) {
561
        return rv;
562
    }
563
    else if (rv != APR_SUCCESS) {
564
        exit(3);
565
    }
566
    proc_slot = ntohl(chunk_header[0]);
567
    thd_slot = ntohl(chunk_header[1]);
568
    chunk_cnt = ntohl(chunk_header[2]);
569
    tot_chunk_cnt = ntohl(chunk_header[3]);
570
    chunk_body_len = ntohl(chunk_header[4]);
571
572
    /* Read the full chunk body, expected to be present in its entirety. */
573
    rv = apr_file_read_full(f_stdin, buf, (apr_size_t)chunk_body_len, nRead);
574
    if (APR_STATUS_IS_EOF(rv)) {
575
        return rv;
576
    }
577
    else if (rv != APR_SUCCESS) {
578
        exit(3);
579
    }
580
581
    if (chunk_cnt != 1 || tot_chunk_cnt != 1) {
582
        /* 
583
         * If this is a multi-chunk log record, stage the chunks so they can be
584
         * reassembled in order.
585
         */
586
        uint32_t chunk_idx = chunk_cnt - 1;
587
        char *chunk_body;
588
        char **chunk_elem;
589
        char *slot_key;
590
        apr_array_header_t *chunks_head;
591
592
        slot_key = apr_psprintf(p, "%i.%i", proc_slot, thd_slot);
593
        chunks_head = apr_hash_get(thread_chunks, slot_key,
594
                                   APR_HASH_KEY_STRING);
595
        /* A thread must write chunks of a message in order. */
596
        if (chunks_head == NULL) {
597
            if (chunk_idx > 0) {
598
                /*
599
                 * Expected to have a table entry here since we're in
600
                 * mid-sequence for this chunk set.
601
                 */
602
                fprintf(stderr, "Chunks found in a non-ordered sequence, "
603
                                "skipping this chunk set\n");
604
                return APR_SUCCESS;
605
            }
606
            chunks_head = apr_array_make(p, 10, sizeof(char *));
607
            apr_hash_set(thread_chunks, slot_key, APR_HASH_KEY_STRING,
608
                         chunks_head);
609
        }
610
        else {
611
            /* Check that the chunk list size jives with chunk_cnt. */
612
            if (chunk_idx != chunks_head->nelts) {
613
                fprintf(stderr, "Chunks found in a non-ordered sequence, "
614
                                "skipping this chunk set\n");
615
                apr_array_clear(chunks_head);
616
                return APR_SUCCESS;
617
            }
618
        }
619
620
        chunk_elem = apr_array_push(chunks_head);
621
622
        /* Stage this chunk. */
623
        chunk_body = malloc(chunk_body_len);
624
        memcpy(chunk_body, buf, chunk_body_len);
625
        *chunk_elem = chunk_body;
626
627
        if (chunk_cnt == tot_chunk_cnt) {
628
            /*
629
             * If this is the final chunk, glue them together so the original
630
             * message can be written below.
631
             */
632
            uint32_t chunk_len;
633
            uint32_t chunk_iter;
634
            uint32_t cpy_len = 0;
635
636
            *msg = malloc(LOG_BUFSIZE_LESS_CHUNKHEAD * tot_chunk_cnt);
637
            for (chunk_iter = 0; chunk_iter < chunks_head->nelts;
638
                 ++chunk_iter) {
639
                char *chunk = ((char**)chunks_head->elts)[chunk_iter];
640
                chunk_len = LOG_BUFSIZE_LESS_CHUNKHEAD;
641
                if (chunk_iter + 1 == tot_chunk_cnt)
642
                    chunk_len = chunk_body_len;
643
                memcpy(*msg + cpy_len, chunk, chunk_len);
644
                cpy_len += chunk_len;
645
                free(chunk);
646
            }
647
            *nRead = cpy_len;
648
            apr_array_clear(chunks_head);
649
        }
650
        else {
651
            /* Otherwise continue staging and writing single-chunk messages. */
652
            return APR_SUCCESS;
653
        }
654
    }
655
    else {
656
        /*
657
         * This log message is transferred in a single chunk, simply return and
658
         * write it.
659
         */
660
        *msg = buf;
661
    }
662
    return APR_SUCCESS;
663
}
664
543
int main (int argc, const char * const argv[])
665
int main (int argc, const char * const argv[])
544
{
666
{
545
    char buf[BUFSIZE];
667
    char buf[BUFSIZE];
Lines 549-556 int main (int argc, const char * const argv[]) Link Here
549
    apr_getopt_t *opt;
671
    apr_getopt_t *opt;
550
    apr_status_t rv;
672
    apr_status_t rv;
551
    char c;
673
    char c;
674
    char *env;
552
    const char *opt_arg;
675
    const char *opt_arg;
553
    const char *err = NULL;
676
    const char *err = NULL;
677
    int chunked_msgs;
678
    apr_hash_t *thread_chunks;
679
    char *msg;
554
#if APR_FILES_AS_SOCKETS
680
#if APR_FILES_AS_SOCKETS
555
    apr_pollfd_t pollfd = { 0 };
681
    apr_pollfd_t pollfd = { 0 };
556
    apr_status_t pollret = APR_SUCCESS;
682
    apr_status_t pollret = APR_SUCCESS;
Lines 670-675 int main (int argc, const char * const argv[]) Link Here
670
    }
796
    }
671
#endif
797
#endif
672
798
799
    rv = apr_env_get(&env, "AP_MOD_LOG_CONFIG_CHUNKED_MSG", status.pool);
800
    chunked_msgs = (rv == APR_SUCCESS && env != NULL);
801
802
    thread_chunks = apr_hash_make(status.pool);
803
673
    /*
804
    /*
674
     * Immediately open the logfile as we start, if we were forced
805
     * Immediately open the logfile as we start, if we were forced
675
     * to do so via '-f'.
806
     * to do so via '-f'.
Lines 679-685 int main (int argc, const char * const argv[]) Link Here
679
    }
810
    }
680
811
681
    for (;;) {
812
    for (;;) {
813
        int freemsg = 0;
814
        int skip_write = 0;
682
        nRead = sizeof(buf);
815
        nRead = sizeof(buf);
816
        msg = NULL;
683
#if APR_FILES_AS_SOCKETS
817
#if APR_FILES_AS_SOCKETS
684
        if (config.create_empty && config.tRotation) {
818
        if (config.create_empty && config.tRotation) {
685
            polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config, NULL) : config.tRotation;
819
            polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config, NULL) : config.tRotation;
Lines 691-706 int main (int argc, const char * const argv[]) Link Here
691
            }
825
            }
692
        }
826
        }
693
        if (pollret == APR_SUCCESS) {
827
        if (pollret == APR_SUCCESS) {
694
            rv = apr_file_read(f_stdin, buf, &nRead);
828
            if (chunked_msgs) {
829
                rv = read_chunk(f_stdin, status.pool, buf, &msg,
830
                                thread_chunks, &nRead);
831
            }
832
            else {
833
                rv = apr_file_read(f_stdin, buf, &nRead);
834
                msg = buf;
835
            }
695
            if (APR_STATUS_IS_EOF(rv)) {
836
            if (APR_STATUS_IS_EOF(rv)) {
696
                break;
837
                break;
697
            }
838
            }
698
            else if (rv != APR_SUCCESS) {
839
            else if (rv != APR_SUCCESS) {
699
                exit(3);
840
                exit(3);
700
            }
841
            }
842
            if (msg == NULL)
843
                skip_write = 1;
844
            else if (msg != buf)
845
                freemsg = 1;
701
        }
846
        }
702
        else if (pollret == APR_TIMEUP) {
847
        else if (pollret == APR_TIMEUP) {
703
            *buf = 0;
848
            *buf = 0;
849
            msg = buf;
704
            nRead = 0;
850
            nRead = 0;
705
        }
851
        }
706
        else {
852
        else {
Lines 708-728 int main (int argc, const char * const argv[]) Link Here
708
            exit(5);
854
            exit(5);
709
        }
855
        }
710
#else /* APR_FILES_AS_SOCKETS */
856
#else /* APR_FILES_AS_SOCKETS */
711
        rv = apr_file_read(f_stdin, buf, &nRead);
857
        if (chunked_msgs) {
858
            rv = read_chunk(f_stdin, status.pool, buf, &msg,
859
                            thread_chunks, &nRead);
860
        }
861
        else {
862
            rv = apr_file_read(f_stdin, buf, &nRead);
863
            msg = buf;
864
        }
712
        if (APR_STATUS_IS_EOF(rv)) {
865
        if (APR_STATUS_IS_EOF(rv)) {
713
            break;
866
            break;
714
        }
867
        }
715
        else if (rv != APR_SUCCESS) {
868
        else if (rv != APR_SUCCESS) {
716
            exit(3);
869
            exit(3);
717
        }
870
        }
871
        if (msg == NULL)
872
            skip_write = 1;
873
        else if (msg != buf)
874
            freemsg = 1;
718
#endif /* APR_FILES_AS_SOCKETS */
875
#endif /* APR_FILES_AS_SOCKETS */
719
        checkRotate(&config, &status);
876
        checkRotate(&config, &status);
720
        if (status.rotateReason != ROTATE_NONE) {
877
        if (status.rotateReason != ROTATE_NONE) {
721
            doRotate(&config, &status);
878
            doRotate(&config, &status);
722
        }
879
        }
723
880
881
        if (skip_write)
882
            continue;
883
724
        nWrite = nRead;
884
        nWrite = nRead;
725
        rv = apr_file_write_full(status.current.fd, buf, nWrite, &nWrite);
885
        rv = apr_file_write_full(status.current.fd, msg, nWrite, &nWrite);
726
        if (nWrite != nRead) {
886
        if (nWrite != nRead) {
727
            apr_off_t cur_offset;
887
            apr_off_t cur_offset;
728
888
Lines 742-752 int main (int argc, const char * const argv[]) Link Here
742
            status.nMessCount++;
902
            status.nMessCount++;
743
        }
903
        }
744
        if (config.echo) {
904
        if (config.echo) {
745
            if (apr_file_write_full(f_stdout, buf, nRead, &nWrite)) {
905
            if (apr_file_write_full(f_stdout, msg, nRead, &nWrite)) {
746
                fprintf(stderr, "Unable to write to stdout\n");
906
                fprintf(stderr, "Unable to write to stdout\n");
747
                exit(4);
907
                exit(4);
748
            }
908
            }
749
        }
909
        }
910
        if (freemsg)
911
            free(msg);
750
    }
912
    }
751
913
752
    return 0; /* reached only at stdin EOF. */
914
    return 0; /* reached only at stdin EOF. */

Return to bug 54339