mirror of
https://github.com/lxc/incus.git
synced 2026-02-05 18:45:46 +01:00
145 lines
3.5 KiB
Go
145 lines
3.5 KiB
Go
package linux
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
"github.com/lxc/incus/v6/shared/revert"
|
|
)
|
|
|
|
// OpenPtyInDevpts creates a new PTS pair, configures them and returns them.
|
|
func OpenPtyInDevpts(devpts_fd int, uid, gid int64) (*os.File, *os.File, error) {
|
|
reverter := revert.New()
|
|
defer reverter.Fail()
|
|
|
|
var fd int
|
|
var ptx *os.File
|
|
var err error
|
|
|
|
// Create a PTS pair.
|
|
if devpts_fd >= 0 {
|
|
fd, err = unix.Openat(devpts_fd, "ptmx", unix.O_RDWR|unix.O_CLOEXEC|unix.O_NOCTTY, 0)
|
|
} else {
|
|
fd, err = unix.Openat(-1, "/dev/ptmx", unix.O_RDWR|unix.O_CLOEXEC|unix.O_NOCTTY, 0)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
ptx = os.NewFile(uintptr(fd), "/dev/pts/ptmx")
|
|
reverter.Add(func() { _ = ptx.Close() })
|
|
|
|
// Unlock the ptx and pty.
|
|
val := 0
|
|
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(ptx.Fd()), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&val)))
|
|
if errno != 0 {
|
|
return nil, nil, unix.Errno(errno)
|
|
}
|
|
|
|
var pty *os.File
|
|
ptyFd, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(ptx.Fd()), unix.TIOCGPTPEER, uintptr(unix.O_NOCTTY|unix.O_CLOEXEC|os.O_RDWR))
|
|
// We can only fallback to looking up the fd in /dev/pts when we aren't dealing with the container's devpts instance.
|
|
if errno == 0 {
|
|
// Get the pty side.
|
|
id := 0
|
|
_, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(ptx.Fd()), unix.TIOCGPTN, uintptr(unsafe.Pointer(&id)))
|
|
if errno != 0 {
|
|
return nil, nil, unix.Errno(errno)
|
|
}
|
|
|
|
pty = os.NewFile(ptyFd, fmt.Sprintf("/dev/pts/%d", id))
|
|
} else {
|
|
if devpts_fd >= 0 {
|
|
return nil, nil, errors.New("TIOCGPTPEER required but not available")
|
|
}
|
|
|
|
// Get the pty side.
|
|
id := 0
|
|
_, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(ptx.Fd()), unix.TIOCGPTN, uintptr(unsafe.Pointer(&id)))
|
|
if errno != 0 {
|
|
return nil, nil, unix.Errno(errno)
|
|
}
|
|
|
|
// Open the pty.
|
|
pty, err = os.OpenFile(fmt.Sprintf("/dev/pts/%d", id), unix.O_NOCTTY|unix.O_CLOEXEC|os.O_RDWR, 0)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
|
|
reverter.Add(func() { _ = pty.Close() })
|
|
|
|
// Configure both sides
|
|
for _, entry := range []*os.File{ptx, pty} {
|
|
// Get termios.
|
|
t, err := unix.IoctlGetTermios(int(entry.Fd()), unix.TCGETS)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Set flags.
|
|
t.Cflag |= unix.IMAXBEL
|
|
t.Cflag |= unix.IUTF8
|
|
t.Cflag |= unix.BRKINT
|
|
t.Cflag |= unix.IXANY
|
|
t.Cflag |= unix.HUPCL
|
|
|
|
// Set termios.
|
|
err = unix.IoctlSetTermios(int(entry.Fd()), unix.TCSETS, t)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Set the default window size.
|
|
sz := &unix.Winsize{
|
|
Col: 80,
|
|
Row: 25,
|
|
}
|
|
|
|
err = unix.IoctlSetWinsize(int(entry.Fd()), unix.TIOCSWINSZ, sz)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Set CLOEXEC.
|
|
_, _, errno = unix.Syscall(unix.SYS_FCNTL, uintptr(entry.Fd()), unix.F_SETFD, unix.FD_CLOEXEC)
|
|
if errno != 0 {
|
|
return nil, nil, unix.Errno(errno)
|
|
}
|
|
}
|
|
|
|
// Fix the ownership of the pty side.
|
|
err = unix.Fchown(int(pty.Fd()), int(uid), int(gid))
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
reverter.Success()
|
|
|
|
return ptx, pty, nil
|
|
}
|
|
|
|
// OpenPty creates a new PTS pair, configures them and returns them.
|
|
func OpenPty(uid, gid int64) (*os.File, *os.File, error) {
|
|
return OpenPtyInDevpts(-1, uid, gid)
|
|
}
|
|
|
|
// SetPtySize issues the correct ioctl to resize a pty.
|
|
func SetPtySize(fd int, width int, height int) (err error) {
|
|
var dimensions [4]uint16
|
|
dimensions[0] = uint16(height)
|
|
dimensions[1] = uint16(width)
|
|
|
|
_, _, errno := unix.Syscall6(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.TIOCSWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0)
|
|
if errno != 0 {
|
|
return errno
|
|
}
|
|
|
|
return nil
|
|
}
|