|
|
6f381c |
From 538bd9b42dabf1145cf7ab77f32347d516b01e88 Mon Sep 17 00:00:00 2001
|
|
|
6f381c |
From: Lennart Poettering <lennart@poettering.net>
|
|
|
6f381c |
Date: Tue, 12 May 2020 18:56:34 +0200
|
|
|
6f381c |
Subject: [PATCH] journald: rework pid change handling
|
|
|
6f381c |
|
|
|
6f381c |
Let's introduce an explicit line ending marker for line endings due to
|
|
|
6f381c |
pid change.
|
|
|
6f381c |
|
|
|
6f381c |
Let's also make sure we don't get confused with buffer management.
|
|
|
6f381c |
|
|
|
6f381c |
Fixes: #15654
|
|
|
6f381c |
(cherry picked from commit 45ba1ea5e9264d385fa565328fe957ef1d78caa1)
|
|
|
6f381c |
|
|
|
6f381c |
Resolves: #2029426
|
|
|
6f381c |
---
|
|
|
6f381c |
src/journal/journald-stream.c | 99 +++++++++++++++++++++++------------
|
|
|
6f381c |
1 file changed, 66 insertions(+), 33 deletions(-)
|
|
|
6f381c |
|
|
|
6f381c |
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
|
|
|
6f381c |
index ab1a855943..5be5b0939c 100644
|
|
|
6f381c |
--- a/src/journal/journald-stream.c
|
|
|
6f381c |
+++ b/src/journal/journald-stream.c
|
|
|
6f381c |
@@ -54,6 +54,7 @@ typedef enum LineBreak {
|
|
|
6f381c |
LINE_BREAK_NUL,
|
|
|
6f381c |
LINE_BREAK_LINE_MAX,
|
|
|
6f381c |
LINE_BREAK_EOF,
|
|
|
6f381c |
+ LINE_BREAK_PID_CHANGE,
|
|
|
6f381c |
_LINE_BREAK_MAX,
|
|
|
6f381c |
_LINE_BREAK_INVALID = -1,
|
|
|
6f381c |
} LineBreak;
|
|
|
6f381c |
@@ -310,6 +311,7 @@ static int stdout_stream_log(
|
|
|
6f381c |
[LINE_BREAK_NUL] = "_LINE_BREAK=nul",
|
|
|
6f381c |
[LINE_BREAK_LINE_MAX] = "_LINE_BREAK=line-max",
|
|
|
6f381c |
[LINE_BREAK_EOF] = "_LINE_BREAK=eof",
|
|
|
6f381c |
+ [LINE_BREAK_PID_CHANGE] = "_LINE_BREAK=pid-change",
|
|
|
6f381c |
};
|
|
|
6f381c |
|
|
|
6f381c |
const char *c = line_break_field_table[line_break];
|
|
|
6f381c |
@@ -431,21 +433,43 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
|
|
|
6f381c |
assert_not_reached("Unknown stream state");
|
|
|
6f381c |
}
|
|
|
6f381c |
|
|
|
6f381c |
-static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
|
|
|
6f381c |
- char *p;
|
|
|
6f381c |
- size_t remaining;
|
|
|
6f381c |
+static int stdout_stream_found(
|
|
|
6f381c |
+ StdoutStream *s,
|
|
|
6f381c |
+ char *p,
|
|
|
6f381c |
+ size_t l,
|
|
|
6f381c |
+ LineBreak line_break) {
|
|
|
6f381c |
+
|
|
|
6f381c |
+ char saved;
|
|
|
6f381c |
int r;
|
|
|
6f381c |
|
|
|
6f381c |
assert(s);
|
|
|
6f381c |
+ assert(p);
|
|
|
6f381c |
+
|
|
|
6f381c |
+ /* Let's NUL terminate the specified buffer for this call, and revert back afterwards */
|
|
|
6f381c |
+ saved = p[l];
|
|
|
6f381c |
+ p[l] = 0;
|
|
|
6f381c |
+ r = stdout_stream_line(s, p, line_break);
|
|
|
6f381c |
+ p[l] = saved;
|
|
|
6f381c |
|
|
|
6f381c |
- p = s->buffer;
|
|
|
6f381c |
- remaining = s->length;
|
|
|
6f381c |
+ return r;
|
|
|
6f381c |
+}
|
|
|
6f381c |
+
|
|
|
6f381c |
+static int stdout_stream_scan(
|
|
|
6f381c |
+ StdoutStream *s,
|
|
|
6f381c |
+ char *p,
|
|
|
6f381c |
+ size_t remaining,
|
|
|
6f381c |
+ LineBreak force_flush,
|
|
|
6f381c |
+ size_t *ret_consumed) {
|
|
|
6f381c |
|
|
|
6f381c |
- /* XXX: This function does nothing if (s->length == 0) */
|
|
|
6f381c |
+ size_t consumed = 0;
|
|
|
6f381c |
+ int r;
|
|
|
6f381c |
+
|
|
|
6f381c |
+ assert(s);
|
|
|
6f381c |
+ assert(p);
|
|
|
6f381c |
|
|
|
6f381c |
for (;;) {
|
|
|
6f381c |
LineBreak line_break;
|
|
|
6f381c |
- size_t skip;
|
|
|
6f381c |
+ size_t skip, found;
|
|
|
6f381c |
char *end1, *end2;
|
|
|
6f381c |
|
|
|
6f381c |
end1 = memchr(p, '\n', remaining);
|
|
|
6f381c |
@@ -453,43 +477,40 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
|
|
|
6f381c |
|
|
|
6f381c |
if (end2) {
|
|
|
6f381c |
/* We found a NUL terminator */
|
|
|
6f381c |
- skip = end2 - p + 1;
|
|
|
6f381c |
+ found = end2 - p;
|
|
|
6f381c |
+ skip = found + 1;
|
|
|
6f381c |
line_break = LINE_BREAK_NUL;
|
|
|
6f381c |
} else if (end1) {
|
|
|
6f381c |
/* We found a \n terminator */
|
|
|
6f381c |
- *end1 = 0;
|
|
|
6f381c |
- skip = end1 - p + 1;
|
|
|
6f381c |
+ found = end1 - p;
|
|
|
6f381c |
+ skip = found + 1;
|
|
|
6f381c |
line_break = LINE_BREAK_NEWLINE;
|
|
|
6f381c |
} else if (remaining >= s->server->line_max) {
|
|
|
6f381c |
/* Force a line break after the maximum line length */
|
|
|
6f381c |
- *(p + s->server->line_max) = 0;
|
|
|
6f381c |
- skip = remaining;
|
|
|
6f381c |
+ found = skip = s->server->line_max;
|
|
|
6f381c |
line_break = LINE_BREAK_LINE_MAX;
|
|
|
6f381c |
} else
|
|
|
6f381c |
break;
|
|
|
6f381c |
|
|
|
6f381c |
- r = stdout_stream_line(s, p, line_break);
|
|
|
6f381c |
+ r = stdout_stream_found(s, p, found, line_break);
|
|
|
6f381c |
if (r < 0)
|
|
|
6f381c |
return r;
|
|
|
6f381c |
|
|
|
6f381c |
- remaining -= skip;
|
|
|
6f381c |
p += skip;
|
|
|
6f381c |
+ consumed += skip;
|
|
|
6f381c |
+ remaining -= skip;
|
|
|
6f381c |
}
|
|
|
6f381c |
|
|
|
6f381c |
- if (force_flush && remaining > 0) {
|
|
|
6f381c |
- p[remaining] = 0;
|
|
|
6f381c |
- r = stdout_stream_line(s, p, LINE_BREAK_EOF);
|
|
|
6f381c |
+ if (force_flush >= 0 && remaining > 0) {
|
|
|
6f381c |
+ r = stdout_stream_found(s, p, remaining, force_flush);
|
|
|
6f381c |
if (r < 0)
|
|
|
6f381c |
return r;
|
|
|
6f381c |
|
|
|
6f381c |
- p += remaining;
|
|
|
6f381c |
- remaining = 0;
|
|
|
6f381c |
+ consumed += remaining;
|
|
|
6f381c |
}
|
|
|
6f381c |
|
|
|
6f381c |
- if (p > s->buffer) {
|
|
|
6f381c |
- memmove(s->buffer, p, remaining);
|
|
|
6f381c |
- s->length = remaining;
|
|
|
6f381c |
- }
|
|
|
6f381c |
+ if (ret_consumed)
|
|
|
6f381c |
+ *ret_consumed = consumed;
|
|
|
6f381c |
|
|
|
6f381c |
return 0;
|
|
|
6f381c |
}
|
|
|
6f381c |
@@ -497,11 +518,12 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
|
|
|
6f381c |
static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
|
|
|
6f381c |
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
|
|
|
6f381c |
StdoutStream *s = userdata;
|
|
|
6f381c |
+ size_t limit, consumed;
|
|
|
6f381c |
struct ucred *ucred = NULL;
|
|
|
6f381c |
struct cmsghdr *cmsg;
|
|
|
6f381c |
struct iovec iovec;
|
|
|
6f381c |
- size_t limit;
|
|
|
6f381c |
ssize_t l;
|
|
|
6f381c |
+ char *p;
|
|
|
6f381c |
int r;
|
|
|
6f381c |
|
|
|
6f381c |
struct msghdr msghdr = {
|
|
|
6f381c |
@@ -529,7 +551,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
|
|
|
6f381c |
/* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also,
|
|
|
6f381c |
* always leave room for a terminating NUL we might need to add. */
|
|
|
6f381c |
limit = MIN(s->allocated - 1, s->server->line_max);
|
|
|
6f381c |
-
|
|
|
6f381c |
+ assert(s->length <= limit);
|
|
|
6f381c |
iovec = IOVEC_MAKE(s->buffer + s->length, limit - s->length);
|
|
|
6f381c |
|
|
|
6f381c |
l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
|
|
|
6f381c |
@@ -543,7 +565,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
|
|
|
6f381c |
cmsg_close_all(&msghdr);
|
|
|
6f381c |
|
|
|
6f381c |
if (l == 0) {
|
|
|
6f381c |
- stdout_stream_scan(s, true);
|
|
|
6f381c |
+ (void) stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_EOF, NULL);
|
|
|
6f381c |
goto terminate;
|
|
|
6f381c |
}
|
|
|
6f381c |
|
|
|
6f381c |
@@ -562,22 +584,33 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
|
|
|
6f381c |
* in the meantime.
|
|
|
6f381c |
*/
|
|
|
6f381c |
if (ucred && ucred->pid != s->ucred.pid) {
|
|
|
6f381c |
- /* force out any previously half-written lines from a
|
|
|
6f381c |
- * different process, before we switch to the new ucred
|
|
|
6f381c |
- * structure for everything we just added */
|
|
|
6f381c |
- r = stdout_stream_scan(s, true);
|
|
|
6f381c |
+ /* Force out any previously half-written lines from a different process, before we switch to
|
|
|
6f381c |
+ * the new ucred structure for everything we just added */
|
|
|
6f381c |
+ r = stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_PID_CHANGE, NULL);
|
|
|
6f381c |
if (r < 0)
|
|
|
6f381c |
goto terminate;
|
|
|
6f381c |
|
|
|
6f381c |
- s->ucred = *ucred;
|
|
|
6f381c |
s->context = client_context_release(s->server, s->context);
|
|
|
6f381c |
+
|
|
|
6f381c |
+ p = s->buffer + s->length;
|
|
|
6f381c |
+ } else {
|
|
|
6f381c |
+ p = s->buffer;
|
|
|
6f381c |
+ l += s->length;
|
|
|
6f381c |
}
|
|
|
6f381c |
|
|
|
6f381c |
- s->length += l;
|
|
|
6f381c |
- r = stdout_stream_scan(s, false);
|
|
|
6f381c |
+ /* Always copy in the new credentials */
|
|
|
6f381c |
+ if (ucred)
|
|
|
6f381c |
+ s->ucred = *ucred;
|
|
|
6f381c |
+
|
|
|
6f381c |
+ r = stdout_stream_scan(s, p, l, _LINE_BREAK_INVALID, &consumed);
|
|
|
6f381c |
if (r < 0)
|
|
|
6f381c |
goto terminate;
|
|
|
6f381c |
|
|
|
6f381c |
+ /* Move what wasn't consumed to the front of the buffer */
|
|
|
6f381c |
+ assert(consumed <= (size_t) l);
|
|
|
6f381c |
+ s->length = l - consumed;
|
|
|
6f381c |
+ memmove(s->buffer, p + consumed, s->length);
|
|
|
6f381c |
+
|
|
|
6f381c |
return 1;
|
|
|
6f381c |
|
|
|
6f381c |
terminate:
|