mirror of
https://github.com/creack/pty.git
synced 2026-03-31 10:37:09 +09:00
14
fd_helper_other_test.go
Normal file
14
fd_helper_other_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build !zos
|
||||
// +build !zos
|
||||
|
||||
package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getNonBlockingFile(t *testing.T, file *os.File, path string) *os.File {
|
||||
t.Helper()
|
||||
return file
|
||||
}
|
||||
20
fd_helper_zos_test.go
Normal file
20
fd_helper_zos_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build zos
|
||||
// +build zos
|
||||
|
||||
package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getNonBlockingFile(t *testing.T, file *os.File, path string) *os.File {
|
||||
t.Helper()
|
||||
// z/OS doesn't open a pollable FD - fix that here
|
||||
if _, err := fcntl(uintptr(file.Fd()), F_SETFL, O_NONBLOCK); err != nil {
|
||||
t.Fatalf("Error: zos-nonblock: %s.\n", err)
|
||||
}
|
||||
nf := os.NewFile(file.Fd(), path)
|
||||
t.Cleanup(func() { _ = nf.Close() })
|
||||
return nf
|
||||
}
|
||||
@@ -106,9 +106,12 @@ func prepare(t *testing.T) (ptmx *os.File, done func()) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error: open: %s.\n", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = ptmx.Close() })
|
||||
_ptmx := ptmx
|
||||
t.Cleanup(func() { _ = _ptmx.Close() })
|
||||
t.Cleanup(func() { _ = pts.Close() })
|
||||
|
||||
ptmx = getNonBlockingFile(t, ptmx, "/dev/ptmx")
|
||||
|
||||
ctx, done := context.WithCancel(context.Background())
|
||||
t.Cleanup(done)
|
||||
go func() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !linux && !darwin && !freebsd && !dragonfly && !netbsd && !openbsd && !solaris
|
||||
// +build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris
|
||||
//go:build !linux && !darwin && !freebsd && !dragonfly && !netbsd && !openbsd && !solaris && !zos
|
||||
// +build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris,!zos
|
||||
|
||||
package pty
|
||||
|
||||
|
||||
141
pty_zos.go
Normal file
141
pty_zos.go
Normal file
@@ -0,0 +1,141 @@
|
||||
//go:build zos
|
||||
// +build zos
|
||||
|
||||
package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SYS_UNLOCKPT = 0x37B
|
||||
SYS_GRANTPT = 0x37A
|
||||
SYS_POSIX_OPENPT = 0xC66
|
||||
SYS_FCNTL = 0x18C
|
||||
SYS___PTSNAME_A = 0x718
|
||||
|
||||
SETCVTON = 1
|
||||
|
||||
O_NONBLOCK = 0x04
|
||||
|
||||
F_SETFL = 4
|
||||
F_CONTROL_CVT = 13
|
||||
)
|
||||
|
||||
type f_cnvrt struct {
|
||||
Cvtcmd int32
|
||||
Pccsid int16
|
||||
Fccsid int16
|
||||
}
|
||||
|
||||
func open() (pty, tty *os.File, err error) {
|
||||
ptmxfd, err := openpt(os.O_RDWR | syscall.O_NOCTTY)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Needed for z/OS so that the characters are not garbled if ptyp* is untagged
|
||||
cvtreq := f_cnvrt{Cvtcmd: SETCVTON, Pccsid: 0, Fccsid: 1047}
|
||||
if _, err = fcntl(uintptr(ptmxfd), F_CONTROL_CVT, uintptr(unsafe.Pointer(&cvtreq))); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
p := os.NewFile(uintptr(ptmxfd), "/dev/ptmx")
|
||||
if p == nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// In case of error after this point, make sure we close the ptmx fd.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = p.Close() // Best effort.
|
||||
}
|
||||
}()
|
||||
|
||||
sname, err := ptsname(ptmxfd)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
_, err = grantpt(ptmxfd)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if _, err = unlockpt(ptmxfd); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ptsfd, err := syscall.Open(sname, os.O_RDWR|syscall.O_NOCTTY, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if _, err = fcntl(uintptr(ptsfd), F_CONTROL_CVT, uintptr(unsafe.Pointer(&cvtreq))); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
t := os.NewFile(uintptr(ptsfd), sname)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return p, t, nil
|
||||
}
|
||||
|
||||
func openpt(oflag int) (fd int, err error) {
|
||||
r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+SYS_POSIX_OPENPT<<4, uintptr(oflag))
|
||||
fd = int(r0)
|
||||
if e1 != 0 {
|
||||
err = syscall.Errno(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fcntl(fd uintptr, cmd int, arg uintptr) (val int, err error) {
|
||||
r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+SYS_FCNTL<<4, uintptr(fd), uintptr(cmd), arg)
|
||||
val = int(r0)
|
||||
if e1 != 0 {
|
||||
err = syscall.Errno(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ptsname(fd int) (name string, err error) {
|
||||
r0, _, e1 := runtime.CallLeFuncWithPtrReturn(runtime.GetZosLibVec()+SYS___PTSNAME_A<<4, uintptr(fd))
|
||||
name = u2s(unsafe.Pointer(r0))
|
||||
if e1 != 0 {
|
||||
err = syscall.Errno(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func grantpt(fildes int) (rc int, err error) {
|
||||
r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+SYS_GRANTPT<<4, uintptr(fildes))
|
||||
rc = int(r0)
|
||||
if e1 != 0 {
|
||||
err = syscall.Errno(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func unlockpt(fildes int) (rc int, err error) {
|
||||
r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+SYS_UNLOCKPT<<4, uintptr(fildes))
|
||||
rc = int(r0)
|
||||
if e1 != 0 {
|
||||
err = syscall.Errno(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func u2s(cstr unsafe.Pointer) string {
|
||||
str := (*[1024]uint8)(cstr)
|
||||
i := 0
|
||||
for str[i] != 0 {
|
||||
i++
|
||||
}
|
||||
return string(str[:i])
|
||||
}
|
||||
Reference in New Issue
Block a user