chiark / gitweb /
journald: add Storage= setting to control where the journal is stored
[elogind.git] / src / journal / journald.c
index e0e7cce1227d4aea19cc2934939efd56ae6445ee..08597ae3eb9630dc22b43151d7163336465a0ead 100644 (file)
@@ -77,6 +77,7 @@
 
 typedef enum StdoutStreamState {
         STDOUT_STREAM_IDENTIFIER,
+        STDOUT_STREAM_UNIT_ID,
         STDOUT_STREAM_PRIORITY,
         STDOUT_STREAM_LEVEL_PREFIX,
         STDOUT_STREAM_FORWARD_TO_SYSLOG,
@@ -97,6 +98,7 @@ struct StdoutStream {
 #endif
 
         char *identifier;
+        char *unit_id;
         int priority;
         bool level_prefix:1;
         bool forward_to_syslog:1;
@@ -109,6 +111,16 @@ struct StdoutStream {
         LIST_FIELDS(StdoutStream, stdout_stream);
 };
 
+static const char* const storage_table[] = {
+        [STORAGE_AUTO] = "auto",
+        [STORAGE_VOLATILE] = "volatile",
+        [STORAGE_PERMANENT] = "permanent",
+        [STORAGE_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
+
 static int server_flush_to_var(Server *s);
 
 static uint64_t available_space(Server *s) {
@@ -395,7 +407,6 @@ static void server_vacuum(Server *s) {
                 free(p);
         }
 
-
         if (s->runtime_journal) {
                 if (asprintf(&p, "/run/log/journal/%s", ids) < 0) {
                         log_error("Out of memory.");
@@ -458,7 +469,8 @@ static void dispatch_message_real(
                 struct iovec *iovec, unsigned n, unsigned m,
                 struct ucred *ucred,
                 struct timeval *tv,
-                const char *label, size_t label_len) {
+                const char *label, size_t label_len,
+                const char *unit_id) {
 
         char *pid = NULL, *uid = NULL, *gid = NULL,
                 *source_time = NULL, *boot_id = NULL, *machine_id = NULL,
@@ -560,10 +572,11 @@ static void dispatch_message_real(
                 if (cg_pid_get_unit(ucred->pid, &t) >= 0) {
                         unit = strappend("_SYSTEMD_UNIT=", t);
                         free(t);
+                } else if (unit_id)
+                        unit = strappend("_SYSTEMD_UNIT=", unit_id);
 
-                        if (unit)
-                                IOVEC_SET_STRING(iovec[n++], unit);
-                }
+                if (unit)
+                        IOVEC_SET_STRING(iovec[n++], unit);
 
 #ifdef HAVE_SELINUX
                 if (label) {
@@ -621,9 +634,7 @@ static void dispatch_message_real(
 
 retry:
         f = find_journal(s, realuid == 0 ? 0 : loginuid);
-        if (!f)
-                log_warning("Dropping message, as we can't find a place to store the data.");
-        else {
+        if (f) {
                 r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
 
                 if ((r == -E2BIG || /* hit limit */
@@ -702,7 +713,7 @@ static void driver_message(Server *s, sd_id128_t message_id, const char *format,
         ucred.uid = getuid();
         ucred.gid = getgid();
 
-        dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0);
+        dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL);
 }
 
 static void dispatch_message(Server *s,
@@ -710,6 +721,7 @@ static void dispatch_message(Server *s,
                              struct ucred *ucred,
                              struct timeval *tv,
                              const char *label, size_t label_len,
+                             const char *unit_id,
                              int priority) {
         int rl;
         char *path = NULL, *c;
@@ -720,6 +732,9 @@ static void dispatch_message(Server *s,
         if (n == 0)
                 return;
 
+        if (LOG_PRI(priority) > s->max_level_store)
+                return;
+
         if (!ucred)
                 goto finish;
 
@@ -757,7 +772,7 @@ static void dispatch_message(Server *s,
         free(path);
 
 finish:
-        dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len);
+        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) {
@@ -829,12 +844,15 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
         log_debug("Failed to forward syslog message: %m");
 }
 
-static void forward_syslog_raw(Server *s, const char *buffer, struct ucred *ucred, struct timeval *tv) {
+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);
 }
@@ -852,6 +870,9 @@ static void forward_syslog(Server *s, int priority, const char *identifier, cons
         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);
@@ -913,6 +934,9 @@ static void forward_kmsg(Server *s, int priority, const char *identifier, const
         assert(priority <= 999);
         assert(message);
 
+        if (LOG_PRI(priority) > s->max_level_kmsg)
+                return;
+
         /* Never allow messages with kernel facility to be written to
          * kmsg, regardless where the data comes from. */
         priority = fixup_priority(priority);
@@ -960,15 +984,19 @@ finish:
         free(ident_buf);
 }
 
-static void forward_console(Server *s, const char *identifier, const char *message, struct ucred *ucred) {
+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) {
@@ -992,14 +1020,16 @@ static void forward_console(Server *s, const char *identifier, const char *messa
         IOVEC_SET_STRING(iovec[n++], message);
         IOVEC_SET_STRING(iovec[n++], "\n");
 
-        fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+        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 /dev/console for logging: %s", strerror(errno));
+                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 /dev/console for logging: %s", strerror(errno));
+                log_debug("Failed to write to %s for logging: %s", tty, strerror(errno));
 
         close_nointr_nofail(fd);
 
@@ -1063,14 +1093,17 @@ static void process_syslog_message(Server *s, const char *buf, struct ucred *ucr
         unsigned n = 0;
         int priority = LOG_USER | LOG_INFO;
         char *identifier = NULL, *pid = NULL;
+        const char *orig;
 
         assert(s);
         assert(buf);
 
+        orig = buf;
+        parse_syslog_priority((char**) &buf, &priority);
+
         if (s->forward_to_syslog)
-                forward_syslog_raw(s, buf, ucred, tv);
+                forward_syslog_raw(s, priority, orig, ucred, tv);
 
-        parse_syslog_priority((char**) &buf, &priority);
         skip_syslog_date((char**) &buf);
         read_identifier(&buf, &identifier, &pid);
 
@@ -1078,7 +1111,7 @@ static void process_syslog_message(Server *s, const char *buf, struct ucred *ucr
                 forward_kmsg(s, priority, identifier, buf, ucred);
 
         if (s->forward_to_console)
-                forward_console(s, identifier, buf, ucred);
+                forward_console(s, priority, identifier, buf, ucred);
 
         IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
 
@@ -1105,7 +1138,7 @@ static void process_syslog_message(Server *s, const char *buf, struct ucred *ucr
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, priority);
+        dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority);
 
         free(message);
         free(identifier);
@@ -1183,7 +1216,7 @@ static void process_native_message(
 
                 if (e == p) {
                         /* Entry separator */
-                        dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, priority);
+                        dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
                         n = 0;
                         priority = LOG_INFO;
 
@@ -1330,10 +1363,10 @@ static void process_native_message(
                         forward_kmsg(s, priority, identifier, message, ucred);
 
                 if (s->forward_to_console)
-                        forward_console(s, identifier, message, ucred);
+                        forward_console(s, priority, identifier, message, ucred);
         }
 
-        dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, priority);
+        dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
 
 finish:
         for (j = 0; j < n; j++)  {
@@ -1428,7 +1461,7 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
                 forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
 
         if (s->forward_to_console || s->server->forward_to_console)
-                forward_console(s->server, s->identifier, p, &s->ucred);
+                forward_console(s->server, priority, s->identifier, p, &s->ucred);
 
         IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
 
@@ -1456,7 +1489,7 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
         }
 #endif
 
-        dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, priority);
+        dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority);
 
         free(message);
         free(syslog_priority);
@@ -1487,6 +1520,22 @@ static int stdout_stream_line(StdoutStream *s, char *p) {
                         }
                 }
 
+                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) {
+                                        log_error("Out of memory");
+                                        return -ENOMEM;
+                                }
+                        }
+                }
+
                 s->state = STDOUT_STREAM_PRIORITY;
                 return 0;
 
@@ -1853,7 +1902,7 @@ 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, NULL, 0, priority);
+        dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority);
 
 finish:
         free(message);
@@ -1913,12 +1962,23 @@ static int system_journal_open(Server *s) {
 
         sd_id128_to_string(machine, ids);
 
-        if (!s->system_journal) {
+        if (!s->system_journal &&
+            (s->storage == STORAGE_PERMANENT ||
+             s->storage == STORAGE_AUTO)) {
+
+                /* If in auto mode: first try to create the machine
+                 * path, but not the prefix.
+                 *
+                 * If in permanent mode: create /var/log/journal and
+                 * the machine path */
+
+                if (s->storage & STORAGE_PERMANENT)
+                        (void) mkdir("/var/log/journal/", 0755);
 
-                /* First try to create the machine path, but not the prefix */
                 fn = strappend("/var/log/journal/", ids);
                 if (!fn)
                         return -ENOMEM;
+
                 (void) mkdir(fn, 0755);
                 free(fn);
 
@@ -1946,7 +2006,8 @@ static int system_journal_open(Server *s) {
                 }
         }
 
-        if (!s->runtime_journal) {
+        if (!s->runtime_journal &&
+            (s->storage != STORAGE_NONE)) {
 
                 fn = join("/run/log/journal/", ids, "/system.journal", NULL);
                 if (!fn)
@@ -2006,6 +2067,10 @@ static int server_flush_to_var(Server *s) {
 
         assert(s);
 
+        if (s->storage != STORAGE_AUTO &&
+            s->storage != STORAGE_PERMANENT)
+                return 0;
+
         if (!s->runtime_journal)
                 return 0;
 
@@ -2122,6 +2187,7 @@ static int server_flush_proc_kmsg(Server *s) {
 
 static int process_event(Server *s, struct epoll_event *ev) {
         assert(s);
+        assert(ev);
 
         if (ev->data.fd == s->signal_fd) {
                 struct signalfd_siginfo sfsi;
@@ -2146,7 +2212,13 @@ static int process_event(Server *s, struct epoll_event *ev) {
 
                 if (sfsi.ssi_signo == SIGUSR1) {
                         server_flush_to_var(s);
-                        return 0;
+                        return 1;
+                }
+
+                if (sfsi.ssi_signo == SIGUSR2) {
+                        server_rotate(s);
+                        server_vacuum(s);
+                        return 1;
                 }
 
                 log_debug("Received SIG%s", signal_to_string(sfsi.ssi_signo));
@@ -2537,7 +2609,7 @@ static int open_signalfd(Server *s) {
         assert(s);
 
         assert_se(sigemptyset(&mask) == 0);
-        sigset_add_many(&mask, SIGINT, SIGTERM, SIGUSR1, -1);
+        sigset_add_many(&mask, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1);
         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
 
         s->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
@@ -2581,25 +2653,26 @@ static int server_parse_proc_cmdline(Server *s) {
                         goto finish;
                 }
 
-                if (startswith(word, "systemd_journald.forward_to_syslog=")) {
+                if (startswith(word, "systemd.journald.forward_to_syslog=")) {
                         r = parse_boolean(word + 35);
                         if (r < 0)
                                 log_warning("Failed to parse forward to syslog switch %s. Ignoring.", word + 35);
                         else
                                 s->forward_to_syslog = r;
-                } else if (startswith(word, "systemd_journald.forward_to_kmsg=")) {
+                } else if (startswith(word, "systemd.journald.forward_to_kmsg=")) {
                         r = parse_boolean(word + 33);
                         if (r < 0)
                                 log_warning("Failed to parse forward to kmsg switch %s. Ignoring.", word + 33);
                         else
                                 s->forward_to_kmsg = r;
-                } else if (startswith(word, "systemd_journald.forward_to_console=")) {
+                } else if (startswith(word, "systemd.journald.forward_to_console=")) {
                         r = parse_boolean(word + 36);
                         if (r < 0)
                                 log_warning("Failed to parse forward to console switch %s. Ignoring.", word + 36);
                         else
                                 s->forward_to_console = r;
-                }
+                } else if (startswith(word, "systemd.journald"))
+                        log_warning("Invalid systemd.journald parameter. Ignoring.");
 
                 free(word);
         }
@@ -2652,6 +2725,11 @@ static int server_init(Server *s) {
         s->forward_to_syslog = true;
         s->import_proc_kmsg = true;
 
+        s->max_level_store = LOG_DEBUG;
+        s->max_level_syslog = LOG_DEBUG;
+        s->max_level_kmsg = LOG_NOTICE;
+        s->max_level_console = LOG_INFO;
+
         memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics));
         memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics));
 
@@ -2782,6 +2860,7 @@ static void server_done(Server *s) {
                 journal_rate_limit_free(s->rate_limit);
 
         free(s->buffer);
+        free(s->tty_path);
 }
 
 int main(int argc, char *argv[]) {