mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-05 09:17:44 +03:00
Merge pull request #1848 from poettering/journal-sync
add journalctl --sync command and other stuff
This commit is contained in:
commit
a2e6fbf5c0
11
TODO
11
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
|
||||
|
||||
|
@ -772,22 +772,42 @@
|
||||
the <option>--verify</option> operation.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--sync</option></term>
|
||||
|
||||
<listitem><para>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
|
||||
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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--flush</option></term>
|
||||
|
||||
<listitem><para>Asks the journal daemon to flush any log data
|
||||
stored in <filename>/run/log/journal</filename> into
|
||||
<filename>/var/log/journal</filename>, if persistent storage is
|
||||
enabled. This call does not return until the operation is
|
||||
complete.</para></listitem>
|
||||
<filename>/var/log/journal</filename>, 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 <filename>/run/log/journal</filename> into
|
||||
<filename>/var/log/journal</filename> 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
|
||||
<filename>/var/log/journal</filename> at the time it
|
||||
returns.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--rotate</option></term>
|
||||
|
||||
<listitem><para>Asks the journal daemon to rotate journal files.
|
||||
</para></listitem>
|
||||
<listitem><para>Asks the journal daemon to rotate journal
|
||||
files. This call does not return until the rotation operation
|
||||
is complete.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
|
@ -131,15 +131,30 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
|
||||
this is enabled). This must be used after
|
||||
<filename>/var/</filename> is mounted, as otherwise log data
|
||||
from <filename>/run</filename> is never flushed to
|
||||
<filename>/var</filename> regardless of the
|
||||
configuration.</para></listitem>
|
||||
<filename>/var</filename> regardless of the configuration. The
|
||||
<command>journalctl --flush</command> command uses this signal
|
||||
to request flushing of the journal files, and then waits for
|
||||
the operation to complete. See
|
||||
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
for details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>SIGUSR2</term>
|
||||
|
||||
<listitem><para>Request immediate rotation of the journal
|
||||
files.</para></listitem>
|
||||
files. The <command>journalctl --rotate</command> command uses
|
||||
this signal to request journal file
|
||||
rotation.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>SIGRTMIN+1</term>
|
||||
|
||||
<listitem><para>Request that all unwritten log data is written
|
||||
to disk. The <command>journalctl --sync</command> command uses
|
||||
this signal to trigger journal synchronization, and then waits
|
||||
for the operation to complete.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
@ -261,7 +276,7 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
|
||||
<citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry project='die-net'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
|
||||
<command>pydoc systemd.journal</command>.
|
||||
<command>pydoc systemd.journal</command>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -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);
|
||||
|
||||
@ -1816,30 +1822,94 @@ static int flush_to_var(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rotate(void) {
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
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;
|
||||
int r;
|
||||
|
||||
r = bus_connect_system_systemd(&bus);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get D-Bus connection: %m");
|
||||
start = now(CLOCK_REALTIME);
|
||||
|
||||
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));
|
||||
/* 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(watch_path, &st) < 0) {
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to stat %s: %m", watch_path);
|
||||
} 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", sig);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1875,6 +1945,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;
|
||||
|
@ -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,10 +1259,13 @@ 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);
|
||||
|
||||
/* Let clients know when the most recent rotation happened. */
|
||||
(void) touch("/run/systemd/journal/rotated");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1277,12 +1280,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 +1330,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 +1900,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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user