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