|
| 1 | +// Copyright 2025 Blindspot Software |
| 2 | +// Use of this source code is governed by a BSD-style |
| 3 | +// license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +//go:build linux || darwin |
| 6 | + |
| 7 | +package main |
| 8 | + |
| 9 | +import "golang.org/x/sys/unix" |
| 10 | + |
| 11 | +// setRawInput puts the terminal into raw input mode so the interactive serial |
| 12 | +// session behaves like a direct console: |
| 13 | +// |
| 14 | +// - ECHO/ICANON off: keystrokes are delivered immediately, character at a |
| 15 | +// time, and not echoed locally (the DUT echoes them back). |
| 16 | +// - ISIG off: control characters such as Ctrl-C, Ctrl-Z and Ctrl-\ are NOT |
| 17 | +// turned into local signals; they are forwarded to the DUT as raw bytes. |
| 18 | +// - IXON off: Ctrl-S/Ctrl-Q flow control is forwarded to the DUT instead of |
| 19 | +// being swallowed by the local terminal. |
| 20 | +// - IEXTEN off: Ctrl-V and friends are forwarded literally. |
| 21 | +// - ICRNL off: a typed CR is sent as CR, not translated to NL. |
| 22 | +// |
| 23 | +// dutctl is exited with the client-side escape sequence (Ctrl-A x), not with a |
| 24 | +// terminal signal — see filterEscape in rpc.go. |
| 25 | +// |
| 26 | +// It returns a restore function, or nil if the fd is not a terminal (in which |
| 27 | +// case input stays line-buffered, which is the correct fallback for pipes). |
| 28 | +// |
| 29 | +// The ioctl request numbers differ per OS (tcGetReq/tcSetReq are defined in the |
| 30 | +// platform-specific files); the termios flags themselves are shared across |
| 31 | +// unix platforms. |
| 32 | +func setRawInput(fileDescriptor int) func() { |
| 33 | + termios, err := unix.IoctlGetTermios(fileDescriptor, tcGetReq) |
| 34 | + if err != nil { |
| 35 | + return nil |
| 36 | + } |
| 37 | + |
| 38 | + old := *termios |
| 39 | + |
| 40 | + termios.Iflag &^= unix.ICRNL | unix.IXON |
| 41 | + termios.Lflag &^= unix.ECHO | unix.ICANON | unix.ISIG | unix.IEXTEN |
| 42 | + termios.Cc[unix.VMIN] = 1 |
| 43 | + termios.Cc[unix.VTIME] = 0 |
| 44 | + |
| 45 | + err = unix.IoctlSetTermios(fileDescriptor, tcSetReq, termios) |
| 46 | + if err != nil { |
| 47 | + return nil |
| 48 | + } |
| 49 | + |
| 50 | + return func() { |
| 51 | + _ = unix.IoctlSetTermios(fileDescriptor, tcSetReq, &old) |
| 52 | + } |
| 53 | +} |
0 commit comments