X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fjournalctl.c;h=9fbc9a3489ef846d8c9d5f03f327f5b66e70c80d;hp=62bdcb7c68ec1ce10fcc9156dbdad1dd4602d6a7;hb=edfb521a21c44f7b4c91d4ef6bffd84f2c241363;hpb=2a7b539a82a45202c0e990c45da25ccdc487d633 diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 62bdcb7c6..9fbc9a348 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -58,17 +58,20 @@ static OutputMode arg_output = OUTPUT_SHORT; static bool arg_follow = false; static bool arg_show_all = false; static bool arg_no_pager = false; -static int arg_lines = -1; +static unsigned arg_lines = 0; static bool arg_no_tail = false; static bool arg_quiet = 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; #ifdef HAVE_GCRYPT static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC; #endif +static usec_t arg_since, arg_until; +static bool arg_since_set = false, arg_until_set = false; static enum { ACTION_SHOW, @@ -87,11 +90,14 @@ 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 Start showing entries from specified cursor\n" + " --since=DATE Start showing entries newer or of the specified date\n" + " --until=DATE Stop showing entries older or of the specified date\n" " -f --follow Follow journal\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, json-pretty, cat)\n" + " verbose, export, json, json-pretty, json-sse, cat)\n" " -q --quiet Don't show privilege warning\n" " -m --merge Show entries from all available journals\n" " -b --this-boot Show data only from current boot\n" @@ -124,7 +130,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_INTERVAL, ARG_VERIFY, ARG_VERIFY_KEY, - ARG_DISK_USAGE + ARG_DISK_USAGE, + ARG_SINCE, + ARG_UNTIL }; static const struct option options[] = { @@ -148,6 +156,9 @@ static int parse_argv(int argc, char *argv[]) { { "verify", no_argument, NULL, ARG_VERIFY }, { "verify-key", required_argument, NULL, ARG_VERIFY_KEY }, { "disk-usage", no_argument, NULL, ARG_DISK_USAGE }, + { "cursor", required_argument, NULL, 'c' }, + { "since", required_argument, NULL, ARG_SINCE }, + { "until", required_argument, NULL, ARG_UNTIL }, { NULL, 0, NULL, 0 } }; @@ -156,7 +167,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:", options, NULL)) >= 0) { switch (c) { @@ -182,10 +193,17 @@ static int parse_argv(int argc, char *argv[]) { case 'o': arg_output = output_mode_from_string(optarg); if (arg_output < 0) { - log_error("Unknown output '%s'.", optarg); + log_error("Unknown output format '%s'.", optarg); return -EINVAL; } + if (arg_output == OUTPUT_EXPORT || + arg_output == OUTPUT_JSON || + arg_output == OUTPUT_JSON_PRETTY || + arg_output == OUTPUT_JSON_SSE || + arg_output == OUTPUT_CAT) + arg_quiet = true; + break; case 'a': @@ -194,8 +212,8 @@ static int parse_argv(int argc, char *argv[]) { case 'n': if (optarg) { - r = safe_atoi(optarg, &arg_lines); - if (r < 0 || arg_lines < 0) { + r = safe_atou(optarg, &arg_lines); + if (r < 0 || arg_lines <= 0) { log_error("Failed to parse lines '%s'", optarg); return -EINVAL; } @@ -228,6 +246,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; @@ -317,6 +339,24 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_SINCE: + r = parse_timestamp(optarg, &arg_since); + if (r < 0) { + log_error("Failed to parse timestamp: %s", optarg); + return -EINVAL; + } + arg_since_set = true; + break; + + case ARG_UNTIL: + r = parse_timestamp(optarg, &arg_until); + if (r < 0) { + log_error("Failed to parse timestamp: %s", optarg); + return -EINVAL; + } + arg_until_set = true; + break; + case '?': return -EINVAL; @@ -326,9 +366,19 @@ static int parse_argv(int argc, char *argv[]) { } } - if (arg_follow && !arg_no_tail && arg_lines < 0) + if (arg_follow && !arg_no_tail && arg_lines <= 0) arg_lines = 10; + if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) { + log_error("--since= must be before --until=."); + return -EINVAL; + } + + if (arg_cursor && arg_since_set) { + log_error("Please specify either --since= or --cursor=, not both."); + return -EINVAL; + } + return 1; } @@ -723,11 +773,11 @@ 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; bool have_pager; + unsigned n_shown = 0; log_parse_environment(); log_open(); @@ -809,27 +859,24 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - if (!arg_quiet) { - usec_t start, end; - char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX]; - - r = sd_journal_get_cutoff_realtime_usec(j, &start, &end); + if (arg_cursor) { + r = sd_journal_seek_cursor(j, arg_cursor); if (r < 0) { - log_error("Failed to get cutoff: %s", strerror(-r)); + log_error("Failed to seek to cursor: %s", strerror(-r)); goto finish; } - if (r > 0) { - if (arg_follow) - printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start)); - else - printf("Logs begin at %s, end at %s.\n", - format_timestamp(start_buf, sizeof(start_buf), start), - format_timestamp(end_buf, sizeof(end_buf), end)); + r = sd_journal_next(j); + + } else if (arg_since_set) { + r = sd_journal_seek_realtime_usec(j, arg_since); + if (r < 0) { + log_error("Failed to seek to date: %s", strerror(-r)); + goto finish; } - } + r = sd_journal_next(j); - if (arg_lines >= 0) { + } else if (arg_lines > 0) { r = sd_journal_seek_tail(j); if (r < 0) { log_error("Failed to seek to tail: %s", strerror(-r)); @@ -837,6 +884,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) { @@ -855,12 +903,29 @@ int main(int argc, char *argv[]) { on_tty(); have_pager = !arg_no_pager && !arg_follow && pager_open(); + if (!arg_quiet) { + usec_t start, end; + char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX]; + + r = sd_journal_get_cutoff_realtime_usec(j, &start, &end); + if (r < 0) { + log_error("Failed to get cutoff: %s", strerror(-r)); + goto finish; + } + + if (r > 0) { + if (arg_follow) + printf("---- Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start)); + else + printf("---- Logs begin at %s, end at %s.\n", + format_timestamp(start_buf, sizeof(start_buf), start), + format_timestamp(end_buf, sizeof(end_buf), end)); + } + } + for (;;) { - for (;;) { - int flags = - arg_show_all * OUTPUT_SHOW_ALL | - have_pager * OUTPUT_FULL_WIDTH | - on_tty() * OUTPUT_COLOR; + while (arg_lines == 0 || arg_follow || n_shown < arg_lines) { + int flags; if (need_seek) { r = sd_journal_next(j); @@ -873,6 +938,16 @@ int main(int argc, char *argv[]) { if (r == 0) break; + if (arg_until_set) { + usec_t usec; + + r = sd_journal_get_realtime_usec(j, &usec); + if (r < 0) { + log_error("Failed to determine timestamp: %s", strerror(-r)); + goto finish; + } + } + if (!arg_merge) { sd_id128_t boot_id; @@ -880,20 +955,24 @@ int main(int argc, char *argv[]) { 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"); + printf(ANSI_HIGHLIGHT_ON "---- Reboot ----" ANSI_HIGHLIGHT_OFF "\n"); previous_boot_id = boot_id; previous_boot_id_valid = true; } } - line ++; + flags = + arg_show_all * OUTPUT_SHOW_ALL | + have_pager * OUTPUT_FULL_WIDTH | + on_tty() * OUTPUT_COLOR; - r = output_journal(j, arg_output, line, 0, flags); + r = output_journal(stdout, j, arg_output, 0, flags); if (r < 0) goto finish; need_seek = true; + n_shown++; } if (!arg_follow) @@ -901,7 +980,7 @@ int main(int argc, char *argv[]) { r = sd_journal_wait(j, (uint64_t) -1); if (r < 0) { - log_error("Couldn't wait for log event: %s", strerror(-r)); + log_error("Couldn't wait for journal event: %s", strerror(-r)); goto finish; } }