summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/journalctl.xml11
-rw-r--r--shell-completion/bash/journalctl2
-rw-r--r--shell-completion/zsh/_journalctl1
-rw-r--r--src/journal/journalctl.c65
4 files changed, 67 insertions, 12 deletions
diff --git a/man/journalctl.xml b/man/journalctl.xml
index 7ff0a479e0..89878c5408 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -619,6 +619,17 @@
</varlistentry>
<varlistentry>
+ <term><option>--cursor-file=<replaceable>FILE</replaceable></option></term>
+
+ <listitem><para>If <replaceable>FILE</replaceable> exists and contains a
+ cursor, start showing entries <emphasis>after</emphasis> this location.
+ Otherwise the show entries according the other given options. At the end,
+ write the cursor of the last entry to <replaceable>FILE</replaceable>. Use
+ this option to continually read the journal by sequentially calling
+ <command>journalctl</command>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--after-cursor=</option></term>
<listitem><para>Start showing entries from the location in the
diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl
index bcd4533a63..f2e882ca00 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 aa6ace0485..a4df88ef4b 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 14a02eda74..75b23c7144 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;