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 476-482 expr=<var>expression</var>]</syntax> Link Here
476
      >ServerRoot</directive>.</dd>
476
      >ServerRoot</directive>.</dd>
477
477
478
      <dt><var>pipe</var></dt>
478
      <dt><var>pipe</var></dt>
479
      <dd>The pipe character "<code>|</code>", followed by the path
479
      <dd>The pipe character "<code>|</code>" (or safe pipe
480
      "<code>|&lt;</code>"), followed by the path
480
      to a program to receive the log information on its standard
481
      to a program to receive the log information on its standard
481
      input. See the notes on <a href="../logs.html#piped">piped logs</a>
482
      input. See the notes on <a href="../logs.html#piped">piped logs</a>
482
      for more information.
483
      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 (-46 / +173 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 165-170 Link Here
165
#include "util_time.h"
167
#include "util_time.h"
166
#include "ap_mpm.h"
168
#include "ap_mpm.h"
167
#include "ap_provider.h"
169
#include "ap_provider.h"
170
#include "scoreboard.h"
168
171
169
#if APR_HAVE_UNISTD_H
172
#if APR_HAVE_UNISTD_H
170
#include <unistd.h>
173
#include <unistd.h>
Lines 178-202 Link Here
178
module AP_MODULE_DECLARE_DATA log_config_module;
181
module AP_MODULE_DECLARE_DATA log_config_module;
179
182
180
183
184
typedef struct {
185
    apr_file_t *handle;
186
    apr_size_t outcnt;
187
    char outbuf[LOG_BUFSIZE];
188
    apr_anylock_t mutex;
189
} buffered_log;
190
181
static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
191
static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
182
static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
192
static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
183
static apr_hash_t *log_hash;
193
static apr_hash_t *log_hash;
194
static apr_status_t write_atomic_pipe_chunks(request_rec *r,
195
                           void *handle,
196
                           const char *str,
197
                           apr_size_t len,
198
                           buffered_log *buf);
184
static apr_status_t ap_default_log_writer(request_rec *r,
199
static apr_status_t ap_default_log_writer(request_rec *r,
185
                           void *handle,
200
                           void *handle,
186
                           const char **strs,
201
                           const char **strs,
187
                           int *strl,
202
                           int *strl,
188
                           int nelts,
203
                           int nelts,
189
                           apr_size_t len);
204
                           apr_size_t len,
205
                           int chunk_msgs);
190
static apr_status_t ap_buffered_log_writer(request_rec *r,
206
static apr_status_t ap_buffered_log_writer(request_rec *r,
191
                           void *handle,
207
                           void *handle,
192
                           const char **strs,
208
                           const char **strs,
193
                           int *strl,
209
                           int *strl,
194
                           int nelts,
210
                           int nelts,
195
                           apr_size_t len);
211
                           apr_size_t len,
212
                           int chunk_msgs);
196
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
213
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
197
                                        const char* name);
214
                                        config_log_state* cls);
198
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
215
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
199
                                        const char* name);
216
                                         config_log_state* cls);
200
217
201
static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle);
218
static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle);
202
static ap_log_writer *ap_log_set_writer(ap_log_writer *handle);
219
static ap_log_writer *ap_log_set_writer(ap_log_writer *handle);
Lines 205-225 static ap_log_writer_init *log_writer_init = ap_default_log_writer_init; Link Here
205
static int buffered_logs = 0; /* default unbuffered */
222
static int buffered_logs = 0; /* default unbuffered */
206
static apr_array_header_t *all_buffered_logs = NULL;
223
static apr_array_header_t *all_buffered_logs = NULL;
207
224
208
/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
209
 * guaranteed to be atomic when writing a pipe.  And PIPE_BUF >= 512
210
 * is guaranteed.  So we'll just guess 512 in the event the system
211
 * doesn't have this.  Now, for file writes there is actually no limit,
212
 * the entire write is atomic.  Whether all systems implement this
213
 * correctly is another question entirely ... so we'll just use PIPE_BUF
214
 * because it's probably a good guess as to what is implemented correctly
215
 * everywhere.
216
 */
217
#ifdef PIPE_BUF
218
#define LOG_BUFSIZE     PIPE_BUF
219
#else
220
#define LOG_BUFSIZE     (512)
221
#endif
222
223
/*
225
/*
224
 * multi_log_state is our per-(virtual)-server configuration. We store
226
 * multi_log_state is our per-(virtual)-server configuration. We store
225
 * an array of the logs we are going to use, each of type config_log_state.
227
 * an array of the logs we are going to use, each of type config_log_state.
Lines 253-266 typedef struct { Link Here
253
 * set to a opaque structure (usually a fd) after it is opened.
255
 * set to a opaque structure (usually a fd) after it is opened.
254
256
255
 */
257
 */
256
typedef struct {
258
struct config_log_state {
257
    apr_file_t *handle;
258
    apr_size_t outcnt;
259
    char outbuf[LOG_BUFSIZE];
260
    apr_anylock_t mutex;
261
} buffered_log;
262
263
typedef struct {
264
    const char *fname;
259
    const char *fname;
265
    const char *format_string;
260
    const char *format_string;
266
    apr_array_header_t *format;
261
    apr_array_header_t *format;
Lines 270-276 typedef struct { Link Here
270
    ap_expr_info_t *condition_expr;
265
    ap_expr_info_t *condition_expr;
271
    /** place of definition or NULL if already checked */
266
    /** place of definition or NULL if already checked */
272
    const ap_directive_t *directive;
267
    const ap_directive_t *directive;
273
} config_log_state;
268
    int chunked;
269
};
274
270
275
/*
271
/*
276
 * log_request_state holds request specific log data that is not
272
 * log_request_state holds request specific log data that is not
Lines 1212-1218 static int config_log_transaction(request_rec *r, config_log_state *cls, Link Here
1212
                "log writer isn't correctly setup");
1208
                "log writer isn't correctly setup");
1213
        return HTTP_INTERNAL_SERVER_ERROR;
1209
        return HTTP_INTERNAL_SERVER_ERROR;
1214
    }
1210
    }
1215
    rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len);
1211
    rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len, cls->chunked);
1216
    if (rv != APR_SUCCESS) {
1212
    if (rv != APR_SUCCESS) {
1217
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646)
1213
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646)
1218
                      "Error writing to %s", cls->fname);
1214
                      "Error writing to %s", cls->fname);
Lines 1364-1369 static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn, Link Here
1364
    }
1360
    }
1365
1361
1366
    cls->fname = fn;
1362
    cls->fname = fn;
1363
    if (fn && (!strncmp(fn, "|<", 2) || !strncmp(fn, "||<", 3))) {
1364
        cls->chunked = 1;
1365
    }
1367
    cls->format_string = fmt;
1366
    cls->format_string = fmt;
1368
    cls->directive = cmd->directive;
1367
    cls->directive = cmd->directive;
1369
    if (fmt == NULL) {
1368
    if (fmt == NULL) {
Lines 1423-1428 static const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag) Link Here
1423
    }
1422
    }
1424
    return NULL;
1423
    return NULL;
1425
}
1424
}
1425
1426
static const command_rec config_log_cmds[] =
1426
static const command_rec config_log_cmds[] =
1427
{
1427
{
1428
AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
1428
AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
Lines 1451-1457 static config_log_state *open_config_log(server_rec *s, apr_pool_t *p, Link Here
1451
        return cls;             /* Leave it NULL to decline.  */
1451
        return cls;             /* Leave it NULL to decline.  */
1452
    }
1452
    }
1453
1453
1454
    cls->log_writer = log_writer_init(p, s, cls->fname);
1454
    cls->log_writer = log_writer_init(p, s, cls);
1455
    if (cls->log_writer == NULL)
1455
    if (cls->log_writer == NULL)
1456
        return NULL;
1456
        return NULL;
1457
1457
Lines 1640-1651 static ap_log_writer *ap_log_set_writer(ap_log_writer *handle) Link Here
1640
    return old;
1640
    return old;
1641
}
1641
}
1642
1642
1643
static apr_status_t write_atomic_pipe_chunks(request_rec *r,
1644
                           void *handle,
1645
                           const char *str,
1646
                           apr_size_t len,
1647
                           buffered_log *buf)
1648
{
1649
    apr_status_t rv;
1650
    apr_size_t chunk_body_len;
1651
    apr_size_t write_cnt;
1652
    apr_size_t msg_read_len = 0;
1653
    uint32_t proc_slot_xfer, thread_slot_xfer;
1654
    char msg_chunk[LOG_BUFSIZE];
1655
    uint32_t chunk_order = 1;
1656
    uint32_t chunk_order_xfer;
1657
    uint32_t total_chunk_cnt = (len / LOG_BUFSIZE_LESS_CHUNKHEAD) +
1658
        !!(len % LOG_BUFSIZE_LESS_CHUNKHEAD);
1659
    uint32_t total_chunk_cnt_xfer = htonl(total_chunk_cnt);
1660
    uint32_t chunk_body_len_xfer;
1661
    ap_sb_handle_t *sbh = r->connection->sbh;
1662
    uint32_t cpy_pos = 0;
1663
    char *msg_buf = msg_chunk;
1664
1665
    if (buf != NULL)
1666
        msg_buf = &buf->outbuf[buf->outcnt];
1667
1668
    proc_slot_xfer = htonl(sbh->child_num);
1669
    thread_slot_xfer = htonl(sbh->thread_num);
1670
1671
    /*
1672
     * Split the log line into PIPE_BUF chunks to avoid interleaving concurrent
1673
     * writes to the pipe that may corrupt the log data.
1674
     */
1675
    do {
1676
        if (buf == NULL)
1677
            cpy_pos = 0;
1678
        chunk_body_len = len - msg_read_len;
1679
        if (chunk_body_len > LOG_BUFSIZE_LESS_CHUNKHEAD)
1680
            chunk_body_len = LOG_BUFSIZE_LESS_CHUNKHEAD;
1681
        memcpy(msg_buf + cpy_pos, &proc_slot_xfer, sizeof(uint32_t));
1682
        cpy_pos += sizeof(uint32_t);
1683
        memcpy(msg_buf + cpy_pos, &thread_slot_xfer, sizeof(uint32_t));
1684
        cpy_pos += sizeof(uint32_t);
1685
        chunk_order_xfer = htonl(chunk_order);
1686
        memcpy(msg_buf + cpy_pos, &chunk_order_xfer, sizeof(uint32_t));
1687
        cpy_pos += sizeof(uint32_t);
1688
        memcpy(msg_buf + cpy_pos, &total_chunk_cnt_xfer, sizeof(uint32_t));
1689
        cpy_pos += sizeof(uint32_t);
1690
1691
        /* Convert potentially long int to message header uint32_t. */
1692
        chunk_body_len_xfer = htonl(chunk_body_len);
1693
        memcpy(msg_buf + cpy_pos, &chunk_body_len_xfer, sizeof(uint32_t));
1694
        cpy_pos += sizeof(uint32_t);
1695
        memcpy(msg_buf + cpy_pos, str + msg_read_len, chunk_body_len);
1696
        cpy_pos += chunk_body_len;
1697
1698
        if (buf == NULL) {
1699
            write_cnt = chunk_body_len + MSG_HEADER_LEN;
1700
            if ((rv = apr_file_write((apr_file_t*)handle, msg_buf, &write_cnt))
1701
                != APR_SUCCESS) {
1702
                return rv;
1703
            }
1704
        }
1705
1706
        msg_read_len += chunk_body_len;
1707
        chunk_order++;
1708
1709
    } while (msg_read_len < len);
1710
1711
    if (buf != NULL)
1712
        buf->outcnt += cpy_pos;
1713
1714
    return rv;
1715
}
1716
1643
static apr_status_t ap_default_log_writer( request_rec *r,
1717
static apr_status_t ap_default_log_writer( request_rec *r,
1644
                           void *handle,
1718
                           void *handle,
1645
                           const char **strs,
1719
                           const char **strs,
1646
                           int *strl,
1720
                           int *strl,
1647
                           int nelts,
1721
                           int nelts,
1648
                           apr_size_t len)
1722
                           apr_size_t len,
1723
                           int chunk_msgs)
1649
1724
1650
{
1725
{
1651
    default_log_writer *log_writer = handle;
1726
    default_log_writer *log_writer = handle;
Lines 1666-1673 static apr_status_t ap_default_log_writer( request_rec *r, Link Here
1666
    }
1741
    }
1667
1742
1668
    if (log_writer->type == LOG_WRITER_FD) {
1743
    if (log_writer->type == LOG_WRITER_FD) {
1669
        rv = apr_file_write_full((apr_file_t*)log_writer->log_writer, str,
1744
        if (chunk_msgs) {
1670
                                 len, NULL);
1745
            rv = write_atomic_pipe_chunks(r, log_writer->log_writer, str, len,
1746
                                          NULL);
1747
        }
1748
        else {
1749
            rv = apr_file_write_full((apr_file_t*)log_writer->log_writer, str,
1750
                                     len, NULL);
1751
        }
1671
    }
1752
    }
1672
    else {
1753
    else {
1673
        errorlog_provider_data *data = log_writer->log_writer;
1754
        errorlog_provider_data *data = log_writer->log_writer;
Lines 1689-1696 static apr_status_t ap_default_log_writer( request_rec *r, Link Here
1689
    return rv;
1770
    return rv;
1690
}
1771
}
1691
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
1772
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
1692
                                        const char* name)
1773
                                        config_log_state* cls)
1693
{
1774
{
1775
    apr_status_t rv;
1776
    const char *name = cls->fname;
1694
    default_log_writer *log_writer;
1777
    default_log_writer *log_writer;
1695
    const char *provider_name = name;
1778
    const char *provider_name = name;
1696
    ap_errorlog_provider *provider = NULL;
1779
    ap_errorlog_provider *provider = NULL;
Lines 1706-1711 static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, Link Here
1706
    if (*name == '|') {
1789
    if (*name == '|') {
1707
        piped_log *pl;
1790
        piped_log *pl;
1708
1791
1792
        if (cls->chunked) {
1793
            if ((rv = apr_env_set("AP_MOD_LOG_CONFIG_CHUNKED_MSG", "", p)) !=
1794
                APR_SUCCESS) {
1795
                ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(035011)
1796
                             "Unable to apr_env_set");
1797
                return NULL;
1798
            }
1799
            /*
1800
             * Skip over the initial '|' because we know a '<' follows
1801
             * somewhere, which will be skipped further below.
1802
             */
1803
            ++name;
1804
1805
            /* To support legacy syntax '||', which has no other effect. */
1806
            if (*name == '|')
1807
                ++name;
1808
        }
1709
        pl = ap_open_piped_log(p, name + 1);
1809
        pl = ap_open_piped_log(p, name + 1);
1710
        if (pl == NULL) {
1810
        if (pl == NULL) {
1711
           return NULL;
1811
           return NULL;
Lines 1763-1773 static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, Link Here
1763
    }
1863
    }
1764
}
1864
}
1765
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
1865
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
1766
                                        const char* name)
1866
                                         config_log_state* cls)
1767
{
1867
{
1768
    buffered_log *b;
1868
    buffered_log *b;
1769
    b = apr_pcalloc(p, sizeof(buffered_log));
1869
    b = apr_pcalloc(p, sizeof(buffered_log));
1770
    b->handle = ap_default_log_writer_init(p, s, name);
1870
    b->handle = ap_default_log_writer_init(p, s, cls);
1771
1871
1772
    if (b->handle) {
1872
    if (b->handle) {
1773
        *(buffered_log **)apr_array_push(all_buffered_logs) = b;
1873
        *(buffered_log **)apr_array_push(all_buffered_logs) = b;
Lines 1781-1803 static apr_status_t ap_buffered_log_writer(request_rec *r, Link Here
1781
                                           const char **strs,
1881
                                           const char **strs,
1782
                                           int *strl,
1882
                                           int *strl,
1783
                                           int nelts,
1883
                                           int nelts,
1784
                                           apr_size_t len)
1884
                                           apr_size_t len,
1885
                                           int chunk_msgs)
1785
1886
1786
{
1887
{
1787
    char *str;
1888
    char *str;
1788
    char *s;
1889
    char *s;
1789
    int i;
1890
    int i;
1790
    apr_status_t rv;
1891
    apr_status_t rv;
1892
    apr_size_t buf_len_limit = LOG_BUFSIZE;
1791
    buffered_log *buf = (buffered_log*)handle;
1893
    buffered_log *buf = (buffered_log*)handle;
1792
1894
1793
    if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
1895
    if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
1794
        return rv;
1896
        return rv;
1795
    }
1897
    }
1796
1898
1797
    if (len + buf->outcnt > LOG_BUFSIZE) {
1899
    if (chunk_msgs) {
1900
        buf_len_limit = LOG_BUFSIZE_LESS_CHUNKHEAD;
1901
    }
1902
1903
    if (len + buf->outcnt > buf_len_limit) {
1798
        flush_log(buf);
1904
        flush_log(buf);
1799
    }
1905
    }
1800
    if (len >= LOG_BUFSIZE) {
1906
    if (len >= buf_len_limit) {
1801
        apr_size_t w;
1907
        apr_size_t w;
1802
1908
1803
        /*
1909
        /*
Lines 1809-1825 static apr_status_t ap_buffered_log_writer(request_rec *r, Link Here
1809
            memcpy(s, strs[i], strl[i]);
1915
            memcpy(s, strs[i], strl[i]);
1810
            s += strl[i];
1916
            s += strl[i];
1811
        }
1917
        }
1812
        w = len;
1918
1813
        rv = apr_file_write_full(buf->handle, str, w, NULL);
1919
        if (chunk_msgs) {
1920
            rv = write_atomic_pipe_chunks(r, buf->handle, str, len, NULL);
1921
        }
1922
        else {
1923
            w = len;
1924
            rv = apr_file_write_full(buf->handle, str, w, NULL);
1925
        }
1814
1926
1815
    }
1927
    }
1816
    else {
1928
    else {
1817
        for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
1929
        if (chunk_msgs) {
1818
            memcpy(s, strs[i], strl[i]);
1930
            /*
1819
            s += strl[i];
1931
             * We do this memcpy dance because write() is atomic for
1932
             * len < PIPE_BUF, while writev() need not be.
1933
             */
1934
            str = apr_palloc(r->pool, len + 1);
1935
            for (i = 0, s = str; i < nelts; ++i) {
1936
                memcpy(s, strs[i], strl[i]);
1937
                s += strl[i];
1938
            }
1939
1940
            rv = write_atomic_pipe_chunks(r, buf->handle, str, len, buf);
1941
        }
1942
        else {
1943
            for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
1944
                memcpy(s, strs[i], strl[i]);
1945
                s += strl[i];
1946
            }
1947
            buf->outcnt += len;
1948
            rv = APR_SUCCESS;
1820
        }
1949
        }
1821
        buf->outcnt += len;
1822
        rv = APR_SUCCESS;
1823
    }
1950
    }
1824
1951
1825
    APR_ANYLOCK_UNLOCK(&buf->mutex);
1952
    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 313-318 static int open_error_log(server_rec *s, int is_main, apr_pool_t *p) Link Here
313
         */
313
         */
314
        if (*fname == '|')
314
        if (*fname == '|')
315
            ++fname;
315
            ++fname;
316
        if (*fname == '<') {
317
            ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, APLOGNO(035010)
318
                         "Safe pipe '<' not supported for ErrorLog: '%s'.",
319
                         s->error_fname);
320
            ++fname;
321
        }
316
        if (*fname == '$') {
322
        if (*fname == '$') {
317
            cmdtype = APR_SHELLCMD_ENV;
323
            cmdtype = APR_SHELLCMD_ENV;
318
            ++fname;
324
            ++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
46
40
#define ROTATE_NONE     0
47
#define ROTATE_NONE     0
Lines 556-561 static const char *get_time_or_size(rotate_config_t *config, Link Here
556
    return NULL;
563
    return NULL;
557
}
564
}
558
565
566
static apr_status_t read_chunk(apr_file_t *f_stdin, apr_pool_t *p, char *buf,
567
                               char **msg, apr_hash_t *thread_chunks,
568
                               apr_size_t *nRead)
569
{
570
    apr_status_t rv;
571
    uint32_t chunk_header[MSG_HEADER_ELT_CNT];
572
    uint32_t proc_slot, thd_slot, chunk_cnt, tot_chunk_cnt, chunk_body_len;
573
574
    /* Read just the chunk header, expected to be present in its entirety. */
575
    rv = apr_file_read_full(f_stdin, chunk_header, MSG_HEADER_LEN, nRead);
576
    if (APR_STATUS_IS_EOF(rv)) {
577
        return rv;
578
    }
579
    else if (rv != APR_SUCCESS) {
580
        exit(3);
581
    }
582
    proc_slot = ntohl(chunk_header[0]);
583
    thd_slot = ntohl(chunk_header[1]);
584
    chunk_cnt = ntohl(chunk_header[2]);
585
    tot_chunk_cnt = ntohl(chunk_header[3]);
586
    chunk_body_len = ntohl(chunk_header[4]);
587
588
    /* Read the full chunk body, expected to be present in its entirety. */
589
    rv = apr_file_read_full(f_stdin, buf, (apr_size_t)chunk_body_len, nRead);
590
    if (APR_STATUS_IS_EOF(rv)) {
591
        return rv;
592
    }
593
    else if (rv != APR_SUCCESS) {
594
        exit(3);
595
    }
596
597
    if (chunk_cnt != 1 || tot_chunk_cnt != 1) {
598
        /* 
599
         * If this is a multi-chunk log record, stage the chunks so they can be
600
         * reassembled in order.
601
         */
602
        uint32_t chunk_idx = chunk_cnt - 1;
603
        char *chunk_body;
604
        char **chunk_elem;
605
        char *slot_key;
606
        apr_array_header_t *chunks_head;
607
608
        slot_key = apr_psprintf(p, "%i.%i", proc_slot, thd_slot);
609
        chunks_head = apr_hash_get(thread_chunks, slot_key,
610
                                   APR_HASH_KEY_STRING);
611
        /* A thread must write chunks of a message in order. */
612
        if (chunks_head == NULL) {
613
            if (chunk_idx > 0) {
614
                /*
615
                 * Expected to have a table entry here since we're in
616
                 * mid-sequence for this chunk set.
617
                 */
618
                fprintf(stderr, "Chunks found in a non-ordered sequence, "
619
                                "skipping this chunk set\n");
620
                return APR_SUCCESS;
621
            }
622
            chunks_head = apr_array_make(p, 10, sizeof(char *));
623
            apr_hash_set(thread_chunks, slot_key, APR_HASH_KEY_STRING,
624
                         chunks_head);
625
        }
626
        else {
627
            /* Check that the chunk list size jives with chunk_cnt. */
628
            if (chunk_idx != chunks_head->nelts) {
629
                fprintf(stderr, "Chunks found in a non-ordered sequence, "
630
                                "skipping this chunk set\n");
631
                apr_array_clear(chunks_head);
632
                return APR_SUCCESS;
633
            }
634
        }
635
636
        chunk_elem = apr_array_push(chunks_head);
637
638
        /* Stage this chunk. */
639
        chunk_body = malloc(chunk_body_len);
640
        memcpy(chunk_body, buf, chunk_body_len);
641
        *chunk_elem = chunk_body;
642
643
        if (chunk_cnt == tot_chunk_cnt) {
644
            /*
645
             * If this is the final chunk, glue them together so the original
646
             * message can be written below.
647
             */
648
            uint32_t chunk_len;
649
            uint32_t chunk_iter;
650
            uint32_t cpy_len = 0;
651
652
            *msg = malloc(LOG_BUFSIZE_LESS_CHUNKHEAD * tot_chunk_cnt);
653
            for (chunk_iter = 0; chunk_iter < chunks_head->nelts;
654
                 ++chunk_iter) {
655
                char *chunk = ((char**)chunks_head->elts)[chunk_iter];
656
                chunk_len = LOG_BUFSIZE_LESS_CHUNKHEAD;
657
                if (chunk_iter + 1 == tot_chunk_cnt)
658
                    chunk_len = chunk_body_len;
659
                memcpy(*msg + cpy_len, chunk, chunk_len);
660
                cpy_len += chunk_len;
661
                free(chunk);
662
            }
663
            *nRead = cpy_len;
664
            apr_array_clear(chunks_head);
665
        }
666
        else {
667
            /* Otherwise continue staging and writing single-chunk messages. */
668
            return APR_SUCCESS;
669
        }
670
    }
671
    else {
672
        /*
673
         * This log message is transferred in a single chunk, simply return and
674
         * write it.
675
         */
676
        *msg = buf;
677
    }
678
    return APR_SUCCESS;
679
}
680
559
int main (int argc, const char * const argv[])
681
int main (int argc, const char * const argv[])
560
{
682
{
561
    char buf[BUFSIZE];
683
    char buf[BUFSIZE];
Lines 565-572 int main (int argc, const char * const argv[]) Link Here
565
    apr_getopt_t *opt;
687
    apr_getopt_t *opt;
566
    apr_status_t rv;
688
    apr_status_t rv;
567
    char c;
689
    char c;
690
    char *env;
568
    const char *opt_arg;
691
    const char *opt_arg;
569
    const char *err = NULL;
692
    const char *err = NULL;
693
    int chunked_msgs;
694
    apr_hash_t *thread_chunks;
695
    char *msg;
570
#if APR_FILES_AS_SOCKETS
696
#if APR_FILES_AS_SOCKETS
571
    apr_pollfd_t pollfd = { 0 };
697
    apr_pollfd_t pollfd = { 0 };
572
    apr_status_t pollret = APR_SUCCESS;
698
    apr_status_t pollret = APR_SUCCESS;
Lines 693-698 int main (int argc, const char * const argv[]) Link Here
693
    }
819
    }
694
#endif
820
#endif
695
821
822
    rv = apr_env_get(&env, "AP_MOD_LOG_CONFIG_CHUNKED_MSG", status.pool);
823
    chunked_msgs = (rv == APR_SUCCESS && env != NULL);
824
825
    thread_chunks = apr_hash_make(status.pool);
826
696
    /*
827
    /*
697
     * Immediately open the logfile as we start, if we were forced
828
     * Immediately open the logfile as we start, if we were forced
698
     * to do so via '-f'.
829
     * to do so via '-f'.
Lines 702-708 int main (int argc, const char * const argv[]) Link Here
702
    }
833
    }
703
834
704
    for (;;) {
835
    for (;;) {
836
        int freemsg = 0;
837
        int skip_write = 0;
705
        nRead = sizeof(buf);
838
        nRead = sizeof(buf);
839
        msg = NULL;
706
#if APR_FILES_AS_SOCKETS
840
#if APR_FILES_AS_SOCKETS
707
        if (config.create_empty && config.tRotation) {
841
        if (config.create_empty && config.tRotation) {
708
            polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config, NULL) : config.tRotation;
842
            polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config, NULL) : config.tRotation;
Lines 714-729 int main (int argc, const char * const argv[]) Link Here
714
            }
848
            }
715
        }
849
        }
716
        if (pollret == APR_SUCCESS) {
850
        if (pollret == APR_SUCCESS) {
717
            rv = apr_file_read(f_stdin, buf, &nRead);
851
            if (chunked_msgs) {
852
                rv = read_chunk(f_stdin, status.pool, buf, &msg,
853
                                thread_chunks, &nRead);
854
            }
855
            else {
856
                rv = apr_file_read(f_stdin, buf, &nRead);
857
                msg = buf;
858
            }
718
            if (APR_STATUS_IS_EOF(rv)) {
859
            if (APR_STATUS_IS_EOF(rv)) {
719
                break;
860
                break;
720
            }
861
            }
721
            else if (rv != APR_SUCCESS) {
862
            else if (rv != APR_SUCCESS) {
722
                exit(3);
863
                exit(3);
723
            }
864
            }
865
            if (msg == NULL)
866
                skip_write = 1;
867
            else if (msg != buf)
868
                freemsg = 1;
724
        }
869
        }
725
        else if (pollret == APR_TIMEUP) {
870
        else if (pollret == APR_TIMEUP) {
726
            *buf = 0;
871
            *buf = 0;
872
            msg = buf;
727
            nRead = 0;
873
            nRead = 0;
728
        }
874
        }
729
        else {
875
        else {
Lines 731-751 int main (int argc, const char * const argv[]) Link Here
731
            exit(5);
877
            exit(5);
732
        }
878
        }
733
#else /* APR_FILES_AS_SOCKETS */
879
#else /* APR_FILES_AS_SOCKETS */
734
        rv = apr_file_read(f_stdin, buf, &nRead);
880
        if (chunked_msgs) {
881
            rv = read_chunk(f_stdin, status.pool, buf, &msg,
882
                            thread_chunks, &nRead);
883
        }
884
        else {
885
            rv = apr_file_read(f_stdin, buf, &nRead);
886
            msg = buf;
887
        }
735
        if (APR_STATUS_IS_EOF(rv)) {
888
        if (APR_STATUS_IS_EOF(rv)) {
736
            break;
889
            break;
737
        }
890
        }
738
        else if (rv != APR_SUCCESS) {
891
        else if (rv != APR_SUCCESS) {
739
            exit(3);
892
            exit(3);
740
        }
893
        }
894
        if (msg == NULL)
895
            skip_write = 1;
896
        else if (msg != buf)
897
            freemsg = 1;
741
#endif /* APR_FILES_AS_SOCKETS */
898
#endif /* APR_FILES_AS_SOCKETS */
742
        checkRotate(&config, &status);
899
        checkRotate(&config, &status);
743
        if (status.rotateReason != ROTATE_NONE) {
900
        if (status.rotateReason != ROTATE_NONE) {
744
            doRotate(&config, &status);
901
            doRotate(&config, &status);
745
        }
902
        }
746
903
904
        if (skip_write)
905
            continue;
906
747
        nWrite = nRead;
907
        nWrite = nRead;
748
        rv = apr_file_write_full(status.current.fd, buf, nWrite, &nWrite);
908
        rv = apr_file_write_full(status.current.fd, msg, nWrite, &nWrite);
749
        if (nWrite != nRead) {
909
        if (nWrite != nRead) {
750
            apr_off_t cur_offset;
910
            apr_off_t cur_offset;
751
            apr_pool_t *pool;
911
            apr_pool_t *pool;
Lines 768-778 int main (int argc, const char * const argv[]) Link Here
768
            status.nMessCount++;
928
            status.nMessCount++;
769
        }
929
        }
770
        if (config.echo) {
930
        if (config.echo) {
771
            if (apr_file_write_full(f_stdout, buf, nRead, NULL)) {
931
            if (apr_file_write_full(f_stdout, msg, nRead, NULL)) {
772
                fprintf(stderr, "Unable to write to stdout\n");
932
                fprintf(stderr, "Unable to write to stdout\n");
773
                exit(4);
933
                exit(4);
774
            }
934
            }
775
        }
935
        }
936
        if (freemsg)
937
            free(msg);
776
    }
938
    }
777
939
778
    return 0; /* reached only at stdin EOF. */
940
    return 0; /* reached only at stdin EOF. */

Return to bug 54339