podman
47 строк · 1.6 Кб
1//go:build linux
2// +build linux
3
4package chroot5
6import (7"fmt"8"os"9"syscall"10"unsafe"11
12"golang.org/x/sys/unix"13)
14
15// Open a PTY using the /dev/ptmx device. The main advantage of using
16// this instead of posix_openpt is that it avoids cgo.
17func getPtyDescriptors() (int, int, error) {18// Create a pseudo-terminal -- open a copy of the master side.19controlFd, err := unix.Open("/dev/ptmx", os.O_RDWR, 0600)20if err != nil {21return -1, -1, fmt.Errorf("opening PTY master using /dev/ptmx: %v", err)22}23// Set the kernel's lock to "unlocked".24locked := 025if result, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(controlFd), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&locked))); int(result) == -1 {26return -1, -1, fmt.Errorf("unlocking PTY descriptor: %v", err)27}28// Get a handle for the other end.29ptyFd, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(controlFd), unix.TIOCGPTPEER, unix.O_RDWR|unix.O_NOCTTY)30if int(ptyFd) == -1 {31if errno, isErrno := err.(syscall.Errno); !isErrno || (errno != syscall.EINVAL && errno != syscall.ENOTTY) {32return -1, -1, fmt.Errorf("getting PTY descriptor: %v", err)33}34// EINVAL means the kernel's too old to understand TIOCGPTPEER. Try TIOCGPTN.35ptyN, err := unix.IoctlGetInt(controlFd, unix.TIOCGPTN)36if err != nil {37return -1, -1, fmt.Errorf("getting PTY number: %v", err)38}39ptyName := fmt.Sprintf("/dev/pts/%d", ptyN)40fd, err := unix.Open(ptyName, unix.O_RDWR|unix.O_NOCTTY, 0620)41if err != nil {42return -1, -1, fmt.Errorf("opening PTY %q: %v", ptyName, err)43}44ptyFd = uintptr(fd)45}46return controlFd, int(ptyFd), nil47}
48