You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
2.8 KiB
Go

package commands
import (
"errors"
"log"
"strconv"
"golang.org/x/sys/unix"
)
func Control(c rune) rune {
return c & 0x1f
}
func sttyCharFromDesc(c string) (rune, error) {
if len(c) > 2 || len(c) < 1 {
return 'i', errors.New(
"stty char description has unsupported length: " +
strconv.Itoa(len(c)),
)
}
if rune(c[0]) == '^' {
return Control(rune(c[1])), nil
}
return rune(c[0]), nil
}
const fakeUname = "Linux 5.16.19-76051619-generic"
type CommandExecutor interface {
Execute(shell *Shell, args []string) error
}
type SttyCommand struct{}
func (c *SttyCommand) Execute(shell *Shell, args []string) error {
// Tramp uses:
// -inlcr: don't translate newline to carriage return
// -onlcr: don't translate newline to carriage return-newline
// -echo: echo input characters
// kill CHAR: CHAR will erase the current line
// erase CHAR: CHAR will erase the last character typed
// icanon: enable special charactersq
fd := int(shell.GetPty().Fd())
const ioctlReadTermios = unix.TCGETS // Linux
const ioctlWriteTermios = unix.TCSETS // Linux
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
panic(err)
}
newState := *termios
var skipNext bool
for i, arg := range args {
if skipNext {
skipNext = false
continue
}
var disable bool
if arg[0] == '-' {
disable = true
arg = arg[1:]
}
switch arg {
case "onlcr":
if disable {
newState.Iflag &^= unix.ONLCR
continue
}
newState.Iflag |= unix.ONLCR
case "inlcr":
if disable {
newState.Iflag &^= unix.INLCR
continue
}
newState.Iflag |= unix.INLCR
case "echo":
if disable {
newState.Lflag &^= unix.ECHO
continue
}
newState.Lflag |= unix.ECHO
case "kill":
skipNext = true
char, err := sttyCharFromDesc(args[i+1])
if err != nil {
log.Printf(
"Warning: Not applying unsupported character description for stty kill: %s",
args[i+1],
)
continue
}
newState.Cc[unix.VKILL] = uint8(char)
case "erase":
skipNext = true
char, err := sttyCharFromDesc(args[i+1])
if err != nil {
log.Printf(
"Warning: Not applying unsupported character description for stty erase: %s",
args[i+1],
)
continue
}
newState.Cc[unix.VERASE] = uint8(char)
case "icanon":
if disable {
newState.Lflag &^= unix.ICANON
continue
}
newState.Lflag |= unix.ICANON
case "tab0":
newState.Oflag = (newState.Oflag & ^uint32(unix.TABDLY)) | unix.TAB0
case "iutf8":
if disable {
newState.Iflag &^= unix.IUTF8
continue
}
newState.Iflag |= unix.IUTF8
default:
log.Printf(
"Warning, tramp requested unexpected stty option %s",
arg,
)
}
}
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil {
return err
}
return nil
}