Download
39 lines 1 KiBGoModified 2026-10-31 raw
123456789101112131415161718192021222324252627282930313233343536373839
package pty

import (
	"fmt"
	"os"
	"syscall"
	"unsafe"
)

// getTermios and setTermios are the ioctls that get and set a
// terminal's settings (see KeyMode).
const getTermios, setTermios = syscall.TCGETS, syscall.TCSETS

// Open opens a new pseudo-terminal: the master, which the opener reads and
// writes, and the slave, the terminal a command gets.
func Open() (master, slave *os.File, err error) {
	m, err := os.OpenFile("/dev/ptmx", os.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
	if err != nil {
		return nil, nil, err
	}
	defer func() {
		if err != nil {
			m.Close()
		}
	}()
	var unlock int32
	if err := ioctl(m, syscall.TIOCSPTLCK, unsafe.Pointer(&unlock)); err != nil {
		return nil, nil, fmt.Errorf("unlocking the pty: %w", err)
	}
	var n uint32
	if err := ioctl(m, syscall.TIOCGPTN, unsafe.Pointer(&n)); err != nil {
		return nil, nil, fmt.Errorf("numbering the pty: %w", err)
	}
	s, err := os.OpenFile(fmt.Sprintf("/dev/pts/%d", n), os.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
	if err != nil {
		return nil, nil, err
	}
	return m, s, nil
}