From: Jörg Sommer Date: Mon, 11 Feb 2019 23:19:13 +0000 (+0100) Subject: journalctl: New option --cursor-file X-Git-Tag: v242-rc1~232 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d9e15cbd188438735f386bc7b50e193094fb79b4;p=thirdparty%2Fsystemd.git journalctl: New option --cursor-file The option cursor-file takes a filename as argument. If the file exists and contains a valid cursor, this is used to start the output after this position. At the end, the last cursor gets written to the file. This allows for an easy implementation of a timer that regularly looks in the journal for some messages. journalctl --cursor-file err-cursor -b -p err journalctl --cursor-file audit-cursor -t audit --grep DENIED Or you might want to walk the journal in steps of 10 messages: journalctl --cursor-file ./curs -n10 --since=today -t systemd --- diff --git a/man/journalctl.xml b/man/journalctl.xml index 7ff0a479e0e..89878c5408e 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -618,6 +618,17 @@ journal specified by the passed cursor. + + + + If FILE exists and contains a + cursor, start showing entries after this location. + Otherwise the show entries according the other given options. At the end, + write the cursor of the last entry to FILE. Use + this option to continually read the journal by sequentially calling + journalctl. + + diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl index bcd4533a635..f2e882ca009 100644 --- a/shell-completion/bash/journalctl +++ b/shell-completion/bash/journalctl @@ -48,7 +48,7 @@ _journalctl() { -M --machine -o --output -u --unit --user-unit -p --priority --root --case-sensitive' [ARGUNKNOWN]='-c --cursor --interval -n --lines -S --since -U --until - --after-cursor --verify-key -g --grep + --after-cursor --cursor-file --verify-key -g --grep --vacuum-size --vacuum-time --vacuum-files --output-fields' ) diff --git a/shell-completion/zsh/_journalctl b/shell-completion/zsh/_journalctl index aa6ace0485e..a4df88ef4be 100644 --- a/shell-completion/zsh/_journalctl +++ b/shell-completion/zsh/_journalctl @@ -104,6 +104,7 @@ _arguments -s \ {-p+,--priority=}'[Show only messages within the specified priority range]:priority:_journalctl_field_values PRIORITY' \ {-t+,--identifier=}'[Show only messages with the specified syslog identifier]:identifier:_journalctl_field_values SYSLOG_IDENTIFIER' \ {-c+,--cursor=}'[Start showing entries from the specified cursor]:cursors:_journalctl_field_values __CURSORS' \ + '--cursor-file=[Show entries using cursor store in file]:file:_files' \ '--after-cursor=[Start showing entries from after the specified cursor]:cursors:_journalctl_field_values __CURSORS' \ '--since=[Start showing entries on or newer than the specified date]:YYYY-MM-DD HH\:MM\:SS' \ '--until=[Stop showing entries on or older than the specified date]:YYYY-MM-DD HH\:MM\:SS' \ diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 14a02eda749..75b23c71444 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -119,6 +119,7 @@ static int arg_boot_offset = 0; static bool arg_dmesg = false; static bool arg_no_hostname = false; static const char *arg_cursor = NULL; +static const char *arg_cursor_file = NULL; static const char *arg_after_cursor = NULL; static bool arg_show_cursor = false; static const char *arg_directory = NULL; @@ -315,6 +316,7 @@ static int help(void) { " -c --cursor=CURSOR Show entries starting at the specified cursor\n" " --after-cursor=CURSOR Show entries after the specified cursor\n" " --show-cursor Print the cursor after all the entries\n" + " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n" " -b --boot[=ID] Show current boot or the specified boot\n" " --list-boots Show terse information about recorded boots\n" " -k --dmesg Show kernel message log from the current boot\n" @@ -396,6 +398,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERIFY_KEY, ARG_DISK_USAGE, ARG_AFTER_CURSOR, + ARG_CURSOR_FILE, ARG_SHOW_CURSOR, ARG_USER_UNIT, ARG_LIST_CATALOG, @@ -450,6 +453,7 @@ static int parse_argv(int argc, char *argv[]) { { "verify-key", required_argument, NULL, ARG_VERIFY_KEY }, { "disk-usage", no_argument, NULL, ARG_DISK_USAGE }, { "cursor", required_argument, NULL, 'c' }, + { "cursor-file", required_argument, NULL, ARG_CURSOR_FILE }, { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, { "since", required_argument, NULL, 'S' }, @@ -661,6 +665,10 @@ static int parse_argv(int argc, char *argv[]) { arg_cursor = optarg; break; + case ARG_CURSOR_FILE: + arg_cursor_file = optarg; + break; + case ARG_AFTER_CURSOR: arg_after_cursor = optarg; break; @@ -2077,6 +2085,7 @@ static int wait_for_change(sd_journal *j, int poll_fd) { int main(int argc, char *argv[]) { bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false; + bool use_cursor = false, after_cursor = false; _cleanup_(sd_journal_closep) sd_journal *j = NULL; sd_id128_t previous_boot_id; int n_shown = 0, r, poll_fd = -1; @@ -2420,19 +2429,41 @@ int main(int argc, char *argv[]) { } } - if (arg_cursor || arg_after_cursor) { - r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor); - if (r < 0) { - log_error_errno(r, "Failed to seek to cursor: %m"); - goto finish; + if (arg_cursor || arg_after_cursor || arg_cursor_file) { + _cleanup_free_ char *cursor_from_file = NULL; + const char *cursor = arg_cursor ?: arg_after_cursor; + + if (arg_cursor_file) { + r = read_one_line_file(arg_cursor_file, &cursor_from_file); + if (r < 0 && r != -ENOENT) { + log_error_errno(r, "Failed to read cursor file %s: %m", arg_cursor_file); + goto finish; + } + + if (r > 0) { + cursor = cursor_from_file; + after_cursor = true; + } + } else + after_cursor = !!arg_after_cursor; + + if (cursor) { + r = sd_journal_seek_cursor(j, cursor); + if (r < 0) { + log_error_errno(r, "Failed to seek to cursor: %m"); + goto finish; + } + use_cursor = true; } + } + if (use_cursor) { if (!arg_reverse) - r = sd_journal_next_skip(j, 1 + !!arg_after_cursor); + r = sd_journal_next_skip(j, 1 + after_cursor); else - r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor); + r = sd_journal_previous_skip(j, 1 + after_cursor); - if (arg_after_cursor && r < 2) { + if (after_cursor && r < 2) { /* We couldn't find the next entry after the cursor. */ if (arg_follow) need_seek = true; @@ -2661,14 +2692,26 @@ int main(int argc, char *argv[]) { if (n_shown == 0 && !arg_quiet) printf("-- No entries --\n"); - if (arg_show_cursor) { + if (arg_show_cursor || arg_cursor_file) { _cleanup_free_ char *cursor = NULL; r = sd_journal_get_cursor(j, &cursor); if (r < 0 && r != -EADDRNOTAVAIL) log_error_errno(r, "Failed to get cursor: %m"); - else if (r >= 0) - printf("-- cursor: %s\n", cursor); + else if (r >= 0) { + if (arg_show_cursor) + printf("-- cursor: %s\n", cursor); + + if (arg_cursor_file) { + r = write_string_file(arg_cursor_file, cursor, + WRITE_STRING_FILE_CREATE | + WRITE_STRING_FILE_ATOMIC); + if (r < 0) + log_error_errno(r, + "Failed to write new cursor to %s: %m", + arg_cursor_file); + } + } } break;