From f73a158a9a62b5dfa171ab28871fbe4275243ca7 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Sat, 29 May 2021 18:39:47 -0400 Subject: [PATCH] Simplify solaris implementation. (#120) Remove golang.org/x/sys/unix dependency for solaris Add new go build tag directives --- asm_solaris_amd64.s | 18 +++++ go.mod | 1 - ioctl.go | 8 +- ioctl_bsd.go | 3 +- ioctl_solaris.go | 31 ++++++-- pty_darwin.go | 3 + pty_dragonfly.go | 3 + pty_freebsd.go | 3 + pty_linux.go | 9 ++- pty_netbsd.go | 3 + pty_openbsd.go | 3 + pty_solaris.go | 148 +++++++++++++++++++----------------- pty_unsupported.go | 3 +- run.go | 27 +++---- types.go | 3 +- types_dragonfly.go | 3 +- types_freebsd.go | 3 +- types_netbsd.go | 9 ++- types_openbsd.go | 3 +- util.go | 64 ---------------- util_solaris.go | 67 ---------------- winsize.go | 24 ++++++ winsize_unix.go | 35 +++++++++ winsize_unsupported.go | 23 ++++++ ztypes_386.go | 3 + ztypes_amd64.go | 3 + ztypes_arm.go | 3 + ztypes_arm64.go | 5 +- ztypes_dragonfly_amd64.go | 3 + ztypes_freebsd_386.go | 3 + ztypes_freebsd_amd64.go | 3 + ztypes_freebsd_arm.go | 3 + ztypes_freebsd_arm64.go | 3 + ztypes_loongarchx.go | 7 +- ztypes_mipsx.go | 7 +- ztypes_netbsd_32bit_int.go | 11 ++- ztypes_openbsd_32bit_int.go | 5 +- ztypes_ppc64.go | 3 +- ztypes_ppc64le.go | 3 +- ztypes_riscvx.go | 5 +- ztypes_s390x.go | 3 +- 41 files changed, 318 insertions(+), 252 deletions(-) create mode 100644 asm_solaris_amd64.s delete mode 100644 util.go delete mode 100644 util_solaris.go create mode 100644 winsize.go create mode 100644 winsize_unix.go create mode 100644 winsize_unsupported.go diff --git a/asm_solaris_amd64.s b/asm_solaris_amd64.s new file mode 100644 index 0000000..7fbef8e --- /dev/null +++ b/asm_solaris_amd64.s @@ -0,0 +1,18 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +//+build gc + +#include "textflag.h" + +// +// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go +// + +TEXT ·sysvicall6(SB),NOSPLIT,$0-88 + JMP syscall·sysvicall6(SB) + +TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88 + JMP syscall·rawSysvicall6(SB) diff --git a/go.mod b/go.mod index e48deca..7731235 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,3 @@ module github.com/creack/pty go 1.13 - diff --git a/ioctl.go b/ioctl.go index c85cdcd..0676437 100644 --- a/ioctl.go +++ b/ioctl.go @@ -1,9 +1,15 @@ -// +build !windows,!solaris +//go:build !windows && !solaris +//+build !windows,!solaris package pty import "syscall" +const ( + TIOCGWINSZ = syscall.TIOCGWINSZ + TIOCSWINSZ = syscall.TIOCSWINSZ +) + func ioctl(fd, cmd, ptr uintptr) error { _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr) if e != 0 { diff --git a/ioctl_bsd.go b/ioctl_bsd.go index 73b12c5..ab53e2d 100644 --- a/ioctl_bsd.go +++ b/ioctl_bsd.go @@ -1,4 +1,5 @@ -// +build darwin dragonfly freebsd netbsd openbsd +//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) +//+build darwin dragonfly freebsd netbsd openbsd package pty diff --git a/ioctl_solaris.go b/ioctl_solaris.go index 249686c..8b6cc0e 100644 --- a/ioctl_solaris.go +++ b/ioctl_solaris.go @@ -1,31 +1,48 @@ +//go:build solaris +//+build solaris + package pty import ( + "syscall" "unsafe" - - "golang.org/x/sys/unix" ) +//go:cgo_import_dynamic libc_ioctl ioctl "libc.so" +//go:linkname procioctl libc_ioctl +var procioctl uintptr + const ( // see /usr/include/sys/stropts.h I_PUSH = uintptr((int32('S')<<8 | 002)) I_STR = uintptr((int32('S')<<8 | 010)) I_FIND = uintptr((int32('S')<<8 | 013)) + // see /usr/include/sys/ptms.h ISPTM = (int32('P') << 8) | 1 UNLKPT = (int32('P') << 8) | 2 PTSSTTY = (int32('P') << 8) | 3 ZONEPT = (int32('P') << 8) | 4 OWNERPT = (int32('P') << 8) | 5 + + // see /usr/include/sys/termios.h + TIOCSWINSZ = (uint32('T') << 8) | 103 + TIOCGWINSZ = (uint32('T') << 8) | 104 ) type strioctl struct { - ic_cmd int32 - ic_timout int32 - ic_len int32 - ic_dp unsafe.Pointer + icCmd int32 + icTimeout int32 + icLen int32 + icDP unsafe.Pointer } +// 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 { - return unix.IoctlSetInt(int(fd), uint(cmd), int(ptr)) + if _, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, fd, cmd, ptr, 0, 0, 0); errno != 0 { + return errno + } + return nil } diff --git a/pty_darwin.go b/pty_darwin.go index 0ed4325..cca0971 100644 --- a/pty_darwin.go +++ b/pty_darwin.go @@ -1,3 +1,6 @@ +//go:build darwin +//+build darwin + package pty import ( diff --git a/pty_dragonfly.go b/pty_dragonfly.go index b7d1f20..7a1fec3 100644 --- a/pty_dragonfly.go +++ b/pty_dragonfly.go @@ -1,3 +1,6 @@ +//go:build dragonfly +//+build dragonfly + package pty import ( diff --git a/pty_freebsd.go b/pty_freebsd.go index 63b6d91..a4cfd92 100644 --- a/pty_freebsd.go +++ b/pty_freebsd.go @@ -1,3 +1,6 @@ +//go:build freebsd +//+build freebsd + package pty import ( diff --git a/pty_linux.go b/pty_linux.go index 4a833de..22ccbe1 100644 --- a/pty_linux.go +++ b/pty_linux.go @@ -1,3 +1,6 @@ +//go:build linux +//+build linux + package pty import ( @@ -28,7 +31,7 @@ func open() (pty, tty *os.File, err error) { return nil, nil, err } - t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) + t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) //nolint:gosec // Expected Open from a variable. if err != nil { return nil, nil, err } @@ -37,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))) + err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) //nolint:gosec // Expected unsafe pointer for Syscall call. if err != nil { return "", err } @@ -47,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))) + return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) //nolint:gosec // Expected unsafe pointer for Syscall call. } diff --git a/pty_netbsd.go b/pty_netbsd.go index 20f9125..98c089c 100644 --- a/pty_netbsd.go +++ b/pty_netbsd.go @@ -1,3 +1,6 @@ +//go:build netbsd +//+build netbsd + package pty import ( diff --git a/pty_openbsd.go b/pty_openbsd.go index a6a35d1..d72b9d8 100644 --- a/pty_openbsd.go +++ b/pty_openbsd.go @@ -1,3 +1,6 @@ +//go:build openbsd +//+build openbsd + package pty import ( diff --git a/pty_solaris.go b/pty_solaris.go index 5c37972..17e4746 100644 --- a/pty_solaris.go +++ b/pty_solaris.go @@ -1,3 +1,6 @@ +//go:build solaris +//+build solaris + package pty /* based on: @@ -10,45 +13,50 @@ import ( "strconv" "syscall" "unsafe" - - "golang.org/x/sys/unix" ) -const NODEV = ^uint64(0) - func open() (pty, tty *os.File, err error) { - masterfd, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|unix.O_NOCTTY, 0) - //masterfd, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_CLOEXEC|unix.O_NOCTTY, 0) + ptmxfd, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY, 0) if err != nil { return nil, nil, err } - p := os.NewFile(uintptr(masterfd), "/dev/ptmx") + p := os.NewFile(uintptr(ptmxfd), "/dev/ptmx") + // 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(p) if err != nil { return nil, nil, err } - err = grantpt(p) - if err != nil { + if err := grantpt(p); err != nil { return nil, nil, err } - err = unlockpt(p) - if err != nil { + if err := unlockpt(p); err != nil { return nil, nil, err } - slavefd, err := syscall.Open(sname, os.O_RDWR|unix.O_NOCTTY, 0) + ptsfd, err := syscall.Open(sname, os.O_RDWR|syscall.O_NOCTTY, 0) if err != nil { return nil, nil, err } - t := os.NewFile(uintptr(slavefd), sname) + t := os.NewFile(uintptr(ptsfd), sname) + + // In case of error after this point, make sure we close the pts fd. + defer func() { + if err != nil { + _ = t.Close() // Best effort. + } + }() // pushing terminal driver STREAMS modules as per pts(7) for _, mod := range []string{"ptem", "ldterm", "ttcompat"} { - err = streams_push(t, mod) - if err != nil { + if err := streamsPush(t, mod); err != nil { return nil, nil, err } } @@ -56,73 +64,79 @@ func open() (pty, tty *os.File, err error) { return p, t, nil } -func minor(x uint64) uint64 { - return x & 0377 -} - -func ptsdev(fd uintptr) uint64 { - istr := strioctl{ISPTM, 0, 0, nil} - err := ioctl(fd, I_STR, uintptr(unsafe.Pointer(&istr))) - if err != nil { - return NODEV - } - var status unix.Stat_t - err = unix.Fstat(int(fd), &status) - if err != nil { - return NODEV - } - return uint64(minor(status.Rdev)) -} - func ptsname(f *os.File) (string, error) { - dev := ptsdev(f.Fd()) - if dev == NODEV { - return "", errors.New("not a master pty") + dev, err := ptsdev(f.Fd()) + if err != nil { + return "", err } fn := "/dev/pts/" + strconv.FormatInt(int64(dev), 10) - // access(2) creates the slave device (if the pty exists) - // F_OK == 0 (unistd.h) - err := unix.Access(fn, 0) - if err != nil { + + if err := syscall.Access(fn, 0); err != nil { return "", err } return fn, nil } -type pt_own struct { - pto_ruid int32 - pto_rgid int32 +func unlockpt(f *os.File) error { + istr := strioctl{ + icCmd: UNLKPT, + icTimeout: 0, + icLen: 0, + icDP: nil, + } + return ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr))) +} + +func minor(x uint64) uint64 { return x & 0377 } + +func ptsdev(fd uintptr) (uint64, error) { + istr := strioctl{ + icCmd: ISPTM, + icTimeout: 0, + icLen: 0, + icDP: nil, + } + + if err := ioctl(fd, 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 { + return 0, err + } + return uint64(minor(status.Rdev)), nil +} + +type ptOwn struct { + rUID int32 + rGID int32 } func grantpt(f *os.File) error { - if ptsdev(f.Fd()) == NODEV { - return errors.New("not a master pty") + if _, err := ptsdev(f.Fd()); err != nil { + return err } - var pto pt_own - pto.pto_ruid = int32(os.Getuid()) - // XXX should first attempt to get gid of DEFAULT_TTY_GROUP="tty" - pto.pto_rgid = int32(os.Getgid()) - var istr strioctl - istr.ic_cmd = OWNERPT - istr.ic_timout = 0 - istr.ic_len = int32(unsafe.Sizeof(istr)) - istr.ic_dp = unsafe.Pointer(&pto) - err := ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr))) - if err != nil { + pto := ptOwn{ + rUID: int32(os.Getuid()), + // XXX should first attempt to get gid of DEFAULT_TTY_GROUP="tty" + rGID: int32(os.Getgid()), + } + istr := strioctl{ + icCmd: OWNERPT, + icTimeout: 0, + icLen: int32(unsafe.Sizeof(strioctl{})), + icDP: unsafe.Pointer(&pto), + } + if err := ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr))); err != nil { return errors.New("access denied") } return nil } -func unlockpt(f *os.File) error { - istr := strioctl{UNLKPT, 0, 0, nil} - return ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr))) -} - -// push STREAMS modules if not already done so -func streams_push(f *os.File, mod string) error { - var err error +// streamsPush pushes STREAMS modules if not already done so. +func streamsPush(f *os.File, mod string) error { buf := []byte(mod) + // XXX I_FIND is not returning an error when the module // is already pushed even though truss reports a return // value of 1. A bug in the Go Solaris syscall interface? @@ -131,10 +145,8 @@ func streams_push(f *os.File, mod string) error { // but since we are not using libc or XPG4.2, we should not be // double-pushing modules - err = ioctl(f.Fd(), I_FIND, uintptr(unsafe.Pointer(&buf[0]))) - if err != nil { + if err := ioctl(f.Fd(), I_FIND, uintptr(unsafe.Pointer(&buf[0]))); err != nil { return nil } - err = ioctl(f.Fd(), I_PUSH, uintptr(unsafe.Pointer(&buf[0]))) - return err + return ioctl(f.Fd(), I_PUSH, uintptr(unsafe.Pointer(&buf[0]))) } diff --git a/pty_unsupported.go b/pty_unsupported.go index 6cd757b..765523a 100644 --- a/pty_unsupported.go +++ b/pty_unsupported.go @@ -1,4 +1,5 @@ -// +build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris +//go:build !linux && !darwin && !freebsd && !dragonfly && !netbsd && !openbsd && !solaris +//+build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris package pty diff --git a/run.go b/run.go index b079425..160001f 100644 --- a/run.go +++ b/run.go @@ -1,4 +1,5 @@ -// +build !windows +//go:build !windows +//+build !windows package pty @@ -13,8 +14,8 @@ import ( // corresponding pty. // // Starts the process in a new session and sets the controlling terminal. -func Start(c *exec.Cmd) (pty *os.File, err error) { - return StartWithSize(c, nil) +func Start(cmd *exec.Cmd) (*os.File, error) { + return StartWithSize(cmd, nil) } // StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, @@ -23,13 +24,13 @@ func Start(c *exec.Cmd) (pty *os.File, err error) { // // This will resize the pty to the specified size before starting the command. // Starts the process in a new session and sets the controlling terminal. -func StartWithSize(c *exec.Cmd, sz *Winsize) (pty *os.File, err error) { - if c.SysProcAttr == nil { - c.SysProcAttr = &syscall.SysProcAttr{} +func StartWithSize(cmd *exec.Cmd, ws *Winsize) (*os.File, error) { + if cmd.SysProcAttr == nil { + cmd.SysProcAttr = &syscall.SysProcAttr{} } - c.SysProcAttr.Setsid = true - c.SysProcAttr.Setctty = true - return StartWithAttrs(c, sz, c.SysProcAttr) + cmd.SysProcAttr.Setsid = true + cmd.SysProcAttr.Setctty = true + return StartWithAttrs(cmd, ws, cmd.SysProcAttr) } // StartWithAttrs assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, @@ -41,16 +42,16 @@ func StartWithSize(c *exec.Cmd, sz *Winsize) (pty *os.File, err error) { // // This should generally not be needed. Used in some edge cases where it is needed to create a pty // without a controlling terminal. -func StartWithAttrs(c *exec.Cmd, sz *Winsize, attrs *syscall.SysProcAttr) (pty *os.File, err error) { +func StartWithAttrs(c *exec.Cmd, sz *Winsize, attrs *syscall.SysProcAttr) (*os.File, error) { pty, tty, err := Open() if err != nil { return nil, err } - defer tty.Close() + defer func() { _ = tty.Close() }() // Best effort. if sz != nil { if err := Setsize(pty, sz); err != nil { - pty.Close() + _ = pty.Close() // Best effort. return nil, err } } @@ -67,7 +68,7 @@ func StartWithAttrs(c *exec.Cmd, sz *Winsize, attrs *syscall.SysProcAttr) (pty * c.SysProcAttr = attrs if err := c.Start(); err != nil { - _ = pty.Close() + _ = pty.Close() // Best effort. return nil, err } return pty, err diff --git a/types.go b/types.go index 5aecb6b..f4cdc2e 100644 --- a/types.go +++ b/types.go @@ -1,4 +1,5 @@ -// +build ignore +//go:build ignore +//+build ignore package pty diff --git a/types_dragonfly.go b/types_dragonfly.go index 5c0493b..7385166 100644 --- a/types_dragonfly.go +++ b/types_dragonfly.go @@ -1,4 +1,5 @@ -// +build ignore +//go:build ignore +//+build ignore package pty diff --git a/types_freebsd.go b/types_freebsd.go index ce3eb95..9dd4e30 100644 --- a/types_freebsd.go +++ b/types_freebsd.go @@ -1,4 +1,5 @@ -// +build ignore +//go:build ignore +//+build ignore package pty diff --git a/types_netbsd.go b/types_netbsd.go index 52ebea7..3e18359 100644 --- a/types_netbsd.go +++ b/types_netbsd.go @@ -1,4 +1,5 @@ -// +build ignore +//go:build ignore +//+build ignore package pty @@ -11,5 +12,7 @@ import "C" type ptmget C.struct_ptmget -var ioctl_TIOCPTSNAME = C.TIOCPTSNAME -var ioctl_TIOCGRANTPT = C.TIOCGRANTPT +var ( + ioctl_TIOCPTSNAME = C.TIOCPTSNAME + ioctl_TIOCGRANTPT = C.TIOCGRANTPT +) diff --git a/types_openbsd.go b/types_openbsd.go index 47701b5..0a5df1b 100644 --- a/types_openbsd.go +++ b/types_openbsd.go @@ -1,4 +1,5 @@ -// +build ignore +//go:build ignore +//+build ignore package pty diff --git a/util.go b/util.go deleted file mode 100644 index 8fdde0b..0000000 --- a/util.go +++ /dev/null @@ -1,64 +0,0 @@ -// +build !windows,!solaris - -package pty - -import ( - "os" - "syscall" - "unsafe" -) - -// InheritSize applies the terminal size of pty to tty. This should be run -// in a signal handler for syscall.SIGWINCH to automatically resize the tty when -// the pty receives a window size change notification. -func InheritSize(pty, tty *os.File) error { - size, err := GetsizeFull(pty) - if err != nil { - return err - } - err = Setsize(tty, size) - if err != nil { - return err - } - return nil -} - -// Setsize resizes t to s. -func Setsize(t *os.File, ws *Winsize) error { - return windowRectCall(ws, t.Fd(), syscall.TIOCSWINSZ) -} - -// GetsizeFull returns the full terminal size description. -func GetsizeFull(t *os.File) (size *Winsize, err error) { - var ws Winsize - err = windowRectCall(&ws, t.Fd(), syscall.TIOCGWINSZ) - return &ws, err -} - -// Getsize returns the number of rows (lines) and cols (positions -// in each line) in terminal t. -func Getsize(t *os.File) (rows, cols int, err error) { - ws, err := GetsizeFull(t) - return int(ws.Rows), int(ws.Cols), err -} - -// Winsize describes the terminal size. -type Winsize struct { - Rows uint16 // ws_row: Number of rows (in cells) - Cols uint16 // ws_col: Number of columns (in cells) - X uint16 // ws_xpixel: Width in pixels - Y uint16 // ws_ypixel: Height in pixels -} - -func windowRectCall(ws *Winsize, fd, a2 uintptr) error { - _, _, errno := syscall.Syscall( - syscall.SYS_IOCTL, - fd, - a2, - uintptr(unsafe.Pointer(ws)), - ) - if errno != 0 { - return syscall.Errno(errno) - } - return nil -} diff --git a/util_solaris.go b/util_solaris.go deleted file mode 100644 index 37a8d53..0000000 --- a/util_solaris.go +++ /dev/null @@ -1,67 +0,0 @@ -// - -package pty - -import ( - "os" - - "golang.org/x/sys/unix" -) - -const ( - TIOCGWINSZ = 21608 // 'T' << 8 | 104 - TIOCSWINSZ = 21607 // 'T' << 8 | 103 -) - -// Winsize describes the terminal size. -type Winsize struct { - Rows uint16 // ws_row: Number of rows (in cells) - Cols uint16 // ws_col: Number of columns (in cells) - X uint16 // ws_xpixel: Width in pixels - Y uint16 // ws_ypixel: Height in pixels -} - -// GetsizeFull returns the full terminal size description. -func GetsizeFull(t *os.File) (size *Winsize, err error) { - var wsz *unix.Winsize - wsz, err = unix.IoctlGetWinsize(int(t.Fd()), TIOCGWINSZ) - - if err != nil { - return nil, err - } else { - return &Winsize{wsz.Row, wsz.Col, wsz.Xpixel, wsz.Ypixel}, nil - } -} - -// Get Windows Size -func Getsize(t *os.File) (rows, cols int, err error) { - var wsz *unix.Winsize - wsz, err = unix.IoctlGetWinsize(int(t.Fd()), TIOCGWINSZ) - - if err != nil { - return 80, 25, err - } else { - return int(wsz.Row), int(wsz.Col), nil - } -} - -// InheritSize applies the terminal size of pty to tty. This should be run -// in a signal handler for syscall.SIGWINCH to automatically resize the tty when -// the pty receives a window size change notification. -func InheritSize(pty, tty *os.File) error { - size, err := GetsizeFull(pty) - if err != nil { - return err - } - err = Setsize(tty, size) - if err != nil { - return err - } - return nil -} - -// Setsize resizes t to s. -func Setsize(t *os.File, ws *Winsize) error { - wsz := unix.Winsize{ws.Rows, ws.Cols, ws.X, ws.Y} - return unix.IoctlSetWinsize(int(t.Fd()), TIOCSWINSZ, &wsz) -} diff --git a/winsize.go b/winsize.go new file mode 100644 index 0000000..9660a93 --- /dev/null +++ b/winsize.go @@ -0,0 +1,24 @@ +package pty + +import "os" + +// InheritSize applies the terminal size of pty to tty. This should be run +// in a signal handler for syscall.SIGWINCH to automatically resize the tty when +// the pty receives a window size change notification. +func InheritSize(pty, tty *os.File) error { + size, err := GetsizeFull(pty) + if err != nil { + return err + } + if err := Setsize(tty, size); err != nil { + return err + } + return nil +} + +// Getsize returns the number of rows (lines) and cols (positions +// in each line) in terminal t. +func Getsize(t *os.File) (rows, cols int, err error) { + ws, err := GetsizeFull(t) + return int(ws.Rows), int(ws.Cols), err +} diff --git a/winsize_unix.go b/winsize_unix.go new file mode 100644 index 0000000..f358e90 --- /dev/null +++ b/winsize_unix.go @@ -0,0 +1,35 @@ +//go:build !windows +//+build !windows + +package pty + +import ( + "os" + "syscall" + "unsafe" +) + +// Winsize describes the terminal size. +type Winsize struct { + Rows uint16 // ws_row: Number of rows (in cells) + Cols uint16 // ws_col: Number of columns (in cells) + X uint16 // ws_xpixel: Width in pixels + Y uint16 // ws_ypixel: Height in pixels +} + +// 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))) +} + +// 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.Fd(), syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))); err != nil { + return nil, err + } + return &ws, nil +} diff --git a/winsize_unsupported.go b/winsize_unsupported.go new file mode 100644 index 0000000..c4bff44 --- /dev/null +++ b/winsize_unsupported.go @@ -0,0 +1,23 @@ +//go:build windows +//+build windows + +package pty + +import ( + "os" +) + +// Winsize is a dummy struct to enable compilation on unsupported platforms. +type Winsize struct { + Rows, Cols, X, Y uint +} + +// Setsize resizes t to s. +func Setsize(*os.File, *Winsize) error { + return ErrUnsupported +} + +// GetsizeFull returns the full terminal size description. +func GetsizeFull(*os.File) (*Winsize, error) { + return nil, ErrUnsupported +} diff --git a/ztypes_386.go b/ztypes_386.go index ff0b8fd..794515b 100644 --- a/ztypes_386.go +++ b/ztypes_386.go @@ -1,3 +1,6 @@ +//go:build 386 +//+build 386 + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go diff --git a/ztypes_amd64.go b/ztypes_amd64.go index ff0b8fd..dc6c525 100644 --- a/ztypes_amd64.go +++ b/ztypes_amd64.go @@ -1,3 +1,6 @@ +//go:build amd64 +//+build amd64 + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go diff --git a/ztypes_arm.go b/ztypes_arm.go index ff0b8fd..eac9b1e 100644 --- a/ztypes_arm.go +++ b/ztypes_arm.go @@ -1,3 +1,6 @@ +//go:build arm +//+build arm + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go diff --git a/ztypes_arm64.go b/ztypes_arm64.go index 6c29a4b..ecb3ddc 100644 --- a/ztypes_arm64.go +++ b/ztypes_arm64.go @@ -1,8 +1,9 @@ +//go:build arm64 +//+build arm64 + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go -// +build arm64 - package pty type ( diff --git a/ztypes_dragonfly_amd64.go b/ztypes_dragonfly_amd64.go index 6b0ba03..f4054cb 100644 --- a/ztypes_dragonfly_amd64.go +++ b/ztypes_dragonfly_amd64.go @@ -1,3 +1,6 @@ +//go:build amd64 && dragonfly +//+build amd64,dragonfly + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_dragonfly.go diff --git a/ztypes_freebsd_386.go b/ztypes_freebsd_386.go index d997537..95a20ab 100644 --- a/ztypes_freebsd_386.go +++ b/ztypes_freebsd_386.go @@ -1,3 +1,6 @@ +//go:build 386 && freebsd +//+build 386,freebsd + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go diff --git a/ztypes_freebsd_amd64.go b/ztypes_freebsd_amd64.go index 5fa102f..e03a071 100644 --- a/ztypes_freebsd_amd64.go +++ b/ztypes_freebsd_amd64.go @@ -1,3 +1,6 @@ +//go:build amd64 && freebsd +//+build amd64,freebsd + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go diff --git a/ztypes_freebsd_arm.go b/ztypes_freebsd_arm.go index d997537..7665bd3 100644 --- a/ztypes_freebsd_arm.go +++ b/ztypes_freebsd_arm.go @@ -1,3 +1,6 @@ +//go:build arm && freebsd +//+build arm,freebsd + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go diff --git a/ztypes_freebsd_arm64.go b/ztypes_freebsd_arm64.go index 4418139..3f95bb8 100644 --- a/ztypes_freebsd_arm64.go +++ b/ztypes_freebsd_arm64.go @@ -1,3 +1,6 @@ +//go:build arm64 && freebsd +//+build arm64,freebsd + // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs types_freebsd.go diff --git a/ztypes_loongarchx.go b/ztypes_loongarchx.go index 6fa946a..674d2a4 100644 --- a/ztypes_loongarchx.go +++ b/ztypes_loongarchx.go @@ -1,9 +1,10 @@ +//go:build (loongarch32 || loongarch64) && linux +//+build linux +//+build loongarch32 loongarch64 + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go -// +build linux -// +build loongarch32 loongarch64 - package pty type ( diff --git a/ztypes_mipsx.go b/ztypes_mipsx.go index f0ce740..eddad16 100644 --- a/ztypes_mipsx.go +++ b/ztypes_mipsx.go @@ -1,9 +1,10 @@ +//go:build (mips || mipsle || mips64 || mips64le) && linux +//+build linux +//+build mips mipsle mips64 mips64le + // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go -// +build linux -// +build mips mipsle mips64 mips64le - package pty type ( diff --git a/ztypes_netbsd_32bit_int.go b/ztypes_netbsd_32bit_int.go index f40a5a6..5b32e63 100644 --- a/ztypes_netbsd_32bit_int.go +++ b/ztypes_netbsd_32bit_int.go @@ -1,5 +1,6 @@ -// +build netbsd -// +build 386 amd64 arm arm64 +//go:build (386 || amd64 || arm || arm64) && netbsd +//+build netbsd +//+build 386 amd64 arm arm64 package pty @@ -10,5 +11,7 @@ type ptmget struct { Sn [1024]int8 } -var ioctl_TIOCPTSNAME = 0x48087448 -var ioctl_TIOCGRANTPT = 0x20007447 +var ( + ioctl_TIOCPTSNAME = 0x48087448 + ioctl_TIOCGRANTPT = 0x20007447 +) diff --git a/ztypes_openbsd_32bit_int.go b/ztypes_openbsd_32bit_int.go index 9c0e4b1..9eaca4d 100644 --- a/ztypes_openbsd_32bit_int.go +++ b/ztypes_openbsd_32bit_int.go @@ -1,5 +1,6 @@ -// +build openbsd -// +build 386 amd64 arm arm64 +//go:build (386 || amd64 || arm || arm64) && solaris +//+build openbsd +//+build 386 amd64 arm arm64 package pty diff --git a/ztypes_ppc64.go b/ztypes_ppc64.go index 4e1af84..6863443 100644 --- a/ztypes_ppc64.go +++ b/ztypes_ppc64.go @@ -1,4 +1,5 @@ -// +build ppc64 +//go:build ppc64 +//+build ppc64 // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go diff --git a/ztypes_ppc64le.go b/ztypes_ppc64le.go index e6780f4..6b5621b 100644 --- a/ztypes_ppc64le.go +++ b/ztypes_ppc64le.go @@ -1,4 +1,5 @@ -// +build ppc64le +//go:build ppc64le +//+build ppc64le // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go diff --git a/ztypes_riscvx.go b/ztypes_riscvx.go index 99eec8e..1233e75 100644 --- a/ztypes_riscvx.go +++ b/ztypes_riscvx.go @@ -1,8 +1,9 @@ +//go:build riscv || riscv64 +//+build riscv riscv64 + // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs types.go -// +build riscv riscv64 - package pty type ( diff --git a/ztypes_s390x.go b/ztypes_s390x.go index a7452b6..02facea 100644 --- a/ztypes_s390x.go +++ b/ztypes_s390x.go @@ -1,4 +1,5 @@ -// +build s390x +//go:build s390x +//+build s390x // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types.go