mirror of
https://github.com/creack/pty.git
synced 2026-03-31 02:27:08 +09:00
Do not set file descriptor into blocking mode
(*os.File).Fd() implicitly sets file descriptor into blocking mode [1], [2] We avoid that by calling (*os.File).SyscallConn instead. This method was added in go1.12 (released on 2019-02-25) [1]: https://pkg.go.dev/os#File.Fd [2]: https://cs.opensource.google/go/go/+/refs/tags/go1.20.3:src/os/file_unix.go;l=80-87
This commit is contained in:
@@ -10,7 +10,7 @@ const (
|
||||
TIOCSWINSZ = syscall.TIOCSWINSZ
|
||||
)
|
||||
|
||||
func ioctl(fd, cmd, ptr uintptr) error {
|
||||
func ioctl_inner(fd, cmd, ptr uintptr) error {
|
||||
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
|
||||
if e != 0 {
|
||||
return e
|
||||
24
ioctl_outer.go
Normal file
24
ioctl_outer.go
Normal file
@@ -0,0 +1,24 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
//
|
||||
package pty
|
||||
|
||||
import "os"
|
||||
|
||||
func ioctl(f *os.File, cmd, ptr uintptr) error {
|
||||
sc, e := f.SyscallConn()
|
||||
if e != nil {
|
||||
return ioctl_inner(f.Fd(), cmd, ptr) // fall back to blocking io (old behavior)
|
||||
}
|
||||
|
||||
ch := make(chan error, 1)
|
||||
defer close(ch)
|
||||
|
||||
e = sc.Control(func(fd uintptr) { ch <- ioctl_inner(fd, cmd, ptr) })
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
e = <-ch
|
||||
return e
|
||||
}
|
||||
@@ -40,7 +40,7 @@ type strioctl struct {
|
||||
// Defined in asm_solaris_amd64.s.
|
||||
func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
|
||||
func ioctl(fd, cmd, ptr uintptr) error {
|
||||
func ioctl_inner(fd, cmd, ptr uintptr) error {
|
||||
if _, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, fd, cmd, ptr, 0, 0, 0); errno != 0 {
|
||||
return errno
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ const (
|
||||
TIOCSWINSZ = 0
|
||||
)
|
||||
|
||||
func ioctl(fd, cmd, ptr uintptr) error {
|
||||
func ioctl_inner(fd, cmd, ptr uintptr) error {
|
||||
return ErrUnsupported
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func open() (pty, tty *os.File, err error) {
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
n := make([]byte, _IOC_PARM_LEN(syscall.TIOCPTYGNAME))
|
||||
|
||||
err := ioctl(f.Fd(), syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0])))
|
||||
err := ioctl(f, syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0])))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -60,9 +60,9 @@ func ptsname(f *os.File) (string, error) {
|
||||
}
|
||||
|
||||
func grantpt(f *os.File) error {
|
||||
return ioctl(f.Fd(), syscall.TIOCPTYGRANT, 0)
|
||||
return ioctl(f, syscall.TIOCPTYGRANT, 0)
|
||||
}
|
||||
|
||||
func unlockpt(f *os.File) error {
|
||||
return ioctl(f.Fd(), syscall.TIOCPTYUNLK, 0)
|
||||
return ioctl(f, syscall.TIOCPTYUNLK, 0)
|
||||
}
|
||||
|
||||
@@ -45,17 +45,17 @@ func open() (pty, tty *os.File, err error) {
|
||||
}
|
||||
|
||||
func grantpt(f *os.File) error {
|
||||
_, err := isptmaster(f.Fd())
|
||||
_, err := isptmaster(f)
|
||||
return err
|
||||
}
|
||||
|
||||
func unlockpt(f *os.File) error {
|
||||
_, err := isptmaster(f.Fd())
|
||||
_, err := isptmaster(f)
|
||||
return err
|
||||
}
|
||||
|
||||
func isptmaster(fd uintptr) (bool, error) {
|
||||
err := ioctl(fd, syscall.TIOCISPTMASTER, 0)
|
||||
func isptmaster(f *os.File) (bool, error) {
|
||||
err := ioctl(f, syscall.TIOCISPTMASTER, 0)
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func ptsname(f *os.File) (string, error) {
|
||||
name := make([]byte, _C_SPECNAMELEN)
|
||||
fa := fiodgnameArg{Name: (*byte)(unsafe.Pointer(&name[0])), Len: _C_SPECNAMELEN, Pad_cgo_0: [4]byte{0, 0, 0, 0}}
|
||||
|
||||
err := ioctl(f.Fd(), ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa)))
|
||||
err := ioctl(f, ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ func open() (pty, tty *os.File, err error) {
|
||||
return p, t, nil
|
||||
}
|
||||
|
||||
func isptmaster(fd uintptr) (bool, error) {
|
||||
err := ioctl(fd, syscall.TIOCPTMASTER, 0)
|
||||
func isptmaster(f *os.File) (bool, error) {
|
||||
err := ioctl(f, syscall.TIOCPTMASTER, 0)
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ var (
|
||||
)
|
||||
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
master, err := isptmaster(f.Fd())
|
||||
master, err := isptmaster(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func ptsname(f *os.File) (string, error) {
|
||||
buf = make([]byte, n)
|
||||
arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))}
|
||||
)
|
||||
if err := ioctl(f.Fd(), ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil {
|
||||
if err := ioctl(f, ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ func open() (pty, tty *os.File, err error) {
|
||||
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
var n _C_uint
|
||||
err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) //nolint:gosec // Expected unsafe pointer for Syscall call.
|
||||
err := ioctl(f, syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) //nolint:gosec // Expected unsafe pointer for Syscall call.
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -50,5 +50,5 @@ func ptsname(f *os.File) (string, error) {
|
||||
func unlockpt(f *os.File) error {
|
||||
var u _C_int
|
||||
// use TIOCSPTLCK with a pointer to zero to clear the lock
|
||||
return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) //nolint:gosec // Expected unsafe pointer for Syscall call.
|
||||
return ioctl(f, syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) //nolint:gosec // Expected unsafe pointer for Syscall call.
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func ptsname(f *os.File) (string, error) {
|
||||
* ioctl(fd, TIOCPTSNAME, &pm) == -1 ? NULL : pm.sn;
|
||||
*/
|
||||
var ptm ptmget
|
||||
if err := ioctl(f.Fd(), uintptr(ioctl_TIOCPTSNAME), uintptr(unsafe.Pointer(&ptm))); err != nil {
|
||||
if err := ioctl(f, uintptr(ioctl_TIOCPTSNAME), uintptr(unsafe.Pointer(&ptm))); err != nil {
|
||||
return "", err
|
||||
}
|
||||
name := make([]byte, len(ptm.Sn))
|
||||
@@ -65,5 +65,5 @@ func grantpt(f *os.File) error {
|
||||
* from grantpt(3): Calling grantpt() is equivalent to:
|
||||
* ioctl(fd, TIOCGRANTPT, 0);
|
||||
*/
|
||||
return ioctl(f.Fd(), uintptr(ioctl_TIOCGRANTPT), 0)
|
||||
return ioctl(f, uintptr(ioctl_TIOCGRANTPT), 0)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func open() (pty, tty *os.File, err error) {
|
||||
defer p.Close()
|
||||
|
||||
var ptm ptmget
|
||||
if err := ioctl(p.Fd(), uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil {
|
||||
if err := ioctl(p, uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ func open() (pty, tty *os.File, err error) {
|
||||
}
|
||||
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
dev, err := ptsdev(f.Fd())
|
||||
dev, err := ptsdev(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -84,12 +84,12 @@ func unlockpt(f *os.File) error {
|
||||
icLen: 0,
|
||||
icDP: nil,
|
||||
}
|
||||
return ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr)))
|
||||
return ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr)))
|
||||
}
|
||||
|
||||
func minor(x uint64) uint64 { return x & 0377 }
|
||||
|
||||
func ptsdev(fd uintptr) (uint64, error) {
|
||||
func ptsdev(f *os.File) (uint64, error) {
|
||||
istr := strioctl{
|
||||
icCmd: ISPTM,
|
||||
icTimeout: 0,
|
||||
@@ -97,14 +97,33 @@ func ptsdev(fd uintptr) (uint64, error) {
|
||||
icDP: nil,
|
||||
}
|
||||
|
||||
if err := ioctl(fd, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
|
||||
if err := ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var status syscall.Stat_t
|
||||
if err := syscall.Fstat(int(fd), &status); err != nil {
|
||||
var errors = make(chan error, 1)
|
||||
var results = make(chan uint64, 1)
|
||||
defer close(errors)
|
||||
defer close(results)
|
||||
|
||||
var err error
|
||||
var sc syscall.RawConn
|
||||
sc, err = f.SyscallConn()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(minor(status.Rdev)), nil
|
||||
err = sc.Control(func(fd uintptr) {
|
||||
var status syscall.Stat_t
|
||||
if err := syscall.Fstat(int(fd), &status); err != nil {
|
||||
results <- 0
|
||||
errors <- err
|
||||
}
|
||||
results <- uint64(minor(status.Rdev))
|
||||
errors <- nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return <-results, <-errors
|
||||
}
|
||||
|
||||
type ptOwn struct {
|
||||
@@ -113,7 +132,7 @@ type ptOwn struct {
|
||||
}
|
||||
|
||||
func grantpt(f *os.File) error {
|
||||
if _, err := ptsdev(f.Fd()); err != nil {
|
||||
if _, err := ptsdev(f); err != nil {
|
||||
return err
|
||||
}
|
||||
pto := ptOwn{
|
||||
@@ -127,7 +146,7 @@ func grantpt(f *os.File) error {
|
||||
icLen: int32(unsafe.Sizeof(strioctl{})),
|
||||
icDP: unsafe.Pointer(&pto),
|
||||
}
|
||||
if err := ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
|
||||
if err := ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
return nil
|
||||
@@ -145,8 +164,8 @@ func streamsPush(f *os.File, mod string) error {
|
||||
// but since we are not using libc or XPG4.2, we should not be
|
||||
// double-pushing modules
|
||||
|
||||
if err := ioctl(f.Fd(), I_FIND, uintptr(unsafe.Pointer(&buf[0]))); err != nil {
|
||||
if err := ioctl(f, I_FIND, uintptr(unsafe.Pointer(&buf[0]))); err != nil {
|
||||
return nil
|
||||
}
|
||||
return ioctl(f.Fd(), I_PUSH, uintptr(unsafe.Pointer(&buf[0])))
|
||||
return ioctl(f, I_PUSH, uintptr(unsafe.Pointer(&buf[0])))
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type Winsize struct {
|
||||
// Setsize resizes t to s.
|
||||
func Setsize(t *os.File, ws *Winsize) error {
|
||||
//nolint:gosec // Expected unsafe pointer for Syscall call.
|
||||
return ioctl(t.Fd(), syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(ws)))
|
||||
return ioctl(t, syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(ws)))
|
||||
}
|
||||
|
||||
// GetsizeFull returns the full terminal size description.
|
||||
@@ -28,7 +28,7 @@ func GetsizeFull(t *os.File) (size *Winsize, err error) {
|
||||
var ws Winsize
|
||||
|
||||
//nolint:gosec // Expected unsafe pointer for Syscall call.
|
||||
if err := ioctl(t.Fd(), syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))); err != nil {
|
||||
if err := ioctl(t, syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ws, nil
|
||||
|
||||
Reference in New Issue
Block a user