]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journalctl: make --list-boots support -n/--lines= option 32491/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 26 Apr 2024 04:40:40 +0000 (13:40 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 10 May 2024 02:43:57 +0000 (11:43 +0900)
Also mention that -r/--reverse is supported by the command.

man/journalctl.xml
src/journal/journalctl-misc.c
src/journal/journalctl.c
src/libsystemd/sd-journal/test-journal-interleaving.c
src/shared/logs-show.c
src/shared/logs-show.h

index 7d6820064ec792922fac3999ffc41510ba56e022..caa10a056b687dae057c7c5ceb115b4fea6513e2 100644 (file)
       <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>
index 65785d4d357b4821c13152ae9056bb36a64d6afb..8ca6ea214368c51c38c1f224e87e42c43f378ee1 100644 (file)
@@ -111,7 +111,11 @@ int action_list_boots(void) {
         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)
@@ -132,13 +136,25 @@ int action_list_boots(void) {
         (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);
         }
index 868808e43277d7ffc43e2113482f3467d05fc942..45173a68133246a60021cc8f97ccff5d400f9f65 100644 (file)
@@ -957,7 +957,7 @@ static int parse_argv(int argc, char *argv[]) {
                 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.");
 
index 6f438915355ca052f5b01bba7aaf065c8adcf533..d98b3ce8cbeea3722f9f271189999f41ebcb60d3 100644 (file)
@@ -468,7 +468,10 @@ static void test_boot_id_one(void (*setup)(void), size_t n_boots_expected) {
         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);
 
@@ -492,6 +495,33 @@ static void test_boot_id_one(void (*setup)(void), size_t 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);
 }
 
index c96f501f0ef8c8a3778133b8c8043d976254fae3..c71c868889cf4b861febfd761e4d00f791ad2297 100644 (file)
@@ -1986,7 +1986,13 @@ int journal_find_boot(sd_journal *j, sd_id128_t boot_id, int offset, sd_id128_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;
@@ -1997,7 +2003,10 @@ int journal_get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots) {
 
         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;
 
@@ -2010,7 +2019,10 @@ int journal_get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots) {
         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)
index b1b42bdae76913ca9612e830944cdcbd7129303e..7e7b2af901e960fb0982fada81f84da7d58731b4 100644 (file)
@@ -71,4 +71,9 @@ void json_escape(
                 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);