From 7fc04b12e0129cfedca05b13068e9c3aa7c3c196 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Nov 2015 12:55:32 +0100 Subject: [PATCH 1/6] sd-bus: don't try to acquire connection selinux label unless selinux is actually enabled Otherwise we might end up mistaking a SMACK label for an selinux label. Also, fixes unexpect debug messages: http://lists.freedesktop.org/archives/systemd-devel/2015-November/034913.html --- src/libsystemd/sd-bus/bus-control.c | 6 +++++- src/libsystemd/sd-bus/bus-socket.c | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index d5bc32e757..ddd3a55b6c 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -981,8 +981,12 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds ** static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; pid_t pid = 0; + bool do_label; int r; - bool do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); + + assert(bus); + + do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); /* Avoid allocating anything if we have no chance of returning useful data */ if (!bus->ucred_valid && !do_label) diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index a5cb667630..25873dea1e 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -36,6 +36,7 @@ #include "hexdecoct.h" #include "macro.h" #include "missing.h" +#include "selinux-util.h" #include "signal-util.h" #include "stdio-util.h" #include "string-util.h" @@ -608,9 +609,11 @@ static void bus_get_peercred(sd_bus *b) { b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; /* Get the SELinux context of the peer */ - r = getpeersec(b->input_fd, &b->label); - if (r < 0 && r != -EOPNOTSUPP) - log_debug_errno(r, "Failed to determine peer security context: %m"); + if (mac_selinux_use()) { + r = getpeersec(b->input_fd, &b->label); + if (r < 0 && r != -EOPNOTSUPP) + log_debug_errno(r, "Failed to determine peer security context: %m"); + } } static int bus_socket_start_auth_client(sd_bus *b) { From 404f08d341c6fcd5f28664902adefd069f2082cd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Nov 2015 12:57:40 +0100 Subject: [PATCH 2/6] systemctl: add a comment that clarifies why we do "return r" at the end of main() To avoid confusion as outlined in #1845. --- src/systemctl/systemctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0c42766a60..616ede814c 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -7709,5 +7709,7 @@ finish: release_busses(); + /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */ + return r < 0 ? EXIT_FAILURE : r; } From 94b6551662e0db8eb09768ed70f77759f322b4c6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Nov 2015 12:59:09 +0100 Subject: [PATCH 3/6] journalctl: add new --sync switch for syncing the journal to disk With this new "--sync" switch we add a synchronous way to sync everything queued to disk, and return only after that's complete. This command gives the guarantee that anything queued before has hit the disk before the command returns. While we are at it, also improve the man pages and help text for journalctl a bit. --- man/journalctl.xml | 24 ++++++- man/systemd-journald.service.xml | 23 +++++-- src/journal/journalctl.c | 106 ++++++++++++++++++++++++++++--- src/journal/journald-server.c | 35 +++++++++- src/journal/journald-server.h | 1 + 5 files changed, 171 insertions(+), 18 deletions(-) diff --git a/man/journalctl.xml b/man/journalctl.xml index a3192539dc..2160f3cba2 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -772,14 +772,32 @@ the operation. + + + + Ask the journal daemon to write all yet + unwritten journal data to the backing file system and + synchronize all journals. This call does not return until the + operation is complete. This command guarantees that any log + messages written before its invocation are safely stored on + disk at the time it returns. + + Asks the journal daemon to flush any log data stored in /run/log/journal into - /var/log/journal, if persistent storage is - enabled. This call does not return until the operation is - complete. + /var/log/journal, if persistent storage + is enabled. This call does not return until the operation is + complete. Note that this call is idempotent: the data is only + flushed from /run/log/journal into + /var/log/journal once during system + runtime, and this command exits cleanly without executing any + operation if this has already has happened. This command + effectively guarantees that all data is flushed to + /var/log/journal at the time it + returns. diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml index 21fd684b8b..f1054b03bb 100644 --- a/man/systemd-journald.service.xml +++ b/man/systemd-journald.service.xml @@ -131,15 +131,30 @@ systemd-tmpfiles --create --prefix /var/log/journal this is enabled). This must be used after /var/ is mounted, as otherwise log data from /run is never flushed to - /var regardless of the - configuration. + /var regardless of the configuration. The + journalctl --flush command uses this signal + to request flushing of the journal files, and then waits for + the operation to complete. See + journalctl1 + for details. SIGUSR2 Request immediate rotation of the journal - files. + files. The journalctl --rotate command uses + this signal to request journal file + rotation. + + + + SIGRTMIN+1 + + Request that all unwritten log data is written + to disk. The journalctl --sync command uses + this signal to trigger journal synchronization, and then waits + for the operation to complete. @@ -261,7 +276,7 @@ systemd-tmpfiles --create --prefix /var/log/journal systemd-coredump8, setfacl1, sd_journal_print4, - pydoc systemd.journal. + pydoc systemd.journal diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 277adba904..071349666c 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -135,6 +135,7 @@ static enum { ACTION_FLUSH, ACTION_ROTATE, ACTION_VACUUM, + ACTION_SYNC, } arg_action = ACTION_SHOW; typedef struct BootId { @@ -201,7 +202,7 @@ static void help(void) { printf("%s [OPTIONS...] [MATCHES...]\n\n" "Query the journal.\n\n" - "Flags:\n" + "Options:\n" " --system Show the system journal\n" " --user Show the user journal for the current user\n" " -M --machine=CONTAINER Operate on local container\n" @@ -234,7 +235,7 @@ static void help(void) { " -m --merge Show entries from all available journals\n" " -D --directory=PATH Show journal files from directory\n" " --file=PATH Show journal file\n" - " --root=ROOT Operate on catalog files underneath the root ROOT\n" + " --root=ROOT Operate on catalog files below a root directory\n" #ifdef HAVE_GCRYPT " --interval=TIME Time interval for changing the FSS sealing key\n" " --verify-key=KEY Specify FSS verification key\n" @@ -244,20 +245,21 @@ static void help(void) { " -h --help Show this help text\n" " --version Show package version\n" " -F --field=FIELD List all values that a specified field takes\n" - " --new-id128 Generate a new 128-bit ID\n" " --disk-usage Show total disk usage of all journal files\n" " --vacuum-size=BYTES Reduce disk usage below specified size\n" " --vacuum-files=INT Leave only the specified number of journal files\n" " --vacuum-time=TIME Remove journal files older than specified time\n" + " --verify Verify journal file consistency\n" + " --sync Synchronize unwritten journal messages to disk\n" " --flush Flush all journal data from /run into /var\n" " --rotate Request immediate rotation of the journal files\n" " --header Show journal header information\n" " --list-catalog Show all message IDs in the catalog\n" " --dump-catalog Show entries in the message catalog\n" " --update-catalog Update the message catalog database\n" + " --new-id128 Generate a new 128-bit ID\n" #ifdef HAVE_GCRYPT " --setup-keys Generate a new FSS key pair\n" - " --verify Verify journal file consistency\n" #endif , program_invocation_short_name); } @@ -289,6 +291,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_UPDATE_CATALOG, ARG_FORCE, ARG_UTC, + ARG_SYNC, ARG_FLUSH, ARG_ROTATE, ARG_VACUUM_SIZE, @@ -345,6 +348,7 @@ static int parse_argv(int argc, char *argv[]) { { "machine", required_argument, NULL, 'M' }, { "utc", no_argument, NULL, ARG_UTC }, { "flush", no_argument, NULL, ARG_FLUSH }, + { "sync", no_argument, NULL, ARG_SYNC }, { "rotate", no_argument, NULL, ARG_ROTATE }, { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE }, { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES }, @@ -729,6 +733,10 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_ROTATE; break; + case ARG_SYNC: + arg_action = ACTION_SYNC; + break; + case '?': return -EINVAL; @@ -1782,10 +1790,8 @@ static int flush_to_var(void) { &error, NULL, "ssi", "systemd-journald.service", "main", SIGUSR1); - if (r < 0) { - log_error("Failed to kill journal service: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); mkdir_p("/run/systemd/journal", 0755); @@ -1840,6 +1846,85 @@ static int rotate(void) { return 0; } +static int sync_journal(void) { + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_close_ int watch_fd = -1; + usec_t start; + int r; + + start = now(CLOCK_REALTIME); + + /* Let's watch /run/systemd/sync until it's mtime is above + * the time we started the sync. Let's enqueue SIGRTMIN+1 to + * start the sync. */ + + for (;;) { + struct stat st; + + /* See if a sync happened by now. */ + if (stat("/run/systemd/journal/synced", &st) < 0) { + if (errno != ENOENT) + return log_error_errno(errno, "Failed to stat /run/systemd/journal/synced: %m"); + } else { + if (timespec_load(&st.st_mtim) >= start) + return 0; + } + + /* Let's ask for a sync, but only once. */ + if (!bus) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + + r = bus_connect_system_systemd(&bus); + if (r < 0) + return log_error_errno(r, "Failed to get D-Bus connection: %m"); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + &error, + NULL, + "ssi", "systemd-journald.service", "main", SIGRTMIN+1); + if (r < 0) + return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); + + continue; + } + + /* Let's install the inotify watch, if we didn't do that yet. */ + if (watch_fd < 0) { + + mkdir_p("/run/systemd/journal", 0755); + + watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (watch_fd < 0) + return log_error_errno(errno, "Failed to create inotify watch: %m"); + + r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_ATTRIB|IN_DONT_FOLLOW|IN_ONLYDIR); + if (r < 0) + return log_error_errno(errno, "Failed to watch journal directory: %m"); + + /* Recheck the flag file immediately, so that we don't miss any event since the last check. */ + continue; + } + + /* OK, all preparatory steps done, let's wait until + * inotify reports an event. */ + + r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY); + if (r < 0) + return log_error_errno(r, "Failed to wait for event: %m"); + + r = flush_fd(watch_fd); + if (r < 0) + return log_error_errno(r, "Failed to flush inotify events: %m"); + } + + return 0; +} + int main(int argc, char *argv[]) { int r; _cleanup_journal_close_ sd_journal *j = NULL; @@ -1875,6 +1960,11 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_action == ACTION_SYNC) { + r = sync_journal(); + goto finish; + } + if (arg_action == ACTION_ROTATE) { r = rotate(); goto finish; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index a6e5e4a20f..f0a3c82d98 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1243,7 +1243,7 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo * assert(s); - log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid); + log_info("Received request to flush runtime journal from PID " PID_FMT, si->ssi_pid); server_flush_to_var(s); server_sync(s); @@ -1259,7 +1259,7 @@ static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo * assert(s); - log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid); + log_info("Received request to rotate journal from PID " PID_FMT, si->ssi_pid); server_rotate(s); server_vacuum(s, true, true); @@ -1277,12 +1277,27 @@ static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo * return 0; } +static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; + + assert(s); + + log_debug("Received request to sync from PID " PID_FMT, si->ssi_pid); + + server_sync(s); + + /* Let clients know when the most recent sync happened. */ + (void) touch("/run/systemd/journal/synced"); + + return 0; +} + static int setup_signals(Server *s) { int r; assert(s); - assert(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1) >= 0); + assert(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0); r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s); if (r < 0) @@ -1312,6 +1327,19 @@ static int setup_signals(Server *s) { if (r < 0) return r; + /* SIGRTMIN+1 causes an immediate sync. We process this very + * late, so that everything else queued at this point is + * really written to disk. Clients can watch + * /run/systemd/journal/synced with inotify until its mtime + * changes to see when a sync happened. */ + r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s); + if (r < 0) + return r; + + r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15); + if (r < 0) + return r; + return 0; } @@ -1869,6 +1897,7 @@ void server_done(Server *s) { sd_event_source_unref(s->sigusr2_event_source); sd_event_source_unref(s->sigterm_event_source); sd_event_source_unref(s->sigint_event_source); + sd_event_source_unref(s->sigrtmin1_event_source); sd_event_source_unref(s->hostname_event_source); sd_event_source_unref(s->notify_event_source); sd_event_source_unref(s->watchdog_event_source); diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 03a61bd2ed..dcc21bb7c3 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -72,6 +72,7 @@ struct Server { sd_event_source *sigusr2_event_source; sd_event_source *sigterm_event_source; sd_event_source *sigint_event_source; + sd_event_source *sigrtmin1_event_source; sd_event_source *hostname_event_source; sd_event_source *notify_event_source; sd_event_source *watchdog_event_source; From dbd6e31cf91ab86a4a2fffeb50ccef211da3126d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Nov 2015 13:56:54 +0100 Subject: [PATCH 4/6] journalctl: make --rotate synchronous, too Of course, ideally we'd just use normal synchronous bus calls, but this is out of the question as long as we rely on dbus-daemon (which logs to journald, and thus cannot use to avoid cyclic sync loops). Hence, instead, reuse the wait logic already implemented for --sync, and use a signal in one direction, and a mtime watch file for the reply. --- man/journalctl.xml | 14 ++++++----- src/journal/journalctl.c | 47 ++++++++++++----------------------- src/journal/journald-server.c | 3 +++ 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/man/journalctl.xml b/man/journalctl.xml index 2160f3cba2..b57afb6ebf 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -775,12 +775,12 @@ - Ask the journal daemon to write all yet + Asks the journal daemon to write all yet unwritten journal data to the backing file system and synchronize all journals. This call does not return until the - operation is complete. This command guarantees that any log - messages written before its invocation are safely stored on - disk at the time it returns. + synchronization operation is complete. This command guarantees + that any log messages written before its invocation are safely + stored on disk at the time it returns. @@ -803,9 +803,11 @@ - Asks the journal daemon to rotate journal files. - + Asks the journal daemon to rotate journal + files. This call does not return until the rotation operation + is complete. + diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 071349666c..521360b11b 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1822,31 +1822,7 @@ static int flush_to_var(void) { return 0; } -static int rotate(void) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; - int r; - - r = bus_connect_system_systemd(&bus); - if (r < 0) - return log_error_errno(r, "Failed to get D-Bus connection: %m"); - - r = sd_bus_call_method( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "KillUnit", - &error, - NULL, - "ssi", "systemd-journald.service", "main", SIGUSR2); - if (r < 0) - return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); - - return 0; -} - -static int sync_journal(void) { +static int send_signal_and_wait(int sig, const char *watch_path) { _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; _cleanup_close_ int watch_fd = -1; usec_t start; @@ -1854,17 +1830,18 @@ static int sync_journal(void) { start = now(CLOCK_REALTIME); - /* Let's watch /run/systemd/sync until it's mtime is above - * the time we started the sync. Let's enqueue SIGRTMIN+1 to - * start the sync. */ + /* This call sends the specified signal to journald, and waits + * for acknowledgment by watching the mtime of the specified + * flag file. This is used to trigger syncing or rotation and + * then wait for the operation to complete. */ for (;;) { struct stat st; /* See if a sync happened by now. */ - if (stat("/run/systemd/journal/synced", &st) < 0) { + if (stat(watch_path, &st) < 0) { if (errno != ENOENT) - return log_error_errno(errno, "Failed to stat /run/systemd/journal/synced: %m"); + return log_error_errno(errno, "Failed to stat %s: %m", watch_path); } else { if (timespec_load(&st.st_mtim) >= start) return 0; @@ -1886,7 +1863,7 @@ static int sync_journal(void) { "KillUnit", &error, NULL, - "ssi", "systemd-journald.service", "main", SIGRTMIN+1); + "ssi", "systemd-journald.service", "main", sig); if (r < 0) return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); @@ -1925,6 +1902,14 @@ static int sync_journal(void) { return 0; } +static int rotate(void) { + return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated"); +} + +static int sync_journal(void) { + return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced"); +} + int main(int argc, char *argv[]) { int r; _cleanup_journal_close_ sd_journal *j = NULL; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index f0a3c82d98..70ff101d5f 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1263,6 +1263,9 @@ static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo * server_rotate(s); server_vacuum(s, true, true); + /* Let clients know when the most recent rotation happened. */ + (void) touch("/run/systemd/journal/rotated"); + return 0; } From bd098bceddfe70dc995c0c4f7bac07475fc0fc41 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Nov 2015 14:32:26 +0100 Subject: [PATCH 5/6] update TODO --- TODO | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 25900c70b8..5dc3d1ffa3 100644 --- a/TODO +++ b/TODO @@ -33,6 +33,15 @@ Janitorial Clean-ups: Features: +* PID1: find a way how we can reload unit file configuration for + specific units only, without reloading the whole of systemd + +* For services: replace the default Requires=basic.target with After=basic.target + Requires=sysinit.target. + +* drop "Overridable" dependency types + +* document precise effect of DefaultDependencies=yes + * add an explicit parser for LimitNICE= and LimitRTPRIO= that verifies the specified range and generates sane error messages for incorrect specifications. Also, for LimitNICE= maybe introduce a syntax such @@ -43,7 +52,7 @@ Features: * when we detect that there are waiting jobs but no running jobs, do something -* push CPUAffinity also into the "cpuset" cgroup controller +* push CPUAffinity also into the "cpuset" cgroup controller (only after the cpuset controller got ported to the unified hierarchy) * add a concept of RemainAfterExit= to scope units From 91d0f17e03e3975cac95c418e101f5266b56e897 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Nov 2015 14:35:37 +0100 Subject: [PATCH 6/6] systemctl: make sure list-jobs doesn't return failure on success --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 616ede814c..e9d73ea9d0 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2186,7 +2186,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); output_jobs_list(jobs, c, skipped); - return r; + return 0; } static int cancel_job(int argc, char *argv[], void *userdata) {