github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/installer/pty.go (about)

     1  // +build linux
     2  
     3  package main
     4  
     5  import (
     6  	"os"
     7  	"strconv"
     8  	"syscall"
     9  	"unsafe"
    10  
    11  	"github.com/Cloud-Foundations/Dominator/lib/wsyscall"
    12  )
    13  
    14  func openPty() (pty, tty *os.File, err error) {
    15  	p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0)
    16  	if err != nil {
    17  		return nil, nil, err
    18  	}
    19  	// In case of error after this point, make sure we close the ptmx fd.
    20  	defer func() {
    21  		if err != nil {
    22  			p.Close() // Best effort.
    23  		}
    24  	}()
    25  	sname, err := ptsname(p)
    26  	if err != nil {
    27  		return nil, nil, err
    28  	}
    29  	if err := unlockpt(p); err != nil {
    30  		return nil, nil, err
    31  	}
    32  	t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0)
    33  	if err != nil {
    34  		return nil, nil, err
    35  	}
    36  	return p, t, nil
    37  }
    38  
    39  func ptsname(f *os.File) (string, error) {
    40  	var n uint32
    41  	err := wsyscall.Ioctl(int(f.Fd()), syscall.TIOCGPTN,
    42  		uintptr(unsafe.Pointer(&n)))
    43  	if err != nil {
    44  		return "", err
    45  	}
    46  	return "/dev/pts/" + strconv.Itoa(int(n)), nil
    47  }
    48  
    49  func unlockpt(f *os.File) error {
    50  	var u int32
    51  	// Use TIOCSPTLCK with a zero valued arg to clear the slave pty lock.
    52  	return wsyscall.Ioctl(int(f.Fd()), syscall.TIOCSPTLCK,
    53  		uintptr(unsafe.Pointer(&u)))
    54  }