summaryrefslogtreecommitdiff
path: root/src/journal/journald.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-01-14 01:53:20 +0100
committerLennart Poettering <lennart@poettering.net>2012-01-14 01:54:33 +0100
commit0dad12c190b7493955cd60d2a1625199b1709f69 (patch)
tree607e747209911ae62a71a23bbc5cb71a6e492580 /src/journal/journald.c
parentf5e04665ebf7124f3ea17dcf258793ed73a95fe1 (diff)
journal: if the data to be sent is larger than the maximum datagram size resort to passing a temporary fd over native protocol
Diffstat (limited to 'src/journal/journald.c')
-rw-r--r--src/journal/journald.c98
1 files changed, 84 insertions, 14 deletions
diff --git a/src/journal/journald.c b/src/journal/journald.c
index f924c9353b..53dbf8e138 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -70,6 +70,8 @@
#define N_IOVEC_META_FIELDS 17
+#define ENTRY_SIZE_MAX (1024*1024*32)
+
typedef enum StdoutStreamState {
STDOUT_STREAM_IDENTIFIER,
STDOUT_STREAM_PRIORITY,
@@ -1291,6 +1293,52 @@ finish:
free(message);
}
+static void process_native_file(Server *s, int fd, struct ucred *ucred, struct timeval *tv) {
+ struct stat st;
+ void *p;
+ ssize_t n;
+
+ assert(s);
+ assert(fd >= 0);
+
+ /* Data is in the passed file, since it didn't fit in a
+ * datagram. We can't map the file here, since clients might
+ * then truncate it and trigger a SIGBUS for us. So let's
+ * stupidly read it */
+
+ if (fstat(fd, &st) < 0) {
+ log_error("Failed to stat passed file, ignoring: %m");
+ return;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ log_error("File passed is not regular. Ignoring.");
+ return;
+ }
+
+ if (st.st_size <= 0)
+ return;
+
+ if (st.st_size > ENTRY_SIZE_MAX) {
+ log_error("File passed too large. Ignoring.");
+ return;
+ }
+
+ p = malloc(st.st_size);
+ if (!p) {
+ log_error("Out of memory");
+ return;
+ }
+
+ n = pread(fd, p, st.st_size, 0);
+ if (n < 0)
+ log_error("Failed to read file, ignoring: %s", strerror(-n));
+ else if (n > 0)
+ process_native_message(s, p, n, ucred, tv);
+
+ free(p);
+}
+
static int stdout_stream_log(StdoutStream *s, const char *p) {
struct iovec iovec[N_IOVEC_META_FIELDS + 5];
char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL;
@@ -1300,6 +1348,9 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
assert(s);
assert(p);
+ if (isempty(p))
+ return 0;
+
priority = s->priority;
if (s->level_prefix)
@@ -1649,6 +1700,9 @@ static void proc_kmsg_line(Server *s, const char *p) {
assert(s);
assert(p);
+ if (isempty(p))
+ return;
+
parse_syslog_priority((char **) &p, &priority);
if (s->forward_to_kmsg && (priority & LOG_FACMASK) != LOG_KERN)
@@ -1697,7 +1751,6 @@ static void proc_kmsg_line(Server *s, const char *p) {
if (message)
IOVEC_SET_STRING(iovec[n++], message);
-
dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, priority);
free(message);
@@ -2027,19 +2080,19 @@ static int process_event(Server *s, struct epoll_event *ev) {
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(struct timeval))];
+ CMSG_SPACE(sizeof(struct timeval)) +
+ CMSG_SPACE(sizeof(int))];
} control;
ssize_t n;
int v;
+ int *fds = NULL;
+ unsigned n_fds = 0;
if (ioctl(ev->data.fd, SIOCINQ, &v) < 0) {
log_error("SIOCINQ failed: %m");
return -errno;
}
- if (v <= 0)
- return 1;
-
if (s->buffer_size < (size_t) v) {
void *b;
size_t l;
@@ -2067,7 +2120,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
msghdr.msg_control = &control;
msghdr.msg_controllen = sizeof(control);
- n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT);
+ n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
if (errno == EINTR || errno == EAGAIN)
@@ -2087,20 +2140,37 @@ static int process_event(Server *s, struct epoll_event *ev) {
cmsg->cmsg_type == SO_TIMESTAMP &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
tv = (struct timeval*) CMSG_DATA(cmsg);
+ else if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ fds = (int*) CMSG_DATA(cmsg);
+ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+ }
}
if (ev->data.fd == s->syslog_fd) {
char *e;
- e = memchr(s->buffer, '\n', n);
- if (e)
- *e = 0;
- else
- s->buffer[n] = 0;
+ if (n > 0 && n_fds == 0) {
+ e = memchr(s->buffer, '\n', n);
+ if (e)
+ *e = 0;
+ else
+ s->buffer[n] = 0;
+
+ process_syslog_message(s, strstrip(s->buffer), ucred, tv);
+ } else if (n_fds > 0)
+ log_warning("Got file descriptors via syslog socket. Ignoring.");
+
+ } else {
+ if (n > 0 && n_fds == 0)
+ process_native_message(s, s->buffer, n, ucred, tv);
+ else if (n == 0 && n_fds == 1)
+ process_native_file(s, fds[0], ucred, tv);
+ else if (n_fds > 0)
+ log_warning("Got too many file descriptors via native socket. Ignoring.");
+ }
- process_syslog_message(s, strstrip(s->buffer), ucred, tv);
- } else
- process_native_message(s, s->buffer, n, ucred, tv);
+ close_many(fds, n_fds);
}
return 1;