From 29f366aaee59f31559d2986f56e4c55d22f04a44 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 11 Feb 2022 16:05:14 +0100 Subject: [PATCH 1/2] zos: share implementation with unix The zos and "unix" implementations were identical, except for the NewPTY() function. This patch extracts that function to non-exported implementations for "zos" and "unix", so that all other bits can be shared. For reference; this was the diff between both files before: diff --git a/console_unix.go b/console_zos.go index 78f70c2..96ccb6f 100644 --- a/console_unix.go +++ b/console_zos.go @@ -17,6 +17,9 @@ package console import ( + "fmt" + "os" + "golang.org/x/sys/unix" ) @@ -24,16 +27,20 @@ import ( // The master is returned as the first console and a string // with the path to the pty slave is returned as the second func NewPty() (Console, string, error) { - f, err := openpt() - if err != nil { - return nil, "", err - } - slave, err := ptsname(f) - if err != nil { - return nil, "", err - } - if err := unlockpt(f); err != nil { - return nil, "", err + var f File + var err error + var slave string + for i := 0; ; i++ { + ptyp := fmt.Sprintf("/dev/ptyp%04d", i) + f, err = os.OpenFile(ptyp, os.O_RDWR, 0600) + if err == nil { + slave = fmt.Sprintf("/dev/ttyp%04d", i) + break + } + if os.IsNotExist(err) { + return nil, "", err + } + // else probably Resource Busy } m, err := newMaster(f) if err != nil { Signed-off-by: Sebastiaan van Stijn --- console_nozos.go | 39 ++++++++++++++++ console_unix.go | 21 ++------- console_zos.go | 118 +---------------------------------------------- 3 files changed, 43 insertions(+), 135 deletions(-) create mode 100644 console_nozos.go diff --git a/console_nozos.go b/console_nozos.go new file mode 100644 index 0000000..e77f9d8 --- /dev/null +++ b/console_nozos.go @@ -0,0 +1,39 @@ +//go:build darwin || freebsd || linux || netbsd || openbsd +// +build darwin freebsd linux netbsd openbsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +func newPty() (Console, string, error) { + f, err := openpt() + if err != nil { + return nil, "", err + } + slave, err := ptsname(f) + if err != nil { + return nil, "", err + } + if err := unlockpt(f); err != nil { + return nil, "", err + } + m, err := newMaster(f) + if err != nil { + return nil, "", err + } + return m, slave, nil +} diff --git a/console_unix.go b/console_unix.go index 022ae6c..eaa0f87 100644 --- a/console_unix.go +++ b/console_unix.go @@ -1,5 +1,5 @@ -//go:build darwin || freebsd || linux || netbsd || openbsd -// +build darwin freebsd linux netbsd openbsd +//go:build darwin || freebsd || linux || netbsd || openbsd || zos +// +build darwin freebsd linux netbsd openbsd zos /* Copyright The containerd Authors. @@ -27,22 +27,7 @@ import ( // The master is returned as the first console and a string // with the path to the pty slave is returned as the second func NewPty() (Console, string, error) { - f, err := openpt() - if err != nil { - return nil, "", err - } - slave, err := ptsname(f) - if err != nil { - return nil, "", err - } - if err := unlockpt(f); err != nil { - return nil, "", err - } - m, err := newMaster(f) - if err != nil { - return nil, "", err - } - return m, slave, nil + return newPty() } type master struct { diff --git a/console_zos.go b/console_zos.go index 06b059b..b48ab4f 100644 --- a/console_zos.go +++ b/console_zos.go @@ -22,14 +22,9 @@ package console import ( "fmt" "os" - - "golang.org/x/sys/unix" ) -// NewPty creates a new pty pair -// The master is returned as the first console and a string -// with the path to the pty slave is returned as the second -func NewPty() (Console, string, error) { +func newPty() (Console, string, error) { var f File var err error var slave string @@ -51,114 +46,3 @@ func NewPty() (Console, string, error) { } return m, slave, nil } - -type master struct { - f File - original *unix.Termios -} - -func (m *master) Read(b []byte) (int, error) { - return m.f.Read(b) -} - -func (m *master) Write(b []byte) (int, error) { - return m.f.Write(b) -} - -func (m *master) Close() error { - return m.f.Close() -} - -func (m *master) Resize(ws WinSize) error { - return tcswinsz(m.f.Fd(), ws) -} - -func (m *master) ResizeFrom(c Console) error { - ws, err := c.Size() - if err != nil { - return err - } - return m.Resize(ws) -} - -func (m *master) Reset() error { - if m.original == nil { - return nil - } - return tcset(m.f.Fd(), m.original) -} - -func (m *master) getCurrent() (unix.Termios, error) { - var termios unix.Termios - if err := tcget(m.f.Fd(), &termios); err != nil { - return unix.Termios{}, err - } - return termios, nil -} - -func (m *master) SetRaw() error { - rawState, err := m.getCurrent() - if err != nil { - return err - } - rawState = cfmakeraw(rawState) - rawState.Oflag = rawState.Oflag | unix.OPOST - return tcset(m.f.Fd(), &rawState) -} - -func (m *master) DisableEcho() error { - rawState, err := m.getCurrent() - if err != nil { - return err - } - rawState.Lflag = rawState.Lflag &^ unix.ECHO - return tcset(m.f.Fd(), &rawState) -} - -func (m *master) Size() (WinSize, error) { - return tcgwinsz(m.f.Fd()) -} - -func (m *master) Fd() uintptr { - return m.f.Fd() -} - -func (m *master) Name() string { - return m.f.Name() -} - -// checkConsole checks if the provided file is a console -func checkConsole(f File) error { - var termios unix.Termios - if tcget(f.Fd(), &termios) != nil { - return ErrNotAConsole - } - return nil -} - -func newMaster(f File) (Console, error) { - m := &master{ - f: f, - } - t, err := m.getCurrent() - if err != nil { - return nil, err - } - m.original = &t - return m, nil -} - -// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair -// created by us acts normally. In particular, a not-very-well-known default of -// Linux unix98 ptys is that they have +onlcr by default. While this isn't a -// problem for terminal emulators, because we relay data from the terminal we -// also relay that funky line discipline. -func ClearONLCR(fd uintptr) error { - return setONLCR(fd, false) -} - -// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair -// created by us acts as intended for a terminal emulator. -func SetONLCR(fd uintptr) error { - return setONLCR(fd, true) -} From 0c7a24405d89fa8aa98f52b84a176db7c8a7d45b Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 11 Feb 2022 17:06:08 +0100 Subject: [PATCH 2/2] zos: further reconcile implementation with other unices Follow-up to the previous commit; instead of using separate implementations for `newPty()` as a whole, create implementations for `openpt()`, `ptsname()` and a stub for `unlockpt()`. This seems slightly more consistent with other implementations, which already had os/arch specific implementations for these functions. Signed-off-by: Sebastiaan van Stijn --- console_nozos.go | 39 ------------------------------------ console_unix.go | 17 +++++++++++++++- console_zos.go => pty_zos.go | 15 +++++--------- tc_zos.go | 13 ++++++++++++ 4 files changed, 34 insertions(+), 50 deletions(-) delete mode 100644 console_nozos.go rename console_zos.go => pty_zos.go (79%) diff --git a/console_nozos.go b/console_nozos.go deleted file mode 100644 index e77f9d8..0000000 --- a/console_nozos.go +++ /dev/null @@ -1,39 +0,0 @@ -//go:build darwin || freebsd || linux || netbsd || openbsd -// +build darwin freebsd linux netbsd openbsd - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -func newPty() (Console, string, error) { - f, err := openpt() - if err != nil { - return nil, "", err - } - slave, err := ptsname(f) - if err != nil { - return nil, "", err - } - if err := unlockpt(f); err != nil { - return nil, "", err - } - m, err := newMaster(f) - if err != nil { - return nil, "", err - } - return m, slave, nil -} diff --git a/console_unix.go b/console_unix.go index eaa0f87..161f5d1 100644 --- a/console_unix.go +++ b/console_unix.go @@ -27,7 +27,22 @@ import ( // The master is returned as the first console and a string // with the path to the pty slave is returned as the second func NewPty() (Console, string, error) { - return newPty() + f, err := openpt() + if err != nil { + return nil, "", err + } + slave, err := ptsname(f) + if err != nil { + return nil, "", err + } + if err := unlockpt(f); err != nil { + return nil, "", err + } + m, err := newMaster(f) + if err != nil { + return nil, "", err + } + return m, slave, nil } type master struct { diff --git a/console_zos.go b/pty_zos.go similarity index 79% rename from console_zos.go rename to pty_zos.go index b48ab4f..58f59ab 100644 --- a/console_zos.go +++ b/pty_zos.go @@ -24,25 +24,20 @@ import ( "os" ) -func newPty() (Console, string, error) { - var f File +// openpt allocates a new pseudo-terminal by opening the first available /dev/ptypXX device +func openpt() (*os.File, error) { + var f *os.File var err error - var slave string for i := 0; ; i++ { ptyp := fmt.Sprintf("/dev/ptyp%04d", i) f, err = os.OpenFile(ptyp, os.O_RDWR, 0600) if err == nil { - slave = fmt.Sprintf("/dev/ttyp%04d", i) break } if os.IsNotExist(err) { - return nil, "", err + return nil, err } // else probably Resource Busy } - m, err := newMaster(f) - if err != nil { - return nil, "", err - } - return m, slave, nil + return f, nil } diff --git a/tc_zos.go b/tc_zos.go index 4262eaf..fc90ba5 100644 --- a/tc_zos.go +++ b/tc_zos.go @@ -17,6 +17,9 @@ package console import ( + "os" + "strings" + "golang.org/x/sys/unix" ) @@ -24,3 +27,13 @@ const ( cmdTcGet = unix.TCGETS cmdTcSet = unix.TCSETS ) + +// unlockpt is a no-op on zos. +func unlockpt(_ *os.File) error { + return nil +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + return "/dev/ttyp" + strings.TrimPrefix(f.Name(), "/dev/ptyp"), nil +}