X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fjournal%2Fjournald.c;h=5d0d2033f2c3425d3ba80d9d1c2cf668c32fc575;hb=2b43f939a4b3ad5aeb2650868b0234ff42ec0045;hp=fbdd688c37816a5baab27958805e79e4ee8ed201;hpb=ef63833d532dd86bdba63211e6a1363cbb3ef61d;p=elogind.git diff --git a/src/journal/journald.c b/src/journal/journald.c index fbdd688c3..5d0d2033f 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -46,15 +46,19 @@ #include "socket-util.h" #include "cgroup-util.h" #include "list.h" -#include "journal-rate-limit.h" +#include "virt.h" +#include "missing.h" +#include "conf-parser.h" #include "journal-internal.h" #include "journal-vacuum.h" #include "journal-authenticate.h" -#include "conf-parser.h" #include "journald.h" +#include "journald-rate-limit.h" #include "journald-kmsg.h" -#include "virt.h" -#include "missing.h" +#include "journald-syslog.h" +#include "journald-stream.h" +#include "journald-console.h" +#include "journald-native.h" #ifdef HAVE_ACL #include @@ -67,51 +71,12 @@ #endif #define USER_JOURNALS_MAX 1024 -#define STDOUT_STREAMS_MAX 4096 #define DEFAULT_RATE_LIMIT_INTERVAL (10*USEC_PER_SEC) #define DEFAULT_RATE_LIMIT_BURST 200 #define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC) -#define ENTRY_SIZE_MAX (1024*1024*32) - -typedef enum StdoutStreamState { - STDOUT_STREAM_IDENTIFIER, - STDOUT_STREAM_UNIT_ID, - STDOUT_STREAM_PRIORITY, - STDOUT_STREAM_LEVEL_PREFIX, - STDOUT_STREAM_FORWARD_TO_SYSLOG, - STDOUT_STREAM_FORWARD_TO_KMSG, - STDOUT_STREAM_FORWARD_TO_CONSOLE, - STDOUT_STREAM_RUNNING -} StdoutStreamState; - -struct StdoutStream { - Server *server; - StdoutStreamState state; - - int fd; - - struct ucred ucred; -#ifdef HAVE_SELINUX - security_context_t security_context; -#endif - - char *identifier; - char *unit_id; - int priority; - bool level_prefix:1; - bool forward_to_syslog:1; - bool forward_to_kmsg:1; - bool forward_to_console:1; - - char buffer[LINE_MAX+1]; - size_t length; - - LIST_FIELDS(StdoutStream, stdout_stream); -}; - static const char* const storage_table[] = { [STORAGE_AUTO] = "auto", [STORAGE_VOLATILE] = "volatile", @@ -339,7 +304,7 @@ static void server_rotate(Server *s) { Iterator i; int r; - log_info("Rotating..."); + log_debug("Rotating..."); if (s->runtime_journal) { r = journal_file_rotate(&s->runtime_journal, s->compress, false); @@ -384,7 +349,7 @@ static void server_vacuum(Server *s) { sd_id128_t machine; int r; - log_info("Vacuuming..."); + log_debug("Vacuuming..."); r = sd_id128_get_machine(&machine); if (r < 0) { @@ -395,7 +360,8 @@ static void server_vacuum(Server *s) { sd_id128_to_string(machine, ids); if (s->system_journal) { - if (asprintf(&p, "/var/log/journal/%s", ids) < 0) { + p = strappend("/var/log/journal/", ids); + if (!p) { log_oom(); return; } @@ -407,7 +373,8 @@ static void server_vacuum(Server *s) { } if (s->runtime_journal) { - if (asprintf(&p, "/run/log/journal/%s", ids) < 0) { + p = strappend("/run/log/journal/", ids); + if (!p) { log_oom(); return; } @@ -477,7 +444,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned return; if (journal_file_rotate_suggested(f)) { - log_info("Journal header limits reached or header out-of-date, rotating."); + log_debug("Journal header limits reached or header out-of-date, rotating."); server_rotate(s); server_vacuum(s); vacuumed = true; @@ -508,11 +475,11 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned } if (r == -E2BIG || r == -EFBIG || r == EDQUOT || r == ENOSPC) - log_info("Allocation limit reached, rotating."); + log_debug("Allocation limit reached, rotating."); else if (r == -EHOSTDOWN) log_info("Journal file from other machine, rotating."); else if (r == -EBUSY) - log_info("Unlcean shutdown, rotating."); + log_info("Unclean shutdown, rotating."); else log_warning("Journal file corrupted, rotating."); @@ -524,7 +491,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned if (!f) return; - log_info("Retrying write."); + log_debug("Retrying write."); } } @@ -807,943 +774,6 @@ finish: dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id); } -static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) { - struct msghdr msghdr; - 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; - 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; - - /* 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; - - /* 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; - - if (errno == EAGAIN) - 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) { - struct iovec iovec; - - assert(s); - assert(buffer); - - if (LOG_PRI(priority) > s->max_level_syslog) - return; - - IOVEC_SET_STRING(iovec, buffer); - forward_syslog_iovec(s, &iovec, 1, ucred, tv); -} - -static void forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) { - struct iovec iovec[5]; - char header_priority[6], header_time[64], header_pid[16]; - int n = 0; - time_t t; - struct tm *tm; - char *ident_buf = NULL; - - assert(s); - assert(priority >= 0); - assert(priority <= 999); - assert(message); - - if (LOG_PRI(priority) > s->max_level_syslog) - return; - - /* First: priority field */ - snprintf(header_priority, sizeof(header_priority), "<%i>", priority); - char_array_0(header_priority); - IOVEC_SET_STRING(iovec[n++], header_priority); - - /* Second: timestamp */ - t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC)); - tm = localtime(&t); - if (!tm) - return; - if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) - return; - IOVEC_SET_STRING(iovec[n++], header_time); - - /* Third: identifier and PID */ - if (ucred) { - if (!identifier) { - get_process_comm(ucred->pid, &ident_buf); - identifier = ident_buf; - } - - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); - char_array_0(header_pid); - - if (identifier) - IOVEC_SET_STRING(iovec[n++], identifier); - - IOVEC_SET_STRING(iovec[n++], header_pid); - } else if (identifier) { - IOVEC_SET_STRING(iovec[n++], identifier); - IOVEC_SET_STRING(iovec[n++], ": "); - } - - /* Fourth: message */ - IOVEC_SET_STRING(iovec[n++], message); - - forward_syslog_iovec(s, iovec, n, ucred, tv); - - free(ident_buf); -} - -static void forward_console(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred) { - struct iovec iovec[4]; - char header_pid[16]; - int n = 0, fd; - char *ident_buf = NULL; - const char *tty; - - assert(s); - assert(message); - - if (LOG_PRI(priority) > s->max_level_console) - return; - - /* First: identifier and PID */ - if (ucred) { - if (!identifier) { - get_process_comm(ucred->pid, &ident_buf); - identifier = ident_buf; - } - - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); - char_array_0(header_pid); - - if (identifier) - IOVEC_SET_STRING(iovec[n++], identifier); - - IOVEC_SET_STRING(iovec[n++], header_pid); - } else if (identifier) { - IOVEC_SET_STRING(iovec[n++], identifier); - IOVEC_SET_STRING(iovec[n++], ": "); - } - - /* Third: message */ - IOVEC_SET_STRING(iovec[n++], message); - IOVEC_SET_STRING(iovec[n++], "\n"); - - tty = s->tty_path ? s->tty_path : "/dev/console"; - - fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (fd < 0) { - log_debug("Failed to open %s for logging: %s", tty, strerror(errno)); - goto finish; - } - - if (writev(fd, iovec, n) < 0) - log_debug("Failed to write to %s for logging: %s", tty, strerror(errno)); - - close_nointr_nofail(fd); - -finish: - free(ident_buf); -} - -int syslog_fixup_facility(int priority) { - - if ((priority & LOG_FACMASK) == 0) - return (priority & LOG_PRIMASK) | LOG_USER; - - return priority; -} - -void syslog_read_identifier(const char **buf, char **identifier, char **pid) { - const char *p; - char *t; - size_t l, e; - - assert(buf); - assert(identifier); - assert(pid); - - p = *buf; - - p += strspn(p, WHITESPACE); - l = strcspn(p, WHITESPACE); - - if (l <= 0 || - p[l-1] != ':') - return; - - e = l; - l--; - - if (p[l-1] == ']') { - size_t k = l-1; - - for (;;) { - - if (p[k] == '[') { - t = strndup(p+k+1, l-k-2); - if (t) - *pid = t; - - l = k; - break; - } - - if (k == 0) - break; - - k--; - } - } - - t = strndup(p, l); - if (t) - *identifier = t; - - *buf = p + e; - *buf += strspn(*buf, WHITESPACE); -} - -static void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, 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; - struct iovec iovec[N_IOVEC_META_FIELDS + 6]; - unsigned n = 0; - int priority = LOG_USER | LOG_INFO; - char *identifier = NULL, *pid = NULL; - const char *orig; - - assert(s); - assert(buf); - - orig = buf; - syslog_parse_priority((char**) &buf, &priority); - - if (s->forward_to_syslog) - forward_syslog_raw(s, priority, orig, ucred, tv); - - syslog_skip_date((char**) &buf); - syslog_read_identifier(&buf, &identifier, &pid); - - if (s->forward_to_kmsg) - server_forward_kmsg(s, priority, identifier, buf, ucred); - - if (s->forward_to_console) - forward_console(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); - - if (priority & LOG_FACMASK) - if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0) - IOVEC_SET_STRING(iovec[n++], syslog_facility); - - if (identifier) { - syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier); - if (syslog_identifier) - IOVEC_SET_STRING(iovec[n++], syslog_identifier); - } - - if (pid) { - syslog_pid = strappend("SYSLOG_PID=", pid); - if (syslog_pid) - IOVEC_SET_STRING(iovec[n++], syslog_pid); - } - - message = strappend("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); -} - -static bool valid_user_field(const char *p, size_t l) { - const char *a; - - /* We kinda enforce POSIX syntax recommendations for - environment variables here, but make a couple of additional - requirements. - - http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */ - - /* No empty field names */ - if (l <= 0) - return false; - - /* Don't allow names longer than 64 chars */ - if (l > 64) - return false; - - /* Variables starting with an underscore are protected */ - if (p[0] == '_') - return false; - - /* Don't allow digits as first character */ - if (p[0] >= '0' && p[0] <= '9') - return false; - - /* Only allow A-Z0-9 and '_' */ - for (a = p; a < p + l; a++) - if (!((*a >= 'A' && *a <= 'Z') || - (*a >= '0' && *a <= '9') || - *a == '_')) - return false; - - return true; -} - -static void process_native_message( - Server *s, - const void *buffer, size_t buffer_size, - struct ucred *ucred, - struct timeval *tv, - const char *label, size_t label_len) { - - struct iovec *iovec = NULL; - unsigned n = 0, m = 0, j, tn = (unsigned) -1; - const char *p; - size_t remaining; - int priority = LOG_INFO; - char *identifier = NULL, *message = NULL; - - assert(s); - assert(buffer || buffer_size == 0); - - p = buffer; - remaining = buffer_size; - - while (remaining > 0) { - const char *e, *q; - - e = memchr(p, '\n', remaining); - - if (!e) { - /* Trailing noise, let's ignore it, and flush what we collected */ - log_debug("Received message with trailing noise, ignoring."); - break; - } - - if (e == p) { - /* Entry separator */ - server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority); - n = 0; - priority = LOG_INFO; - - p++; - remaining--; - continue; - } - - if (*p == '.' || *p == '#') { - /* Ignore control commands for now, and - * comments too. */ - remaining -= (e - p) + 1; - p = e + 1; - continue; - } - - /* A property follows */ - - if (n+N_IOVEC_META_FIELDS >= m) { - struct iovec *c; - unsigned u; - - u = MAX((n+N_IOVEC_META_FIELDS+1) * 2U, 4U); - c = realloc(iovec, u * sizeof(struct iovec)); - if (!c) { - log_oom(); - break; - } - - iovec = c; - m = u; - } - - q = memchr(p, '=', e - p); - if (q) { - if (valid_user_field(p, q - p)) { - size_t l; - - l = e - p; - - /* If the field name starts with an - * underscore, skip the variable, - * since that indidates a trusted - * field */ - iovec[n].iov_base = (char*) p; - iovec[n].iov_len = l; - n++; - - /* We need to determine the priority - * of this entry for the rate limiting - * logic */ - if (l == 10 && - memcmp(p, "PRIORITY=", 9) == 0 && - p[9] >= '0' && p[9] <= '9') - priority = (priority & LOG_FACMASK) | (p[9] - '0'); - - else if (l == 17 && - memcmp(p, "SYSLOG_FACILITY=", 16) == 0 && - p[16] >= '0' && p[16] <= '9') - priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3); - - else if (l == 18 && - memcmp(p, "SYSLOG_FACILITY=", 16) == 0 && - p[16] >= '0' && p[16] <= '9' && - p[17] >= '0' && p[17] <= '9') - priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3); - - else if (l >= 19 && - memcmp(p, "SYSLOG_IDENTIFIER=", 18) == 0) { - char *t; - - t = strndup(p + 18, l - 18); - if (t) { - free(identifier); - identifier = t; - } - } else if (l >= 8 && - memcmp(p, "MESSAGE=", 8) == 0) { - char *t; - - t = strndup(p + 8, l - 8); - if (t) { - free(message); - message = t; - } - } - } - - remaining -= (e - p) + 1; - p = e + 1; - continue; - } else { - le64_t l_le; - uint64_t l; - char *k; - - if (remaining < e - p + 1 + sizeof(uint64_t) + 1) { - log_debug("Failed to parse message, ignoring."); - break; - } - - memcpy(&l_le, e + 1, sizeof(uint64_t)); - l = le64toh(l_le); - - if (remaining < e - p + 1 + sizeof(uint64_t) + l + 1 || - e[1+sizeof(uint64_t)+l] != '\n') { - log_debug("Failed to parse message, ignoring."); - break; - } - - k = malloc((e - p) + 1 + l); - if (!k) { - log_oom(); - break; - } - - memcpy(k, p, e - p); - k[e - p] = '='; - memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l); - - if (valid_user_field(p, e - p)) { - iovec[n].iov_base = k; - iovec[n].iov_len = (e - p) + 1 + l; - n++; - } else - free(k); - - remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1; - p = e + 1 + sizeof(uint64_t) + l + 1; - } - } - - if (n <= 0) - goto finish; - - tn = n++; - IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal"); - - if (message) { - if (s->forward_to_syslog) - forward_syslog(s, priority, identifier, message, ucred, tv); - - if (s->forward_to_kmsg) - server_forward_kmsg(s, priority, identifier, message, ucred); - - if (s->forward_to_console) - forward_console(s, priority, identifier, message, ucred); - } - - server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority); - -finish: - for (j = 0; j < n; j++) { - if (j == tn) - continue; - - if (iovec[j].iov_base < buffer || - (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size) - free(iovec[j].iov_base); - } - - free(iovec); - free(identifier); - free(message); -} - -static void process_native_file( - Server *s, - int fd, - struct ucred *ucred, - struct timeval *tv, - const char *label, size_t label_len) { - - 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_oom(); - 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, label, label_len); - - 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; - unsigned n = 0; - int priority; - char *label = NULL; - size_t label_len = 0; - - assert(s); - assert(p); - - if (isempty(p)) - return 0; - - priority = s->priority; - - if (s->level_prefix) - syslog_parse_priority((char**) &p, &priority); - - if (s->forward_to_syslog || s->server->forward_to_syslog) - forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL); - - if (s->forward_to_kmsg || s->server->forward_to_kmsg) - server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred); - - if (s->forward_to_console || s->server->forward_to_console) - forward_console(s->server, priority, s->identifier, p, &s->ucred); - - IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout"); - - if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0) - 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 (s->identifier) { - syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier); - if (syslog_identifier) - IOVEC_SET_STRING(iovec[n++], syslog_identifier); - } - - message = strappend("MESSAGE=", p); - if (message) - IOVEC_SET_STRING(iovec[n++], message); - -#ifdef HAVE_SELINUX - if (s->security_context) { - label = (char*) s->security_context; - label_len = strlen((char*) s->security_context); - } -#endif - - server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority); - - free(message); - free(syslog_priority); - free(syslog_facility); - free(syslog_identifier); - - return 0; -} - -static int stdout_stream_line(StdoutStream *s, char *p) { - int r; - - assert(s); - assert(p); - - p = strstrip(p); - - switch (s->state) { - - case STDOUT_STREAM_IDENTIFIER: - if (isempty(p)) - s->identifier = NULL; - else { - s->identifier = strdup(p); - if (!s->identifier) - return log_oom(); - } - - s->state = STDOUT_STREAM_UNIT_ID; - return 0; - - case STDOUT_STREAM_UNIT_ID: - if (s->ucred.uid == 0) { - if (isempty(p)) - s->unit_id = NULL; - else { - s->unit_id = strdup(p); - if (!s->unit_id) - return log_oom(); - } - } - - s->state = STDOUT_STREAM_PRIORITY; - return 0; - - case STDOUT_STREAM_PRIORITY: - r = safe_atoi(p, &s->priority); - if (r < 0 || s->priority <= 0 || s->priority >= 999) { - log_warning("Failed to parse log priority line."); - return -EINVAL; - } - - s->state = STDOUT_STREAM_LEVEL_PREFIX; - return 0; - - case STDOUT_STREAM_LEVEL_PREFIX: - r = parse_boolean(p); - if (r < 0) { - log_warning("Failed to parse level prefix line."); - return -EINVAL; - } - - s->level_prefix = !!r; - s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG; - return 0; - - case STDOUT_STREAM_FORWARD_TO_SYSLOG: - r = parse_boolean(p); - if (r < 0) { - log_warning("Failed to parse forward to syslog line."); - return -EINVAL; - } - - s->forward_to_syslog = !!r; - s->state = STDOUT_STREAM_FORWARD_TO_KMSG; - return 0; - - case STDOUT_STREAM_FORWARD_TO_KMSG: - r = parse_boolean(p); - if (r < 0) { - log_warning("Failed to parse copy to kmsg line."); - return -EINVAL; - } - - s->forward_to_kmsg = !!r; - s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE; - return 0; - - case STDOUT_STREAM_FORWARD_TO_CONSOLE: - r = parse_boolean(p); - if (r < 0) { - log_warning("Failed to parse copy to console line."); - return -EINVAL; - } - - s->forward_to_console = !!r; - s->state = STDOUT_STREAM_RUNNING; - return 0; - - case STDOUT_STREAM_RUNNING: - return stdout_stream_log(s, p); - } - - assert_not_reached("Unknown stream state"); -} - -static int stdout_stream_scan(StdoutStream *s, bool force_flush) { - char *p; - size_t remaining; - int r; - - assert(s); - - p = s->buffer; - remaining = s->length; - for (;;) { - char *end; - size_t skip; - - end = memchr(p, '\n', remaining); - if (end) - skip = end - p + 1; - else if (remaining >= sizeof(s->buffer) - 1) { - end = p + sizeof(s->buffer) - 1; - skip = remaining; - } else - break; - - *end = 0; - - r = stdout_stream_line(s, p); - if (r < 0) - return r; - - remaining -= skip; - p += skip; - } - - if (force_flush && remaining > 0) { - p[remaining] = 0; - r = stdout_stream_line(s, p); - if (r < 0) - return r; - - p += remaining; - remaining = 0; - } - - if (p > s->buffer) { - memmove(s->buffer, p, remaining); - s->length = remaining; - } - - return 0; -} - -static int stdout_stream_process(StdoutStream *s) { - ssize_t l; - int r; - - assert(s); - - l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length); - if (l < 0) { - - if (errno == EAGAIN) - return 0; - - log_warning("Failed to read from stream: %m"); - return -errno; - } - - if (l == 0) { - r = stdout_stream_scan(s, true); - if (r < 0) - return r; - - return 0; - } - - s->length += l; - r = stdout_stream_scan(s, false); - if (r < 0) - return r; - - return 1; - -} - -static void stdout_stream_free(StdoutStream *s) { - assert(s); - - if (s->server) { - assert(s->server->n_stdout_streams > 0); - s->server->n_stdout_streams --; - LIST_REMOVE(StdoutStream, stdout_stream, s->server->stdout_streams, s); - } - - if (s->fd >= 0) { - if (s->server) - epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL); - - close_nointr_nofail(s->fd); - } - -#ifdef HAVE_SELINUX - if (s->security_context) - freecon(s->security_context); -#endif - - free(s->identifier); - free(s); -} - -static int stdout_stream_new(Server *s) { - StdoutStream *stream; - int fd, r; - socklen_t len; - struct epoll_event ev; - - assert(s); - - fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); - if (fd < 0) { - if (errno == EAGAIN) - return 0; - - log_error("Failed to accept stdout connection: %m"); - return -errno; - } - - if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) { - log_warning("Too many stdout streams, refusing connection."); - close_nointr_nofail(fd); - return 0; - } - - stream = new0(StdoutStream, 1); - if (!stream) { - close_nointr_nofail(fd); - return log_oom(); - } - - stream->fd = fd; - - len = sizeof(stream->ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) { - log_error("Failed to determine peer credentials: %m"); - r = -errno; - goto fail; - } - -#ifdef HAVE_SELINUX - if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT) - log_error("Failed to determine peer security context: %m"); -#endif - - if (shutdown(fd, SHUT_WR) < 0) { - log_error("Failed to shutdown writing side of socket: %m"); - r = -errno; - goto fail; - } - - zero(ev); - ev.data.ptr = stream; - ev.events = EPOLLIN; - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - log_error("Failed to add stream to event loop: %m"); - r = -errno; - goto fail; - } - - stream->server = s; - LIST_PREPEND(StdoutStream, stdout_stream, s->stdout_streams, stream); - s->n_stdout_streams ++; - - return 0; - -fail: - stdout_stream_free(stream); - return r; -} static int system_journal_open(Server *s) { int r; @@ -1860,7 +890,7 @@ static int server_flush_to_var(Server *s) { if (!s->system_journal) return 0; - log_info("Flushing to /var..."); + log_debug("Flushing to /var..."); r = sd_id128_get_machine(&machine); if (r < 0) { @@ -1888,7 +918,7 @@ static int server_flush_to_var(Server *s) { r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL); if (r == -E2BIG) { - log_info("Allocation limit reached."); + log_debug("Allocation limit reached."); journal_file_post_change(s->system_journal); server_rotate(s); @@ -1924,7 +954,7 @@ static int process_event(Server *s, struct epoll_event *ev) { ssize_t n; if (ev->events != EPOLLIN) { - log_info("Got invalid event from epoll."); + log_error("Got invalid event from epoll."); return -EIO; } @@ -1960,7 +990,7 @@ static int process_event(Server *s, struct epoll_event *ev) { int r; if (ev->events != EPOLLIN) { - log_info("Got invalid event from epoll."); + log_error("Got invalid event from epoll."); return -EIO; } @@ -1974,7 +1004,7 @@ static int process_event(Server *s, struct epoll_event *ev) { ev->data.fd == s->syslog_fd) { if (ev->events != EPOLLIN) { - log_info("Got invalid event from epoll."); + log_error("Got invalid event from epoll."); return -EIO; } @@ -2081,15 +1111,15 @@ static int process_event(Server *s, struct epoll_event *ev) { else s->buffer[n] = 0; - process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len); + server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len); } 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, label, label_len); + server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len); else if (n == 0 && n_fds == 1) - process_native_file(s, fds[0], ucred, tv, label, label_len); + server_process_native_file(s, fds[0], ucred, tv, label, label_len); else if (n_fds > 0) log_warning("Got too many file descriptors via native socket. Ignoring."); } @@ -2102,7 +1132,7 @@ static int process_event(Server *s, struct epoll_event *ev) { } else if (ev->data.fd == s->stdout_fd) { if (ev->events != EPOLLIN) { - log_info("Got invalid event from epoll."); + log_error("Got invalid event from epoll."); return -EIO; } @@ -2113,7 +1143,7 @@ static int process_event(Server *s, struct epoll_event *ev) { StdoutStream *stream; if ((ev->events|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) { - log_info("Got invalid event from epoll."); + log_error("Got invalid event from epoll."); return -EIO; } @@ -2136,179 +1166,6 @@ static int process_event(Server *s, struct epoll_event *ev) { return 0; } -static int open_syslog_socket(Server *s) { - union sockaddr_union sa; - int one, r; - struct epoll_event ev; - - assert(s); - - if (s->syslog_fd < 0) { - - s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (s->syslog_fd < 0) { - log_error("socket() failed: %m"); - 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"); - return -errno; - } - - 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)); - if (r < 0) { - log_error("SO_PASSCRED failed: %m"); - return -errno; - } - -#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"); -#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; - } - - return 0; -} - -static int open_native_socket(Server*s) { - union sockaddr_union sa; - int one, r; - struct epoll_event ev; - - assert(s); - - if (s->native_fd < 0) { - - s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (s->native_fd < 0) { - log_error("socket() failed: %m"); - return -errno; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path)); - - unlink(sa.un.sun_path); - - r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); - if (r < 0) { - log_error("bind() failed: %m"); - return -errno; - } - - 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)); - if (r < 0) { - log_error("SO_PASSCRED failed: %m"); - return -errno; - } - -#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"); -#endif - - one = 1; - r = setsockopt(s->native_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->native_fd; - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->native_fd, &ev) < 0) { - log_error("Failed to add native server fd to epoll object: %m"); - return -errno; - } - - return 0; -} - -static int open_stdout_socket(Server *s) { - union sockaddr_union sa; - int r; - struct epoll_event ev; - - assert(s); - - if (s->stdout_fd < 0) { - - s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (s->stdout_fd < 0) { - log_error("socket() failed: %m"); - return -errno; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path)); - - unlink(sa.un.sun_path); - - r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); - if (r < 0) { - log_error("bind() failed: %m"); - return -errno; - } - - chmod(sa.un.sun_path, 0666); - - if (listen(s->stdout_fd, SOMAXCONN) < 0) { - log_error("liste() failed: %m"); - return -errno; - } - } else - fd_nonblock(s->stdout_fd, 1); - - zero(ev); - ev.events = EPOLLIN; - ev.data.fd = s->stdout_fd; - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->stdout_fd, &ev) < 0) { - log_error("Failed to add stdout server fd to epoll object: %m"); - return -errno; - } - - return 0; -} - static int open_signalfd(Server *s) { sigset_t mask; struct epoll_event ev; @@ -2500,15 +1357,15 @@ static int server_init(Server *s) { } } - r = open_syslog_socket(s); + r = server_open_syslog_socket(s); if (r < 0) return r; - r = open_native_socket(s); + r = server_open_native_socket(s); if (r < 0) return r; - r = open_stdout_socket(s); + r = server_open_stdout_socket(s); if (r < 0) return r; @@ -2539,7 +1396,7 @@ static int server_init(Server *s) { return 0; } -static void maybe_append_tags(Server *s) { +static void server_maybe_append_tags(Server *s) { #ifdef HAVE_GCRYPT JournalFile *f; Iterator i; @@ -2684,7 +1541,7 @@ int main(int argc, char *argv[]) { break; } - maybe_append_tags(&server); + server_maybe_append_tags(&server); } log_debug("systemd-journald stopped as pid %lu", (unsigned long) getpid());