X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fjournal%2Fjournalctl.c;h=cbf9833184f06d852b55dc02e3315d1261eccc85;hb=b2e6df73aa508cc09b1b536a2fb9f90f152b89fa;hp=3fcdf4b4a2e9797a4bd99fe1412e65efd224a594;hpb=197c0da22536121acc1377525458844a5ccabb7d;p=elogind.git diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 3fcdf4b4a..cbf983318 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -29,9 +29,12 @@ #include #include #include +#include #include #include #include +#include +#include #include @@ -58,8 +61,9 @@ static bool arg_no_pager = false; static int arg_lines = -1; static bool arg_no_tail = false; static bool arg_quiet = false; -static bool arg_local = false; +static bool arg_merge = false; static bool arg_this_boot = false; +static const char *arg_cursor = NULL; static const char *arg_directory = NULL; static int arg_priorities = 0xFF; static const char *arg_verify_key = NULL; @@ -72,7 +76,8 @@ static enum { ACTION_NEW_ID128, ACTION_PRINT_HEADER, ACTION_SETUP_KEYS, - ACTION_VERIFY + ACTION_VERIFY, + ACTION_DISK_USAGE, } arg_action = ACTION_SHOW; static int help(void) { @@ -83,19 +88,21 @@ static int help(void) { " --version Show package version\n" " --no-pager Do not pipe output into a pager\n" " -a --all Show all fields, including long and unprintable\n" + " -c --cursor=CURSOR Jump to the specified cursor\n" " -f --follow Follow journal\n" - " -n --lines=INTEGER Journal entries to show\n" + " -n --lines[=INTEGER] Number of journal entries to show\n" " --no-tail Show all lines, even in follow mode\n" " -o --output=STRING Change journal output mode (short, short-monotonic,\n" - " verbose, export, json, cat)\n" + " verbose, export, json, json-pretty, cat)\n" " -q --quiet Don't show privilege warning\n" - " -l --local Only local entries\n" + " -m --merge Show entries from all available journals\n" " -b --this-boot Show data only from current boot\n" " -D --directory=PATH Show journal files from directory\n" " -p --priority=RANGE Show only messages within the specified priority range\n\n" "Commands:\n" " --new-id128 Generate a new 128 Bit ID\n" " --header Show journal header information\n" + " --disk-usage Show total disk usage\n" #ifdef HAVE_GCRYPT " --setup-keys Generate new FSS key pair\n" " --interval=TIME Time interval for changing the FSS sealing key\n" @@ -118,7 +125,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_SETUP_KEYS, ARG_INTERVAL, ARG_VERIFY, - ARG_VERIFY_KEY + ARG_VERIFY_KEY, + ARG_DISK_USAGE }; static const struct option options[] = { @@ -128,11 +136,11 @@ static int parse_argv(int argc, char *argv[]) { { "follow", no_argument, NULL, 'f' }, { "output", required_argument, NULL, 'o' }, { "all", no_argument, NULL, 'a' }, - { "lines", required_argument, NULL, 'n' }, + { "lines", optional_argument, NULL, 'n' }, { "no-tail", no_argument, NULL, ARG_NO_TAIL }, { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, { "quiet", no_argument, NULL, 'q' }, - { "local", no_argument, NULL, 'l' }, + { "merge", no_argument, NULL, 'm' }, { "this-boot", no_argument, NULL, 'b' }, { "directory", required_argument, NULL, 'D' }, { "header", no_argument, NULL, ARG_HEADER }, @@ -141,6 +149,8 @@ static int parse_argv(int argc, char *argv[]) { { "interval", required_argument, NULL, ARG_INTERVAL }, { "verify", no_argument, NULL, ARG_VERIFY }, { "verify-key", required_argument, NULL, ARG_VERIFY_KEY }, + { "disk-usage", no_argument, NULL, ARG_DISK_USAGE }, + { "cursor", no_argument, NULL, 'c' }, { NULL, 0, NULL, 0 } }; @@ -149,7 +159,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hfo:an:qlbD:p:", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:", options, NULL)) >= 0) { switch (c) { @@ -169,10 +179,11 @@ static int parse_argv(int argc, char *argv[]) { case 'f': arg_follow = true; + signal(SIGWINCH, columns_cache_reset); break; case 'o': - arg_output = output_mode_from_string(optarg); + arg_output = output_mode_from_string(optarg); if (arg_output < 0) { log_error("Unknown output '%s'.", optarg); return -EINVAL; @@ -185,11 +196,15 @@ static int parse_argv(int argc, char *argv[]) { break; case 'n': - r = safe_atoi(optarg, &arg_lines); - if (r < 0 || arg_lines < 0) { - log_error("Failed to parse lines '%s'", optarg); - return -EINVAL; - } + if (optarg) { + r = safe_atoi(optarg, &arg_lines); + if (r < 0 || arg_lines < 0) { + log_error("Failed to parse lines '%s'", optarg); + return -EINVAL; + } + } else + arg_lines = 10; + break; case ARG_NO_TAIL: @@ -204,8 +219,8 @@ static int parse_argv(int argc, char *argv[]) { arg_quiet = true; break; - case 'l': - arg_local = true; + case 'm': + arg_merge = true; break; case 'b': @@ -216,6 +231,10 @@ static int parse_argv(int argc, char *argv[]) { arg_directory = optarg; break; + case 'c': + arg_cursor = optarg; + break; + case ARG_HEADER: arg_action = ACTION_PRINT_HEADER; break; @@ -224,6 +243,10 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_VERIFY; break; + case ARG_DISK_USAGE: + arg_action = ACTION_DISK_USAGE; + break; + #ifdef HAVE_GCRYPT case ARG_SETUP_KEYS: arg_action = ACTION_SETUP_KEYS; @@ -233,6 +256,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERIFY_KEY: arg_action = ACTION_VERIFY; arg_verify_key = optarg; + arg_merge = false; break; case ARG_INTERVAL: @@ -590,7 +614,8 @@ static int setup_keys(void) { fprintf(stderr, "\n" "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n" - "the following local file. It should not be used on multiple hosts.\n" + "the following local file. This key file is automatically updated when the\n" + "sealing key is advanced. It should not be used on multiple hosts.\n" "\n" "\t%s\n" "\n" @@ -619,14 +644,18 @@ static int setup_keys(void) { if (hn) { hostname_cleanup(hn); - fprintf(stderr, "The keys have been generated for host %s (" SD_ID128_FORMAT_STR ").\n", hn, SD_ID128_FORMAT_VAL(machine)); + fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine)); } else - fprintf(stderr, "The keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine)); + fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine)); #ifdef HAVE_QRENCODE - fputc('\n', stderr); - print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine); - fprintf(stderr, "\nScan this QR code with your mobile phone to transfer the verification key to it.\n"); + /* If this is not an UTF-8 system don't print any QR codes */ + setlocale(LC_CTYPE, ""); + + if (streq_ptr(nl_langinfo(CODESET), "UTF-8")) { + fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr); + print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine); + } #endif free(hn); } @@ -658,16 +687,18 @@ static int verify(sd_journal *j) { assert(j); + log_show_color(true); + HASHMAP_FOREACH(f, j->files, i) { int k; - usec_t from, to, total; + usec_t first, validated, last; #ifdef HAVE_GCRYPT if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) - log_warning("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path); + 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, &from, &to, &total, true); + k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true); if (k == -EINVAL) { /* If the key was invalid give up right-away. */ return k; @@ -678,11 +709,18 @@ static int verify(sd_journal *j) { char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX]; log_info("PASS: %s", f->path); - if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) - log_info("=> Validated from %s to %s, %s missing", - format_timestamp(a, sizeof(a), from), - format_timestamp(b, sizeof(b), to), - format_timespan(c, sizeof(c), total > to ? total - to : 0)); + if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) { + if (validated > 0) { + log_info("=> Validated from %s to %s, final %s entries not sealed.", + format_timestamp(a, sizeof(a), first), + format_timestamp(b, sizeof(b), validated), + format_timespan(c, sizeof(c), last > validated ? last - validated : 0)); + } else if (last > 0) + log_info("=> No sealing yet, %s of entries not sealed.", + format_timespan(c, sizeof(c), last - first)); + else + log_info("=> No sealing yet, no entries in file."); + } } } @@ -692,7 +730,6 @@ static int verify(sd_journal *j) { int main(int argc, char *argv[]) { int r; sd_journal *j = NULL; - unsigned line = 0; bool need_seek = false; sd_id128_t previous_boot_id; bool previous_boot_id_valid = false; @@ -718,7 +755,7 @@ int main(int argc, char *argv[]) { if (arg_directory) r = sd_journal_open_directory(&j, arg_directory, 0); else - r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0); + r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY); if (r < 0) { log_error("Failed to open journal: %s", strerror(-r)); @@ -736,9 +773,34 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_action == ACTION_DISK_USAGE) { + uint64_t bytes; + char sbytes[FORMAT_BYTES_MAX]; + + r = sd_journal_get_usage(j, &bytes); + if (r < 0) + goto finish; + + printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes)); + r = 0; + goto finish; + } + #ifdef HAVE_ACL + if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) { + log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages."); + r = -EACCES; + goto finish; + } + if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0) - log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off."); + log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off."); +#else + if (geteuid() != 0 && in_group("adm") <= 0) { + log_error("No access to messages. Only users in the group 'adm' can see messages."); + r = -EACCES; + goto finish; + } #endif r = add_this_boot(j); @@ -773,7 +835,16 @@ int main(int argc, char *argv[]) { } } - if (arg_lines >= 0) { + if (arg_cursor) { + r = sd_journal_seek_cursor(j, arg_cursor); + if (r < 0) { + log_error("Failed to seek to cursor: %s", strerror(-r)); + goto finish; + } + + r = sd_journal_next(j); + + } else if (arg_lines >= 0) { r = sd_journal_seek_tail(j); if (r < 0) { log_error("Failed to seek to tail: %s", strerror(-r)); @@ -781,6 +852,7 @@ int main(int argc, char *argv[]) { } r = sd_journal_previous_skip(j, arg_lines); + } else { r = sd_journal_seek_head(j); if (r < 0) { @@ -799,14 +871,8 @@ int main(int argc, char *argv[]) { on_tty(); have_pager = !arg_no_pager && !arg_follow && pager_open(); - if (arg_output == OUTPUT_JSON) { - fputc('[', stdout); - fflush(stdout); - } - for (;;) { for (;;) { - sd_id128_t boot_id; int flags = arg_show_all * OUTPUT_SHOW_ALL | have_pager * OUTPUT_FULL_WIDTH | @@ -823,19 +889,21 @@ int main(int argc, char *argv[]) { if (r == 0) break; - r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); - if (r >= 0) { - if (previous_boot_id_valid && - !sd_id128_equal(boot_id, previous_boot_id)) - printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n"); + if (!arg_merge) { + sd_id128_t boot_id; - previous_boot_id = boot_id; - previous_boot_id_valid = true; - } + r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); + if (r >= 0) { + if (previous_boot_id_valid && + !sd_id128_equal(boot_id, previous_boot_id)) + printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n"); - line ++; + previous_boot_id = boot_id; + previous_boot_id_valid = true; + } + } - r = output_journal(j, arg_output, line, 0, flags); + r = output_journal(stdout, j, arg_output, 0, flags); if (r < 0) goto finish; @@ -852,9 +920,6 @@ int main(int argc, char *argv[]) { } } - if (arg_output == OUTPUT_JSON) - fputs("\n]\n", stdout); - finish: if (j) sd_journal_close(j);