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