X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fjournal%2Fjournald.c;h=a25f81ef666d942a17a2d1df30887db2f381da9b;hb=b3a0ad5ab142a142ab526aeb3d0b69e98e4e523c;hp=1efe0420dbdb869b35a12841c3f6d95023c333a2;hpb=cf244689e9d1ab50082c9ddd0f3c4d1eb982badc;p=elogind.git diff --git a/src/journal/journald.c b/src/journal/journald.c index 1efe0420d..a25f81ef6 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -51,6 +51,10 @@ #define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC) +#define RECHECK_VAR_AVAILABLE_USEC (30*USEC_PER_SEC) + +#define SYSLOG_TIMEOUT_USEC (5*USEC_PER_SEC) + typedef struct StdoutStream StdoutStream; typedef struct Server { @@ -78,6 +82,8 @@ typedef struct Server { uint64_t cached_available_space; usec_t cached_available_space_timestamp; + uint64_t var_available_timestamp; + LIST_HEAD(StdoutStream, stdout_streams); unsigned n_stdout_streams; } Server; @@ -372,11 +378,22 @@ static char *shortened_cgroup_path(pid_t pid) { if (streq(init_path, "/")) init_path[0] = 0; - if (startswith(process_path, init_path)) - path = process_path + strlen(init_path); - else + if (startswith(process_path, init_path)) { + char *p; + + p = strdup(process_path + strlen(init_path)); + if (!p) { + free(process_path); + free(init_path); + return NULL; + } + path = p; + } else { path = process_path; + process_path = NULL; + } + free(process_path); free(init_path); return path; @@ -538,7 +555,7 @@ static void dispatch_message(Server *s, struct timeval *tv, int priority) { int rl; - char *path, *c; + char *path = NULL, *c; assert(s); assert(iovec || n == 0); @@ -1200,12 +1217,22 @@ static int server_flush_to_var(Server *s) { int r; sd_id128_t machine; sd_journal *j; + usec_t ts; assert(s); + if (!s->runtime_journal) + return 0; + + ts = now(CLOCK_MONOTONIC); + if (s->var_available_timestamp + RECHECK_VAR_AVAILABLE_USEC > ts) + return 0; + + s->var_available_timestamp = ts; + system_journal_open(s); - if (!s->system_journal || !s->runtime_journal) + if (!s->system_journal) return 0; r = sd_id128_get_machine(&machine); @@ -1262,6 +1289,69 @@ finish: return r; } +static void forward_syslog(Server *s, const void *buffer, size_t length, struct ucred *ucred, struct timeval *tv) { + struct msghdr msghdr; + struct iovec iovec; + struct cmsghdr *cmsg; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(struct timeval))]; + } control; + union sockaddr_union sa; + + assert(s); + + zero(msghdr); + + zero(iovec); + iovec.iov_base = (void*) buffer; + iovec.iov_len = length; + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + + zero(sa); + sa.un.sun_family = AF_UNIX; + strncpy(sa.un.sun_path, "/run/systemd/syslog", sizeof(sa.un.sun_path)); + msghdr.msg_name = &sa; + msghdr.msg_namelen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path); + + zero(control); + msghdr.msg_control = &control; + msghdr.msg_controllen = sizeof(control); + + cmsg = CMSG_FIRSTHDR(&msghdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred)); + msghdr.msg_controllen = cmsg->cmsg_len; + + /* Forward the syslog message we received via /dev/log to + * /run/systemd/syslog. Unfortunately we currently can't set + * the SO_TIMESTAMP auxiliary data, and hence we don't. */ + + if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0) + return; + + if (errno == ESRCH) { + struct ucred u; + + /* Hmm, presumably the sender process vanished + * by now, so let's fix it as good as we + * can, and retry */ + + u = *ucred; + u.pid = getpid(); + memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred)); + + if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0) + return; + } + + log_debug("Failed to forward syslog message: %m"); +} + static int process_event(Server *s, struct epoll_event *ev) { assert(s); @@ -1382,6 +1472,7 @@ static int process_event(Server *s, struct epoll_event *ev) { else s->buffer[n] = 0; + forward_syslog(s, s->buffer, n, ucred, tv); process_syslog_message(s, strstrip(s->buffer), ucred, tv); } else process_native_message(s, s->buffer, n, ucred, tv); @@ -1430,6 +1521,7 @@ static int open_syslog_socket(Server *s) { union sockaddr_union sa; int one, r; struct epoll_event ev; + struct timeval tv; assert(s); @@ -1443,7 +1535,7 @@ static int open_syslog_socket(Server *s) { zero(sa); sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/run/systemd/syslog", sizeof(sa.un.sun_path)); + strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path)); unlink(sa.un.sun_path); @@ -1470,6 +1562,15 @@ 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; @@ -1738,6 +1839,8 @@ static void server_done(Server *s) { if (s->rate_limit) journal_rate_limit_free(s->rate_limit); + + free(s->buffer); } int main(int argc, char *argv[]) { @@ -1755,7 +1858,6 @@ int main(int argc, char *argv[]) { } log_set_target(LOG_TARGET_CONSOLE); - log_set_max_level(LOG_DEBUG); log_parse_environment(); log_open();