Skip to content

Commit c8d9621

Browse files
authored
Merge pull request #86 from cyphar/newpty-from-file
pty: add GetPtyFromFile as safer GetPty
2 parents fa4de4c + c79e45e commit c8d9621

File tree

11 files changed

+43
-29
lines changed

11 files changed

+43
-29
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
go install github.com/golangci/golangci-lint/cmd/[email protected]
3838
3939
- name: Project Checks
40-
uses: containerd/project-checks@v1.1.0
40+
uses: containerd/project-checks@v1.2.2
4141
with:
4242
working-directory: src/github.com/containerd/console
4343

console_test.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ func TestWinSize(t *testing.T) {
5454
}
5555
}
5656

57-
func TestConsolePty(t *testing.T) {
58-
console, slavePath, err := NewPty()
57+
func testConsolePty(t *testing.T, newPty func() (Console, string, error)) {
58+
console, slavePath, err := newPty()
5959
if err != nil {
6060
t.Fatal(err)
6161
}
@@ -100,3 +100,18 @@ func TestConsolePty(t *testing.T) {
100100
t.Errorf("unexpected output %q", out)
101101
}
102102
}
103+
104+
func TestConsolePty_NewPty(t *testing.T) {
105+
testConsolePty(t, NewPty)
106+
}
107+
108+
func TestConsolePty_NewPtyFromFile(t *testing.T) {
109+
testConsolePty(t, func() (Console, string, error) {
110+
// Equivalent to NewPty().
111+
f, err := openpt()
112+
if err != nil {
113+
return nil, "", err
114+
}
115+
return NewPtyFromFile(f)
116+
})
117+
}

console_unix.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ func NewPty() (Console, string, error) {
3131
if err != nil {
3232
return nil, "", err
3333
}
34+
return NewPtyFromFile(f)
35+
}
36+
37+
// NewPtyFromFile creates a new pty pair, just like [NewPty] except that the
38+
// provided [os.File] is used as the master rather than automatically creating
39+
// a new master from /dev/ptmx. The ownership of [os.File] is passed to the
40+
// returned [Console], so the caller must be careful to not call Close on the
41+
// underlying file.
42+
func NewPtyFromFile(f File) (Console, string, error) {
3443
slave, err := ptsname(f)
3544
if err != nil {
3645
return nil, "", err

tc_darwin.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package console
1818

1919
import (
2020
"fmt"
21-
"os"
2221

2322
"golang.org/x/sys/unix"
2423
)
@@ -30,12 +29,12 @@ const (
3029

3130
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
3231
// unlockpt should be called before opening the slave side of a pty.
33-
func unlockpt(f *os.File) error {
32+
func unlockpt(f File) error {
3433
return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCPTYUNLK, 0)
3534
}
3635

3736
// ptsname retrieves the name of the first available pts for the given master.
38-
func ptsname(f *os.File) (string, error) {
37+
func ptsname(f File) (string, error) {
3938
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCPTYGNAME)
4039
if err != nil {
4140
return "", err

tc_freebsd_cgo.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ package console
2121

2222
import (
2323
"fmt"
24-
"os"
2524

2625
"golang.org/x/sys/unix"
2726
)
@@ -39,7 +38,7 @@ const (
3938

4039
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
4140
// unlockpt should be called before opening the slave side of a pty.
42-
func unlockpt(f *os.File) error {
41+
func unlockpt(f File) error {
4342
fd := C.int(f.Fd())
4443
if _, err := C.unlockpt(fd); err != nil {
4544
C.close(fd)
@@ -49,7 +48,7 @@ func unlockpt(f *os.File) error {
4948
}
5049

5150
// ptsname retrieves the name of the first available pts for the given master.
52-
func ptsname(f *os.File) (string, error) {
51+
func ptsname(f File) (string, error) {
5352
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
5453
if err != nil {
5554
return "", err

tc_freebsd_nocgo.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ package console
2121

2222
import (
2323
"fmt"
24-
"os"
2524

2625
"golang.org/x/sys/unix"
2726
)
@@ -42,12 +41,12 @@ const (
4241

4342
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
4443
// unlockpt should be called before opening the slave side of a pty.
45-
func unlockpt(f *os.File) error {
44+
func unlockpt(f File) error {
4645
panic("unlockpt() support requires cgo.")
4746
}
4847

4948
// ptsname retrieves the name of the first available pts for the given master.
50-
func ptsname(f *os.File) (string, error) {
49+
func ptsname(f File) (string, error) {
5150
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
5251
if err != nil {
5352
return "", err

tc_linux.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package console
1818

1919
import (
2020
"fmt"
21-
"os"
2221
"unsafe"
2322

2423
"golang.org/x/sys/unix"
@@ -31,7 +30,7 @@ const (
3130

3231
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
3332
// unlockpt should be called before opening the slave side of a pty.
34-
func unlockpt(f *os.File) error {
33+
func unlockpt(f File) error {
3534
var u int32
3635
// XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81.
3736
if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 {
@@ -41,7 +40,7 @@ func unlockpt(f *os.File) error {
4140
}
4241

4342
// ptsname retrieves the name of the first available pts for the given master.
44-
func ptsname(f *os.File) (string, error) {
43+
func ptsname(f File) (string, error) {
4544
var u uint32
4645
// XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81.
4746
if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 {

tc_netbsd.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package console
1818

1919
import (
2020
"bytes"
21-
"os"
2221

2322
"golang.org/x/sys/unix"
2423
)
@@ -31,12 +30,12 @@ const (
3130
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
3231
// unlockpt should be called before opening the slave side of a pty.
3332
// This does not exist on NetBSD, it does not allocate controlling terminals on open
34-
func unlockpt(f *os.File) error {
33+
func unlockpt(f File) error {
3534
return nil
3635
}
3736

3837
// ptsname retrieves the name of the first available pts for the given master.
39-
func ptsname(f *os.File) (string, error) {
38+
func ptsname(f File) (string, error) {
4039
ptm, err := unix.IoctlGetPtmget(int(f.Fd()), unix.TIOCPTSNAME)
4140
if err != nil {
4241
return "", err

tc_openbsd_cgo.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
package console
2121

2222
import (
23-
"os"
24-
2523
"golang.org/x/sys/unix"
2624
)
2725

@@ -34,7 +32,7 @@ const (
3432
)
3533

3634
// ptsname retrieves the name of the first available pts for the given master.
37-
func ptsname(f *os.File) (string, error) {
35+
func ptsname(f File) (string, error) {
3836
ptspath, err := C.ptsname(C.int(f.Fd()))
3937
if err != nil {
4038
return "", err
@@ -44,7 +42,7 @@ func ptsname(f *os.File) (string, error) {
4442

4543
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
4644
// unlockpt should be called before opening the slave side of a pty.
47-
func unlockpt(f *os.File) error {
45+
func unlockpt(f File) error {
4846
if _, err := C.grantpt(C.int(f.Fd())); err != nil {
4947
return err
5048
}

tc_openbsd_nocgo.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
package console
3030

3131
import (
32-
"os"
33-
3432
"golang.org/x/sys/unix"
3533
)
3634

@@ -39,10 +37,10 @@ const (
3937
cmdTcSet = unix.TIOCSETA
4038
)
4139

42-
func ptsname(f *os.File) (string, error) {
40+
func ptsname(f File) (string, error) {
4341
panic("ptsname() support requires cgo.")
4442
}
4543

46-
func unlockpt(f *os.File) error {
44+
func unlockpt(f File) error {
4745
panic("unlockpt() support requires cgo.")
4846
}

tc_zos.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package console
1818

1919
import (
20-
"os"
2120
"strings"
2221

2322
"golang.org/x/sys/unix"
@@ -29,11 +28,11 @@ const (
2928
)
3029

3130
// unlockpt is a no-op on zos.
32-
func unlockpt(_ *os.File) error {
31+
func unlockpt(File) error {
3332
return nil
3433
}
3534

3635
// ptsname retrieves the name of the first available pts for the given master.
37-
func ptsname(f *os.File) (string, error) {
36+
func ptsname(f File) (string, error) {
3837
return "/dev/ttyp" + strings.TrimPrefix(f.Name(), "/dev/ptyp"), nil
3938
}

0 commit comments

Comments
 (0)