mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
journalctl: split get_boots() into three
Previously, get_boots() used for three ways; finding boot entry by boot ID, finding boot entry by offset, listing up all boot IDs. Let's split it into three for each usecase. No functional change, just refactoring.
This commit is contained in:
parent
c93d3c0512
commit
e44f06065b
@ -173,9 +173,8 @@ static enum {
|
||||
|
||||
typedef struct BootId {
|
||||
sd_id128_t id;
|
||||
uint64_t first;
|
||||
uint64_t last;
|
||||
LIST_FIELDS(struct BootId, boot_list);
|
||||
usec_t first_usec;
|
||||
usec_t last_usec;
|
||||
} BootId;
|
||||
|
||||
static int add_matches_for_device(sd_journal *j, const char *devpath) {
|
||||
@ -1190,22 +1189,13 @@ static int add_matches(sd_journal *j, char **args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void boot_id_free_all(BootId *l) {
|
||||
|
||||
while (l) {
|
||||
BootId *i = l;
|
||||
LIST_REMOVE(boot_list, l, i);
|
||||
free(i);
|
||||
}
|
||||
}
|
||||
|
||||
static int discover_next_boot(sd_journal *j,
|
||||
static int discover_next_boot(
|
||||
sd_journal *j,
|
||||
sd_id128_t previous_boot_id,
|
||||
bool advance_older,
|
||||
BootId **ret) {
|
||||
BootId *ret) {
|
||||
|
||||
_cleanup_free_ BootId *next_boot = NULL;
|
||||
sd_id128_t boot_id;
|
||||
BootId boot;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
@ -1229,10 +1219,12 @@ static int discover_next_boot(sd_journal *j,
|
||||
r = sd_journal_next(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else if (r == 0)
|
||||
else if (r == 0) {
|
||||
*ret = (BootId) {};
|
||||
return 0; /* End of journal, yay. */
|
||||
}
|
||||
|
||||
r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
|
||||
r = sd_journal_get_monotonic_usec(j, NULL, &boot.id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1244,20 +1236,14 @@ static int discover_next_boot(sd_journal *j,
|
||||
* speed things up, but let's not trust that it is complete, and hence, manually advance as
|
||||
* necessary. */
|
||||
|
||||
} while (sd_id128_equal(boot_id, previous_boot_id));
|
||||
} while (sd_id128_equal(boot.id, previous_boot_id));
|
||||
|
||||
next_boot = new0(BootId, 1);
|
||||
if (!next_boot)
|
||||
return -ENOMEM;
|
||||
|
||||
next_boot->id = boot_id;
|
||||
|
||||
r = sd_journal_get_realtime_usec(j, &next_boot->first);
|
||||
r = sd_journal_get_realtime_usec(j, &boot.first_usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Now seek to the last occurrence of this boot ID. */
|
||||
r = add_match_boot_id(j, next_boot->id);
|
||||
r = add_match_boot_id(j, boot.id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1278,70 +1264,49 @@ static int discover_next_boot(sd_journal *j,
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA),
|
||||
"Whoopsie! We found a boot ID but can't read its last entry."); /* This shouldn't happen. We just came from this very boot ID. */
|
||||
|
||||
r = sd_journal_get_realtime_usec(j, &next_boot->last);
|
||||
r = sd_journal_get_realtime_usec(j, &boot.last_usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(next_boot);
|
||||
|
||||
return 0;
|
||||
sd_journal_flush_matches(j);
|
||||
*ret = boot;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_boots(
|
||||
sd_journal *j,
|
||||
BootId **boots,
|
||||
sd_id128_t *boot_id,
|
||||
int offset) {
|
||||
|
||||
bool skip_once;
|
||||
int r, count = 0;
|
||||
BootId *head = NULL, *tail = NULL;
|
||||
const bool advance_older = boot_id && offset <= 0;
|
||||
sd_id128_t previous_boot_id;
|
||||
static int find_boot_by_id(sd_journal *j) {
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
/* Adjust for the asymmetry that offset 0 is
|
||||
* the last (and current) boot, while 1 is considered the
|
||||
* (chronological) first boot in the journal. */
|
||||
skip_once = boot_id && sd_id128_is_null(*boot_id) && offset <= 0;
|
||||
|
||||
/* Advance to the earliest/latest occurrence of our reference
|
||||
* boot ID (taking our lookup direction into account), so that
|
||||
* discover_next_boot() can do its job.
|
||||
* If no reference is given, the journal head/tail will do,
|
||||
* they're "virtual" boots after all. */
|
||||
if (boot_id && !sd_id128_is_null(*boot_id)) {
|
||||
sd_journal_flush_matches(j);
|
||||
|
||||
r = add_match_boot_id(j, *boot_id);
|
||||
r = add_match_boot_id(j, arg_boot_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (advance_older)
|
||||
r = sd_journal_seek_head(j); /* seek to oldest */
|
||||
else
|
||||
r = sd_journal_seek_tail(j); /* seek to newest */
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (advance_older)
|
||||
r = sd_journal_next(j); /* read the oldest entry */
|
||||
else
|
||||
r = sd_journal_previous(j); /* read the most recently added entry */
|
||||
if (r < 0)
|
||||
return r;
|
||||
else if (r == 0)
|
||||
goto finish;
|
||||
else if (offset == 0) {
|
||||
count = 1;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* At this point the read pointer is positioned at the oldest/newest occurrence of the reference boot
|
||||
* ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
|
||||
* the following entry, which must then have an older/newer boot ID */
|
||||
} else {
|
||||
/* At this point the read pointer is positioned at the oldest occurrence of the reference boot ID.
|
||||
* After flushing the matches, one more invocation of _previous() will hence place us at the
|
||||
* following entry, which must then have an older boot ID */
|
||||
|
||||
sd_journal_flush_matches(j);
|
||||
return r > 0;
|
||||
}
|
||||
|
||||
static int find_boot_by_offset(sd_journal *j) {
|
||||
bool advance_older, skip_once;
|
||||
int r;
|
||||
|
||||
/* Adjust for the asymmetry that offset 0 is the last (and current) boot, while 1 is considered the
|
||||
* (chronological) first boot in the journal. */
|
||||
advance_older = skip_once = arg_boot_offset <= 0;
|
||||
|
||||
if (advance_older)
|
||||
r = sd_journal_seek_tail(j); /* seek to newest */
|
||||
@ -1355,68 +1320,89 @@ static int get_boots(
|
||||
* At this point the read pointer is positioned after the newest/before the oldest entry in the whole
|
||||
* journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
|
||||
* entry we have. */
|
||||
}
|
||||
|
||||
previous_boot_id = SD_ID128_NULL;
|
||||
int offset = arg_boot_offset;
|
||||
sd_id128_t previous_boot_id = SD_ID128_NULL;
|
||||
for (;;) {
|
||||
_cleanup_free_ BootId *current = NULL;
|
||||
BootId boot;
|
||||
|
||||
r = discover_next_boot(j, previous_boot_id, advance_older, ¤t);
|
||||
if (r < 0) {
|
||||
boot_id_free_all(head);
|
||||
r = discover_next_boot(j, previous_boot_id, advance_older, &boot);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!current)
|
||||
break;
|
||||
previous_boot_id = boot.id;
|
||||
|
||||
previous_boot_id = current->id;
|
||||
|
||||
if (boot_id) {
|
||||
if (!skip_once)
|
||||
offset += advance_older ? 1 : -1;
|
||||
skip_once = false;
|
||||
|
||||
if (offset == 0) {
|
||||
count = 1;
|
||||
*boot_id = current->id;
|
||||
arg_boot_id = boot.id;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots) {
|
||||
_cleanup_free_ BootId *boots = NULL;
|
||||
size_t n_boots = 0;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
assert(ret_boots);
|
||||
assert(ret_n_boots);
|
||||
|
||||
r = sd_journal_seek_head(j); /* seek to oldest */
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* No sd_journal_next()/_previous() here.
|
||||
*
|
||||
* At this point the read pointer is positioned before the oldest entry in the whole journal. The
|
||||
* next invocation of _next() will hence position us at the oldest entry we have. */
|
||||
|
||||
sd_id128_t previous_boot_id = SD_ID128_NULL;
|
||||
for (;;) {
|
||||
BootId boot;
|
||||
|
||||
r = discover_next_boot(j, previous_boot_id, /* advance_older = */ false, &boot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LIST_FOREACH(boot_list, id, head) {
|
||||
if (sd_id128_equal(id->id, current->id)) {
|
||||
/* boot id already stored, something wrong with the journal files */
|
||||
/* exiting as otherwise this problem would cause forever loop */
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
LIST_INSERT_AFTER(boot_list, head, tail, current);
|
||||
tail = TAKE_PTR(current);
|
||||
count++;
|
||||
}
|
||||
|
||||
previous_boot_id = boot.id;
|
||||
|
||||
FOREACH_ARRAY(i, boots, n_boots)
|
||||
if (sd_id128_equal(i->id, boot.id))
|
||||
/* The boot id is already stored, something wrong with the journal files.
|
||||
* Exiting as otherwise this problem would cause an infinite loop. */
|
||||
break;
|
||||
|
||||
if (!GREEDY_REALLOC(boots, n_boots + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
boots[n_boots++] = boot;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (boots)
|
||||
*boots = head;
|
||||
|
||||
sd_journal_flush_matches(j);
|
||||
|
||||
return count;
|
||||
*ret_boots = TAKE_PTR(boots);
|
||||
*ret_n_boots = n_boots;
|
||||
return n_boots > 0;
|
||||
}
|
||||
|
||||
static int list_boots(sd_journal *j) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
BootId *all_ids;
|
||||
int count, i, r;
|
||||
_cleanup_free_ BootId *boots = NULL;
|
||||
size_t n_boots;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
count = get_boots(j, &all_ids, NULL, 0);
|
||||
if (count < 0)
|
||||
return log_error_errno(count, "Failed to determine boots: %m");
|
||||
if (count == 0)
|
||||
return count;
|
||||
r = get_boots(j, &boots, &n_boots);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine boots: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
table = table_new("idx", "boot id", "first entry", "last entry");
|
||||
if (!table)
|
||||
@ -1432,30 +1418,25 @@ static int list_boots(sd_journal *j) {
|
||||
(void) table_set_sort(table, (size_t) 0);
|
||||
(void) table_set_reverse(table, 0, arg_reverse);
|
||||
|
||||
i = 0;
|
||||
LIST_FOREACH(boot_list, id, all_ids) {
|
||||
FOREACH_ARRAY(i, boots, n_boots) {
|
||||
r = table_add_many(table,
|
||||
TABLE_INT, i - count + 1,
|
||||
TABLE_INT, (int)(i - boots) - (int) n_boots + 1,
|
||||
TABLE_SET_ALIGN_PERCENT, 100,
|
||||
TABLE_ID128, id->id,
|
||||
TABLE_TIMESTAMP, id->first,
|
||||
TABLE_TIMESTAMP, id->last);
|
||||
TABLE_ID128, i->id,
|
||||
TABLE_TIMESTAMP, i->first_usec,
|
||||
TABLE_TIMESTAMP, i->last_usec);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
i++;
|
||||
}
|
||||
|
||||
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, !arg_quiet);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
boot_id_free_all(all_ids);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_boot(sd_journal *j) {
|
||||
sd_id128_t boot_id;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
@ -1470,23 +1451,27 @@ static int add_boot(sd_journal *j) {
|
||||
!arg_directory && !arg_file && !arg_root)
|
||||
return add_match_this_boot(j, arg_machine);
|
||||
|
||||
boot_id = arg_boot_id;
|
||||
r = get_boots(j, NULL, &boot_id, arg_boot_offset);
|
||||
assert(r <= 1);
|
||||
if (r <= 0) {
|
||||
const char *reason = (r == 0) ? "No such boot ID in journal" : STRERROR(r);
|
||||
|
||||
if (sd_id128_is_null(arg_boot_id))
|
||||
log_error("Data from the specified boot (%+i) is not available: %s",
|
||||
arg_boot_offset, reason);
|
||||
else
|
||||
log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s",
|
||||
SD_ID128_FORMAT_VAL(arg_boot_id), reason);
|
||||
|
||||
return r == 0 ? -ENODATA : r;
|
||||
if (sd_id128_is_null(arg_boot_id)) {
|
||||
r = find_boot_by_offset(j);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find journal entry from the specified boot offset (%+i): %m",
|
||||
arg_boot_offset);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENODATA),
|
||||
"No journal boot entry found from the specified boot offset (%+i).",
|
||||
arg_boot_offset);
|
||||
} else {
|
||||
r = find_boot_by_id(j);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find journal entry from the specified boot ID (%s): %m",
|
||||
SD_ID128_TO_STRING(arg_boot_id));
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENODATA),
|
||||
"No journal boot entry found from the specified boot ID (%s).",
|
||||
SD_ID128_TO_STRING(arg_boot_id));
|
||||
}
|
||||
|
||||
r = add_match_boot_id(j, boot_id);
|
||||
r = add_match_boot_id(j, arg_boot_id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add match: %m");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user