mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
journalctl: support --lines=+N for showing the oldest N entries
After f582695107, the wrong behavior
occurred when --since= and --lines= are both specified is fixed.
However, it seems that the old behavior is already being somewhat
widely used, and the function itself makes sense, i.e. to allow --lines=
to output the first N journal entries.
Therefore, let's support prefixing the number for --lines= with '+',
and provide such functionality.
Related: #28746
This commit is contained in:
committed by
Zbigniew Jędrzejewski-Szmek
parent
d401182643
commit
8d6791d2aa
@@ -371,7 +371,8 @@
|
|||||||
sensitive. This can be overridden with the <option>--case-sensitive</option> option, see
|
sensitive. This can be overridden with the <option>--case-sensitive</option> option, see
|
||||||
below.</para>
|
below.</para>
|
||||||
|
|
||||||
<para>When used with <option>--lines=</option>, <option>--reverse</option> is implied.</para></listitem>
|
<para>When used with <option>--lines=</option> (not prefixed with <literal>+</literal>),
|
||||||
|
<option>--reverse</option> is implied.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@@ -552,12 +553,13 @@
|
|||||||
<term><option>-n</option></term>
|
<term><option>-n</option></term>
|
||||||
<term><option>--lines=</option></term>
|
<term><option>--lines=</option></term>
|
||||||
|
|
||||||
<listitem><para>Show the most recent journal events and limit the number of events shown. If
|
<listitem><para>Show the most recent journal events and limit the number of events shown. The argument
|
||||||
<option>--follow</option> is used, this option is implied. The argument is a positive integer or
|
is a positive integer or <literal>all</literal> to disable the limit. Additionally, if the number is
|
||||||
<literal>all</literal> to disable line limiting. The default value is 10 if no argument is
|
prefixed with <literal>+</literal>, the oldest journal events are used instead. The default value is
|
||||||
given.</para>
|
10 if no argument is given.</para>
|
||||||
|
|
||||||
<para>When used with <option>--grep=</option>, <option>--reverse</option> is implied.</para></listitem>
|
<para>If <option>--follow</option> is used, this option is implied. When not prefixed with <literal>+</literal>
|
||||||
|
and used with <option>--grep=</option>, <option>--reverse</option> is implied.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ static bool arg_full = true;
|
|||||||
static bool arg_all = false;
|
static bool arg_all = false;
|
||||||
static PagerFlags arg_pager_flags = 0;
|
static PagerFlags arg_pager_flags = 0;
|
||||||
static int arg_lines = ARG_LINES_DEFAULT;
|
static int arg_lines = ARG_LINES_DEFAULT;
|
||||||
|
static int arg_lines_oldest = false;
|
||||||
static bool arg_no_tail = false;
|
static bool arg_no_tail = false;
|
||||||
static bool arg_truncate_newline = false;
|
static bool arg_truncate_newline = false;
|
||||||
static bool arg_quiet = false;
|
static bool arg_quiet = false;
|
||||||
@@ -298,6 +299,44 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_lines(const char *arg, bool graceful) {
|
||||||
|
const char *l;
|
||||||
|
int n, r;
|
||||||
|
|
||||||
|
assert(arg || graceful);
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
goto default_noarg;
|
||||||
|
|
||||||
|
if (streq(arg, "all")) {
|
||||||
|
arg_lines = ARG_LINES_ALL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = startswith(arg, "+");
|
||||||
|
|
||||||
|
r = safe_atoi(l ?: arg, &n);
|
||||||
|
if (r < 0 || n < 0) {
|
||||||
|
if (graceful)
|
||||||
|
goto default_noarg;
|
||||||
|
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse --lines='%s'.", arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_lines = n;
|
||||||
|
arg_lines_oldest = !!l;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default_noarg:
|
||||||
|
arg_lines = 10;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool arg_lines_needs_seek_end(void) {
|
||||||
|
return arg_lines >= 0 && !arg_lines_oldest;
|
||||||
|
}
|
||||||
|
|
||||||
static int help_facilities(void) {
|
static int help_facilities(void) {
|
||||||
if (!arg_quiet)
|
if (!arg_quiet)
|
||||||
puts("Available facilities:");
|
puts("Available facilities:");
|
||||||
@@ -358,7 +397,7 @@ static int help(void) {
|
|||||||
" json, json-pretty, json-sse, json-seq, cat,\n"
|
" json, json-pretty, json-sse, json-seq, cat,\n"
|
||||||
" with-unit)\n"
|
" with-unit)\n"
|
||||||
" --output-fields=LIST Select fields to print in verbose/export/json modes\n"
|
" --output-fields=LIST Select fields to print in verbose/export/json modes\n"
|
||||||
" -n --lines[=INTEGER] Number of journal entries to show\n"
|
" -n --lines[=[+]INTEGER] Number of journal entries to show\n"
|
||||||
" -r --reverse Show the newest entries first\n"
|
" -r --reverse Show the newest entries first\n"
|
||||||
" --show-cursor Print the cursor after all the entries\n"
|
" --show-cursor Print the cursor after all the entries\n"
|
||||||
" --utc Express time in Coordinated Universal Time (UTC)\n"
|
" --utc Express time in Coordinated Universal Time (UTC)\n"
|
||||||
@@ -592,33 +631,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
if (optarg) {
|
r = parse_lines(optarg ?: optind < argc ? argv[optind] : NULL, !optarg);
|
||||||
if (streq(optarg, "all"))
|
if (r < 0)
|
||||||
arg_lines = ARG_LINES_ALL;
|
return r;
|
||||||
else {
|
if (r > 0 && !optarg)
|
||||||
r = safe_atoi(optarg, &arg_lines);
|
optind++;
|
||||||
if (r < 0 || arg_lines < 0)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse lines '%s'", optarg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
arg_lines = 10;
|
|
||||||
|
|
||||||
/* Hmm, no argument? Maybe the next
|
|
||||||
* word on the command line is
|
|
||||||
* supposed to be the argument? Let's
|
|
||||||
* see if there is one, and is
|
|
||||||
* parsable. */
|
|
||||||
if (optind < argc) {
|
|
||||||
int n;
|
|
||||||
if (streq(argv[optind], "all")) {
|
|
||||||
arg_lines = ARG_LINES_ALL;
|
|
||||||
optind++;
|
|
||||||
} else if (safe_atoi(argv[optind], &n) >= 0 && n >= 0) {
|
|
||||||
arg_lines = n;
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1083,7 +1100,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
|
|
||||||
if (arg_follow && arg_reverse)
|
if (arg_follow && arg_reverse)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Please specify either --reverse= or --follow=, not both.");
|
"Please specify either --reverse or --follow, not both.");
|
||||||
|
|
||||||
|
if (arg_lines >= 0 && arg_lines_oldest && (arg_reverse || arg_follow))
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"--lines=+N is unsupported when --reverse or --follow is specified.");
|
||||||
|
|
||||||
if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc)
|
if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
@@ -1110,11 +1131,12 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* When --grep is used along with --lines, we don't know how many lines we can print.
|
/* When --grep is used along with --lines without '+', i.e. when we start from the end of the
|
||||||
* So we search backwards and count until enough lines have been printed or we hit the head.
|
* journal, we don't know how many lines we can print. So we search backwards and count until
|
||||||
|
* enough lines have been printed or we hit the head.
|
||||||
* An exception is that --follow might set arg_lines, so let's not imply --reverse
|
* An exception is that --follow might set arg_lines, so let's not imply --reverse
|
||||||
* if that is specified. */
|
* if that is specified. */
|
||||||
if (arg_lines >= 0 && !arg_follow)
|
if (arg_lines_needs_seek_end() && !arg_follow)
|
||||||
arg_reverse = true;
|
arg_reverse = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2667,8 +2689,8 @@ static int run(int argc, char *argv[]) {
|
|||||||
arg_lines = 0;
|
arg_lines = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (arg_until_set && (arg_reverse || arg_lines >= 0)) {
|
} else if (arg_until_set && (arg_reverse || arg_lines_needs_seek_end())) {
|
||||||
/* If both --until and any of --reverse and --lines is specified, things get
|
/* If both --until and any of --reverse and --lines=N is specified, things get
|
||||||
* a little tricky. We seek to the place of --until first. If only --reverse or
|
* a little tricky. We seek to the place of --until first. If only --reverse or
|
||||||
* --reverse and --lines is specified, we search backwards and let the output
|
* --reverse and --lines is specified, we search backwards and let the output
|
||||||
* counter handle --lines for us. If only --lines is used, we just jump backwards
|
* counter handle --lines for us. If only --lines is used, we just jump backwards
|
||||||
@@ -2680,7 +2702,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
|
|
||||||
if (arg_reverse)
|
if (arg_reverse)
|
||||||
r = sd_journal_previous(j);
|
r = sd_journal_previous(j);
|
||||||
else /* arg_lines >= 0 */
|
else /* arg_lines_needs_seek_end */
|
||||||
r = sd_journal_previous_skip(j, arg_lines);
|
r = sd_journal_previous_skip(j, arg_lines);
|
||||||
|
|
||||||
} else if (arg_reverse) {
|
} else if (arg_reverse) {
|
||||||
@@ -2690,7 +2712,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
|
|
||||||
r = sd_journal_previous(j);
|
r = sd_journal_previous(j);
|
||||||
|
|
||||||
} else if (arg_lines >= 0) {
|
} else if (arg_lines_needs_seek_end()) {
|
||||||
r = sd_journal_seek_tail(j);
|
r = sd_journal_seek_tail(j);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to seek to tail: %m");
|
return log_error_errno(r, "Failed to seek to tail: %m");
|
||||||
|
|||||||
Reference in New Issue
Block a user