mirror of https://github.com/coder/coder.git
128 lines
3.3 KiB
Go
128 lines
3.3 KiB
Go
|
//go:build !windows
|
||
|
|
||
|
package pty
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
|
||
|
"github.com/gliderlabs/ssh"
|
||
|
"github.com/u-root/u-root/pkg/termios"
|
||
|
gossh "golang.org/x/crypto/ssh"
|
||
|
"golang.org/x/xerrors"
|
||
|
)
|
||
|
|
||
|
// terminalModeFlagNames maps the SSH terminal mode flags to mnemonic
|
||
|
// names used by the termios package.
|
||
|
var terminalModeFlagNames = map[uint8]string{
|
||
|
gossh.VINTR: "intr",
|
||
|
gossh.VQUIT: "quit",
|
||
|
gossh.VERASE: "erase",
|
||
|
gossh.VKILL: "kill",
|
||
|
gossh.VEOF: "eof",
|
||
|
gossh.VEOL: "eol",
|
||
|
gossh.VEOL2: "eol2",
|
||
|
gossh.VSTART: "start",
|
||
|
gossh.VSTOP: "stop",
|
||
|
gossh.VSUSP: "susp",
|
||
|
gossh.VDSUSP: "dsusp",
|
||
|
gossh.VREPRINT: "rprnt",
|
||
|
gossh.VWERASE: "werase",
|
||
|
gossh.VLNEXT: "lnext",
|
||
|
gossh.VFLUSH: "flush",
|
||
|
gossh.VSWTCH: "swtch",
|
||
|
gossh.VSTATUS: "status",
|
||
|
gossh.VDISCARD: "discard",
|
||
|
gossh.IGNPAR: "ignpar",
|
||
|
gossh.PARMRK: "parmrk",
|
||
|
gossh.INPCK: "inpck",
|
||
|
gossh.ISTRIP: "istrip",
|
||
|
gossh.INLCR: "inlcr",
|
||
|
gossh.IGNCR: "igncr",
|
||
|
gossh.ICRNL: "icrnl",
|
||
|
gossh.IUCLC: "iuclc",
|
||
|
gossh.IXON: "ixon",
|
||
|
gossh.IXANY: "ixany",
|
||
|
gossh.IXOFF: "ixoff",
|
||
|
gossh.IMAXBEL: "imaxbel",
|
||
|
gossh.IUTF8: "iutf8",
|
||
|
gossh.ISIG: "isig",
|
||
|
gossh.ICANON: "icanon",
|
||
|
gossh.XCASE: "xcase",
|
||
|
gossh.ECHO: "echo",
|
||
|
gossh.ECHOE: "echoe",
|
||
|
gossh.ECHOK: "echok",
|
||
|
gossh.ECHONL: "echonl",
|
||
|
gossh.NOFLSH: "noflsh",
|
||
|
gossh.TOSTOP: "tostop",
|
||
|
gossh.IEXTEN: "iexten",
|
||
|
gossh.ECHOCTL: "echoctl",
|
||
|
gossh.ECHOKE: "echoke",
|
||
|
gossh.PENDIN: "pendin",
|
||
|
gossh.OPOST: "opost",
|
||
|
gossh.OLCUC: "olcuc",
|
||
|
gossh.ONLCR: "onlcr",
|
||
|
gossh.OCRNL: "ocrnl",
|
||
|
gossh.ONOCR: "onocr",
|
||
|
gossh.ONLRET: "onlret",
|
||
|
gossh.CS7: "cs7",
|
||
|
gossh.CS8: "cs8",
|
||
|
gossh.PARENB: "parenb",
|
||
|
gossh.PARODD: "parodd",
|
||
|
gossh.TTY_OP_ISPEED: "tty_op_ispeed",
|
||
|
gossh.TTY_OP_OSPEED: "tty_op_ospeed",
|
||
|
}
|
||
|
|
||
|
// applyTerminalModesToFd applies the terminal settings from the SSH
|
||
|
// request to the given fd.
|
||
|
//
|
||
|
// This is based on code from Tailscale's tailssh package:
|
||
|
// https://github.com/tailscale/tailscale/blob/main/ssh/tailssh/incubator.go
|
||
|
func applyTerminalModesToFd(logger *log.Logger, fd uintptr, req ssh.Pty) error {
|
||
|
// Get the current TTY configuration.
|
||
|
tios, err := termios.GTTY(int(fd))
|
||
|
if err != nil {
|
||
|
return xerrors.Errorf("GTTY: %w", err)
|
||
|
}
|
||
|
|
||
|
// Apply the modes from the SSH request.
|
||
|
tios.Row = req.Window.Height
|
||
|
tios.Col = req.Window.Width
|
||
|
|
||
|
for c, v := range req.Modes {
|
||
|
if c == gossh.TTY_OP_ISPEED {
|
||
|
tios.Ispeed = int(v)
|
||
|
continue
|
||
|
}
|
||
|
if c == gossh.TTY_OP_OSPEED {
|
||
|
tios.Ospeed = int(v)
|
||
|
continue
|
||
|
}
|
||
|
k, ok := terminalModeFlagNames[c]
|
||
|
if !ok {
|
||
|
if logger != nil {
|
||
|
logger.Printf("unknown terminal mode: %d", c)
|
||
|
}
|
||
|
continue
|
||
|
}
|
||
|
if _, ok := tios.CC[k]; ok {
|
||
|
tios.CC[k] = uint8(v)
|
||
|
continue
|
||
|
}
|
||
|
if _, ok := tios.Opts[k]; ok {
|
||
|
tios.Opts[k] = v > 0
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if logger != nil {
|
||
|
logger.Printf("unsupported terminal mode: k=%s, c=%d, v=%d", k, c, v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Save the new TTY configuration.
|
||
|
if _, err := tios.STTY(int(fd)); err != nil {
|
||
|
return xerrors.Errorf("STTY: %w", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|