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",
1725
                             "", p) != 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 518-523 static const char *get_time_or_size(rotate_config_t *config, Link Here
518
    return NULL;
525
    return NULL;
519
}
526
}
520
527
528
static apr_status_t read_chunk(apr_file_t *f_stdin, apr_pool_t *p, char *buf,
529
                               char **msg, apr_hash_t *thread_chunks,
530
                               apr_size_t *nRead)
531
{
532
    apr_status_t rv;
533
    uint32_t chunk_header[MSG_HEADER_ELT_CNT];
534
    uint32_t proc_slot, thd_slot, chunk_cnt, tot_chunk_cnt, chunk_body_len;
535
536
    /* Read just the chunk header, expected to be present in its entirety. */
537
    rv = apr_file_read_full(f_stdin, chunk_header, MSG_HEADER_LEN, nRead);
538
    if (APR_STATUS_IS_EOF(rv)) {
539
        return rv;
540
    }
541
    else if (rv != APR_SUCCESS) {
542
        exit(3);
543
    }
544
    proc_slot = ntohl(chunk_header[0]);
545
    thd_slot = ntohl(chunk_header[1]);
546
    chunk_cnt = ntohl(chunk_header[2]);
547
    tot_chunk_cnt = ntohl(chunk_header[3]);
548
    chunk_body_len = ntohl(chunk_header[4]);
549
550
    /* Read the full chunk body, expected to be present in its entirety. */
551
    rv = apr_file_read_full(f_stdin, buf, (apr_size_t)chunk_body_len, nRead);
552
    if (APR_STATUS_IS_EOF(rv)) {
553
        return rv;
554
    }
555
    else if (rv != APR_SUCCESS) {
556
        exit(3);
557
    }
558
559
    if (chunk_cnt != 1 || tot_chunk_cnt != 1) {
560
        /* 
561
         * If this is a multi-chunk log record, stage the chunks so they can be
562
         * reassembled in order.
563
         */
564
        uint32_t chunk_idx = chunk_cnt - 1;
565
        char *chunk_body;
566
        char **chunk_elem;
567
        char *slot_key;
568
        apr_array_header_t *chunks_head;
569
570
        slot_key = apr_psprintf(p, "%i.%i", proc_slot, thd_slot);
571
        chunks_head = apr_hash_get(thread_chunks, slot_key,
572
                                   APR_HASH_KEY_STRING);
573
        /* A thread must write chunks of a message in order. */
574
        if (chunks_head == NULL) {
575
            if (chunk_idx > 0) {
576
                /*
577
                 * Expected to have a table entry here since we're in
578
                 * mid-sequence for this chunk set.
579
                 */
580
                fprintf(stderr, "Chunks found in a non-ordered sequence, "
581
                                "skipping this chunk set\n");
582
                return APR_SUCCESS;
583
            }
584
            chunks_head = apr_array_make(p, 10, sizeof(char *));
585
            apr_hash_set(thread_chunks, slot_key, APR_HASH_KEY_STRING,
586
                         chunks_head);
587
        }
588
        else {
589
            /* Check that the chunk list size jives with chunk_cnt. */
590
            if (chunk_idx != chunks_head->nelts) {
591
                fprintf(stderr, "Chunks found in a non-ordered sequence, "
592
                                "skipping this chunk set\n");
593
                apr_array_clear(chunks_head);
594
                return APR_SUCCESS;
595
            }
596
        }
597
598
        chunk_elem = apr_array_push(chunks_head);
599
600
        /* Stage this chunk. */
601
        chunk_body = malloc(chunk_body_len);
602
        memcpy(chunk_body, buf, chunk_body_len);
603
        *chunk_elem = chunk_body;
604
605
        if (chunk_cnt == tot_chunk_cnt) {
606
            /*
607
             * If this is the final chunk, glue them together so the original
608
             * message can be written below.
609
             */
610
            uint32_t chunk_len;
611
            uint32_t chunk_iter;
612
            uint32_t cpy_len = 0;
613
614
            *msg = malloc(LOG_BUFSIZE_LESS_CHUNKHEAD * tot_chunk_cnt);
615
            for (chunk_iter = 0; chunk_iter < chunks_head->nelts;
616
                 ++chunk_iter) {
617
                char *chunk = ((char**)chunks_head->elts)[chunk_iter];
618
                chunk_len = LOG_BUFSIZE_LESS_CHUNKHEAD;
619
                if (chunk_iter + 1 == tot_chunk_cnt)
620
                    chunk_len = chunk_body_len;
621
                memcpy(*msg + cpy_len, chunk, chunk_len);
622
                cpy_len += chunk_len;
623
                free(chunk);
624
            }
625
            *nRead = cpy_len;
626
            apr_array_clear(chunks_head);
627
        }
628
        else {
629
            /* Otherwise continue staging and writing single-chunk messages. */
630
            return APR_SUCCESS;
631
        }
632
    }
633
    else {
634
        /*
635
         * This log message is transferred in a single chunk, simply return and
636
         * write it.
637
         */
638
        *msg = buf;
639
    }
640
    return APR_SUCCESS;
641
}
642
521
int main (int argc, const char * const argv[])
643
int main (int argc, const char * const argv[])
522
{
644
{
523
    char buf[BUFSIZE];
645
    char buf[BUFSIZE];
Lines 527-534 int main (int argc, const char * const argv[]) Link Here
527
    apr_getopt_t *opt;
649
    apr_getopt_t *opt;
528
    apr_status_t rv;
650
    apr_status_t rv;
529
    char c;
651
    char c;
652
    char *env;
530
    const char *opt_arg;
653
    const char *opt_arg;
531
    const char *err = NULL;
654
    const char *err = NULL;
655
    int chunked_msgs;
656
    apr_hash_t *thread_chunks;
657
    char *msg;
532
#if APR_FILES_AS_SOCKETS
658
#if APR_FILES_AS_SOCKETS
533
    apr_pollfd_t pollfd = { 0 };
659
    apr_pollfd_t pollfd = { 0 };
534
    apr_status_t pollret = APR_SUCCESS;
660
    apr_status_t pollret = APR_SUCCESS;
Lines 648-653 int main (int argc, const char * const argv[]) Link Here
648
    }
774
    }
649
#endif
775
#endif
650
776
777
    rv = apr_env_get(&env, "AP_MOD_LOG_CONFIG_CHUNKED_MSG", status.pool);
778
    chunked_msgs = (rv == APR_SUCCESS && env != NULL);
779
780
    thread_chunks = apr_hash_make(status.pool);
781
651
    /*
782
    /*
652
     * Immediately open the logfile as we start, if we were forced
783
     * Immediately open the logfile as we start, if we were forced
653
     * to do so via '-f'.
784
     * to do so via '-f'.
Lines 657-663 int main (int argc, const char * const argv[]) Link Here
657
    }
788
    }
658
789
659
    for (;;) {
790
    for (;;) {
791
        int freemsg = 0;
792
        int skip_write = 0;
660
        nRead = sizeof(buf);
793
        nRead = sizeof(buf);
794
        msg = NULL;
661
#if APR_FILES_AS_SOCKETS
795
#if APR_FILES_AS_SOCKETS
662
        if (config.create_empty && config.tRotation) {
796
        if (config.create_empty && config.tRotation) {
663
            polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config) : config.tRotation;
797
            polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config) : config.tRotation;
Lines 669-684 int main (int argc, const char * const argv[]) Link Here
669
            }
803
            }
670
        }
804
        }
671
        if (pollret == APR_SUCCESS) {
805
        if (pollret == APR_SUCCESS) {
672
            rv = apr_file_read(f_stdin, buf, &nRead);
806
            if (chunked_msgs) {
807
                rv = read_chunk(f_stdin, status.pool, buf, &msg,
808
                                thread_chunks, &nRead);
809
            }
810
            else {
811
                rv = apr_file_read(f_stdin, buf, &nRead);
812
                msg = buf;
813
            }
673
            if (APR_STATUS_IS_EOF(rv)) {
814
            if (APR_STATUS_IS_EOF(rv)) {
674
                break;
815
                break;
675
            }
816
            }
676
            else if (rv != APR_SUCCESS) {
817
            else if (rv != APR_SUCCESS) {
677
                exit(3);
818
                exit(3);
678
            }
819
            }
820
            if (msg == NULL)
821
                skip_write = 1;
822
            else if (msg != buf)
823
                freemsg = 1;
679
        }
824
        }
680
        else if (pollret == APR_TIMEUP) {
825
        else if (pollret == APR_TIMEUP) {
681
            *buf = 0;
826
            *buf = 0;
827
            msg = buf;
682
            nRead = 0;
828
            nRead = 0;
683
        }
829
        }
684
        else {
830
        else {
Lines 686-706 int main (int argc, const char * const argv[]) Link Here
686
            exit(5);
832
            exit(5);
687
        }
833
        }
688
#else /* APR_FILES_AS_SOCKETS */
834
#else /* APR_FILES_AS_SOCKETS */
689
        rv = apr_file_read(f_stdin, buf, &nRead);
835
        if (chunked_msgs) {
836
            rv = read_chunk(f_stdin, status.pool, buf, &msg,
837
                            thread_chunks, &nRead);
838
        }
839
        else {
840
            rv = apr_file_read(f_stdin, buf, &nRead);
841
            msg = buf;
842
        }
690
        if (APR_STATUS_IS_EOF(rv)) {
843
        if (APR_STATUS_IS_EOF(rv)) {
691
            break;
844
            break;
692
        }
845
        }
693
        else if (rv != APR_SUCCESS) {
846
        else if (rv != APR_SUCCESS) {
694
            exit(3);
847
            exit(3);
695
        }
848
        }
849
        if (msg == NULL)
850
            skip_write = 1;
851
        else if (msg != buf)
852
            freemsg = 1;
696
#endif /* APR_FILES_AS_SOCKETS */
853
#endif /* APR_FILES_AS_SOCKETS */
697
        checkRotate(&config, &status);
854
        checkRotate(&config, &status);
698
        if (status.rotateReason != ROTATE_NONE) {
855
        if (status.rotateReason != ROTATE_NONE) {
699
            doRotate(&config, &status);
856
            doRotate(&config, &status);
700
        }
857
        }
701
858
859
        if (skip_write)
860
            continue;
861
702
        nWrite = nRead;
862
        nWrite = nRead;
703
        rv = apr_file_write_full(status.current.fd, buf, nWrite, &nWrite);
863
        rv = apr_file_write_full(status.current.fd, msg, nWrite, &nWrite);
704
        if (nWrite != nRead) {
864
        if (nWrite != nRead) {
705
            apr_off_t cur_offset;
865
            apr_off_t cur_offset;
706
866
Lines 720-730 int main (int argc, const char * const argv[]) Link Here
720
            status.nMessCount++;
880
            status.nMessCount++;
721
        }
881
        }
722
        if (config.echo) {
882
        if (config.echo) {
723
            if (apr_file_write_full(f_stdout, buf, nRead, &nWrite)) {
883
            if (apr_file_write_full(f_stdout, msg, nRead, &nWrite)) {
724
                fprintf(stderr, "Unable to write to stdout\n");
884
                fprintf(stderr, "Unable to write to stdout\n");
725
                exit(4);
885
                exit(4);
726
            }
886
            }
727
        }
887
        }
888
        if (freemsg)
889
            free(msg);
728
    }
890
    }
729
891
730
    return 0; /* reached only at stdin EOF. */
892
    return 0; /* reached only at stdin EOF. */

Return to bug 54339