X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fjournald-syslog.c;h=ce6c2a3af4f2bca112ce65de54fdde320725809d;hp=12c5b2849ce66ea11e5841b0f62f9527f01c1ead;hb=2b0073e1d2fb0611733e0b83bd41cc753b254593;hpb=5809560d858f45351856d6fe786a8117306dd0f2 diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index 12c5b2849..ce6c2a3af 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -20,36 +20,44 @@ ***/ #include +#include #include +#include "systemd/sd-messages.h" #include "socket-util.h" -#include "journald.h" +#include "selinux-util.h" +#include "journald-server.h" #include "journald-syslog.h" #include "journald-kmsg.h" +#include "journald-console.h" +#include "journald-wall.h" -static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) { - struct msghdr msghdr; +/* Warn once every 30s if we missed syslog message */ +#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC) + +static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, const struct ucred *ucred, const struct timeval *tv) { + + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/syslog", + }; + struct msghdr msghdr = { + .msg_iov = (struct iovec *) iovec, + .msg_iovlen = n_iovec, + .msg_name = (struct sockaddr*) &sa.sa, + .msg_namelen = offsetof(union sockaddr_union, un.sun_path) + + strlen("/run/systemd/journal/syslog"), + }; struct cmsghdr *cmsg; union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; } control; - union sockaddr_union sa; assert(s); assert(iovec); assert(n_iovec > 0); - zero(msghdr); - msghdr.msg_iov = (struct iovec*) iovec; - msghdr.msg_iovlen = n_iovec; - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/run/systemd/journal/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); - if (ucred) { zero(control); msghdr.msg_control = &control; @@ -72,8 +80,10 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned /* The socket is full? I guess the syslog implementation is * too slow, and we shouldn't wait for that... */ - if (errno == EAGAIN) + if (errno == EAGAIN) { + s->n_forward_syslog_missed++; return; + } if (ucred && errno == ESRCH) { struct ucred u; @@ -89,15 +99,17 @@ 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) + if (errno == EAGAIN) { + s->n_forward_syslog_missed++; return; + } } if (errno != ENOENT) log_debug("Failed to forward syslog message: %m"); } -static void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) { +static void forward_syslog_raw(Server *s, int priority, const char *buffer, const struct ucred *ucred, const struct timeval *tv) { struct iovec iovec; assert(s); @@ -110,7 +122,7 @@ static void forward_syslog_raw(Server *s, int priority, const char *buffer, stru forward_syslog_iovec(s, &iovec, 1, ucred, tv); } -void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) { +void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv) { struct iovec iovec[5]; char header_priority[6], header_time[64], header_pid[16]; int n = 0; @@ -147,7 +159,7 @@ void server_forward_syslog(Server *s, int priority, const char *identifier, cons identifier = ident_buf; } - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); + snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", ucred->pid); char_array_0(header_pid); if (identifier) @@ -175,7 +187,7 @@ int syslog_fixup_facility(int priority) { return priority; } -void syslog_parse_identifier(const char **buf, char **identifier, char **pid) { +size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid) { const char *p; char *t; size_t l, e; @@ -191,7 +203,7 @@ void syslog_parse_identifier(const char **buf, char **identifier, char **pid) { if (l <= 0 || p[l-1] != ':') - return; + return 0; e = l; l--; @@ -221,11 +233,12 @@ void syslog_parse_identifier(const char **buf, char **identifier, char **pid) { if (t) *identifier = t; + e += strspn(p + e, WHITESPACE); *buf = p + e; - *buf += strspn(*buf, WHITESPACE); + return e; } -void syslog_parse_priority(char **p, int *priority) { +void syslog_parse_priority(const char **p, int *priority, bool with_facility) { int a = 0, b = 0, c = 0; int k; @@ -254,10 +267,14 @@ void syslog_parse_priority(char **p, int *priority) { } else return; - if (a < 0 || b < 0 || c < 0) + if (a < 0 || b < 0 || c < 0 || + (!with_facility && (a || b || c > 7))) return; - *priority = a*100+b*10+c; + if (with_facility) + *priority = a*100 + b*10 + c; + else + *priority = (*priority & LOG_FACMASK) | c; *p += k; } @@ -334,23 +351,25 @@ static void syslog_skip_date(char **buf) { void server_process_syslog_message( Server *s, const char *buf, - struct ucred *ucred, - struct timeval *tv, + const struct ucred *ucred, + const struct timeval *tv, const char *label, size_t label_len) { - char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL; + char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)], + syslog_facility[sizeof("SYSLOG_FACILITY") + DECIMAL_STR_MAX(int)]; + const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL; struct iovec iovec[N_IOVEC_META_FIELDS + 6]; unsigned n = 0; int priority = LOG_USER | LOG_INFO; - char *identifier = NULL, *pid = NULL; + _cleanup_free_ char *identifier = NULL, *pid = NULL; const char *orig; assert(s); assert(buf); orig = buf; - syslog_parse_priority((char**) &buf, &priority); + syslog_parse_priority(&buf, &priority, true); if (s->forward_to_syslog) forward_syslog_raw(s, priority, orig, ucred, tv); @@ -364,50 +383,49 @@ void server_process_syslog_message( if (s->forward_to_console) server_forward_console(s, priority, identifier, buf, ucred); + if (s->forward_to_wall) + server_forward_wall(s, priority, identifier, buf, ucred); + IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog"); - if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0) - IOVEC_SET_STRING(iovec[n++], syslog_priority); + sprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK); + IOVEC_SET_STRING(iovec[n++], syslog_priority); - if (priority & LOG_FACMASK) - if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0) - IOVEC_SET_STRING(iovec[n++], syslog_facility); + if (priority & LOG_FACMASK) { + sprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)); + IOVEC_SET_STRING(iovec[n++], syslog_facility); + } if (identifier) { - syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier); + syslog_identifier = strappenda("SYSLOG_IDENTIFIER=", identifier); if (syslog_identifier) IOVEC_SET_STRING(iovec[n++], syslog_identifier); } if (pid) { - syslog_pid = strappend("SYSLOG_PID=", pid); + syslog_pid = strappenda("SYSLOG_PID=", pid); if (syslog_pid) IOVEC_SET_STRING(iovec[n++], syslog_pid); } - message = strappend("MESSAGE=", buf); + message = strappenda("MESSAGE=", buf); if (message) IOVEC_SET_STRING(iovec[n++], message); - server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority); - - free(message); - free(identifier); - free(pid); - free(syslog_priority); - free(syslog_facility); - free(syslog_identifier); - free(syslog_pid); + server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority, 0); } int server_open_syslog_socket(Server *s) { - union sockaddr_union sa; - int one, r; - struct epoll_event ev; + static const int one = 1; + int r; assert(s); if (s->syslog_fd < 0) { + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/dev-log", + }; s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (s->syslog_fd < 0) { @@ -415,15 +433,11 @@ int server_open_syslog_socket(Server *s) { return -errno; } - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path)); - unlink(sa.un.sun_path); r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); if (r < 0) { - log_error("bind() failed: %m"); + log_error("bind(%s) failed: %m", sa.un.sun_path); return -errno; } @@ -431,7 +445,6 @@ int server_open_syslog_socket(Server *s) { } else fd_nonblock(s->syslog_fd, 1); - one = 1; r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); if (r < 0) { log_error("SO_PASSCRED failed: %m"); @@ -439,26 +452,41 @@ int server_open_syslog_socket(Server *s) { } #ifdef HAVE_SELINUX - one = 1; - r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); - if (r < 0) - log_warning("SO_PASSSEC failed: %m"); + if (mac_selinux_use()) { + r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); + if (r < 0) + log_warning("SO_PASSSEC failed: %m"); + } #endif - one = 1; r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)); if (r < 0) { log_error("SO_TIMESTAMP failed: %m"); return -errno; } - zero(ev); - ev.events = EPOLLIN; - ev.data.fd = s->syslog_fd; - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->syslog_fd, &ev) < 0) { - log_error("Failed to add syslog server fd to epoll object: %m"); - return -errno; + r = sd_event_add_io(s->event, &s->syslog_event_source, s->syslog_fd, EPOLLIN, process_datagram, s); + if (r < 0) { + log_error("Failed to add syslog server fd to event loop: %s", strerror(-r)); + return r; } return 0; } + +void server_maybe_warn_forward_syslog_missed(Server *s) { + usec_t n; + assert(s); + + if (s->n_forward_syslog_missed <= 0) + return; + + n = now(CLOCK_MONOTONIC); + if (s->last_warn_forward_syslog_missed + WARN_FORWARD_SYSLOG_MISSED_USEC > n) + return; + + server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED, "Forwarding to syslog missed %u messages.", s->n_forward_syslog_missed); + + s->n_forward_syslog_missed = 0; + s->last_warn_forward_syslog_missed = n; +}