...

Source file src/github.com/Microsoft/hcsshim/internal/guest/stdio/tty.go

Documentation: github.com/Microsoft/hcsshim/internal/guest/stdio

     1  //go:build linux
     2  // +build linux
     3  
     4  package stdio
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"syscall"
    10  	"unsafe"
    11  
    12  	"github.com/pkg/errors"
    13  	"golang.org/x/sys/unix"
    14  )
    15  
    16  // NewConsole allocates a new console and returns the File for its master and
    17  // path for its slave.
    18  func NewConsole() (*os.File, string, error) {
    19  	master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
    20  	if err != nil {
    21  		return nil, "", errors.Wrap(err, "failed to open master pseudoterminal file")
    22  	}
    23  	console, err := ptsname(master)
    24  	if err != nil {
    25  		return nil, "", err
    26  	}
    27  	if err := unlockpt(master); err != nil {
    28  		return nil, "", err
    29  	}
    30  	// TODO: Do we need to keep this chmod call?
    31  	if err := os.Chmod(console, 0600); err != nil {
    32  		return nil, "", errors.Wrap(err, "failed to change permissions on the slave pseudoterminal file")
    33  	}
    34  	if err := os.Chown(console, 0, 0); err != nil {
    35  		return nil, "", errors.Wrap(err, "failed to change ownership on the slave pseudoterminal file")
    36  	}
    37  	return master, console, nil
    38  }
    39  
    40  // ResizeConsole sends the appropriate resize to a pTTY FD
    41  // Synchronization of pty should be handled in the callers context.
    42  func ResizeConsole(pty *os.File, height, width uint16) error {
    43  	type consoleSize struct {
    44  		Height uint16
    45  		Width  uint16
    46  		x      uint16
    47  		y      uint16
    48  	}
    49  
    50  	return ioctl(pty.Fd(), uintptr(unix.TIOCSWINSZ), uintptr(unsafe.Pointer(&consoleSize{Height: height, Width: width})))
    51  }
    52  
    53  func ioctl(fd uintptr, flag, data uintptr) error {
    54  	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 {
    55  		return err
    56  	}
    57  	return nil
    58  }
    59  
    60  // ptsname is a Go wrapper around the ptsname system call. It returns the name
    61  // of the slave pseudoterminal device corresponding to the given master.
    62  func ptsname(f *os.File) (string, error) {
    63  	var n int32
    64  	if err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil {
    65  		return "", errors.Wrap(err, "ioctl TIOCGPTN failed for ptsname")
    66  	}
    67  	return fmt.Sprintf("/dev/pts/%d", n), nil
    68  }
    69  
    70  // unlockpt is a Go wrapper around the unlockpt system call. It unlocks the
    71  // slave pseudoterminal device corresponding to the given master.
    72  func unlockpt(f *os.File) error {
    73  	var u int32
    74  	if err := ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != nil {
    75  		return errors.Wrap(err, "ioctl TIOCSPTLCK failed for unlockpt")
    76  	}
    77  	return nil
    78  }
    79  

View as plain text