From 1682c4bf5b993b956b0367aedc9f0638055540f4 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 19 Jul 2012 21:12:16 +0000 Subject: [PATCH 1/3] journalctl: fix assertion failure in ellipsize_mem() When showing the journal through "journalctl --no-pager", if the prefix of the log message (i.e. the date and syslog identifier) is less than 3 characters shorter than the width of the terminal, you get: Assertion 'new_length >= 3' failed at src/shared/util.c:3859, function ellipsize_mem(). Aborting. because there is not enough space for the "...". This patch add the necessary check. --- src/logs-show.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logs-show.c b/src/logs-show.c index eb9a902..72367f2 100644 --- a/src/logs-show.c +++ b/src/logs-show.c @@ -230,7 +230,7 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); } else if (message_len + n < n_columns) printf(": %.*s\n", (int) message_len, message); - else if (n < n_columns) { + else if (n < n_columns && n_columns - n - 2 >= 3) { char *e; e = ellipsize_mem(message, message_len, n_columns - n - 2, 90); -- 1.7.10.4 From ee385756e10862a8bcc0e5c7a3776135af84c750 Mon Sep 17 00:00:00 2001 From: Zbigniew Jedrzejewski-Szmek Date: Fri, 20 Jul 2012 09:06:26 +0200 Subject: [PATCH 2/3] journalctl: fix ellipsization with PAGER=cat There are other reasons for not opening the pager then the --no-pager or --follow options (described below). If the pager is not used, messages must be ellipsized. On Fri, Jul 20, 2012 at 05:42:44AM +0000, Shawn Landen wrote: > "Pager to use when --no-pager is not given; overrides $PAGER. > Setting this to an empty string or the value cat is equivalent to passing --no-pager." Conflicts: src/journal/journalctl.c --- src/journal/journalctl.c | 5 +---- src/pager.c | 17 ++++++++++------- src/pager.h | 4 +++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index f90b2dd..3a3b043 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -259,10 +259,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (!arg_no_pager && !arg_follow) { - columns(); - pager_open(); - } + have_pager = !arg_no_pager && !arg_follow && pager_open(); if (arg_output == OUTPUT_JSON) { fputc('[', stdout); diff --git a/src/pager.c b/src/pager.c index 3fc8182..8065841 100644 --- a/src/pager.c +++ b/src/pager.c @@ -44,20 +44,20 @@ _noreturn_ static void pager_fallback(void) { _exit(EXIT_SUCCESS); } -void pager_open(void) { +bool pager_open(void) { int fd[2]; const char *pager; pid_t parent_pid; if (pager_pid > 0) - return; + return false; if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER"))) if (!*pager || streq(pager, "cat")) - return; + return false; if (isatty(STDOUT_FILENO) <= 0) - return; + return false; /* Determine and cache number of columns before we spawn the * pager so that we get the value from the actual tty */ @@ -65,7 +65,7 @@ void pager_open(void) { if (pipe(fd) < 0) { log_error("Failed to create pager pipe: %m"); - return; + return false; } parent_pid = getpid(); @@ -74,7 +74,7 @@ void pager_open(void) { if (pager_pid < 0) { log_error("Failed to fork pager: %m"); close_pipe(fd); - return; + return false; } /* In the child start the pager */ @@ -115,10 +115,13 @@ void pager_open(void) { } /* Return in the parent */ - if (dup2(fd[1], STDOUT_FILENO) < 0) + if (dup2(fd[1], STDOUT_FILENO) < 0) { log_error("Failed to duplicate pager pipe: %m"); + return false; + } close_pipe(fd); + return true; } void pager_close(void) { diff --git a/src/pager.h b/src/pager.h index b5b4998..bd1a983 100644 --- a/src/pager.h +++ b/src/pager.h @@ -22,7 +22,9 @@ along with systemd; If not, see . ***/ -void pager_open(void); +#include + +bool pager_open(void); void pager_close(void); #endif -- 1.7.10.4 From ae88e07aec6280e90582703f7950468604182a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 17 Jul 2012 07:35:08 +0200 Subject: [PATCH 3/3] journalctl: do not ellipsize when using pager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a pager is used, ellipsization is redundant — the pager does that better by hiding the part that cannot be shown. Pager's advantage is that the user can press → to view the hidden part of a message, and then ← to return. cherry-picked from 92a1fd9e95954a557d6fe27b56f5ef1b89fc2f5e and 25277cd7fbd77e4c8b20572570aa77c7da9abcc2 --- src/journal/journalctl.c | 7 ++++- src/logs-show.c | 66 ++++++++++++++++++++++++++++------------------ src/logs-show.h | 14 +++++++--- src/systemctl.c | 8 +++++- 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 3a3b043..197af71 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -198,6 +198,7 @@ int main(int argc, char *argv[]) { sd_journal *j = NULL; unsigned line = 0; bool need_seek = false; + bool have_pager; log_parse_environment(); log_open(); @@ -268,6 +269,10 @@ int main(int argc, char *argv[]) { for (;;) { for (;;) { + int flags = + arg_show_all * OUTPUT_SHOW_ALL | + have_pager * OUTPUT_FULL_WIDTH; + if (need_seek) { r = sd_journal_next(j); if (r < 0) { @@ -281,7 +286,7 @@ int main(int argc, char *argv[]) { line ++; - r = output_journal(j, arg_output, line, 0, arg_show_all); + r = output_journal(j, arg_output, line, 0, flags); if (r < 0) goto finish; diff --git a/src/logs-show.c b/src/logs-show.c index 72367f2..06ba569 100644 --- a/src/logs-show.c +++ b/src/logs-show.c @@ -86,7 +86,8 @@ static bool shall_print(bool show_all, char *p, size_t l) { return true; } -static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool show_all, bool monotonic_mode) { +static int output_short(sd_journal *j, unsigned line, unsigned n_columns, + OutputFlags flags) { int r; const void *data; size_t length; @@ -150,7 +151,7 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s goto finish; } - if (monotonic_mode) { + if (flags & OUTPUT_MONOTONIC_MODE) { uint64_t t; sd_id128_t boot_id; @@ -202,33 +203,39 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s n += strlen(buf); } - if (hostname && shall_print(show_all, hostname, hostname_len)) { + if (hostname && shall_print(flags & OUTPUT_SHOW_ALL, + hostname, hostname_len)) { printf(" %.*s", (int) hostname_len, hostname); n += hostname_len + 1; } - if (identifier && shall_print(show_all, identifier, identifier_len)) { + if (identifier && shall_print(flags & OUTPUT_SHOW_ALL, + identifier, identifier_len)) { printf(" %.*s", (int) identifier_len, identifier); n += identifier_len + 1; - } else if (comm && shall_print(show_all, comm, comm_len)) { + } else if (comm && shall_print(flags & OUTPUT_SHOW_ALL, + comm, comm_len)) { printf(" %.*s", (int) comm_len, comm); n += comm_len + 1; - } + } else + putchar(' '); - if (pid && shall_print(show_all, pid, pid_len)) { + if (pid && shall_print(flags & OUTPUT_SHOW_ALL, pid, pid_len)) { printf("[%.*s]", (int) pid_len, pid); n += pid_len + 2; - } else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) { + } else if (fake_pid && shall_print(flags & OUTPUT_SHOW_ALL, + fake_pid, fake_pid_len)) { printf("[%.*s]", (int) fake_pid_len, fake_pid); n += fake_pid_len + 2; } - if (show_all) + if (flags & OUTPUT_SHOW_ALL) printf(": %.*s\n", (int) message_len, message); else if (contains_unprintable(message, message_len)) { char bytes[FORMAT_BYTES_MAX]; printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); - } else if (message_len + n < n_columns) + } else if ((flags & OUTPUT_FULL_WIDTH) || + (message_len + n + 1 < n_columns)) printf(": %.*s\n", (int) message_len, message); else if (n < n_columns && n_columns - n - 2 >= 3) { char *e; @@ -259,15 +266,18 @@ finish: return r; } -static int output_short_realtime(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { - return output_short(j, line, n_columns, show_all, false); +static int output_short_realtime(sd_journal *j, unsigned line, + unsigned n_columns, OutputFlags flags) { + return output_short(j, line, n_columns, flags & ~OUTPUT_MONOTONIC_MODE); } -static int output_short_monotonic(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { - return output_short(j, line, n_columns, show_all, true); +static int output_short_monotonic(sd_journal *j, unsigned line, + unsigned n_columns, OutputFlags flags) { + return output_short(j, line, n_columns, flags | OUTPUT_MONOTONIC_MODE); } -static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +static int output_verbose(sd_journal *j, unsigned line, + unsigned n_columns, OutputFlags flags) { const void *data; size_t length; char *cursor; @@ -296,7 +306,7 @@ static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool free(cursor); SD_JOURNAL_FOREACH_DATA(j, data, length) { - if (!show_all && (length > PRINT_THRESHOLD || + if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD || contains_unprintable(data, length))) { const char *c; char bytes[FORMAT_BYTES_MAX]; @@ -318,7 +328,8 @@ static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool return 0; } -static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +static int output_export(sd_journal *j, unsigned line, + unsigned n_columns, OutputFlags flags) { sd_id128_t boot_id; char sid[33]; int r; @@ -424,7 +435,8 @@ static void json_escape(const char* p, size_t l) { } } -static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +static int output_json(sd_journal *j, unsigned line, + unsigned n_columns, OutputFlags flags) { uint64_t realtime, monotonic; char *cursor; const void *data; @@ -491,7 +503,8 @@ static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool sh return 0; } -static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +static int output_cat(sd_journal *j, unsigned line, + unsigned n_columns, OutputFlags flags) { const void *data; size_t l; int r; @@ -512,7 +525,8 @@ static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool sho return 0; } -static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsigned n_columns, bool show_all) = { +static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, + unsigned n_columns, OutputFlags flags) = { [OUTPUT_SHORT] = output_short_realtime, [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic, [OUTPUT_VERBOSE] = output_verbose, @@ -521,14 +535,15 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsign [OUTPUT_CAT] = output_cat }; -int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all) { +int output_journal(sd_journal *j, OutputMode mode, unsigned line, + unsigned n_columns, OutputFlags flags) { assert(mode >= 0); assert(mode < _OUTPUT_MODE_MAX); if (n_columns <= 0) n_columns = columns(); - return output_funcs[mode](j, line, n_columns, show_all); + return output_funcs[mode](j, line, n_columns, flags); } int show_journal_by_unit( @@ -537,8 +552,7 @@ int show_journal_by_unit( unsigned n_columns, usec_t not_before, unsigned how_many, - bool show_all, - bool follow) { + OutputFlags flags) { char *m = NULL; sd_journal *j = NULL; @@ -621,12 +635,12 @@ int show_journal_by_unit( line ++; - r = output_journal(j, mode, line, n_columns, show_all); + r = output_journal(j, mode, line, n_columns, flags); if (r < 0) goto finish; } - if (!follow) + if (!(flags & OUTPUT_FOLLOW)) break; r = fd_wait_for_event(fd, POLLIN, (usec_t) -1); diff --git a/src/logs-show.h b/src/logs-show.h index db9c7e3..e8c6b03 100644 --- a/src/logs-show.h +++ b/src/logs-show.h @@ -39,7 +39,16 @@ typedef enum OutputMode { _OUTPUT_MODE_INVALID = -1 } OutputMode; -int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all); +typedef enum OutputFlags { + OUTPUT_SHOW_ALL = 1 << 0, + OUTPUT_MONOTONIC_MODE = 1 << 1, + OUTPUT_FOLLOW = 1 << 2, + OUTPUT_WARN_CUTOFF = 1 << 3, + OUTPUT_FULL_WIDTH = 1 << 4, +} OutputFlags; + +int output_journal(sd_journal *j, OutputMode mode, unsigned line, + unsigned n_columns, OutputFlags flags); int show_journal_by_unit( const char *unit, @@ -47,8 +56,7 @@ int show_journal_by_unit( unsigned n_columns, usec_t not_before, unsigned how_many, - bool show_all, - bool follow); + OutputFlags flags); const char* output_mode_to_string(OutputMode m); OutputMode output_mode_from_string(const char *s); diff --git a/src/systemctl.c b/src/systemctl.c index f51085f..e94e024 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -2374,8 +2374,14 @@ static void print_status_info(UnitStatusInfo *i) { } if (i->id && arg_transport != TRANSPORT_SSH) { + int flags = + arg_lines * OUTPUT_SHOW_ALL | + arg_follow * OUTPUT_FOLLOW; + printf("\n"); - show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow); + show_journal_by_unit(i->id, arg_output, 0, + i->inactive_exit_timestamp_monotonic, + arg_lines, flags); } if (i->need_daemon_reload) -- 1.7.10.4