github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/termios/termios_linux.go (about) 1 // Copyright 2015-2017 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !plan9 6 7 package termios 8 9 import ( 10 "fmt" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "syscall" 15 16 "golang.org/x/sys/unix" 17 ) 18 19 type TTYIO struct { 20 f *os.File 21 } 22 23 // Winsize embeds unix.Winsize. 24 type Winsize struct { 25 unix.Winsize 26 } 27 28 // New creates a new TTYIO using /dev/tty 29 func New() (*TTYIO, error) { 30 return NewWithDev("/dev/tty") 31 } 32 33 // NewWithDev creates a new TTYIO with the specified device 34 func NewWithDev(device string) (*TTYIO, error) { 35 f, err := os.OpenFile(device, os.O_RDWR, 0) 36 if err != nil { 37 return nil, err 38 } 39 return &TTYIO{f: f}, nil 40 } 41 42 // NewTTYS returns a new TTYIO. 43 func NewTTYS(port string) (*TTYIO, error) { 44 f, err := os.OpenFile(filepath.Join("/dev", port), unix.O_RDWR|unix.O_NOCTTY|unix.O_NONBLOCK, 0620) 45 if err != nil { 46 return nil, err 47 } 48 return &TTYIO{f: f}, nil 49 } 50 51 // GetTermios returns a filled-in Termios, from an fd. 52 func GetTermios(fd uintptr) (*Termios, error) { 53 t, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) 54 if err != nil { 55 return nil, err 56 } 57 return &Termios{Termios: t}, nil 58 } 59 60 // Get terms a Termios from a TTYIO. 61 func (t *TTYIO) Get() (*Termios, error) { 62 return GetTermios(t.f.Fd()) 63 } 64 65 // SetTermios sets tty parameters for an fd from a Termios. 66 func SetTermios(fd uintptr, ti *Termios) error { 67 return unix.IoctlSetTermios(int(fd), unix.TCSETS, ti.Termios) 68 } 69 70 // Set sets tty parameters for a TTYIO from a Termios. 71 func (t *TTYIO) Set(ti *Termios) error { 72 return SetTermios(t.f.Fd(), ti) 73 } 74 75 // GetWinSize gets window size from an fd. 76 func GetWinSize(fd uintptr) (*Winsize, error) { 77 w, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) 78 return &Winsize{Winsize: *w}, err 79 } 80 81 // GetWinSize gets window size from a TTYIO. 82 func (t *TTYIO) GetWinSize() (*Winsize, error) { 83 return GetWinSize(t.f.Fd()) 84 } 85 86 // SetWinSize sets window size for an fd from a Winsize. 87 func SetWinSize(fd uintptr, w *Winsize) error { 88 return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &w.Winsize) 89 } 90 91 // SetWinSize sets window size for a TTYIO from a Winsize. 92 func (t *TTYIO) SetWinSize(w *Winsize) error { 93 return SetWinSize(t.f.Fd(), w) 94 } 95 96 // Ctty sets the control tty into a Cmd, from a TTYIO. 97 func (t *TTYIO) Ctty(c *exec.Cmd) { 98 c.Stdin, c.Stdout, c.Stderr = t.f, t.f, t.f 99 if c.SysProcAttr == nil { 100 c.SysProcAttr = &syscall.SysProcAttr{} 101 } 102 c.SysProcAttr.Setctty = true 103 c.SysProcAttr.Setsid = true 104 c.SysProcAttr.Ctty = int(t.f.Fd()) 105 } 106 107 // MakeRaw modifies Termio state so, if it used for an fd or tty, it will set it to raw mode. 108 func MakeRaw(term *Termios) *Termios { 109 raw := *term 110 raw.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON 111 raw.Oflag &^= unix.OPOST 112 raw.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN 113 raw.Cflag &^= unix.CSIZE | unix.PARENB 114 raw.Cflag |= unix.CS8 115 116 raw.Cc[unix.VMIN] = 1 117 raw.Cc[unix.VTIME] = 0 118 119 return &raw 120 } 121 122 // MakeSerialBaud updates the Termios to set the baudrate 123 func MakeSerialBaud(term *Termios, baud int) (*Termios, error) { 124 t := *term 125 rate, ok := baud2unixB[baud] 126 if !ok { 127 return nil, fmt.Errorf("%d: Unrecognized baud rate", baud) 128 } 129 130 t.Cflag &^= unix.CBAUD 131 t.Cflag |= rate 132 t.Ispeed = rate 133 t.Ospeed = rate 134 135 return &t, nil 136 } 137 138 // MakeSerialDefault updates the Termios to typical serial configuration: 139 // - Ignore all flow control (modem, hardware, software...) 140 // - Translate carriage return to newline on input 141 // - Enable canonical mode: Input is available line by line, with line editing 142 // enabled (ERASE, KILL are supported) 143 // - Local ECHO is added (and handled by line editing) 144 // - Map newline to carriage return newline on output 145 func MakeSerialDefault(term *Termios) *Termios { 146 t := *term 147 /* Clear all except baud, stop bit and parity settings */ 148 t.Cflag &= unix.CBAUD | unix.CSTOPB | unix.PARENB | unix.PARODD 149 /* Set: 8 bits; ignore Carrier Detect; enable receive */ 150 t.Cflag |= unix.CS8 | unix.CLOCAL | unix.CREAD 151 t.Iflag = unix.ICRNL 152 t.Lflag = unix.ICANON | unix.ISIG | unix.ECHO | unix.ECHOE | unix.ECHOK | unix.ECHOKE | unix.ECHOCTL 153 /* non-raw output; add CR to each NL */ 154 t.Oflag = unix.OPOST | unix.ONLCR 155 /* reads will block only if < 1 char is available */ 156 t.Cc[unix.VMIN] = 1 157 /* no timeout (reads block forever) */ 158 t.Cc[unix.VTIME] = 0 159 t.Line = 0 160 161 return &t 162 }