From: Lennart Poettering Date: Wed, 5 Feb 2025 08:35:51 +0000 (+0100) Subject: terminal-util: tweak any_key_to_proceed() a bit X-Git-Tag: v258-rc1~1322^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8fcd85768beef5382fb4cb238148889c0b7eee4b;p=thirdparty%2Fsystemd.git terminal-util: tweak any_key_to_proceed() a bit 1. Make the message a bit more visible, by adding ANSI color. This matters in particular during boot, where the message otherwise might be overprinted by other output 2. Let's turn off terminal echo so that whatever key is entered is not made visible on screen, and we can handle newline and other keys reasonably uniformly. --- diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 678cd4ed4dd..b2cbadb579c 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -103,22 +103,25 @@ int chvt(int vt) { return RET_NERRNO(ioctl(fd, VT_ACTIVATE, vt)); } -int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { +int read_one_char(FILE *f, char *ret, usec_t t, bool echo, bool *need_nl) { _cleanup_free_ char *line = NULL; struct termios old_termios; int r, fd; - assert(f); assert(ret); + if (!f) + f = stdin; + /* If this is a terminal, then switch canonical mode off, so that we can read a single * character. (Note that fmemopen() streams do not have an fd associated with them, let's handle that - * nicely.) */ + * nicely.) If 'echo' is false we'll also disable ECHO mode so that the pressed key is not made + * visible to the user. */ fd = fileno(f); if (fd >= 0 && tcgetattr(fd, &old_termios) >= 0) { struct termios new_termios = old_termios; - new_termios.c_lflag &= ~ICANON; + new_termios.c_lflag &= ~(ICANON|(echo ? 0 : ECHO)); new_termios.c_cc[VMIN] = 1; new_termios.c_cc[VTIME] = 0; @@ -201,7 +204,7 @@ int ask_char(char *ret, const char *replies, const char *fmt, ...) { fflush(stdout); - r = read_one_char(stdin, &c, DEFAULT_ASK_REFRESH_USEC, &need_nl); + r = read_one_char(stdin, &c, DEFAULT_ASK_REFRESH_USEC, /* echo= */ true, &need_nl); if (r < 0) { if (r == -ETIMEDOUT) @@ -257,20 +260,23 @@ int ask_string(char **ret, const char *text, ...) { } bool any_key_to_proceed(void) { - char key = 0; - bool need_nl = true; - /* - * Insert a new line here as well as to when the user inputs, as this is also used during the - * boot up sequence when status messages may be interleaved with the current program output. - * This ensures that the status messages aren't appended on the same line as this message. - */ - puts("-- Press any key to proceed --"); + /* Insert a new line here as well as to when the user inputs, as this is also used during the boot up + * sequence when status messages may be interleaved with the current program output. This ensures + * that the status messages aren't appended on the same line as this message. */ + + fputc('\n', stdout); + fputs(ansi_highlight_magenta(), stdout); + fputs("-- Press any key to proceed --", stdout); + fputs(ansi_normal(), stdout); + fflush(stdout); - (void) read_one_char(stdin, &key, USEC_INFINITY, &need_nl); + char key = 0; + (void) read_one_char(stdin, &key, USEC_INFINITY, /* echo= */ false, /* need_nl= */ NULL); - if (need_nl) - putchar('\n'); + fputc('\n', stdout); + fputc('\n', stdout); + fflush(stdout); return key != 'q'; } @@ -312,10 +318,9 @@ int show_menu(char **x, unsigned n_columns, unsigned width, unsigned percentage) putchar('\n'); /* on the first screen we reserve 2 extra lines for the title */ - if (i % break_lines == break_modulo) { + if (i % break_lines == break_modulo) if (!any_key_to_proceed()) return 0; - } } return 0; diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index d6dd394bcf4..d11daefb561 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -80,7 +80,7 @@ int proc_cmdline_tty_size(const char *tty, unsigned *ret_rows, unsigned *ret_col int chvt(int vt); -int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl); +int read_one_char(FILE *f, char *ret, usec_t timeout, bool echo, bool *need_nl); int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4); int ask_string(char **ret, const char *text, ...) _printf_(2, 3); bool any_key_to_proceed(void); diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 08eae5988b0..ce73599d902 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -954,7 +954,7 @@ static int loop(const char *root) { if (arg_batch) (void) usleep_safe(usec_add(usec_sub_unsigned(last_refresh, t), arg_delay)); else { - r = read_one_char(stdin, &key, usec_add(usec_sub_unsigned(last_refresh, t), arg_delay), NULL); + r = read_one_char(stdin, &key, usec_add(usec_sub_unsigned(last_refresh, t), arg_delay), /* echo= */ false, /* need_nl= */ NULL); if (r == -ETIMEDOUT) continue; if (r < 0) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index d00886fb808..aaff8a8e885 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -128,7 +128,7 @@ static void print_welcome(int rfd) { else printf("\nWelcome to your new installation of %s!\n", pn); - printf("\nPlease configure your system!\n\n"); + printf("\nPlease configure your system!\n"); any_key_to_proceed(); diff --git a/src/home/homectl.c b/src/home/homectl.c index bfd4b3b574b..89e9c8b82b1 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -2485,7 +2485,12 @@ static int create_interactively(void) { return 0; } - any_key_to_proceed(); + printf("\nPlease create your user account!\n"); + + if (!any_key_to_proceed()) { + log_notice("Skipping."); + return 0; + } (void) terminal_reset_defensive_locked(STDOUT_FILENO, /* switch_to_text= */ false); diff --git a/src/journal/bsod.c b/src/journal/bsod.c index 2f06808cd4c..68361b084a6 100644 --- a/src/journal/bsod.c +++ b/src/journal/bsod.c @@ -228,9 +228,9 @@ static int display_emergency_message_fullscreen(const char *message) { goto cleanup; } - r = read_one_char(f, &read_character_buffer, USEC_INFINITY, NULL); + r = read_one_char(f, &read_character_buffer, USEC_INFINITY, /* echo= */ true, /* need_nl= */ NULL); if (r < 0 && r != -EINTR) - log_error_errno(r, "Failed to read character: %m"); + log_warning_errno(r, "Failed to read character, ignoring: %m"); r = 0; diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index ac7eacb01a0..87304346e9e 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -55,20 +55,20 @@ TEST(read_one_char) { assert_se(fputs("c\n", file) >= 0); rewind(file); - assert_se(read_one_char(file, &r, 1000000, &need_nl) >= 0); + assert_se(read_one_char(file, &r, 1000000, /* echo= */ true, &need_nl) >= 0); assert_se(!need_nl); assert_se(r == 'c'); - assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0); + assert_se(read_one_char(file, &r, 1000000, /* echo= */ true, &need_nl) < 0); rewind(file); assert_se(fputs("foobar\n", file) >= 0); rewind(file); - assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0); + assert_se(read_one_char(file, &r, 1000000, /* echo= */ true, &need_nl) < 0); rewind(file); assert_se(fputs("\n", file) >= 0); rewind(file); - assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0); + assert_se(read_one_char(file, &r, 1000000, /* echo= */ true, &need_nl) < 0); } TEST(getttyname_malloc) {