From 256084b0b9dd09a365b312df4ff378c9ce30c526 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Mon, 24 Jul 2023 17:19:51 +0100 Subject: [PATCH] top: Disable echo and line buffering on startup This means we no longer show any characters the user types while top is running. Disabling line buffering has the same effect as enabling non-blocking I/O, but it doesn't crash the terminal when we exit the program without restoring stdin to its original state. This would previously happen when a SIGKILL signal was received, for example. --- Userland/Utilities/top.cpp | 41 +++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/Userland/Utilities/top.cpp b/Userland/Utilities/top.cpp index fde1a9fc8b..d7691784a4 100644 --- a/Userland/Utilities/top.cpp +++ b/Userland/Utilities/top.cpp @@ -201,18 +201,26 @@ static bool check_quit() return c == 'q' || c == 'Q'; } -static int g_old_stdin; +static struct termios g_previous_tty_settings; -static void restore_stdin() +static ErrorOr setup_tty() { - fcntl(STDIN_FILENO, F_SETFL, g_old_stdin); + g_previous_tty_settings = TRY(Core::System::tcgetattr(STDOUT_FILENO)); + + struct termios raw = g_previous_tty_settings; + raw.c_lflag &= ~(ECHO | ICANON); + + // Disable echo and line buffering + TRY(Core::System::tcsetattr(STDOUT_FILENO, TCSAFLUSH, raw)); + + return {}; } -static void enable_nonblocking_stdin() +static void restore_tty() { - g_old_stdin = fcntl(STDIN_FILENO, F_GETFL); - fcntl(STDIN_FILENO, F_SETFL, g_old_stdin | O_NONBLOCK); - atexit(restore_stdin); + auto maybe_error = Core::System::tcsetattr(STDOUT_FILENO, TCSAFLUSH, g_previous_tty_settings); + if (maybe_error.is_error()) + warnln("Failed to reset original terminal state: {}", strerror(maybe_error.error().code())); } ErrorOr serenity_main(Main::Arguments arguments) @@ -225,15 +233,24 @@ ErrorOr serenity_main(Main::Arguments arguments) TRY(Core::System::signal(SIGWINCH, [](int) { g_window_size_changed = true; })); - TRY(Core::System::signal(SIGINT, [](int) { - exit(0); - })); - TRY(Core::System::pledge("stdio rpath tty")); TopOption top_option; parse_args(arguments, top_option); - enable_nonblocking_stdin(); + TRY(setup_tty()); + ScopeGuard restore_tty_guard([] { + restore_tty(); + }); + auto restore_tty_sigaction_handler = [](auto) { + restore_tty(); + exit(1); + }; + struct sigaction restore_tty_action; + restore_tty_action.sa_handler = restore_tty_sigaction_handler; + TRY(Core::System::sigaction(SIGINT, &restore_tty_action, nullptr)); + TRY(Core::System::sigaction(SIGTERM, &restore_tty_action, nullptr)); + + TRY(Core::System::pledge("stdio rpath tty")); Vector threads; auto prev = TRY(get_snapshot(top_option.pids_to_filter_by));