diff options
Diffstat (limited to '')
-rw-r--r-- | src/journal/journalctl-misc.c | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/src/journal/journalctl-misc.c b/src/journal/journalctl-misc.c new file mode 100644 index 0000000..8ca6ea2 --- /dev/null +++ b/src/journal/journalctl-misc.c @@ -0,0 +1,298 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "dirent-util.h" +#include "fd-util.h" +#include "format-table.h" +#include "format-util.h" +#include "journal-internal.h" +#include "journal-verify.h" +#include "journalctl.h" +#include "journalctl-misc.h" +#include "journalctl-util.h" +#include "logs-show.h" +#include "syslog-util.h" + +int action_print_header(void) { + _cleanup_(sd_journal_closep) sd_journal *j = NULL; + int r; + + assert(arg_action == ACTION_PRINT_HEADER); + + r = acquire_journal(&j); + if (r < 0) + return r; + + journal_print_header(j); + return 0; +} + +int action_verify(void) { + _cleanup_(sd_journal_closep) sd_journal *j = NULL; + int r; + + assert(arg_action == ACTION_VERIFY); + + r = acquire_journal(&j); + if (r < 0) + return r; + + log_show_color(true); + + JournalFile *f; + ORDERED_HASHMAP_FOREACH(f, j->files) { + int k; + usec_t first = 0, validated = 0, last = 0; + +#if HAVE_GCRYPT + if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) + log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path); +#endif + + k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, /* show_progress = */ !arg_quiet); + if (k == -EINVAL) + /* If the key was invalid give up right-away. */ + return k; + if (k < 0) + r = log_warning_errno(k, "FAIL: %s (%m)", f->path); + else { + char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX]; + log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "PASS: %s", f->path); + + if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) { + if (validated > 0) { + log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, + "=> Validated from %s to %s, final %s entries not sealed.", + format_timestamp_maybe_utc(a, sizeof(a), first), + format_timestamp_maybe_utc(b, sizeof(b), validated), + FORMAT_TIMESPAN(last > validated ? last - validated : 0, 0)); + } else if (last > 0) + log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, + "=> No sealing yet, %s of entries not sealed.", + FORMAT_TIMESPAN(last - first, 0)); + else + log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, + "=> No sealing yet, no entries in file."); + } + } + } + + return r; +} + +int action_disk_usage(void) { + _cleanup_(sd_journal_closep) sd_journal *j = NULL; + uint64_t bytes = 0; + int r; + + assert(arg_action == ACTION_DISK_USAGE); + + r = acquire_journal(&j); + if (r < 0) + return r; + + r = sd_journal_get_usage(j, &bytes); + if (r < 0) + return log_error_errno(r, "Failed to get disk usage: %m"); + + printf("Archived and active journals take up %s in the file system.\n", FORMAT_BYTES(bytes)); + return 0; +} + +int action_list_boots(void) { + _cleanup_(sd_journal_closep) sd_journal *j = NULL; + _cleanup_(table_unrefp) Table *table = NULL; + _cleanup_free_ BootId *boots = NULL; + size_t n_boots; + int r; + + assert(arg_action == ACTION_LIST_BOOTS); + + r = acquire_journal(&j); + if (r < 0) + return r; + + 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) + return log_full_errno(arg_quiet ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(ENODATA), + "No boot found."); + + table = table_new("idx", "boot id", "first entry", "last entry"); + if (!table) + return log_oom(); + + if (arg_full) + table_set_width(table, 0); + + r = table_set_json_field_name(table, 0, "index"); + if (r < 0) + return log_error_errno(r, "Failed to set JSON field name of column 0: %m"); + + (void) table_set_sort(table, (size_t) 0); + (void) table_set_reverse(table, 0, arg_reverse); + + 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, index, + TABLE_SET_ALIGN_PERCENT, 100, + 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); + } + + r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, !arg_quiet); + if (r < 0) + return table_log_print_error(r); + + return 0; +} + +int action_list_fields(void) { + _cleanup_(sd_journal_closep) sd_journal *j = NULL; + int r, n_shown = 0; + + assert(arg_action == ACTION_LIST_FIELDS); + assert(arg_field); + + r = acquire_journal(&j); + if (r < 0) + return r; + + if (!journal_boot_has_effect(j)) + return 0; + + r = sd_journal_set_data_threshold(j, 0); + if (r < 0) + return log_error_errno(r, "Failed to unset data size threshold: %m"); + + r = sd_journal_query_unique(j, arg_field); + if (r < 0) + return log_error_errno(r, "Failed to query unique data objects: %m"); + + const void *data; + size_t size; + SD_JOURNAL_FOREACH_UNIQUE(j, data, size) { + const void *eq; + + if (arg_lines >= 0 && n_shown >= arg_lines) + break; + + eq = memchr(data, '=', size); + if (eq) + printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1); + else + printf("%.*s\n", (int) size, (const char*) data); + + n_shown++; + } + + return 0; +} + +int action_list_field_names(void) { + _cleanup_(sd_journal_closep) sd_journal *j = NULL; + int r; + + assert(arg_action == ACTION_LIST_FIELD_NAMES); + + r = acquire_journal(&j); + if (r < 0) + return r; + + const char *field; + SD_JOURNAL_FOREACH_FIELD(j, field) + printf("%s\n", field); + + return 0; +} + +int action_list_namespaces(void) { + _cleanup_(table_unrefp) Table *table = NULL; + sd_id128_t machine; + int r; + + assert(arg_action == ACTION_LIST_NAMESPACES); + + r = sd_id128_get_machine(&machine); + if (r < 0) + return log_error_errno(r, "Failed to get machine ID: %m"); + + table = table_new("namespace"); + if (!table) + return log_oom(); + + (void) table_set_sort(table, (size_t) 0); + + FOREACH_STRING(dir, "/var/log/journal", "/run/log/journal") { + _cleanup_free_ char *path = NULL; + _cleanup_closedir_ DIR *dirp = NULL; + + path = path_join(arg_root, dir); + if (!path) + return log_oom(); + + dirp = opendir(path); + if (!dirp) { + log_debug_errno(errno, "Failed to open directory %s, ignoring: %m", path); + continue; + } + + FOREACH_DIRENT(de, dirp, return log_error_errno(errno, "Failed to iterate through %s: %m", path)) { + + const char *e = strchr(de->d_name, '.'); + if (!e) + continue; + + _cleanup_free_ char *ids = strndup(de->d_name, e - de->d_name); + if (!ids) + return log_oom(); + + sd_id128_t id; + r = sd_id128_from_string(ids, &id); + if (r < 0) + continue; + + if (!sd_id128_equal(machine, id)) + continue; + + e++; + + if (!log_namespace_name_valid(e)) + continue; + + r = table_add_cell(table, NULL, TABLE_STRING, e); + if (r < 0) + return table_log_add_error(r); + } + } + + if (table_isempty(table) && FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) { + if (!arg_quiet) + log_notice("No namespaces found."); + } else { + r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, !arg_quiet); + if (r < 0) + return r; + } + + return 0; +} |