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  }