diff options
| author | gbc dev <gbc@localhost> | 2026-07-16 11:25:43 +0200 |
|---|---|---|
| committer | gbc dev <gbc@localhost> | 2026-07-16 11:25:43 +0200 |
| commit | 283040a1a5356e774276ba8f6c7404483b81bc11 (patch) | |
| tree | 846c6c51fde7b96bbbce13e268fa660062f75bdd | |
| parent | serial: deliver EOF (0x04) on stdin end for headless console (diff) | |
| download | sl0pboy-283040a1a5356e774276ba8f6c7404483b81bc11.tar.gz sl0pboy-283040a1a5356e774276ba8f6c7404483b81bc11.tar.xz sl0pboy-283040a1a5356e774276ba8f6c7404483b81bc11.zip | |
headless: interactive TTY mode (raw stdin) for driving a guest OS live
When stdin is a terminal, --headless now disables canonical mode + local echo
so keystrokes reach the guest immediately and only the guest echoes (no doubled
chars). Piped/redirected stdin is untouched (scripted input still works). Keep
ISIG so Ctrl-C quits; restore termios on exit. VMIN=1 so a no-data non-blocking
read is EAGAIN, not a 0-byte read the serial layer would misread as EOF.
| -rw-r--r-- | src/main.c | 17 |
1 files changed, 17 insertions, 0 deletions
@@ -9,6 +9,7 @@ #include <signal.h> #include <fcntl.h> #include <unistd.h> +#include <termios.h> static volatile sig_atomic_t running = 1; static void on_sig(int s) { (void)s; running = 0; } @@ -100,6 +101,21 @@ int main(int argc, char **argv) { if (fl != -1) fcntl(STDIN_FILENO, F_SETFL, fl | O_NONBLOCK); signal(SIGINT, on_sig); signal(SIGTERM, on_sig); + // Interactive: if stdin is a terminal, drop line-buffering + local echo + // so keystrokes reach the guest immediately and only the guest echoes. + // (Piped/redirected stdin is left alone, for scripted input.) + struct termios saved_tio; + bool raw_tty = isatty(STDIN_FILENO) && tcgetattr(STDIN_FILENO, &saved_tio) == 0; + if (raw_tty) { + struct termios t = saved_tio; + t.c_lflag &= ~(ICANON | ECHO); // char-at-a-time, no echo (keep ISIG) + // VMIN=1 (not 0): with O_NONBLOCK, "no data" is EAGAIN, not a 0-byte + // read that we'd otherwise misread as EOF. + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + tcsetattr(STDIN_FILENO, TCSANOW, &t); + fprintf(stderr, "[gbc: interactive serial console - Ctrl-C to quit]\n"); + } bool uncapped = (target_fps <= 0); double start_t = now_sec(); u64 start_cyc = gb->cycles; @@ -118,6 +134,7 @@ int main(int argc, char **argv) { } } } + if (raw_tty) tcsetattr(STDIN_FILENO, TCSANOW, &saved_tio); cart_free(&gb->cart); free(gb); return 0; } |
