X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fjournal%2Fjournalctl.c;h=c32028268a37a1935bbb8080747873e85dddbd86;hb=bf3d3e2bb7ae2d3854be57f28dd1403c8f7e4c3c;hp=395f85c9aea0cf5e0265a68c5c672856f3754321;hpb=9fd290443f5f99fca0dcd4216b1de70f7d3b8db1;p=elogind.git diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 395f85c9a..c32028268 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -31,8 +31,10 @@ #include #include #include +#include #include #include +#include #include #ifdef HAVE_ACL @@ -40,7 +42,8 @@ #include "acl-util.h" #endif -#include "systemd/sd-journal.h" +#include "sd-journal.h" +#include "sd-bus.h" #include "log.h" #include "logs-show.h" @@ -59,9 +62,18 @@ #include "fsprg.h" #include "unit-name.h" #include "catalog.h" +#include "mkdir.h" +#include "bus-util.h" +#include "bus-error.h" #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) +enum { + /* Special values for arg_lines */ + ARG_LINES_DEFAULT = -2, + ARG_LINES_ALL = -1, +}; + static OutputMode arg_output = OUTPUT_SHORT; static bool arg_utc = false; static bool arg_pager_end = false; @@ -69,7 +81,7 @@ static bool arg_follow = false; static bool arg_full = true; static bool arg_all = false; static bool arg_no_pager = false; -static int arg_lines = -2; +static int arg_lines = ARG_LINES_DEFAULT; static bool arg_no_tail = false; static bool arg_quiet = false; static bool arg_merge = false; @@ -111,6 +123,7 @@ static enum { ACTION_DUMP_CATALOG, ACTION_UPDATE_CATALOG, ACTION_LIST_BOOTS, + ACTION_FLUSH, } arg_action = ACTION_SHOW; typedef struct boot_id_t { @@ -127,6 +140,14 @@ static void pager_open_if_enabled(void) { pager_open(arg_pager_end); } +static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) { + + if (arg_utc) + return format_timestamp_utc(buf, l, t); + + return format_timestamp(buf, l, t); +} + static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) { sd_id128_t id = SD_ID128_NULL; int off = 0, r; @@ -217,6 +238,7 @@ static void help(void) { " --list-catalog Show message IDs of all entries in the message catalog\n" " --dump-catalog Show entries in the message catalog\n" " --update-catalog Update the message catalog database\n" + " --flush Flush all journal data from /run into /var\n" #ifdef HAVE_GCRYPT " --setup-keys Generate a new FSS key pair\n" " --verify Verify journal file consistency\n" @@ -253,6 +275,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_UPDATE_CATALOG, ARG_FORCE, ARG_UTC, + ARG_FLUSH, }; static const struct option options[] = { @@ -303,6 +326,7 @@ static int parse_argv(int argc, char *argv[]) { { "reverse", no_argument, NULL, 'r' }, { "machine", required_argument, NULL, 'M' }, { "utc", no_argument, NULL, ARG_UTC }, + { "flush", no_argument, NULL, ARG_FLUSH }, {} }; @@ -331,7 +355,7 @@ static int parse_argv(int argc, char *argv[]) { case 'e': arg_pager_end = true; - if (arg_lines < -1) + if (arg_lines == ARG_LINES_DEFAULT) arg_lines = 1000; break; @@ -371,7 +395,7 @@ static int parse_argv(int argc, char *argv[]) { case 'n': if (optarg) { if (streq(optarg, "all")) - arg_lines = -1; + arg_lines = ARG_LINES_ALL; else { r = safe_atoi(optarg, &arg_lines); if (r < 0 || arg_lines < 0) { @@ -390,7 +414,7 @@ static int parse_argv(int argc, char *argv[]) { if (optind < argc) { int n; if (streq(argv[optind], "all")) { - arg_lines = -1; + arg_lines = ARG_LINES_ALL; optind++; } else if (safe_atoi(argv[optind], &n) >= 0 && n >= 0) { arg_lines = n; @@ -647,6 +671,10 @@ static int parse_argv(int argc, char *argv[]) { arg_utc = true; break; + case ARG_FLUSH: + arg_action = ACTION_FLUSH; + break; + case '?': return -EINVAL; @@ -654,7 +682,7 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } - if (arg_follow && !arg_no_tail && arg_lines < -1) + if (arg_follow && !arg_no_tail && arg_lines == ARG_LINES_DEFAULT) arg_lines = 10; if (!!arg_directory + !!arg_file + !!arg_machine > 1) { @@ -829,9 +857,10 @@ static int list_boots(sd_journal *j) { if (r < 0) return r; + pager_open_if_enabled(); + SD_JOURNAL_FOREACH_UNIQUE(j, data, length) { - if (length < strlen("_BOOT_ID=")) - continue; + assert(startswith(data, "_BOOT_ID=")); if (!GREEDY_REALLOC(all_ids, allocated, count + 1)) return log_oom(); @@ -890,8 +919,8 @@ static int list_boots(sd_journal *j) { printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n", w, i - count + 1, SD_ID128_FORMAT_VAL(id->id), - format_timestamp(a, sizeof(a), id->first), - format_timestamp(b, sizeof(b), id->last)); + format_timestamp_maybe_utc(a, sizeof(a), id->first), + format_timestamp_maybe_utc(b, sizeof(b), id->last)); } return 0; @@ -1502,8 +1531,8 @@ static int verify(sd_journal *j) { if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) { if (validated > 0) { log_info("=> Validated from %s to %s, final %s entries not sealed.", - format_timestamp(a, sizeof(a), first), - format_timestamp(b, sizeof(b), validated), + format_timestamp_maybe_utc(a, sizeof(a), first), + format_timestamp_maybe_utc(b, sizeof(b), validated), format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0)); } else if (last > 0) log_info("=> No sealing yet, %s of entries not sealed.", @@ -1626,6 +1655,77 @@ static int access_check(sd_journal *j) { return r; } +static int flush_to_var(void) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_close_ int watch_fd = -1; + int r; + + /* Quick exit */ + if (access("/run/systemd/journal/flushed", F_OK) >= 0) + return 0; + + /* OK, let's actually do the full logic, send SIGUSR1 to the + * daemon and set up inotify to wait for the flushed file to appear */ + r = bus_open_system_systemd(&bus); + if (r < 0) { + log_error("Failed to get D-Bus connection: %s", strerror(-r)); + return r; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + &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; + } + + mkdir_p("/run/systemd/journal", 0755); + + watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (watch_fd < 0) { + log_error("Failed to create inotify watch: %m"); + return -errno; + } + + r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR); + if (r < 0) { + log_error("Failed to watch journal directory: %m"); + return -errno; + } + + for (;;) { + if (access("/run/systemd/journal/flushed", F_OK) >= 0) + break; + + if (errno != ENOENT) { + log_error("Failed to check for existance of /run/systemd/journal/flushed: %m"); + return -errno; + } + + r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY); + if (r < 0) { + log_error("Failed to wait for event: %s", strerror(-r)); + return r; + } + + r = flush_fd(watch_fd); + if (r < 0) { + log_error("Failed to flush inotify events: %s", strerror(-r)); + return r; + } + } + + return 0; +} + int main(int argc, char *argv[]) { int r; _cleanup_journal_close_ sd_journal *j = NULL; @@ -1650,6 +1750,11 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_action == ACTION_FLUSH) { + r = flush_to_var(); + goto finish; + } + if (arg_action == ACTION_SETUP_KEYS) { r = setup_keys(); goto finish; @@ -1898,11 +2003,11 @@ int main(int argc, char *argv[]) { if (r > 0) { if (arg_follow) printf("-- Logs begin at %s. --\n", - format_timestamp(start_buf, sizeof(start_buf), start)); + format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start)); else printf("-- Logs begin at %s, end at %s. --\n", - format_timestamp(start_buf, sizeof(start_buf), start), - format_timestamp(end_buf, sizeof(end_buf), end)); + format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start), + format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end)); } }