diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 678cd4ed4d..b2cbadb579 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) { + + /* 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); + char key = 0; - bool need_nl = true; + (void) read_one_char(stdin, &key, USEC_INFINITY, /* echo= */ false, /* need_nl= */ NULL); - /* - * 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 --"); - - (void) read_one_char(stdin, &key, USEC_INFINITY, &need_nl); - - 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 d6dd394bcf..d11daefb56 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 08eae5988b..ce73599d90 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 d00886fb80..aaff8a8e88 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 bfd4b3b574..89e9c8b82b 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 2f06808cd4..68361b084a 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 ac7eacb01a..87304346e9 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) {