#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
-static const char* const storage_table[] = {
+static const char* const storage_table[_STORAGE_MAX] = {
[STORAGE_AUTO] = "auto",
[STORAGE_VOLATILE] = "volatile",
[STORAGE_PERSISTENT] = "persistent",
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",
+static const char* const split_mode_table[_SPLIT_MAX] = {
+ [SPLIT_LOGIN] = "login",
[SPLIT_UID] = "uid",
- [SPLIT_LOGIN] = "login"
+ [SPLIT_NONE] = "none",
};
DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
}
ss_avail = ss.f_bsize * ss.f_bavail;
- avail = ss_avail > m->keep_free ? ss_avail - m->keep_free : 0;
- s->cached_available_space = MIN(m->max_use, avail) > sum ? MIN(m->max_use, avail) - sum : 0;
+ /* If we reached a high mark, we will always allow this much
+ * again, unless usage goes above max_use. This watermark
+ * value is cached so that we don't give up space on pressure,
+ * but hover below the maximum usage. */
+
+ if (m->use < sum)
+ m->use = sum;
+
+ avail = LESS_BY(ss_avail, m->keep_free);
+
+ s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum);
s->cached_available_space_timestamp = ts;
if (verbose) {
fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX];
server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
- "%s journal is using %s (max %s, leaving %s of free %s, current limit %s).",
+ "%s journal is using %s (max allowed %s, "
+ "trying to leave %s free of %s available → current limit %s).",
s->system_journal ? "Permanent" : "Runtime",
format_bytes(fb1, sizeof(fb1), sum),
format_bytes(fb2, sizeof(fb2), m->max_use),
format_bytes(fb3, sizeof(fb3), m->keep_free),
format_bytes(fb4, sizeof(fb4), ss_avail),
- format_bytes(fb5, sizeof(fb5), MIN(m->max_use, avail)));
+ format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum));
}
return s->cached_available_space;
return f;
}
+static int do_rotate(Server *s, JournalFile **f, const char* name,
+ bool seal, uint32_t uid) {
+ int r;
+ assert(s);
+
+ if (!*f)
+ return -EINVAL;
+
+ r = journal_file_rotate(f, s->compress, seal);
+ if (r < 0)
+ if (*f)
+ log_error("Failed to rotate %s: %s",
+ (*f)->path, strerror(-r));
+ else
+ log_error("Failed to create new %s journal: %s",
+ name, strerror(-r));
+ else
+ server_fix_perms(s, *f, uid);
+ return r;
+}
+
void server_rotate(Server *s) {
JournalFile *f;
void *k;
log_debug("Rotating...");
- if (s->runtime_journal) {
- r = journal_file_rotate(&s->runtime_journal, s->compress, false);
- if (r < 0)
- if (s->runtime_journal)
- log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r));
- else
- log_error("Failed to create new runtime journal: %s", strerror(-r));
- else
- server_fix_perms(s, s->runtime_journal, 0);
- }
-
- if (s->system_journal) {
- r = journal_file_rotate(&s->system_journal, s->compress, s->seal);
- if (r < 0)
- if (s->system_journal)
- log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r));
- else
- log_error("Failed to create new system journal: %s", strerror(-r));
-
- else
- server_fix_perms(s, s->system_journal, 0);
- }
+ do_rotate(s, &s->runtime_journal, "runtime", false, 0);
+ do_rotate(s, &s->system_journal, "system", s->seal, 0);
HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
- r = journal_file_rotate(&f, s->compress, s->seal);
- if (r < 0)
- if (f)
- log_error("Failed to rotate %s: %s", f->path, strerror(-r));
- else {
- log_error("Failed to create user journal: %s", strerror(-r));
- hashmap_remove(s->user_journals, k);
- }
- else {
+ r = do_rotate(s, &f, "user", s->seal, PTR_TO_UINT32(k));
+ if (r >= 0)
hashmap_replace(s->user_journals, k, f);
- server_fix_perms(s, f, PTR_TO_UINT32(k));
- }
+ else if (!f)
+ /* Old file has been closed and deallocated */
+ hashmap_remove(s->user_journals, k);
}
}
s->sync_scheduled = false;
}
+static void do_vacuum(Server *s, char *ids, JournalFile *f, const char* path,
+ JournalMetrics *metrics) {
+ char *p;
+ int r;
+
+ if (!f)
+ return;
+
+ p = strappenda(path, ids);
+ r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec);
+ if (r < 0 && r != -ENOENT)
+ log_error("Failed to vacuum %s: %s", p, strerror(-r));
+}
+
void server_vacuum(Server *s) {
char ids[33];
sd_id128_t machine;
log_error("Failed to get machine ID: %s", strerror(-r));
return;
}
-
sd_id128_to_string(machine, ids);
- if (s->system_journal) {
- char *p = strappenda("/var/log/journal/", ids);
-
- 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));
- }
-
- if (s->runtime_journal) {
- char *p = strappenda("/run/log/journal/", ids);
-
- 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));
- }
+ do_vacuum(s, ids, s->system_journal, "/var/log/journal/", &s->system_metrics);
+ do_vacuum(s, ids, s->runtime_journal, "/run/log/journal/", &s->runtime_metrics);
s->cached_available_space_timestamp = 0;
}
#ifdef HAVE_SELINUX
if (use_selinux()) {
if (label) {
- x = alloca(sizeof("_SELINUX_CONTEXT=") + label_len);
+ x = alloca(strlen("_SELINUX_CONTEXT=") + label_len + 1);
*((char*) mempcpy(stpcpy(x, "_SELINUX_CONTEXT="), label, label_len)) = 0;
IOVEC_SET_STRING(iovec[n++], x);
union {
struct cmsghdr cmsghdr;
- /* We use NAME_MAX space for the
- * SELinux label here. The kernel
- * currently enforces no limit, but
- * according to suggestions from the
- * SELinux people this will change and
- * it will probably be identical to
- * NAME_MAX. For now we use that, but
- * this should be updated one day when
- * the final limit is known.*/
+ /* We use NAME_MAX space for the SELinux label
+ * here. The kernel currently enforces no
+ * limit, but according to suggestions from
+ * the SELinux people this will change and it
+ * will probably be identical to NAME_MAX. For
+ * now we use that, but this should be updated
+ * one day when the final limit is known.*/
uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
CMSG_SPACE(sizeof(struct timeval)) +
CMSG_SPACE(sizeof(int)) + /* fd */
close_many(fds, n_fds);
}
-
- return 0;
}
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
assert(s);
- log_info("Received SIG%s", signal_to_string(si->ssi_signo));
+ log_received_signal(LOG_INFO, si);
sd_event_exit(s->event, 0);
return 0;
sigset_add_many(&mask, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
- r = sd_event_add_signal(s->event, SIGUSR1, dispatch_sigusr1, s, &s->sigusr1_event_source);
+ r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
if (r < 0)
return r;
- r = sd_event_add_signal(s->event, SIGUSR2, dispatch_sigusr2, s, &s->sigusr2_event_source);
+ r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2, dispatch_sigusr2, s);
if (r < 0)
return r;
- r = sd_event_add_signal(s->event, SIGTERM, dispatch_sigterm, s, &s->sigterm_event_source);
+ r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM, dispatch_sigterm, s);
if (r < 0)
return r;
- r = sd_event_add_signal(s->event, SIGINT, dispatch_sigterm, s, &s->sigint_event_source);
+ r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
if (r < 0)
return r;
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.forward_to_wall=")) {
+ r = parse_boolean(word + 33);
+ if (r < 0)
+ log_warning("Failed to parse forward to wall switch %s. Ignoring.", word + 33);
+ else
+ s->forward_to_wall = r;
} else if (startswith(word, "systemd.journald"))
log_warning("Invalid systemd.journald parameter. Ignoring.");
}
if (s->sync_interval_usec > 0) {
usec_t when;
- r = sd_event_get_now_monotonic(s->event, &when);
+ r = sd_event_now(s->event, CLOCK_MONOTONIC, &when);
if (r < 0)
return r;
when += s->sync_interval_usec;
if (!s->sync_event_source) {
- r = sd_event_add_monotonic(s->event, when, 0, server_dispatch_sync, s, &s->sync_event_source);
+ r = sd_event_add_time(
+ s->event,
+ &s->sync_event_source,
+ CLOCK_MONOTONIC,
+ when, 0,
+ server_dispatch_sync, s);
if (r < 0)
return r;
return -errno;
}
- r = sd_event_add_io(s->event, s->hostname_fd, 0, dispatch_hostname_change, s, &s->hostname_event_source);
+ r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s);
if (r < 0) {
+ /* kernels prior to 3.2 don't support polling this file. Ignore
+ * the failure. */
+ if (r == -EPERM) {
+ log_warning("Failed to register hostname fd in event loop: %s. Ignoring.",
+ strerror(-r));
+ s->hostname_fd = safe_close(s->hostname_fd);
+ return 0;
+ }
+
log_error("Failed to register hostname fd in event loop: %s", strerror(-r));
return r;
}
s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST;
s->forward_to_syslog = true;
+ s->forward_to_wall = 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;
+ s->max_level_wall = LOG_EMERG;
memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics));
memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics));
sd_event_source_unref(s->hostname_event_source);
sd_event_unref(s->event);
- if (s->syslog_fd >= 0)
- close_nointr_nofail(s->syslog_fd);
-
- if (s->native_fd >= 0)
- close_nointr_nofail(s->native_fd);
-
- if (s->stdout_fd >= 0)
- close_nointr_nofail(s->stdout_fd);
-
- if (s->dev_kmsg_fd >= 0)
- close_nointr_nofail(s->dev_kmsg_fd);
-
- if (s->hostname_fd >= 0)
- close_nointr_nofail(s->hostname_fd);
+ safe_close(s->syslog_fd);
+ safe_close(s->native_fd);
+ safe_close(s->stdout_fd);
+ safe_close(s->dev_kmsg_fd);
+ safe_close(s->hostname_fd);
if (s->rate_limit)
journal_rate_limit_free(s->rate_limit);