X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fjournal%2Fjournald.c;h=73f8ed6ae8474b14ace2df49f7f56b27960f60c1;hb=632117b71fdd2d1b9da7418d00ec21c18d60dedd;hp=56cd31317e93f19eec92652163ed55beafe9f516;hpb=8a0f04e6a283cc6734ee09a20305c13e09ba0418;p=elogind.git diff --git a/src/journal/journald.c b/src/journal/journald.c index 56cd31317..73f8ed6ae 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -66,10 +66,10 @@ #define RECHECK_VAR_AVAILABLE_USEC (30*USEC_PER_SEC) -#define SYSLOG_TIMEOUT_USEC (250*USEC_PER_MSEC) - #define N_IOVEC_META_FIELDS 17 +#define ENTRY_SIZE_MAX (1024*1024*32) + typedef enum StdoutStreamState { STDOUT_STREAM_IDENTIFIER, STDOUT_STREAM_PRIORITY, @@ -487,7 +487,7 @@ static void dispatch_message_real(Server *s, exe = strappend("_EXE=", t); free(t); - if (comm) + if (exe) IOVEC_SET_STRING(iovec[n++], exe); } @@ -752,6 +752,11 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0) return; + /* The socket is full? I guess the syslog implementation is + * too slow, and we shouldn't wait for that... */ + if (errno == EAGAIN) + return; + if (ucred && errno == ESRCH) { struct ucred u; @@ -765,6 +770,9 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0) return; + + if (errno == EAGAIN) + return; } log_debug("Failed to forward syslog message: %m"); @@ -1283,6 +1291,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; @@ -1292,6 +1346,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) @@ -1346,10 +1403,14 @@ static int stdout_stream_line(StdoutStream *s, char *p) { switch (s->state) { case STDOUT_STREAM_IDENTIFIER: - s->identifier = strdup(p); - if (!s->identifier) { - log_error("Out of memory"); - return -ENOMEM; + if (isempty(p)) + s->identifier = NULL; + else { + s->identifier = strdup(p); + if (!s->identifier) { + log_error("Out of memory"); + return -ENOMEM; + } } s->state = STDOUT_STREAM_PRIORITY; @@ -1641,6 +1702,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) @@ -1689,7 +1753,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); @@ -2019,19 +2082,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; @@ -2059,7 +2122,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) @@ -2079,20 +2142,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; @@ -2138,7 +2218,6 @@ static int open_syslog_socket(Server *s) { union sockaddr_union sa; int one, r; struct epoll_event ev; - struct timeval tv; assert(s); @@ -2163,7 +2242,8 @@ static int open_syslog_socket(Server *s) { } chmod(sa.un.sun_path, 0666); - } + } else + fd_nonblock(s->syslog_fd, 1); one = 1; r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); @@ -2179,15 +2259,6 @@ static int open_syslog_socket(Server *s) { return -errno; } - /* Since we use the same socket for forwarding this to some - * other syslog implementation, make sure we don't hang - * forever */ - timeval_store(&tv, SYSLOG_TIMEOUT_USEC); - if (setsockopt(s->syslog_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { - log_error("SO_SNDTIMEO failed: %m"); - return -errno; - } - zero(ev); ev.events = EPOLLIN; ev.data.fd = s->syslog_fd; @@ -2227,7 +2298,8 @@ static int open_native_socket(Server*s) { } chmod(sa.un.sun_path, 0666); - } + } else + fd_nonblock(s->native_fd, 1); one = 1; r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); @@ -2287,7 +2359,8 @@ static int open_stdout_socket(Server *s) { log_error("liste() failed: %m"); return -errno; } - } + } else + fd_nonblock(s->stdout_fd, 1); zero(ev); ev.events = EPOLLIN;