Download
36 lines 1.1 KiBGoModified 2026-10-30 raw
123456789101112131415161718192021222324252627282930313233343536
// Package pty opens pseudo-terminals, for running a command on a terminal
// of its own: the sandbox command gives one to an interactive program
// instead of the user's real terminal.
package pty

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

// ioctl calls ioctl(2) on f. Through the file's raw connection, not Fd,
// which would make it blocking: a pending Read must end when f is closed.
func ioctl(f *os.File, req uintptr, arg unsafe.Pointer) error {
	conn, err := f.SyscallConn()
	if err != nil {
		return err
	}
	var errno syscall.Errno
	if err := conn.Control(func(fd uintptr) {
		_, _, errno = syscall.Syscall(syscall.SYS_IOCTL, fd, req, uintptr(arg))
	}); err != nil {
		return err
	}
	if errno != 0 {
		return errno
	}
	return nil
}

// SetSize sets a terminal's size, in columns and rows. On a pty, the
// kernel tells the programs on it (SIGWINCH).
func SetSize(f *os.File, cols, rows int) error {
	ws := struct{ Row, Col, X, Y uint16 }{Row: uint16(min(max(rows, 1), 0xffff)), Col: uint16(min(max(cols, 1), 0xffff))}
	return ioctl(f, syscall.TIOCSWINSZ, unsafe.Pointer(&ws))
}