mirror of
https://github.com/systemd/systemd.git
synced 2024-11-06 16:59:03 +03:00
journal: if the data to be sent is larger than the maximum datagram size resort to passing a temporary fd over native protocol
This commit is contained in:
parent
f5e04665eb
commit
0dad12c190
@ -23,6 +23,8 @@
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "sd-journal.h"
|
||||
#include "util.h"
|
||||
@ -132,12 +134,19 @@ fail:
|
||||
}
|
||||
|
||||
_public_ int sd_journal_sendv(const struct iovec *iov, int n) {
|
||||
int fd;
|
||||
int fd, buffer_fd;
|
||||
struct iovec *w;
|
||||
uint64_t *l;
|
||||
int i, j = 0;
|
||||
struct msghdr mh;
|
||||
struct sockaddr_un sa;
|
||||
char path[] = "/tmp/journal.XXXXXX";
|
||||
ssize_t k;
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
uint8_t buf[CMSG_SPACE(sizeof(int))];
|
||||
} control;
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
if (!iov || n <= 0)
|
||||
return -EINVAL;
|
||||
@ -203,7 +212,51 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
|
||||
mh.msg_iov = w;
|
||||
mh.msg_iovlen = j;
|
||||
|
||||
if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0)
|
||||
k = sendmsg(fd, &mh, MSG_NOSIGNAL);
|
||||
if (k >= 0)
|
||||
return 0;
|
||||
|
||||
if (errno != EMSGSIZE)
|
||||
return -errno;
|
||||
|
||||
/* Message doesn't fit... Let's dump the data in a temporary
|
||||
* file and just pass a file descriptor of it to the other
|
||||
* side */
|
||||
|
||||
buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
|
||||
if (buffer_fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (unlink(path) < 0) {
|
||||
close_nointr_nofail(buffer_fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
n = writev(buffer_fd, w, j);
|
||||
if (n < 0) {
|
||||
close_nointr_nofail(buffer_fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
mh.msg_iov = NULL;
|
||||
mh.msg_iovlen = 0;
|
||||
|
||||
zero(control);
|
||||
mh.msg_control = &control;
|
||||
mh.msg_controllen = sizeof(control);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&mh);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
|
||||
|
||||
mh.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
k = sendmsg(fd, &mh, MSG_NOSIGNAL);
|
||||
close_nointr_nofail(buffer_fd);
|
||||
|
||||
if (k < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
|
@ -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,11 +2140,17 @@ 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;
|
||||
|
||||
if (n > 0 && n_fds == 0) {
|
||||
e = memchr(s->buffer, '\n', n);
|
||||
if (e)
|
||||
*e = 0;
|
||||
@ -2099,8 +2158,19 @@ static int process_event(Server *s, struct epoll_event *ev) {
|
||||
s->buffer[n] = 0;
|
||||
|
||||
process_syslog_message(s, strstrip(s->buffer), ucred, tv);
|
||||
} else
|
||||
} 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.");
|
||||
}
|
||||
|
||||
close_many(fds, n_fds);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
Loading…
Reference in New Issue
Block a user