Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ go get github.com/creack/pty

## Examples

Note that those examples are for demonstration purpose only, to showcase how to use the library. They are not meant to be used in any kind of production environment. If you want to **set deadlines to work** and `Close()` **interrupting** `Read()` on the returned `*os.File`, you will need to call `syscall.SetNonblock` manually.
Note that those examples are for demonstration purpose only, to showcase how to use the library. They are not meant to be used in any kind of production environment.

### Command

Expand Down
7 changes: 0 additions & 7 deletions io_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"os"
"runtime"
"sync"
"syscall"
"testing"
"time"
)
Expand All @@ -30,9 +29,6 @@ var glTestFdLock sync.Mutex
//nolint:paralleltest // Potential in (*os.File).Fd().
func TestReadDeadline(t *testing.T) {
ptmx, success := prepare(t)
if err := syscall.SetNonblock(int(ptmx.Fd()), true); err != nil {
t.Fatalf("Error: set non block: %s", err)
}

if err := ptmx.SetDeadline(time.Now().Add(timeout / 10)); err != nil {
if errors.Is(err, os.ErrNoDeadline) {
Expand Down Expand Up @@ -62,9 +58,6 @@ func TestReadDeadline(t *testing.T) {
//nolint:paralleltest // Potential in (*os.File).Fd().
func TestReadClose(t *testing.T) {
ptmx, success := prepare(t)
if err := syscall.SetNonblock(int(ptmx.Fd()), true); err != nil {
t.Fatalf("Error: set non block: %s", err)
}

go func() {
time.Sleep(timeout / 10)
Expand Down
7 changes: 1 addition & 6 deletions ioctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ package pty

import "os"

func ioctl(f *os.File, cmd, ptr uintptr) error {
return ioctlInner(f.Fd(), cmd, ptr) // Fall back to blocking io.
}

// NOTE: Unused. Keeping for reference.
func ioctlNonblock(f *os.File, cmd, ptr uintptr) error {
func ioctl(f *os.File, cmd uintptr, ptr any) error {
sc, e := f.SyscallConn()
if e != nil {
return ioctlInner(f.Fd(), cmd, ptr) // Fall back to blocking io (old behavior).
Expand Down
18 changes: 13 additions & 5 deletions ioctl_inner.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
//go:build !windows && !solaris && !aix
// +build !windows,!solaris,!aix
//go:build !windows && !solaris && !aix && go1.12
// +build !windows,!solaris,!aix,go1.12

package pty

import "syscall"
import (
"reflect"
"syscall"
)

// Local syscall const values.
const (
TIOCGWINSZ = syscall.TIOCGWINSZ
TIOCSWINSZ = syscall.TIOCSWINSZ
)

func ioctlInner(fd, cmd, ptr uintptr) error {
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
func ioctlInner(fd, cmd uintptr, ptr any) error {
var e syscall.Errno
if ptr == nil {
_, _, e = syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, uintptr(0))
} else {
_, _, e = syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, uintptr(reflect.ValueOf(ptr).UnsafePointer())) //nolint:gosec // ptr-to-uintptr at syscall site.
}
if e != 0 {
return e
}
Expand Down
21 changes: 19 additions & 2 deletions ioctl_legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,25 @@

package pty

import "os"
import (
"os"
"reflect"
"syscall"
)

func ioctl(f *os.File, cmd, ptr uintptr) error {
func ioctl(f *os.File, cmd uintptr, ptr interface{}) error {
return ioctlInner(f.Fd(), cmd, ptr) // fall back to blocking io (old behavior)
}

func ioctlInner(fd, cmd uintptr, ptr interface{}) error {
var e syscall.Errno
if ptr == nil {
_, _, e = syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, uintptr(0))
} else {
_, _, e = syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, reflect.ValueOf(ptr).UnsafeAddr()) //nolint:gosec // ptr-to-uintptr at syscall site.
}
if e != 0 {
return e
}
return nil
}
11 changes: 9 additions & 2 deletions ioctl_solaris.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package pty

import (
"reflect"
"syscall"
"unsafe"
)
Expand Down Expand Up @@ -40,8 +41,14 @@ 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 ioctlInner(fd, cmd, ptr uintptr) error {
if _, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, fd, cmd, ptr, 0, 0, 0); errno != 0 {
func ioctlInner(fd, cmd uintptr, ptr any) error {
var errno syscall.Errno
if ptr == nil {
_, _, errno = sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, fd, cmd, uintptr(0), 0, 0, 0)
} else {
_, _, errno = sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, fd, cmd, uintptr(reflect.ValueOf(ptr).UnsafePointer()), 0, 0, 0) //nolint:gosec // ptr-to-uintptr at syscall site.
}
if errno != 0 {
return errno
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion ioctl_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ const (
TIOCSWINSZ = 0
)

func ioctlInner(fd, cmd, ptr uintptr) error {
func ioctlInner(fd, cmd uintptr, ptr any) error {
return ErrUnsupported
}
7 changes: 3 additions & 4 deletions pty_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"errors"
"os"
"syscall"
"unsafe"
)

func open() (pty, tty *os.File, err error) {
Expand Down Expand Up @@ -46,7 +45,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, syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0])))
err := ioctl(f, syscall.TIOCPTYGNAME, &n[0])
if err != nil {
return "", err
}
Expand All @@ -60,9 +59,9 @@ func ptsname(f *os.File) (string, error) {
}

func grantpt(f *os.File) error {
return ioctl(f, syscall.TIOCPTYGRANT, 0)
return ioctl(f, syscall.TIOCPTYGRANT, nil)
}

func unlockpt(f *os.File) error {
return ioctl(f, syscall.TIOCPTYUNLK, 0)
return ioctl(f, syscall.TIOCPTYUNLK, nil)
}
5 changes: 2 additions & 3 deletions pty_dragonfly.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ func unlockpt(f *os.File) error {
}

func isptmaster(f *os.File) (bool, error) {
err := ioctl(f, syscall.TIOCISPTMASTER, 0)
err := ioctl(f, syscall.TIOCISPTMASTER, nil)
return err == nil, err
}

var (
emptyFiodgnameArg fiodgnameArg
ioctl_FIODNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg))
Expand All @@ -68,7 +67,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, ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa)))
err := ioctl(f, ioctl_FIODNAME, &fa)
if err != nil {
return "", err
}
Expand Down
5 changes: 2 additions & 3 deletions pty_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ func open() (pty, tty *os.File, err error) {
}

func isptmaster(f *os.File) (bool, error) {
err := ioctl(f, syscall.TIOCPTMASTER, 0)
err := ioctl(f, syscall.TIOCPTMASTER, nil)
return err == nil, err
}

var (
emptyFiodgnameArg fiodgnameArg
ioctlFIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg))
Expand All @@ -68,7 +67,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, ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil {
if err := ioctl(f, ioctlFIODGNAME, &arg); err != nil {
return "", err
}

Expand Down
5 changes: 2 additions & 3 deletions pty_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"os"
"strconv"
"syscall"
"unsafe"
)

func open() (pty, tty *os.File, err error) {
Expand Down Expand Up @@ -40,7 +39,7 @@ func open() (pty, tty *os.File, err error) {

func ptsname(f *os.File) (string, error) {
var n _C_uint
err := ioctl(f, syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) //nolint:gosec // Expected unsafe pointer for Syscall call.
err := ioctl(f, syscall.TIOCGPTN, &n)
if err != nil {
return "", err
}
Expand All @@ -50,5 +49,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, syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) //nolint:gosec // Expected unsafe pointer for Syscall call.
return ioctl(f, syscall.TIOCSPTLCK, &u)
}
5 changes: 2 additions & 3 deletions pty_netbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"errors"
"os"
"syscall"
"unsafe"
)

func open() (pty, tty *os.File, err error) {
Expand Down Expand Up @@ -47,7 +46,7 @@ func ptsname(f *os.File) (string, error) {
* ioctl(fd, TIOCPTSNAME, &pm) == -1 ? NULL : pm.sn;
*/
var ptm ptmget
if err := ioctl(f, uintptr(ioctl_TIOCPTSNAME), uintptr(unsafe.Pointer(&ptm))); err != nil {
if err := ioctl(f, uintptr(ioctl_TIOCPTSNAME), &ptm); err != nil {
return "", err
}
name := make([]byte, len(ptm.Sn))
Expand All @@ -65,5 +64,5 @@ func grantpt(f *os.File) error {
* from grantpt(3): Calling grantpt() is equivalent to:
* ioctl(fd, TIOCGRANTPT, 0);
*/
return ioctl(f, uintptr(ioctl_TIOCGRANTPT), 0)
return ioctl(f, uintptr(ioctl_TIOCGRANTPT), nil)
}
3 changes: 1 addition & 2 deletions pty_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package pty
import (
"os"
"syscall"
"unsafe"
)

func cInt8ToString(in []int8) string {
Expand Down Expand Up @@ -36,7 +35,7 @@ func open() (pty, tty *os.File, err error) {
defer p.Close()

var ptm ptmget
if err := ioctl(p, uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil {
if err := ioctl(p, uintptr(ioctl_PTMGET), &ptm); err != nil {
return nil, nil, err
}

Expand Down
10 changes: 5 additions & 5 deletions pty_solaris.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func unlockpt(f *os.File) error {
icLen: 0,
icDP: nil,
}
return ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr)))
return ioctl(f, I_STR, &istr)
}

func minor(x uint64) uint64 { return x & 0377 }
Expand All @@ -97,7 +97,7 @@ func ptsdev(f *os.File) (uint64, error) {
icDP: nil,
}

if err := ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
if err := ioctl(f, I_STR, &istr); err != nil {
return 0, err
}
var errors = make(chan error, 1)
Expand Down Expand Up @@ -146,7 +146,7 @@ func grantpt(f *os.File) error {
icLen: int32(unsafe.Sizeof(strioctl{})),
icDP: unsafe.Pointer(&pto),
}
if err := ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
if err := ioctl(f, I_STR, &istr); err != nil {
return errors.New("access denied")
}
return nil
Expand All @@ -164,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, I_FIND, uintptr(unsafe.Pointer(&buf[0]))); err != nil {
if err := ioctl(f, I_FIND, &buf[0]); err != nil {
return nil
}
return ioctl(f, I_PUSH, uintptr(unsafe.Pointer(&buf[0])))
return ioctl(f, I_PUSH, &buf[0])
}
7 changes: 2 additions & 5 deletions winsize_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package pty
import (
"os"
"syscall"
"unsafe"
)

// Winsize describes the terminal size.
Expand All @@ -19,16 +18,14 @@ 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, syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(ws)))
return ioctl(t, syscall.TIOCSWINSZ, ws)
}

// GetsizeFull returns the full terminal size description.
func GetsizeFull(t *os.File) (size *Winsize, err error) {
var ws Winsize

//nolint:gosec // Expected unsafe pointer for Syscall call.
if err := ioctl(t, syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))); err != nil {
if err := ioctl(t, syscall.TIOCGWINSZ, &ws); err != nil {
return nil, err
}
return &ws, nil
Expand Down
Loading