chiark / gitweb /
docs: install README files into /var/log and 7etc/rc.d/init.d
[elogind.git] / src / journal / journald.c
index a1deceabdf2bef696239a695b2c37538c42e7177..f56e8224289955f4591798a994899839c901c8db 100644 (file)
@@ -87,6 +87,15 @@ static const char* const storage_table[] = {
 DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
 
+static const char* const split_mode_table[] = {
+        [SPLIT_NONE] = "none",
+        [SPLIT_UID] = "uid",
+        [SPLIT_LOGIN] = "login"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
+
 static uint64_t available_space(Server *s) {
         char ids[33], *p;
         const char *f;
@@ -132,9 +141,10 @@ static uint64_t available_space(Server *s) {
 
         for (;;) {
                 struct stat st;
-                struct dirent buf, *de;
+                struct dirent *de;
+                union dirent_storage buf;
 
-                r = readdir_r(d, &buf, &de);
+                r = readdir_r(d, &buf.de, &de);
                 if (r != 0)
                         break;
 
@@ -304,7 +314,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);
@@ -338,7 +348,7 @@ static void server_rotate(Server *s) {
                                 log_error("Failed to create user journal: %s", strerror(-r));
                 else {
                         hashmap_replace(s->user_journals, k, f);
-                        server_fix_perms(s, s->system_journal, PTR_TO_UINT32(k));
+                        server_fix_perms(s, f, PTR_TO_UINT32(k));
                 }
         }
 }
@@ -349,7 +359,9 @@ static void server_vacuum(Server *s) {
         sd_id128_t machine;
         int r;
 
-        log_info("Vacuuming...");
+        log_debug("Vacuuming...");
+
+        s->oldest_file_usec = 0;
 
         r = sd_id128_get_machine(&machine);
         if (r < 0) {
@@ -366,7 +378,7 @@ static void server_vacuum(Server *s) {
                         return;
                 }
 
-                r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free);
+                r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec);
                 if (r < 0 && r != -ENOENT)
                         log_error("Failed to vacuum %s: %s", p, strerror(-r));
                 free(p);
@@ -379,7 +391,7 @@ static void server_vacuum(Server *s) {
                         return;
                 }
 
-                r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free);
+                r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec);
                 if (r < 0 && r != -ENOENT)
                         log_error("Failed to vacuum %s: %s", p, strerror(-r));
                 free(p);
@@ -430,6 +442,35 @@ static char *shortened_cgroup_path(pid_t pid) {
         return path;
 }
 
+static bool shall_try_append_again(JournalFile *f, int r) {
+
+        /* -E2BIG            Hit configured limit
+           -EFBIG            Hit fs limit
+           -EDQUOT           Quota limit hit
+           -ENOSPC           Disk full
+           -EHOSTDOWN        Other machine
+           -EBUSY            Unclean shutdown
+           -EPROTONOSUPPORT  Unsupported feature
+           -EBADMSG          Corrupted
+           -ENODATA          Truncated
+           -ESHUTDOWN        Already archived */
+
+        if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC)
+                log_debug("%s: Allocation limit reached, rotating.", f->path);
+        else if (r == -EHOSTDOWN)
+                log_info("%s: Journal file from other machine, rotating.", f->path);
+        else if (r == -EBUSY)
+                log_info("%s: Unclean shutdown, rotating.", f->path);
+        else if (r == -EPROTONOSUPPORT)
+                log_info("%s: Unsupported feature, rotating.", f->path);
+        else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN)
+                log_warning("%s: Journal file corrupted, rotating.", f->path);
+        else
+                return false;
+
+        return true;
+}
+
 static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned n) {
         JournalFile *f;
         bool vacuumed = false;
@@ -443,8 +484,8 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
         if (!f)
                 return;
 
-        if (journal_file_rotate_suggested(f)) {
-                log_info("Journal header limits reached or header out-of-date, rotating.");
+        if (journal_file_rotate_suggested(f, s->max_file_usec)) {
+                log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
                 server_rotate(s);
                 server_vacuum(s);
                 vacuumed = true;
@@ -454,45 +495,26 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
                         return;
         }
 
-        for (;;) {
-                r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
-                if (r >= 0)
-                        return;
-
-                if (vacuumed ||
-                    (r != -E2BIG && /* hit limit */
-                     r != -EFBIG && /* hit fs limit */
-                     r != -EDQUOT && /* quota hit */
-                     r != -ENOSPC && /* disk full */
-                     r != -EBADMSG && /* corrupted */
-                     r != -ENODATA && /* truncated */
-                     r != -EHOSTDOWN && /* other machine */
-                     r != -EPROTONOSUPPORT && /* unsupported feature */
-                     r != -EBUSY && /* unclean shutdown */
-                     r != -ESHUTDOWN /* already archived */)) {
-                        log_error("Failed to write entry, ignoring: %s", strerror(-r));
-                        return;
-                }
+        r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
+        if (r >= 0)
+                return;
 
-                if (r == -E2BIG || r == -EFBIG || r == EDQUOT || r == ENOSPC)
-                        log_info("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.");
-                else
-                        log_warning("Journal file corrupted, rotating.");
+        if (vacuumed || !shall_try_append_again(f, r)) {
+                log_error("Failed to write entry, ignoring: %s", strerror(-r));
+                return;
+        }
 
-                server_rotate(s);
-                server_vacuum(s);
-                vacuumed = true;
+        server_rotate(s);
+        server_vacuum(s);
 
-                f = find_journal(s, uid);
-                if (!f)
-                        return;
+        f = find_journal(s, uid);
+        if (!f)
+                return;
 
-                log_info("Retrying write.");
-        }
+        log_debug("Retrying write.");
+        r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
+        if (r < 0)
+                log_error("Failed to write entry, ignoring: %s", strerror(-r));
 }
 
 static void dispatch_message_real(
@@ -659,7 +681,10 @@ static void dispatch_message_real(
 
         assert(n <= m);
 
-        write_to_journal(s, realuid == 0 ? 0 : loginuid, iovec, n);
+        write_to_journal(s,
+                         s->split_mode == SPLIT_NONE ? 0 :
+                         (s->split_mode == SPLIT_UID ? realuid :
+                          (realuid == 0 ? 0 : loginuid)), iovec, n);
 
         free(pid);
         free(uid);
@@ -701,9 +726,11 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
         char_array_0(buffer);
         IOVEC_SET_STRING(iovec[n++], buffer);
 
-        snprintf(mid, sizeof(mid), "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(message_id));
-        char_array_0(mid);
-        IOVEC_SET_STRING(iovec[n++], mid);
+        if (!sd_id128_equal(message_id, SD_ID128_NULL)) {
+                snprintf(mid, sizeof(mid), MESSAGE_ID(message_id));
+                char_array_0(mid);
+                IOVEC_SET_STRING(iovec[n++], mid);
+        }
 
         zero(ucred);
         ucred.pid = getpid();
@@ -814,9 +841,14 @@ static int system_journal_open(Server *s) {
                 r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
                 free(fn);
 
-                if (r >= 0)
+                if (r >= 0) {
+                        char fb[FORMAT_BYTES_MAX];
+
                         server_fix_perms(s, s->system_journal, 0);
-                else if (r < 0) {
+                        server_driver_message(s, SD_ID128_NULL, "Allowing system journal files to grow to %s.",
+                                              format_bytes(fb, sizeof(fb), s->system_metrics.max_use));
+
+                } else if (r < 0) {
 
                         if (r != -ENOENT && r != -EROFS)
                                 log_warning("Failed to open system journal: %s", strerror(-r));
@@ -863,18 +895,22 @@ static int system_journal_open(Server *s) {
                         }
                 }
 
-                if (s->runtime_journal)
+                if (s->runtime_journal) {
+                        char fb[FORMAT_BYTES_MAX];
+
                         server_fix_perms(s, s->runtime_journal, 0);
+                        server_driver_message(s, SD_ID128_NULL, "Allowing runtime journal files to grow to %s.",
+                                              format_bytes(fb, sizeof(fb), s->runtime_metrics.max_use));
+                }
         }
 
         return r;
 }
 
 static int server_flush_to_var(Server *s) {
-        Object *o = NULL;
         int r;
         sd_id128_t machine;
-        sd_journal *j;
+        sd_journal *j = NULL;
 
         assert(s);
 
@@ -890,7 +926,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) {
@@ -905,6 +941,7 @@ static int server_flush_to_var(Server *s) {
         }
 
         SD_JOURNAL_FOREACH(j) {
+                Object *o = NULL;
                 JournalFile *f;
 
                 f = j->current_file;
@@ -917,16 +954,19 @@ 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.");
-
-                        journal_file_post_change(s->system_journal);
-                        server_rotate(s);
-                        server_vacuum(s);
+                if (r >= 0)
+                        continue;
 
-                        r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL);
+                if (!shall_try_append_again(s->system_journal, r)) {
+                        log_error("Can't write entry: %s", strerror(-r));
+                        goto finish;
                 }
 
+                server_rotate(s);
+                server_vacuum(s);
+
+                log_debug("Retrying write.");
+                r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL);
                 if (r < 0) {
                         log_error("Can't write entry: %s", strerror(-r));
                         goto finish;
@@ -942,6 +982,9 @@ finish:
         if (r >= 0)
                 rm_rf("/run/log/journal", false, true, false);
 
+        if (j)
+                sd_journal_close(j);
+
         return r;
 }
 
@@ -954,7 +997,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;
                 }
 
@@ -990,7 +1033,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;
                 }
 
@@ -1004,7 +1047,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;
                 }
 
@@ -1132,7 +1175,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;
                 }
 
@@ -1143,7 +1186,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;
                 }
 
@@ -1480,7 +1523,6 @@ int main(int argc, char *argv[]) {
 
         log_set_target(LOG_TARGET_SAFE);
         log_set_facility(LOG_SYSLOG);
-        log_set_max_level(LOG_DEBUG);
         log_parse_environment();
         log_open();
 
@@ -1503,24 +1545,38 @@ int main(int argc, char *argv[]) {
 
         for (;;) {
                 struct epoll_event event;
-                int t;
+                int t = -1;
+                usec_t n;
 
-#ifdef HAVE_GCRYPT
-                usec_t u;
+                n = now(CLOCK_REALTIME);
+
+                if (server.max_retention_usec > 0 && server.oldest_file_usec > 0) {
 
-                if (server.system_journal &&
-                    journal_file_next_evolve_usec(server.system_journal, &u)) {
-                        usec_t n;
+                        /* The retention time is reached, so let's vacuum! */
+                        if (server.oldest_file_usec + server.max_retention_usec < n) {
+                                log_info("Retention time reached.");
+                                server_rotate(&server);
+                                server_vacuum(&server);
+                                continue;
+                        }
 
-                        n = now(CLOCK_REALTIME);
+                        /* Calculate when to rotate the next time */
+                        t = (int) ((server.oldest_file_usec + server.max_retention_usec - n + USEC_PER_MSEC - 1) / USEC_PER_MSEC);
+                        log_info("Sleeping for %i ms", t);
+                }
 
-                        if (n >= u)
-                                t = 0;
-                        else
-                                t = (int) ((u - n + USEC_PER_MSEC - 1) / USEC_PER_MSEC);
-                } else
+#ifdef HAVE_GCRYPT
+                if (server.system_journal) {
+                        usec_t u;
+
+                        if (journal_file_next_evolve_usec(server.system_journal, &u)) {
+                                if (n >= u)
+                                        t = 0;
+                                else
+                                        t = MIN(t, (int) ((u - n + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
+                        }
+                }
 #endif
-                        t = -1;
 
                 r = epoll_wait(server.epoll_fd, &event, 1, t);
                 if (r < 0) {
@@ -1542,6 +1598,7 @@ int main(int argc, char *argv[]) {
                 }
 
                 server_maybe_append_tags(&server);
+                server_maybe_warn_forward_syslog_missed(&server);
         }
 
         log_debug("systemd-journald stopped as pid %lu", (unsigned long) getpid());