From 1d9fb8c12dd7856cc68a864560dd3395c13ae49d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Feb 2024 15:32:49 +0100 Subject: [PATCH 1/8] bsod: adjust --help text to match our usual output --- src/journal/bsod.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/journal/bsod.c b/src/journal/bsod.c index 7d8aa54b15b..688ebdb3510 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -34,19 +34,21 @@ static int help(void) { if (r < 0) return log_oom(); - printf("%s\n\n" - "%sFilter the journal to fetch the first message from the\n" - "current boot with an emergency log level and displays it\n" - "as a string and a QR code.\n\n%s" + printf("%1$s [OPTIONS...]\n\n" + "%5$sFilter the journal to fetch the first message from the current boot with an%6$s\n" + "%5$semergency log level and display it as a string and a QR code.%6$s\n" + "\n%3$sOptions:%4$s\n" " -h --help Show this help\n" " --version Show package version\n" " -c --continuous Make systemd-bsod wait continuously\n" " for changes in the journal\n" - "\nSee the %s for details.\n", + "\nSee the %2$s for details.\n", program_invocation_short_name, - ansi_highlight(), + link, + ansi_underline(), ansi_normal(), - link); + ansi_highlight(), + ansi_normal()); return 0; } From 9655cd3c95e5374f41617b8e998c7265ecba1a3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Feb 2024 15:41:16 +0100 Subject: [PATCH 2/8] bsod: add new option --tty= to specify TTY to output on If specified we'll not try to find a free V, but instead just output directly to the specified TTY. This is particularly useful for debugging, as it means "systemd-bsod --tty=/dev/tty" just works. --- man/systemd-bsod.service.xml | 11 ++++++ src/journal/bsod.c | 66 +++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/man/systemd-bsod.service.xml b/man/systemd-bsod.service.xml index 9b0a9f4e484..1726b7b5d05 100644 --- a/man/systemd-bsod.service.xml +++ b/man/systemd-bsod.service.xml @@ -55,6 +55,17 @@ + + + + + Specify the TTY to output to. By default systemd-bsod will + automatically find a free VT to display the message on. If this option is specified a TTY may be + selected explicitly. Use to direct output to the terminal the command + is invoked on. + + + diff --git a/src/journal/bsod.c b/src/journal/bsod.c index 688ebdb3510..65107981c8d 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -17,6 +17,7 @@ #include "log.h" #include "logs-show.h" #include "main-func.h" +#include "parse-argument.h" #include "pretty-print.h" #include "qrcode-util.h" #include "sigbus.h" @@ -25,6 +26,9 @@ #include "terminal-util.h" static bool arg_continuous = false; +static char *arg_tty = NULL; + +STATIC_DESTRUCTOR_REGISTER(arg_tty, freep); static int help(void) { _cleanup_free_ char *link = NULL; @@ -42,6 +46,7 @@ static int help(void) { " --version Show package version\n" " -c --continuous Make systemd-bsod wait continuously\n" " for changes in the journal\n" + " --tty=TTY Specify path to TTY to use\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -135,9 +140,9 @@ static int find_next_free_vt(int fd, int *ret_free_vt, int *ret_original_vt) { } static int display_emergency_message_fullscreen(const char *message) { - int r, ret = 0, free_vt = 0, original_vt = 0; + int r, ret = 0, free_vt = -1, original_vt = 0; unsigned qr_code_start_row = 1, qr_code_start_column = 1; - char tty[STRLEN("/dev/tty") + DECIMAL_STR_MAX(int) + 1]; + char ttybuf[STRLEN("/dev/tty") + DECIMAL_STR_MAX(int) + 1]; _cleanup_close_ int fd = -EBADF; _cleanup_fclose_ FILE *stream = NULL; char read_character_buffer = '\0'; @@ -145,30 +150,36 @@ static int display_emergency_message_fullscreen(const char *message) { .ws_col = 80, .ws_row = 25, }; + const char *tty; assert(message); - fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (arg_tty) + tty = arg_tty; + else { + fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return log_error_errno(fd, "Failed to open /dev/tty1: %m"); + + r = find_next_free_vt(fd, &free_vt, &original_vt); + if (r < 0) + return log_error_errno(r, "Failed to find a free VT: %m"); + + xsprintf(ttybuf, "/dev/tty%d", free_vt + 1); + tty = ttybuf; + + fd = safe_close(fd); + } + + fd = open_terminal(tty, O_RDWR|O_NOCTTY|O_CLOEXEC); if (fd < 0) - return log_error_errno(fd, "Failed to open tty1: %m"); - - r = find_next_free_vt(fd, &free_vt, &original_vt); - if (r < 0) - return log_error_errno(r, "Failed to find a free VT: %m"); - - xsprintf(tty, "/dev/tty%d", free_vt + 1); - - r = open_terminal(tty, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (r < 0) - return log_error_errno(fd, "Failed to open tty: %m"); - - close_and_replace(fd, r); + return log_error_errno(fd, "Failed to open %s: %m", tty); if (ioctl(fd, TIOCGWINSZ, &w) < 0) log_warning_errno(errno, "Failed to fetch tty size, ignoring: %m"); - if (ioctl(fd, VT_ACTIVATE, free_vt + 1) < 0) - return log_error_errno(errno, "Failed to activate tty: %m"); + if (free_vt >= 0 && ioctl(fd, VT_ACTIVATE, free_vt + 1) < 0) + return log_error_errno(errno, "Failed to activate tty, ignoring: %m"); r = loop_write(fd, ANSI_BACKGROUND_BLUE ANSI_HOME_CLEAR, SIZE_MAX); if (r < 0) @@ -221,7 +232,7 @@ static int display_emergency_message_fullscreen(const char *message) { ret = log_error_errno(r, "Failed to read character: %m"); cleanup: - if (ioctl(fd, VT_ACTIVATE, original_vt) < 0) + if (original_vt > 0 && ioctl(fd, VT_ACTIVATE, original_vt) < 0) return log_error_errno(errno, "Failed to switch back to original VT: %m"); return ret; @@ -231,16 +242,18 @@ static int parse_argv(int argc, char * argv[]) { enum { ARG_VERSION = 0x100, + ARG_TTY, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "continuous", no_argument, NULL, 'c' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "continuous", no_argument, NULL, 'c' }, + { "tty", required_argument, NULL, ARG_TTY }, {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -259,6 +272,13 @@ static int parse_argv(int argc, char * argv[]) { arg_continuous = true; break; + case ARG_TTY: + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_tty); + if (r < 0) + return r; + + break; + case '?': return -EINVAL; From 8b23b9e5e55aaf3d90b445ad6990b56074a32bc0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Feb 2024 15:42:10 +0100 Subject: [PATCH 3/8] bsod: remove some duplicate logging display_emergency_message_fullscreen() already logs about all erros, hence don't log again. --- src/journal/bsod.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/journal/bsod.c b/src/journal/bsod.c index 65107981c8d..046858e8a64 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -136,7 +136,7 @@ static int find_next_free_vt(int fd, int *ret_free_vt, int *ret_original_vt) { return 0; } - return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "No free VT found: %m"); + return -ENOTTY; } static int display_emergency_message_fullscreen(const char *message) { @@ -314,7 +314,7 @@ static int run(int argc, char *argv[]) { r = acquire_first_emergency_log_message(&message); if (r < 0) - return log_error_errno(r, "Failed to acquire first emergency log message: %m"); + return r; if (!message) { log_debug("No emergency-level entries"); @@ -323,11 +323,7 @@ static int run(int argc, char *argv[]) { assert_se(sigaction_many(&nop_sigaction, SIGTERM, SIGINT) >= 0); - r = display_emergency_message_fullscreen((const char*) message); - if (r < 0) - return log_error_errno(r, "Failed to display emergency message on terminal: %m"); - - return 0; + return display_emergency_message_fullscreen(message); } DEFINE_MAIN_FUNCTION(run); From 0a1126c7c2edab13ca281f2ba28afd2b5a98eb30 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Feb 2024 16:33:01 +0100 Subject: [PATCH 4/8] bsod: make sure "Press Any Key" has a blue background too --- src/journal/bsod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/journal/bsod.c b/src/journal/bsod.c index 046858e8a64..05c3205d447 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -221,7 +221,7 @@ static int display_emergency_message_fullscreen(const char *message) { if (r < 0) log_warning_errno(r, "Failed to move terminal cursor position, ignoring: %m"); - r = loop_write(fd, "Press any key to exit...", SIZE_MAX); + r = loop_write(fd, ANSI_BACKGROUND_BLUE "Press any key to exit...", SIZE_MAX); if (r < 0) { ret = log_warning_errno(r, "Failed to write to terminal: %m"); goto cleanup; From 8f894121d15ea63c6047cad6b2a9a95ea472a0d2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2024 09:46:15 +0100 Subject: [PATCH 5/8] bsod: correct log level on some messages --- src/journal/bsod.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/journal/bsod.c b/src/journal/bsod.c index 05c3205d447..30f790dbbe3 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -73,16 +73,16 @@ static int acquire_first_emergency_log_message(char **ret) { r = add_match_this_boot(j, NULL); if (r < 0) - return log_warning_errno(r, "Failed to add boot ID filter: %m"); + return log_error_errno(r, "Failed to add boot ID filter: %m"); r = sd_journal_add_match(j, "_UID=0", 0); if (r < 0) - return log_warning_errno(r, "Failed to add User ID filter: %m"); + return log_error_errno(r, "Failed to add User ID filter: %m"); assert_cc(0 == LOG_EMERG); r = sd_journal_add_match(j, "PRIORITY=0", 0); if (r < 0) - return log_warning_errno(r, "Failed to add Emergency filter: %m"); + return log_error_errno(r, "Failed to add Emergency filter: %m"); r = sd_journal_seek_head(j); if (r < 0) @@ -191,7 +191,7 @@ static int display_emergency_message_fullscreen(const char *message) { r = loop_write(fd, "The current boot has failed!", SIZE_MAX); if (r < 0) { - ret = log_warning_errno(r, "Failed to write to terminal: %m"); + ret = log_error_errno(r, "Failed to write to terminal: %m"); goto cleanup; } @@ -203,7 +203,7 @@ static int display_emergency_message_fullscreen(const char *message) { r = loop_write(fd, message, SIZE_MAX); if (r < 0) { - ret = log_warning_errno(r, "Failed to write emergency message to terminal: %m"); + ret = log_error_errno(r, "Failed to write emergency message to terminal: %m"); goto cleanup; } @@ -223,7 +223,7 @@ static int display_emergency_message_fullscreen(const char *message) { r = loop_write(fd, ANSI_BACKGROUND_BLUE "Press any key to exit...", SIZE_MAX); if (r < 0) { - ret = log_warning_errno(r, "Failed to write to terminal: %m"); + ret = log_error_errno(r, "Failed to write to terminal: %m"); goto cleanup; } From 5e0c2c3e71931eef98e27ffb13a595899463519e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2024 09:53:58 +0100 Subject: [PATCH 6/8] bsod: normalize VT indexes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 1-based VT indexes are what people usually expect, since the primary name of VTs uses them (i.e. /dev/tty1, /dev/tty2, …). Hence, let's always use 1-based VT indexes, and early on convert 0-based VT indexes to minimize confusion. --- src/journal/bsod.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/journal/bsod.c b/src/journal/bsod.c index 30f790dbbe3..c4022cdf6ea 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -131,7 +131,7 @@ static int find_next_free_vt(int fd, int *ret_free_vt, int *ret_original_vt) { for (size_t i = 0; i < sizeof(terminal_status.v_state) * 8; i++) if ((terminal_status.v_state & (1 << i)) == 0) { - *ret_free_vt = i; + *ret_free_vt = i + 1; *ret_original_vt = terminal_status.v_active; return 0; } @@ -140,7 +140,7 @@ static int find_next_free_vt(int fd, int *ret_free_vt, int *ret_original_vt) { } static int display_emergency_message_fullscreen(const char *message) { - int r, ret = 0, free_vt = -1, original_vt = 0; + int r, ret = 0, free_vt = 0, original_vt = 0; unsigned qr_code_start_row = 1, qr_code_start_column = 1; char ttybuf[STRLEN("/dev/tty") + DECIMAL_STR_MAX(int) + 1]; _cleanup_close_ int fd = -EBADF; @@ -165,7 +165,7 @@ static int display_emergency_message_fullscreen(const char *message) { if (r < 0) return log_error_errno(r, "Failed to find a free VT: %m"); - xsprintf(ttybuf, "/dev/tty%d", free_vt + 1); + xsprintf(ttybuf, "/dev/tty%d", free_vt); tty = ttybuf; fd = safe_close(fd); @@ -178,8 +178,8 @@ static int display_emergency_message_fullscreen(const char *message) { if (ioctl(fd, TIOCGWINSZ, &w) < 0) log_warning_errno(errno, "Failed to fetch tty size, ignoring: %m"); - if (free_vt >= 0 && ioctl(fd, VT_ACTIVATE, free_vt + 1) < 0) - return log_error_errno(errno, "Failed to activate tty, ignoring: %m"); + if (free_vt > 0 && ioctl(fd, VT_ACTIVATE, free_vt) < 0) + return log_error_errno(errno, "Failed to activate /dev/tty%i, ignoring: %m", free_vt); r = loop_write(fd, ANSI_BACKGROUND_BLUE ANSI_HOME_CLEAR, SIZE_MAX); if (r < 0) @@ -233,7 +233,7 @@ static int display_emergency_message_fullscreen(const char *message) { cleanup: if (original_vt > 0 && ioctl(fd, VT_ACTIVATE, original_vt) < 0) - return log_error_errno(errno, "Failed to switch back to original VT: %m"); + return log_error_errno(errno, "Failed to switch back to original VT /dev/tty%i: %m", original_vt); return ret; } From beb15ff639d6c4405c1ecf3fa2fbe6d77f6dafbc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2024 09:59:35 +0100 Subject: [PATCH 7/8] bsod: remove one redundant variable --- src/journal/bsod.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/journal/bsod.c b/src/journal/bsod.c index c4022cdf6ea..3c64a838909 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -140,7 +140,7 @@ static int find_next_free_vt(int fd, int *ret_free_vt, int *ret_original_vt) { } static int display_emergency_message_fullscreen(const char *message) { - int r, ret = 0, free_vt = 0, original_vt = 0; + int r, free_vt = 0, original_vt = 0; unsigned qr_code_start_row = 1, qr_code_start_column = 1; char ttybuf[STRLEN("/dev/tty") + DECIMAL_STR_MAX(int) + 1]; _cleanup_close_ int fd = -EBADF; @@ -191,7 +191,7 @@ static int display_emergency_message_fullscreen(const char *message) { r = loop_write(fd, "The current boot has failed!", SIZE_MAX); if (r < 0) { - ret = log_error_errno(r, "Failed to write to terminal: %m"); + log_error_errno(r, "Failed to write to terminal: %m"); goto cleanup; } @@ -203,13 +203,13 @@ static int display_emergency_message_fullscreen(const char *message) { r = loop_write(fd, message, SIZE_MAX); if (r < 0) { - ret = log_error_errno(r, "Failed to write emergency message to terminal: %m"); + log_error_errno(r, "Failed to write emergency message to terminal: %m"); goto cleanup; } r = fdopen_independent(fd, "r+", &stream); if (r < 0) { - ret = log_error_errno(errno, "Failed to open output file: %m"); + r = log_error_errno(errno, "Failed to open output file: %m"); goto cleanup; } @@ -223,19 +223,21 @@ static int display_emergency_message_fullscreen(const char *message) { r = loop_write(fd, ANSI_BACKGROUND_BLUE "Press any key to exit...", SIZE_MAX); if (r < 0) { - ret = log_error_errno(r, "Failed to write to terminal: %m"); + log_error_errno(r, "Failed to write to terminal: %m"); goto cleanup; } r = read_one_char(stream, &read_character_buffer, USEC_INFINITY, NULL); if (r < 0 && r != -EINTR) - ret = log_error_errno(r, "Failed to read character: %m"); + log_error_errno(r, "Failed to read character: %m"); + + r = 0; cleanup: if (original_vt > 0 && ioctl(fd, VT_ACTIVATE, original_vt) < 0) return log_error_errno(errno, "Failed to switch back to original VT /dev/tty%i: %m", original_vt); - return ret; + return r; } static int parse_argv(int argc, char * argv[]) { From 0d10b4f573847c71649befb62455a8b26bff4a2d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2024 09:59:51 +0100 Subject: [PATCH 8/8] bsod: don't fail in an error path If we fail in an error path, don't override the error we are processing, just print a warning and continue. --- src/journal/bsod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/journal/bsod.c b/src/journal/bsod.c index 3c64a838909..a4788b828cf 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -235,7 +235,7 @@ static int display_emergency_message_fullscreen(const char *message) { cleanup: if (original_vt > 0 && ioctl(fd, VT_ACTIVATE, original_vt) < 0) - return log_error_errno(errno, "Failed to switch back to original VT /dev/tty%i: %m", original_vt); + log_warning_errno(errno, "Failed to switch back to original VT /dev/tty%i: %m", original_vt); return r; }