X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=logger.c;h=f81d2c5c8a627c7d3d9d10ade247869c6524cb92;hp=46cce5f09d074747ac84748fd5ccd071f9d49793;hb=ed42e037bc93f8f6b54ee7b0b692c1200d2f4903;hpb=2fa086a8e02b1b2d62a9a424b41944f3a2251e60 diff --git a/logger.c b/logger.c index 46cce5f09..f81d2c5c8 100644 --- a/logger.c +++ b/logger.c @@ -35,10 +35,10 @@ #include "util.h" #include "log.h" #include "list.h" +#include "sd-daemon.h" #define STREAM_BUFFER 2048 #define STREAMS_MAX 256 -#define SERVER_FD_START 3 #define SERVER_FD_MAX 16 #define TIMEOUT ((int) (10*MSEC_PER_SEC)) @@ -55,18 +55,19 @@ typedef struct Server { unsigned n_streams; } Server; +typedef enum StreamTarget { + STREAM_SYSLOG, + STREAM_KMSG +} StreamTarget; + typedef enum StreamState { - STREAM_LOG_TARGET, + STREAM_TARGET, STREAM_PRIORITY, STREAM_PROCESS, + STREAM_PREFIX, STREAM_RUNNING } StreamState; -typedef enum LogTarget { - LOG_TARGET_SYSLOG, - LOG_TARGET_KMSG -} LogTarget; - struct Stream { Server *server; @@ -80,6 +81,8 @@ struct Stream { pid_t pid; uid_t uid; + bool prefix; + char buffer[STREAM_BUFFER]; size_t length; @@ -89,12 +92,25 @@ struct Stream { static int stream_log(Stream *s, char *p, usec_t timestamp) { char header_priority[16], header_time[64], header_pid[16]; - struct msghdr msghdr; struct iovec iovec[5]; + int priority; assert(s); assert(p); + priority = s->priority; + + if (s->prefix && + p[0] == '<' && + p[1] >= '0' && p[1] <= '7' && + p[2] == '>') { + + /* Detected priority prefix */ + priority = LOG_MAKEPRI(LOG_FAC(priority), (p[1] - '0')); + + p += 3; + } + if (*p == 0) return 0; @@ -111,10 +127,10 @@ static int stream_log(Stream *s, char *p, usec_t timestamp) { */ snprintf(header_priority, sizeof(header_priority), "<%i>", - s->target == LOG_TARGET_SYSLOG ? s->priority : LOG_PRI(s->priority)); + s->target == STREAM_SYSLOG ? priority : LOG_PRI(priority)); char_array_0(header_priority); - if (s->target == LOG_TARGET_SYSLOG) { + if (s->target == STREAM_SYSLOG) { time_t t; struct tm *tm; @@ -132,7 +148,9 @@ static int stream_log(Stream *s, char *p, usec_t timestamp) { zero(iovec); IOVEC_SET_STRING(iovec[0], header_priority); - if (s->target == LOG_TARGET_SYSLOG) { + if (s->target == STREAM_SYSLOG) { + struct msghdr msghdr; + IOVEC_SET_STRING(iovec[1], header_time); IOVEC_SET_STRING(iovec[2], s->process); IOVEC_SET_STRING(iovec[3], header_pid); @@ -145,7 +163,7 @@ static int stream_log(Stream *s, char *p, usec_t timestamp) { if (sendmsg(s->server->syslog_fd, &msghdr, MSG_NOSIGNAL) < 0) return -errno; - } else if (s->target == LOG_TARGET_KMSG) { + } else if (s->target == STREAM_KMSG) { IOVEC_SET_STRING(iovec[1], s->process); IOVEC_SET_STRING(iovec[2], header_pid); IOVEC_SET_STRING(iovec[3], p); @@ -169,13 +187,13 @@ static int stream_line(Stream *s, char *p, usec_t timestamp) { switch (s->state) { - case STREAM_LOG_TARGET: + case STREAM_TARGET: if (streq(p, "syslog")) - s->target = LOG_TARGET_SYSLOG; + s->target = STREAM_SYSLOG; else if (streq(p, "kmsg")) { if (s->server->kmsg_fd >= 0 && s->uid == 0) - s->target = LOG_TARGET_KMSG; + s->target = STREAM_KMSG; else { log_warning("/dev/kmsg logging not available."); return -EPERM; @@ -205,6 +223,15 @@ static int stream_line(Stream *s, char *p, usec_t timestamp) { if (!(s->process = strdup(p))) return -ENOMEM; + s->state = STREAM_PREFIX; + return 0; + + case STREAM_PREFIX: + + if ((r = parse_boolean(p)) < 0) + return r; + + s->prefix = r; s->state = STREAM_RUNNING; return 0; @@ -287,7 +314,7 @@ static void stream_free(Stream *s) { if (s->server) epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL); - assert_se(close_nointr(s->fd) == 0); + close_nointr_nofail(s->fd); } free(s->process); @@ -309,12 +336,12 @@ static int stream_new(Server *s, int server_fd) { if (s->n_streams >= STREAMS_MAX) { log_warning("Too many connections, refusing connection."); - assert_se(close_nointr(fd) == 0); + close_nointr_nofail(fd); return 0; } if (!(stream = new0(Stream, 1))) { - assert_se(close_nointr(fd) == 0); + close_nointr_nofail(fd); return -ENOMEM; } @@ -352,49 +379,6 @@ fail: return r; } -static int verify_environment(unsigned *n_sockets) { - unsigned long long pid; - const char *e; - int r; - unsigned ns; - - assert_se(n_sockets); - - if (!(e = getenv("LISTEN_PID"))) { - log_error("Missing $LISTEN_PID environment variable."); - return -ENOENT; - } - - if ((r = safe_atollu(e, &pid)) < 0) { - log_error("Failed to parse $LISTEN_PID: %s", strerror(-r)); - return r; - } - - if (pid != (unsigned long long) getpid()) { - log_error("Socket nor for me."); - return -ENOENT; - } - - if (!(e = getenv("LISTEN_FDS"))) { - log_error("Missing $LISTEN_FDS environment variable."); - return -ENOENT; - } - - if ((r = safe_atou(e, &ns)) < 0) { - log_error("Failed to parse $LISTEN_FDS: %s", strerror(-r)); - return -E2BIG; - } - - if (ns <= 0 || ns > SERVER_FD_MAX) { - log_error("Wrong number of file descriptors passed: %s", e); - return -E2BIG; - } - - *n_sockets = ns; - - return 0; -} - static void server_done(Server *s) { unsigned i; assert(s); @@ -403,16 +387,16 @@ static void server_done(Server *s) { stream_free(s->streams); for (i = 0; i < s->n_server_fd; i++) - assert_se(close_nointr(SERVER_FD_START+i) == 0); + close_nointr_nofail(SD_LISTEN_FDS_START+i); if (s->syslog_fd >= 0) - assert_se(close_nointr(s->syslog_fd) == 0); + close_nointr_nofail(s->syslog_fd); if (s->epoll_fd >= 0) - assert_se(close_nointr(s->epoll_fd) == 0); + close_nointr_nofail(s->epoll_fd); if (s->kmsg_fd >= 0) - assert_se(close_nointr(s->kmsg_fd) == 0); + close_nointr_nofail(s->kmsg_fd); } static int server_init(Server *s, unsigned n_sockets) { @@ -443,8 +427,8 @@ static int server_init(Server *s, unsigned n_sockets) { zero(ev); ev.events = EPOLLIN; - ev.data.ptr = UINT_TO_PTR(SERVER_FD_START+i); - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SERVER_FD_START+i, &ev) < 0) { + ev.data.ptr = UINT_TO_PTR(SD_LISTEN_FDS_START+i); + if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SD_LISTEN_FDS_START+i, &ev) < 0) { r = -errno; log_error("Failed to add server fd to epoll object: %s", strerror(errno)); goto fail; @@ -484,13 +468,13 @@ static int process_event(Server *s, struct epoll_event *ev) { assert(s); /* Yes, this is a bit ugly, we assume that that valid pointers - * are > SERVER_FD_START+SERVER_FD_MAX. Which is certainly + * are > SD_LISTEN_FDS_START+SERVER_FD_MAX. Which is certainly * true on Linux (and probably most other OSes, too, since the * first 4k usually are part of a seperate null pointer * dereference page. */ - if (PTR_TO_UINT(ev->data.ptr) >= SERVER_FD_START && - PTR_TO_UINT(ev->data.ptr) < SERVER_FD_START+s->n_server_fd) { + if (PTR_TO_UINT(ev->data.ptr) >= SD_LISTEN_FDS_START && + PTR_TO_UINT(ev->data.ptr) < SD_LISTEN_FDS_START+s->n_server_fd) { if (ev->events != EPOLLIN) { log_info("Got invalid event from epoll. (1)"); @@ -509,7 +493,7 @@ static int process_event(Server *s, struct epoll_event *ev) { timestamp = now(CLOCK_REALTIME); if (!(ev->events & EPOLLIN)) { - log_info("Got invalid event from epoll. (3)"); + log_info("Got invalid event from epoll. (2)"); stream_free(stream); return 0; } @@ -529,16 +513,25 @@ static int process_event(Server *s, struct epoll_event *ev) { int main(int argc, char *argv[]) { Server server; - int r = 3; - unsigned n; + int r = 3, n; + + log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); + log_parse_environment(); log_info("systemd-logger running as pid %llu", (unsigned long long) getpid()); - if (verify_environment(&n) < 0) + if ((n = sd_listen_fds(true)) < 0) { + log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); return 1; + } - if (server_init(&server, n) < 0) + if (n <= 0 || n > SERVER_FD_MAX) { + log_error("No or too many file descriptors passed."); return 2; + } + + if (server_init(&server, (unsigned) n) < 0) + return 3; for (;;) { struct epoll_event event;