Also mention that -r/--reverse is supported by the command.
<varlistentry>
<term><option>--list-boots</option></term>
- <listitem><para>Show a tabular list of boot numbers (relative to the current boot), their IDs, and
- the timestamps of the first and last message pertaining to the boot.</para>
-
- <xi:include href="version-info.xml" xpointer="v209"/></listitem>
+ <listitem>
+ <para>Show a tabular list of boot numbers (relative to the current boot), their IDs, and the
+ timestamps of the first and last message pertaining to the boot. When specified with
+ <option>-n/--lines=<optional>+</optional><replaceable>N</replaceable></option> option, only the
+ first (when the number prefixed with <literal>+</literal>) or the last (without prefix)
+ <replaceable>N</replaceable> entries will be shown. When specified with
+ <option>-r/--reverse</option>, the list will be shown in the reverse order.</para>
+
+ <xi:include href="version-info.xml" xpointer="v209"/>
+ </listitem>
</varlistentry>
<varlistentry>
if (r < 0)
return r;
- r = journal_get_boots(j, &boots, &n_boots);
+ r = journal_get_boots(
+ j,
+ /* advance_older = */ arg_lines_needs_seek_end(),
+ /* max_ids = */ arg_lines >= 0 ? (size_t) arg_lines : SIZE_MAX,
+ &boots, &n_boots);
if (r < 0)
return log_error_errno(r, "Failed to determine boots: %m");
if (r == 0)
(void) table_set_sort(table, (size_t) 0);
(void) table_set_reverse(table, 0, arg_reverse);
- FOREACH_ARRAY(i, boots, n_boots) {
+ for (int i = 0; i < (int) n_boots; i++) {
+ int index;
+
+ if (arg_lines_needs_seek_end())
+ /* With --lines=N, we only know the negative index, and the older ID is located earlier. */
+ index = -i;
+ else if (arg_lines >= 0)
+ /* With --lines=+N, we only know the positive index, and the newer ID is located earlier. */
+ index = i + 1;
+ else
+ /* Otherwise, show negative index. Note, in this case, newer ID is located earlier. */
+ index = i + 1 - (int) n_boots;
+
r = table_add_many(table,
- TABLE_INT, (int)(i - boots) - (int) n_boots + 1,
+ TABLE_INT, index,
TABLE_SET_ALIGN_PERCENT, 100,
- TABLE_ID128, i->id,
- TABLE_TIMESTAMP, i->first_usec,
- TABLE_TIMESTAMP, i->last_usec);
+ TABLE_ID128, boots[i].id,
+ TABLE_TIMESTAMP, boots[i].first_usec,
+ TABLE_TIMESTAMP, boots[i].last_usec);
if (r < 0)
return table_log_add_error(r);
}
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Please specify either --reverse or --follow, not both.");
- if (arg_lines >= 0 && arg_lines_oldest && (arg_reverse || arg_follow))
+ if (arg_action == ACTION_SHOW && 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.");
setup();
assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
- assert_se(journal_get_boots(j, &boots, &n_boots) >= 0);
+ assert_se(journal_get_boots(
+ j,
+ /* advance_older = */ false, /* max_ids = */ SIZE_MAX,
+ &boots, &n_boots) >= 0);
assert_se(boots);
assert_se(n_boots == n_boots_expected);
}
}
+ for (size_t i = 0; i <= n_boots_expected + 1; i++) {
+ _cleanup_free_ BootId *boots_limited = NULL;
+ size_t n_boots_limited;
+
+ assert_se(journal_get_boots(
+ j,
+ /* advance_older = */ false, /* max_ids = */ i,
+ &boots_limited, &n_boots_limited) >= 0);
+ assert_se(boots_limited || i == 0);
+ assert_se(n_boots_limited == MIN(i, n_boots_expected));
+ assert_se(memcmp_safe(boots, boots_limited, n_boots_limited * sizeof(BootId)) == 0);
+ }
+
+ for (size_t i = 0; i <= n_boots_expected + 1; i++) {
+ _cleanup_free_ BootId *boots_limited = NULL;
+ size_t n_boots_limited;
+
+ assert_se(journal_get_boots(
+ j,
+ /* advance_older = */ true, /* max_ids = */ i,
+ &boots_limited, &n_boots_limited) >= 0);
+ assert_se(boots_limited || i == 0);
+ assert_se(n_boots_limited == MIN(i, n_boots_expected));
+ for (size_t k = 0; k < n_boots_limited; k++)
+ assert_se(memcmp(&boots[n_boots - k - 1], &boots_limited[k], sizeof(BootId)) == 0);
+ }
+
test_done(t);
}
}
}
-int journal_get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots) {
+int journal_get_boots(
+ sd_journal *j,
+ bool advance_older,
+ size_t max_ids,
+ BootId **ret_boots,
+ size_t *ret_n_boots) {
+
_cleanup_free_ BootId *boots = NULL;
size_t n_boots = 0;
int r;
sd_journal_flush_matches(j);
- r = sd_journal_seek_head(j); /* seek to oldest */
+ if (advance_older)
+ r = sd_journal_seek_tail(j); /* seek to newest */
+ else
+ r = sd_journal_seek_head(j); /* seek to oldest */
if (r < 0)
return r;
for (;;) {
BootId boot;
- r = discover_next_boot(j, previous_boot_id, /* advance_older = */ false, &boot);
+ if (n_boots >= max_ids)
+ break;
+
+ r = discover_next_boot(j, previous_boot_id, advance_older, &boot);
if (r < 0)
return r;
if (r == 0)
OutputFlags flags);
int journal_find_boot(sd_journal *j, sd_id128_t boot_id, int offset, sd_id128_t *ret);
-int journal_get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots);
+int journal_get_boots(
+ sd_journal *j,
+ bool advance_older,
+ size_t max_ids,
+ BootId **ret_boots,
+ size_t *ret_n_boots);