commit 7fba356b1378b0d470f746b45797c229e9d882cd
parent cedfe51030470abecc325b54656098376cc70305
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date: Fri, 22 Jan 2021 19:10:56 +0000
bugfix: make s6-log -l actually split
Diffstat:
2 files changed, 37 insertions(+), 20 deletions(-)
diff --git a/doc/s6-log.html b/doc/s6-log.html
@@ -68,11 +68,13 @@ Currently supported verbosity levels:
<li> 1: write alerts, warnings and fatal errors </li>
</ul> </li>
<li> <tt>-l <em>linelimit</em></tt> : if a log line is longer than
-<em>linelimit</em> bytes, cut it in two by inserting a newline. The newline
-may appear anywhere after <em>linelimit</em> or more bytes. <em>linelimit</em>
-cannot be less than 48. Using this option ensures that an ill-formatted log
-stream will not make s6-log uncontrollably eat memory by trying to read and
-process an extremely long line in one go. The default is 8192 bytes. </li>
+<em>linelimit</em> bytes, split it by inserting a newline after the
+<em>linelimit</em>th byte. After the split, the remainder of the line will
+also be processed, so it will go through the selection process, timestamping,
+etc. <em>linelimit</em> cannot be less than 48, unless it is 0 (which means
+infinite). The default is 8192 bytes. Setting <em>linelimit</em> to 0 ensures
+that lines will never be split; this may cause important memory consumption
+by s6-log if it is fed extremely long lines, so use with caution. </li>
</ul>
<h2> Logdirs </h2>
diff --git a/src/daemontools-extras/s6-log.c b/src/daemontools-extras/s6-log.c
@@ -31,7 +31,6 @@
#include <skalibs/sig.h>
#include <skalibs/selfpipe.h>
#include <skalibs/siovec.h>
-#include <skalibs/skamisc.h>
#include <skalibs/exec.h>
#include <s6/config.h>
@@ -1010,6 +1009,29 @@ static void prepare_to_exit (void)
flagexiting = 1 ;
}
+static inline int getchunk (buffer *b, stralloc *sa, size_t linelimit)
+{
+ struct iovec v[2] ;
+ size_t pos ;
+ int r ;
+ buffer_rpeek(b, v) ;
+ pos = siovec_bytein(v, 2, "\n", 2) ;
+ if (linelimit && sa->len + pos > linelimit)
+ {
+ r = 2 ;
+ pos = linelimit - sa->len ;
+ }
+ else
+ {
+ r = pos < buffer_len(b) ;
+ pos += r ;
+ }
+ if (!stralloc_readyplus(sa, pos + (r == 2))) return -1 ;
+ buffer_getnofill(b, sa->s + sa->len, pos) ; sa->len += pos ;
+ if (r == 2) sa->s[sa->len++] = 0 ;
+ return r ;
+}
+
static void normal_stdin (scriptelem_t const *script, unsigned int scriptlen, size_t linelimit, unsigned int gflags)
{
ssize_t r = sanitize_read(buffer_fill(buffer_0)) ;
@@ -1018,21 +1040,14 @@ static void normal_stdin (scriptelem_t const *script, unsigned int scriptlen, si
if ((errno != EPIPE) && verbosity) strerr_warnwu1sys("read from stdin") ;
prepare_to_exit() ;
}
- else if (r)
+ else if (r) for (;;)
{
- while (skagetln_nofill(buffer_0, &indata, '\n') > 0)
- {
- indata.s[indata.len - 1] = 0 ;
- script_run(script, scriptlen, indata.s, indata.len - 1, gflags) ;
- indata.len = 0 ;
- }
- if (linelimit && indata.len > linelimit)
- {
- if (!stralloc_0(&indata)) dienomem() ;
- if (verbosity) strerr_warnw2x("input line too long, ", "inserting a newline") ;
- script_run(script, scriptlen, indata.s, indata.len - 1, gflags) ;
- indata.len = 0 ;
- }
+ r = getchunk(buffer_0, &indata, linelimit) ;
+ if (r < 0) dienomem() ;
+ else if (!r) break ;
+ indata.s[indata.len - 1] = 0 ;
+ script_run(script, scriptlen, indata.s, indata.len - 1, gflags) ;
+ indata.len = 0 ;
}
}