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));