kr/pty was moved to creak/pty and the old location was
archived.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
... | ... |
@@ -3,7 +3,7 @@ Copyright 2012-2017 Docker, Inc. |
3 | 3 |
|
4 | 4 |
This product includes software developed at Docker, Inc. (https://www.docker.com). |
5 | 5 |
|
6 |
-This product contains software (https://github.com/kr/pty) developed |
|
6 |
+This product contains software (https://github.com/creack/pty) developed |
|
7 | 7 |
by Keith Rarick, licensed under the MIT License. |
8 | 8 |
|
9 | 9 |
The following is courtesy of our legal counsel: |
... | ... |
@@ -24,6 +24,7 @@ import ( |
24 | 24 |
"time" |
25 | 25 |
|
26 | 26 |
"github.com/cloudflare/cfssl/helpers" |
27 |
+ "github.com/creack/pty" |
|
27 | 28 |
"github.com/docker/docker/api/types" |
28 | 29 |
"github.com/docker/docker/integration-cli/checker" |
29 | 30 |
"github.com/docker/docker/integration-cli/cli" |
... | ... |
@@ -36,7 +37,6 @@ import ( |
36 | 36 |
"github.com/docker/libnetwork/iptables" |
37 | 37 |
"github.com/docker/libtrust" |
38 | 38 |
"github.com/go-check/check" |
39 |
- "github.com/kr/pty" |
|
40 | 39 |
"golang.org/x/sys/unix" |
41 | 40 |
"gotest.tools/assert" |
42 | 41 |
"gotest.tools/icmd" |
... | ... |
@@ -17,6 +17,7 @@ import ( |
17 | 17 |
"syscall" |
18 | 18 |
"time" |
19 | 19 |
|
20 |
+ "github.com/creack/pty" |
|
20 | 21 |
"github.com/docker/docker/client" |
21 | 22 |
"github.com/docker/docker/integration-cli/checker" |
22 | 23 |
"github.com/docker/docker/integration-cli/cli" |
... | ... |
@@ -26,7 +27,6 @@ import ( |
26 | 26 |
"github.com/docker/docker/pkg/parsers" |
27 | 27 |
"github.com/docker/docker/pkg/sysinfo" |
28 | 28 |
"github.com/go-check/check" |
29 |
- "github.com/kr/pty" |
|
30 | 29 |
"gotest.tools/assert" |
31 | 30 |
"gotest.tools/icmd" |
32 | 31 |
) |
... | ... |
@@ -10,12 +10,12 @@ import ( |
10 | 10 |
"strings" |
11 | 11 |
"time" |
12 | 12 |
|
13 |
+ "github.com/creack/pty" |
|
13 | 14 |
"github.com/docker/docker/api/types" |
14 | 15 |
"github.com/docker/docker/client" |
15 | 16 |
"github.com/docker/docker/internal/test/request" |
16 | 17 |
"github.com/docker/docker/pkg/parsers/kernel" |
17 | 18 |
"github.com/go-check/check" |
18 |
- "github.com/kr/pty" |
|
19 | 19 |
"gotest.tools/assert" |
20 | 20 |
) |
21 | 21 |
|
... | ... |
@@ -8,8 +8,8 @@ github.com/google/uuid 0cd6bf5da1e1c83f8b45653022c7 |
8 | 8 |
github.com/gorilla/mux ed099d42384823742bba0bf9a72b53b55c9e2e38 # v1.7.2 |
9 | 9 |
github.com/Microsoft/opengcs a10967154e143a36014584a6f664344e3bb0aa64 |
10 | 10 |
|
11 |
+github.com/creack/pty 2769f65a3a94eb8f876f44a0459d24ae7ad2e488 # v1.1.7 |
|
11 | 12 |
github.com/konsorten/go-windows-terminal-sequences f55edac94c9bbba5d6182a4be46d86a2c9b5b50e # v1.0.2 |
12 |
-github.com/kr/pty 521317be5ebc228a0f0ede099fa2a0b5ece22e49 # v1.1.4 |
|
13 | 13 |
github.com/mattn/go-shellwords a72fbe27a1b0ed0df2f02754945044ce1456608b # v1.0.5 |
14 | 14 |
github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f # v1.4.1 |
15 | 15 |
github.com/tchap/go-patricia a7f0089c6f496e8e70402f61733606daa326cac5 # v2.3.0 |
16 | 16 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,23 @@ |
0 |
+Copyright (c) 2011 Keith Rarick |
|
1 |
+ |
|
2 |
+Permission is hereby granted, free of charge, to any person |
|
3 |
+obtaining a copy of this software and associated |
|
4 |
+documentation files (the "Software"), to deal in the |
|
5 |
+Software without restriction, including without limitation |
|
6 |
+the rights to use, copy, modify, merge, publish, distribute, |
|
7 |
+sublicense, and/or sell copies of the Software, and to |
|
8 |
+permit persons to whom the Software is furnished to do so, |
|
9 |
+subject to the following conditions: |
|
10 |
+ |
|
11 |
+The above copyright notice and this permission notice shall |
|
12 |
+be included in all copies or substantial portions of the |
|
13 |
+Software. |
|
14 |
+ |
|
15 |
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
|
16 |
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|
17 |
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
18 |
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS |
|
19 |
+OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
|
20 |
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
21 |
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
22 |
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
0 | 23 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,100 @@ |
0 |
+# pty |
|
1 |
+ |
|
2 |
+Pty is a Go package for using unix pseudo-terminals. |
|
3 |
+ |
|
4 |
+## Install |
|
5 |
+ |
|
6 |
+ go get github.com/creack/pty |
|
7 |
+ |
|
8 |
+## Example |
|
9 |
+ |
|
10 |
+### Command |
|
11 |
+ |
|
12 |
+```go |
|
13 |
+package main |
|
14 |
+ |
|
15 |
+import ( |
|
16 |
+ "github.com/creack/pty" |
|
17 |
+ "io" |
|
18 |
+ "os" |
|
19 |
+ "os/exec" |
|
20 |
+) |
|
21 |
+ |
|
22 |
+func main() { |
|
23 |
+ c := exec.Command("grep", "--color=auto", "bar") |
|
24 |
+ f, err := pty.Start(c) |
|
25 |
+ if err != nil { |
|
26 |
+ panic(err) |
|
27 |
+ } |
|
28 |
+ |
|
29 |
+ go func() { |
|
30 |
+ f.Write([]byte("foo\n")) |
|
31 |
+ f.Write([]byte("bar\n")) |
|
32 |
+ f.Write([]byte("baz\n")) |
|
33 |
+ f.Write([]byte{4}) // EOT |
|
34 |
+ }() |
|
35 |
+ io.Copy(os.Stdout, f) |
|
36 |
+} |
|
37 |
+``` |
|
38 |
+ |
|
39 |
+### Shell |
|
40 |
+ |
|
41 |
+```go |
|
42 |
+package main |
|
43 |
+ |
|
44 |
+import ( |
|
45 |
+ "io" |
|
46 |
+ "log" |
|
47 |
+ "os" |
|
48 |
+ "os/exec" |
|
49 |
+ "os/signal" |
|
50 |
+ "syscall" |
|
51 |
+ |
|
52 |
+ "github.com/creack/pty" |
|
53 |
+ "golang.org/x/crypto/ssh/terminal" |
|
54 |
+) |
|
55 |
+ |
|
56 |
+func test() error { |
|
57 |
+ // Create arbitrary command. |
|
58 |
+ c := exec.Command("bash") |
|
59 |
+ |
|
60 |
+ // Start the command with a pty. |
|
61 |
+ ptmx, err := pty.Start(c) |
|
62 |
+ if err != nil { |
|
63 |
+ return err |
|
64 |
+ } |
|
65 |
+ // Make sure to close the pty at the end. |
|
66 |
+ defer func() { _ = ptmx.Close() }() // Best effort. |
|
67 |
+ |
|
68 |
+ // Handle pty size. |
|
69 |
+ ch := make(chan os.Signal, 1) |
|
70 |
+ signal.Notify(ch, syscall.SIGWINCH) |
|
71 |
+ go func() { |
|
72 |
+ for range ch { |
|
73 |
+ if err := pty.InheritSize(os.Stdin, ptmx); err != nil { |
|
74 |
+ log.Printf("error resizing pty: %s", err) |
|
75 |
+ } |
|
76 |
+ } |
|
77 |
+ }() |
|
78 |
+ ch <- syscall.SIGWINCH // Initial resize. |
|
79 |
+ |
|
80 |
+ // Set stdin in raw mode. |
|
81 |
+ oldState, err := terminal.MakeRaw(int(os.Stdin.Fd())) |
|
82 |
+ if err != nil { |
|
83 |
+ panic(err) |
|
84 |
+ } |
|
85 |
+ defer func() { _ = terminal.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort. |
|
86 |
+ |
|
87 |
+ // Copy stdin to the pty and the pty to stdout. |
|
88 |
+ go func() { _, _ = io.Copy(ptmx, os.Stdin) }() |
|
89 |
+ _, _ = io.Copy(os.Stdout, ptmx) |
|
90 |
+ |
|
91 |
+ return nil |
|
92 |
+} |
|
93 |
+ |
|
94 |
+func main() { |
|
95 |
+ if err := test(); err != nil { |
|
96 |
+ log.Fatal(err) |
|
97 |
+ } |
|
98 |
+} |
|
99 |
+``` |
0 | 100 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,16 @@ |
0 |
+// Package pty provides functions for working with Unix terminals. |
|
1 |
+package pty |
|
2 |
+ |
|
3 |
+import ( |
|
4 |
+ "errors" |
|
5 |
+ "os" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+// ErrUnsupported is returned if a function is not |
|
9 |
+// available on the current platform. |
|
10 |
+var ErrUnsupported = errors.New("unsupported") |
|
11 |
+ |
|
12 |
+// Opens a pty and its corresponding tty. |
|
13 |
+func Open() (pty, tty *os.File, err error) { |
|
14 |
+ return open() |
|
15 |
+} |
0 | 13 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,39 @@ |
0 |
+// +build darwin dragonfly freebsd netbsd openbsd |
|
1 |
+ |
|
2 |
+package pty |
|
3 |
+ |
|
4 |
+// from <sys/ioccom.h> |
|
5 |
+const ( |
|
6 |
+ _IOC_VOID uintptr = 0x20000000 |
|
7 |
+ _IOC_OUT uintptr = 0x40000000 |
|
8 |
+ _IOC_IN uintptr = 0x80000000 |
|
9 |
+ _IOC_IN_OUT uintptr = _IOC_OUT | _IOC_IN |
|
10 |
+ _IOC_DIRMASK = _IOC_VOID | _IOC_OUT | _IOC_IN |
|
11 |
+ |
|
12 |
+ _IOC_PARAM_SHIFT = 13 |
|
13 |
+ _IOC_PARAM_MASK = (1 << _IOC_PARAM_SHIFT) - 1 |
|
14 |
+) |
|
15 |
+ |
|
16 |
+func _IOC_PARM_LEN(ioctl uintptr) uintptr { |
|
17 |
+ return (ioctl >> 16) & _IOC_PARAM_MASK |
|
18 |
+} |
|
19 |
+ |
|
20 |
+func _IOC(inout uintptr, group byte, ioctl_num uintptr, param_len uintptr) uintptr { |
|
21 |
+ return inout | (param_len&_IOC_PARAM_MASK)<<16 | uintptr(group)<<8 | ioctl_num |
|
22 |
+} |
|
23 |
+ |
|
24 |
+func _IO(group byte, ioctl_num uintptr) uintptr { |
|
25 |
+ return _IOC(_IOC_VOID, group, ioctl_num, 0) |
|
26 |
+} |
|
27 |
+ |
|
28 |
+func _IOR(group byte, ioctl_num uintptr, param_len uintptr) uintptr { |
|
29 |
+ return _IOC(_IOC_OUT, group, ioctl_num, param_len) |
|
30 |
+} |
|
31 |
+ |
|
32 |
+func _IOW(group byte, ioctl_num uintptr, param_len uintptr) uintptr { |
|
33 |
+ return _IOC(_IOC_IN, group, ioctl_num, param_len) |
|
34 |
+} |
|
35 |
+ |
|
36 |
+func _IOWR(group byte, ioctl_num uintptr, param_len uintptr) uintptr { |
|
37 |
+ return _IOC(_IOC_IN_OUT, group, ioctl_num, param_len) |
|
38 |
+} |
0 | 39 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,30 @@ |
0 |
+package pty |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "golang.org/x/sys/unix" |
|
4 |
+ "unsafe" |
|
5 |
+) |
|
6 |
+ |
|
7 |
+const ( |
|
8 |
+ // see /usr/include/sys/stropts.h |
|
9 |
+ I_PUSH = uintptr((int32('S')<<8 | 002)) |
|
10 |
+ I_STR = uintptr((int32('S')<<8 | 010)) |
|
11 |
+ I_FIND = uintptr((int32('S')<<8 | 013)) |
|
12 |
+ // see /usr/include/sys/ptms.h |
|
13 |
+ ISPTM = (int32('P') << 8) | 1 |
|
14 |
+ UNLKPT = (int32('P') << 8) | 2 |
|
15 |
+ PTSSTTY = (int32('P') << 8) | 3 |
|
16 |
+ ZONEPT = (int32('P') << 8) | 4 |
|
17 |
+ OWNERPT = (int32('P') << 8) | 5 |
|
18 |
+) |
|
19 |
+ |
|
20 |
+type strioctl struct { |
|
21 |
+ ic_cmd int32 |
|
22 |
+ ic_timout int32 |
|
23 |
+ ic_len int32 |
|
24 |
+ ic_dp unsafe.Pointer |
|
25 |
+} |
|
26 |
+ |
|
27 |
+func ioctl(fd, cmd, ptr uintptr) error { |
|
28 |
+ return unix.IoctlSetInt(int(fd), uint(cmd), int(ptr)) |
|
29 |
+} |
0 | 30 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,65 @@ |
0 |
+package pty |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "os" |
|
5 |
+ "syscall" |
|
6 |
+ "unsafe" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+func open() (pty, tty *os.File, err error) { |
|
10 |
+ pFD, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_CLOEXEC, 0) |
|
11 |
+ if err != nil { |
|
12 |
+ return nil, nil, err |
|
13 |
+ } |
|
14 |
+ p := os.NewFile(uintptr(pFD), "/dev/ptmx") |
|
15 |
+ // In case of error after this point, make sure we close the ptmx fd. |
|
16 |
+ defer func() { |
|
17 |
+ if err != nil { |
|
18 |
+ _ = p.Close() // Best effort. |
|
19 |
+ } |
|
20 |
+ }() |
|
21 |
+ |
|
22 |
+ sname, err := ptsname(p) |
|
23 |
+ if err != nil { |
|
24 |
+ return nil, nil, err |
|
25 |
+ } |
|
26 |
+ |
|
27 |
+ if err := grantpt(p); err != nil { |
|
28 |
+ return nil, nil, err |
|
29 |
+ } |
|
30 |
+ |
|
31 |
+ if err := unlockpt(p); err != nil { |
|
32 |
+ return nil, nil, err |
|
33 |
+ } |
|
34 |
+ |
|
35 |
+ t, err := os.OpenFile(sname, os.O_RDWR, 0) |
|
36 |
+ if err != nil { |
|
37 |
+ return nil, nil, err |
|
38 |
+ } |
|
39 |
+ return p, t, nil |
|
40 |
+} |
|
41 |
+ |
|
42 |
+func ptsname(f *os.File) (string, error) { |
|
43 |
+ n := make([]byte, _IOC_PARM_LEN(syscall.TIOCPTYGNAME)) |
|
44 |
+ |
|
45 |
+ err := ioctl(f.Fd(), syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0]))) |
|
46 |
+ if err != nil { |
|
47 |
+ return "", err |
|
48 |
+ } |
|
49 |
+ |
|
50 |
+ for i, c := range n { |
|
51 |
+ if c == 0 { |
|
52 |
+ return string(n[:i]), nil |
|
53 |
+ } |
|
54 |
+ } |
|
55 |
+ return "", errors.New("TIOCPTYGNAME string not NUL-terminated") |
|
56 |
+} |
|
57 |
+ |
|
58 |
+func grantpt(f *os.File) error { |
|
59 |
+ return ioctl(f.Fd(), syscall.TIOCPTYGRANT, 0) |
|
60 |
+} |
|
61 |
+ |
|
62 |
+func unlockpt(f *os.File) error { |
|
63 |
+ return ioctl(f.Fd(), syscall.TIOCPTYUNLK, 0) |
|
64 |
+} |
0 | 65 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,80 @@ |
0 |
+package pty |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "os" |
|
5 |
+ "strings" |
|
6 |
+ "syscall" |
|
7 |
+ "unsafe" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+// same code as pty_darwin.go |
|
11 |
+func open() (pty, tty *os.File, err error) { |
|
12 |
+ p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) |
|
13 |
+ if err != nil { |
|
14 |
+ return nil, nil, err |
|
15 |
+ } |
|
16 |
+ // In case of error after this point, make sure we close the ptmx fd. |
|
17 |
+ defer func() { |
|
18 |
+ if err != nil { |
|
19 |
+ _ = p.Close() // Best effort. |
|
20 |
+ } |
|
21 |
+ }() |
|
22 |
+ |
|
23 |
+ sname, err := ptsname(p) |
|
24 |
+ if err != nil { |
|
25 |
+ return nil, nil, err |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ if err := grantpt(p); err != nil { |
|
29 |
+ return nil, nil, err |
|
30 |
+ } |
|
31 |
+ |
|
32 |
+ if err := unlockpt(p); err != nil { |
|
33 |
+ return nil, nil, err |
|
34 |
+ } |
|
35 |
+ |
|
36 |
+ t, err := os.OpenFile(sname, os.O_RDWR, 0) |
|
37 |
+ if err != nil { |
|
38 |
+ return nil, nil, err |
|
39 |
+ } |
|
40 |
+ return p, t, nil |
|
41 |
+} |
|
42 |
+ |
|
43 |
+func grantpt(f *os.File) error { |
|
44 |
+ _, err := isptmaster(f.Fd()) |
|
45 |
+ return err |
|
46 |
+} |
|
47 |
+ |
|
48 |
+func unlockpt(f *os.File) error { |
|
49 |
+ _, err := isptmaster(f.Fd()) |
|
50 |
+ return err |
|
51 |
+} |
|
52 |
+ |
|
53 |
+func isptmaster(fd uintptr) (bool, error) { |
|
54 |
+ err := ioctl(fd, syscall.TIOCISPTMASTER, 0) |
|
55 |
+ return err == nil, err |
|
56 |
+} |
|
57 |
+ |
|
58 |
+var ( |
|
59 |
+ emptyFiodgnameArg fiodgnameArg |
|
60 |
+ ioctl_FIODNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg)) |
|
61 |
+) |
|
62 |
+ |
|
63 |
+func ptsname(f *os.File) (string, error) { |
|
64 |
+ name := make([]byte, _C_SPECNAMELEN) |
|
65 |
+ fa := fiodgnameArg{Name: (*byte)(unsafe.Pointer(&name[0])), Len: _C_SPECNAMELEN, Pad_cgo_0: [4]byte{0, 0, 0, 0}} |
|
66 |
+ |
|
67 |
+ err := ioctl(f.Fd(), ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa))) |
|
68 |
+ if err != nil { |
|
69 |
+ return "", err |
|
70 |
+ } |
|
71 |
+ |
|
72 |
+ for i, c := range name { |
|
73 |
+ if c == 0 { |
|
74 |
+ s := "/dev/" + string(name[:i]) |
|
75 |
+ return strings.Replace(s, "ptm", "pts", -1), nil |
|
76 |
+ } |
|
77 |
+ } |
|
78 |
+ return "", errors.New("TIOCPTYGNAME string not NUL-terminated") |
|
79 |
+} |
0 | 80 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,78 @@ |
0 |
+package pty |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "os" |
|
5 |
+ "syscall" |
|
6 |
+ "unsafe" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+func posixOpenpt(oflag int) (fd int, err error) { |
|
10 |
+ r0, _, e1 := syscall.Syscall(syscall.SYS_POSIX_OPENPT, uintptr(oflag), 0, 0) |
|
11 |
+ fd = int(r0) |
|
12 |
+ if e1 != 0 { |
|
13 |
+ err = e1 |
|
14 |
+ } |
|
15 |
+ return fd, err |
|
16 |
+} |
|
17 |
+ |
|
18 |
+func open() (pty, tty *os.File, err error) { |
|
19 |
+ fd, err := posixOpenpt(syscall.O_RDWR | syscall.O_CLOEXEC) |
|
20 |
+ if err != nil { |
|
21 |
+ return nil, nil, err |
|
22 |
+ } |
|
23 |
+ p := os.NewFile(uintptr(fd), "/dev/pts") |
|
24 |
+ // In case of error after this point, make sure we close the pts fd. |
|
25 |
+ defer func() { |
|
26 |
+ if err != nil { |
|
27 |
+ _ = p.Close() // Best effort. |
|
28 |
+ } |
|
29 |
+ }() |
|
30 |
+ |
|
31 |
+ sname, err := ptsname(p) |
|
32 |
+ if err != nil { |
|
33 |
+ return nil, nil, err |
|
34 |
+ } |
|
35 |
+ |
|
36 |
+ t, err := os.OpenFile("/dev/"+sname, os.O_RDWR, 0) |
|
37 |
+ if err != nil { |
|
38 |
+ return nil, nil, err |
|
39 |
+ } |
|
40 |
+ return p, t, nil |
|
41 |
+} |
|
42 |
+ |
|
43 |
+func isptmaster(fd uintptr) (bool, error) { |
|
44 |
+ err := ioctl(fd, syscall.TIOCPTMASTER, 0) |
|
45 |
+ return err == nil, err |
|
46 |
+} |
|
47 |
+ |
|
48 |
+var ( |
|
49 |
+ emptyFiodgnameArg fiodgnameArg |
|
50 |
+ ioctlFIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg)) |
|
51 |
+) |
|
52 |
+ |
|
53 |
+func ptsname(f *os.File) (string, error) { |
|
54 |
+ master, err := isptmaster(f.Fd()) |
|
55 |
+ if err != nil { |
|
56 |
+ return "", err |
|
57 |
+ } |
|
58 |
+ if !master { |
|
59 |
+ return "", syscall.EINVAL |
|
60 |
+ } |
|
61 |
+ |
|
62 |
+ const n = _C_SPECNAMELEN + 1 |
|
63 |
+ var ( |
|
64 |
+ buf = make([]byte, n) |
|
65 |
+ arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))} |
|
66 |
+ ) |
|
67 |
+ if err := ioctl(f.Fd(), ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil { |
|
68 |
+ return "", err |
|
69 |
+ } |
|
70 |
+ |
|
71 |
+ for i, c := range buf { |
|
72 |
+ if c == 0 { |
|
73 |
+ return string(buf[:i]), nil |
|
74 |
+ } |
|
75 |
+ } |
|
76 |
+ return "", errors.New("FIODGNAME string not NUL-terminated") |
|
77 |
+} |
0 | 78 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,51 @@ |
0 |
+package pty |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "os" |
|
4 |
+ "strconv" |
|
5 |
+ "syscall" |
|
6 |
+ "unsafe" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+func open() (pty, tty *os.File, err error) { |
|
10 |
+ p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) |
|
11 |
+ if err != nil { |
|
12 |
+ return nil, nil, err |
|
13 |
+ } |
|
14 |
+ // In case of error after this point, make sure we close the ptmx fd. |
|
15 |
+ defer func() { |
|
16 |
+ if err != nil { |
|
17 |
+ _ = p.Close() // Best effort. |
|
18 |
+ } |
|
19 |
+ }() |
|
20 |
+ |
|
21 |
+ sname, err := ptsname(p) |
|
22 |
+ if err != nil { |
|
23 |
+ return nil, nil, err |
|
24 |
+ } |
|
25 |
+ |
|
26 |
+ if err := unlockpt(p); err != nil { |
|
27 |
+ return nil, nil, err |
|
28 |
+ } |
|
29 |
+ |
|
30 |
+ t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) |
|
31 |
+ if err != nil { |
|
32 |
+ return nil, nil, err |
|
33 |
+ } |
|
34 |
+ return p, t, nil |
|
35 |
+} |
|
36 |
+ |
|
37 |
+func ptsname(f *os.File) (string, error) { |
|
38 |
+ var n _C_uint |
|
39 |
+ err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) |
|
40 |
+ if err != nil { |
|
41 |
+ return "", err |
|
42 |
+ } |
|
43 |
+ return "/dev/pts/" + strconv.Itoa(int(n)), nil |
|
44 |
+} |
|
45 |
+ |
|
46 |
+func unlockpt(f *os.File) error { |
|
47 |
+ var u _C_int |
|
48 |
+ // use TIOCSPTLCK with a pointer to zero to clear the lock |
|
49 |
+ return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) |
|
50 |
+} |
0 | 51 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,33 @@ |
0 |
+package pty |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "os" |
|
4 |
+ "syscall" |
|
5 |
+ "unsafe" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+func open() (pty, tty *os.File, err error) { |
|
9 |
+ /* |
|
10 |
+ * from ptm(4): |
|
11 |
+ * The PTMGET command allocates a free pseudo terminal, changes its |
|
12 |
+ * ownership to the caller, revokes the access privileges for all previous |
|
13 |
+ * users, opens the file descriptors for the pty and tty devices and |
|
14 |
+ * returns them to the caller in struct ptmget. |
|
15 |
+ */ |
|
16 |
+ |
|
17 |
+ p, err := os.OpenFile("/dev/ptm", os.O_RDWR|syscall.O_CLOEXEC, 0) |
|
18 |
+ if err != nil { |
|
19 |
+ return nil, nil, err |
|
20 |
+ } |
|
21 |
+ defer p.Close() |
|
22 |
+ |
|
23 |
+ var ptm ptmget |
|
24 |
+ if err := ioctl(p.Fd(), uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil { |
|
25 |
+ return nil, nil, err |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ pty = os.NewFile(uintptr(ptm.Cfd), "/dev/ptm") |
|
29 |
+ tty = os.NewFile(uintptr(ptm.Sfd), "/dev/ptm") |
|
30 |
+ |
|
31 |
+ return pty, tty, nil |
|
32 |
+} |
0 | 33 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,139 @@ |
0 |
+package pty |
|
1 |
+ |
|
2 |
+/* based on: |
|
3 |
+http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libc/port/gen/pt.c |
|
4 |
+*/ |
|
5 |
+ |
|
6 |
+import ( |
|
7 |
+ "errors" |
|
8 |
+ "golang.org/x/sys/unix" |
|
9 |
+ "os" |
|
10 |
+ "strconv" |
|
11 |
+ "syscall" |
|
12 |
+ "unsafe" |
|
13 |
+) |
|
14 |
+ |
|
15 |
+const NODEV = ^uint64(0) |
|
16 |
+ |
|
17 |
+func open() (pty, tty *os.File, err error) { |
|
18 |
+ masterfd, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|unix.O_NOCTTY, 0) |
|
19 |
+ //masterfd, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_CLOEXEC|unix.O_NOCTTY, 0) |
|
20 |
+ if err != nil { |
|
21 |
+ return nil, nil, err |
|
22 |
+ } |
|
23 |
+ p := os.NewFile(uintptr(masterfd), "/dev/ptmx") |
|
24 |
+ |
|
25 |
+ sname, err := ptsname(p) |
|
26 |
+ if err != nil { |
|
27 |
+ return nil, nil, err |
|
28 |
+ } |
|
29 |
+ |
|
30 |
+ err = grantpt(p) |
|
31 |
+ if err != nil { |
|
32 |
+ return nil, nil, err |
|
33 |
+ } |
|
34 |
+ |
|
35 |
+ err = unlockpt(p) |
|
36 |
+ if err != nil { |
|
37 |
+ return nil, nil, err |
|
38 |
+ } |
|
39 |
+ |
|
40 |
+ slavefd, err := syscall.Open(sname, os.O_RDWR|unix.O_NOCTTY, 0) |
|
41 |
+ if err != nil { |
|
42 |
+ return nil, nil, err |
|
43 |
+ } |
|
44 |
+ t := os.NewFile(uintptr(slavefd), sname) |
|
45 |
+ |
|
46 |
+ // pushing terminal driver STREAMS modules as per pts(7) |
|
47 |
+ for _, mod := range([]string{"ptem", "ldterm", "ttcompat"}) { |
|
48 |
+ err = streams_push(t, mod) |
|
49 |
+ if err != nil { |
|
50 |
+ return nil, nil, err |
|
51 |
+ } |
|
52 |
+ } |
|
53 |
+ |
|
54 |
+ return p, t, nil |
|
55 |
+} |
|
56 |
+ |
|
57 |
+func minor(x uint64) uint64 { |
|
58 |
+ return x & 0377 |
|
59 |
+} |
|
60 |
+ |
|
61 |
+func ptsdev(fd uintptr) uint64 { |
|
62 |
+ istr := strioctl{ISPTM, 0, 0, nil} |
|
63 |
+ err := ioctl(fd, I_STR, uintptr(unsafe.Pointer(&istr))) |
|
64 |
+ if err != nil { |
|
65 |
+ return NODEV |
|
66 |
+ } |
|
67 |
+ var status unix.Stat_t |
|
68 |
+ err = unix.Fstat(int(fd), &status) |
|
69 |
+ if err != nil { |
|
70 |
+ return NODEV |
|
71 |
+ } |
|
72 |
+ return uint64(minor(status.Rdev)) |
|
73 |
+} |
|
74 |
+ |
|
75 |
+func ptsname(f *os.File) (string, error) { |
|
76 |
+ dev := ptsdev(f.Fd()) |
|
77 |
+ if dev == NODEV { |
|
78 |
+ return "", errors.New("not a master pty") |
|
79 |
+ } |
|
80 |
+ fn := "/dev/pts/" + strconv.FormatInt(int64(dev), 10) |
|
81 |
+ // access(2) creates the slave device (if the pty exists) |
|
82 |
+ // F_OK == 0 (unistd.h) |
|
83 |
+ err := unix.Access(fn, 0) |
|
84 |
+ if err != nil { |
|
85 |
+ return "", err |
|
86 |
+ } |
|
87 |
+ return fn, nil |
|
88 |
+} |
|
89 |
+ |
|
90 |
+type pt_own struct { |
|
91 |
+ pto_ruid int32 |
|
92 |
+ pto_rgid int32 |
|
93 |
+} |
|
94 |
+ |
|
95 |
+func grantpt(f *os.File) error { |
|
96 |
+ if ptsdev(f.Fd()) == NODEV { |
|
97 |
+ return errors.New("not a master pty") |
|
98 |
+ } |
|
99 |
+ var pto pt_own |
|
100 |
+ pto.pto_ruid = int32(os.Getuid()) |
|
101 |
+ // XXX should first attempt to get gid of DEFAULT_TTY_GROUP="tty" |
|
102 |
+ pto.pto_rgid = int32(os.Getgid()) |
|
103 |
+ var istr strioctl |
|
104 |
+ istr.ic_cmd = OWNERPT |
|
105 |
+ istr.ic_timout = 0 |
|
106 |
+ istr.ic_len = int32(unsafe.Sizeof(istr)) |
|
107 |
+ istr.ic_dp = unsafe.Pointer(&pto) |
|
108 |
+ err := ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr))) |
|
109 |
+ if err != nil { |
|
110 |
+ return errors.New("access denied") |
|
111 |
+ } |
|
112 |
+ return nil |
|
113 |
+} |
|
114 |
+ |
|
115 |
+func unlockpt(f *os.File) error { |
|
116 |
+ istr := strioctl{UNLKPT, 0, 0, nil} |
|
117 |
+ return ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr))) |
|
118 |
+} |
|
119 |
+ |
|
120 |
+// push STREAMS modules if not already done so |
|
121 |
+func streams_push(f *os.File, mod string) error { |
|
122 |
+ var err error |
|
123 |
+ buf := []byte(mod) |
|
124 |
+ // XXX I_FIND is not returning an error when the module |
|
125 |
+ // is already pushed even though truss reports a return |
|
126 |
+ // value of 1. A bug in the Go Solaris syscall interface? |
|
127 |
+ // XXX without this we are at risk of the issue |
|
128 |
+ // https://www.illumos.org/issues/9042 |
|
129 |
+ // but since we are not using libc or XPG4.2, we should not be |
|
130 |
+ // double-pushing modules |
|
131 |
+ |
|
132 |
+ err = ioctl(f.Fd(), I_FIND, uintptr(unsafe.Pointer(&buf[0]))) |
|
133 |
+ if err != nil { |
|
134 |
+ return nil |
|
135 |
+ } |
|
136 |
+ err = ioctl(f.Fd(), I_PUSH, uintptr(unsafe.Pointer(&buf[0]))) |
|
137 |
+ return err |
|
138 |
+} |
0 | 11 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,57 @@ |
0 |
+// +build !windows |
|
1 |
+ |
|
2 |
+package pty |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "os" |
|
6 |
+ "os/exec" |
|
7 |
+ "syscall" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+// Start assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, |
|
11 |
+// and c.Stderr, calls c.Start, and returns the File of the tty's |
|
12 |
+// corresponding pty. |
|
13 |
+func Start(c *exec.Cmd) (pty *os.File, err error) { |
|
14 |
+ return StartWithSize(c, nil) |
|
15 |
+} |
|
16 |
+ |
|
17 |
+// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, |
|
18 |
+// and c.Stderr, calls c.Start, and returns the File of the tty's |
|
19 |
+// corresponding pty. |
|
20 |
+// |
|
21 |
+// This will resize the pty to the specified size before starting the command |
|
22 |
+func StartWithSize(c *exec.Cmd, sz *Winsize) (pty *os.File, err error) { |
|
23 |
+ pty, tty, err := Open() |
|
24 |
+ if err != nil { |
|
25 |
+ return nil, err |
|
26 |
+ } |
|
27 |
+ defer tty.Close() |
|
28 |
+ if sz != nil { |
|
29 |
+ err = Setsize(pty, sz) |
|
30 |
+ if err != nil { |
|
31 |
+ pty.Close() |
|
32 |
+ return nil, err |
|
33 |
+ } |
|
34 |
+ } |
|
35 |
+ if c.Stdout == nil { |
|
36 |
+ c.Stdout = tty |
|
37 |
+ } |
|
38 |
+ if c.Stderr == nil { |
|
39 |
+ c.Stderr = tty |
|
40 |
+ } |
|
41 |
+ if c.Stdin == nil { |
|
42 |
+ c.Stdin = tty |
|
43 |
+ } |
|
44 |
+ if c.SysProcAttr == nil { |
|
45 |
+ c.SysProcAttr = &syscall.SysProcAttr{} |
|
46 |
+ } |
|
47 |
+ c.SysProcAttr.Setctty = true |
|
48 |
+ c.SysProcAttr.Setsid = true |
|
49 |
+ c.SysProcAttr.Ctty = int(tty.Fd()) |
|
50 |
+ err = c.Start() |
|
51 |
+ if err != nil { |
|
52 |
+ pty.Close() |
|
53 |
+ return nil, err |
|
54 |
+ } |
|
55 |
+ return pty, err |
|
56 |
+} |
0 | 57 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,64 @@ |
0 |
+// +build !windows,!solaris |
|
1 |
+ |
|
2 |
+package pty |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "os" |
|
6 |
+ "syscall" |
|
7 |
+ "unsafe" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+// InheritSize applies the terminal size of pty to tty. This should be run |
|
11 |
+// in a signal handler for syscall.SIGWINCH to automatically resize the tty when |
|
12 |
+// the pty receives a window size change notification. |
|
13 |
+func InheritSize(pty, tty *os.File) error { |
|
14 |
+ size, err := GetsizeFull(pty) |
|
15 |
+ if err != nil { |
|
16 |
+ return err |
|
17 |
+ } |
|
18 |
+ err = Setsize(tty, size) |
|
19 |
+ if err != nil { |
|
20 |
+ return err |
|
21 |
+ } |
|
22 |
+ return nil |
|
23 |
+} |
|
24 |
+ |
|
25 |
+// Setsize resizes t to s. |
|
26 |
+func Setsize(t *os.File, ws *Winsize) error { |
|
27 |
+ return windowRectCall(ws, t.Fd(), syscall.TIOCSWINSZ) |
|
28 |
+} |
|
29 |
+ |
|
30 |
+// GetsizeFull returns the full terminal size description. |
|
31 |
+func GetsizeFull(t *os.File) (size *Winsize, err error) { |
|
32 |
+ var ws Winsize |
|
33 |
+ err = windowRectCall(&ws, t.Fd(), syscall.TIOCGWINSZ) |
|
34 |
+ return &ws, err |
|
35 |
+} |
|
36 |
+ |
|
37 |
+// Getsize returns the number of rows (lines) and cols (positions |
|
38 |
+// in each line) in terminal t. |
|
39 |
+func Getsize(t *os.File) (rows, cols int, err error) { |
|
40 |
+ ws, err := GetsizeFull(t) |
|
41 |
+ return int(ws.Rows), int(ws.Cols), err |
|
42 |
+} |
|
43 |
+ |
|
44 |
+// Winsize describes the terminal size. |
|
45 |
+type Winsize struct { |
|
46 |
+ Rows uint16 // ws_row: Number of rows (in cells) |
|
47 |
+ Cols uint16 // ws_col: Number of columns (in cells) |
|
48 |
+ X uint16 // ws_xpixel: Width in pixels |
|
49 |
+ Y uint16 // ws_ypixel: Height in pixels |
|
50 |
+} |
|
51 |
+ |
|
52 |
+func windowRectCall(ws *Winsize, fd, a2 uintptr) error { |
|
53 |
+ _, _, errno := syscall.Syscall( |
|
54 |
+ syscall.SYS_IOCTL, |
|
55 |
+ fd, |
|
56 |
+ a2, |
|
57 |
+ uintptr(unsafe.Pointer(ws)), |
|
58 |
+ ) |
|
59 |
+ if errno != 0 { |
|
60 |
+ return syscall.Errno(errno) |
|
61 |
+ } |
|
62 |
+ return nil |
|
63 |
+} |
0 | 64 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,51 @@ |
0 |
+// |
|
1 |
+ |
|
2 |
+package pty |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "os" |
|
6 |
+ "golang.org/x/sys/unix" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+const ( |
|
10 |
+ TIOCGWINSZ = 21608 // 'T' << 8 | 104 |
|
11 |
+ TIOCSWINSZ = 21607 // 'T' << 8 | 103 |
|
12 |
+) |
|
13 |
+ |
|
14 |
+// Winsize describes the terminal size. |
|
15 |
+type Winsize struct { |
|
16 |
+ Rows uint16 // ws_row: Number of rows (in cells) |
|
17 |
+ Cols uint16 // ws_col: Number of columns (in cells) |
|
18 |
+ X uint16 // ws_xpixel: Width in pixels |
|
19 |
+ Y uint16 // ws_ypixel: Height in pixels |
|
20 |
+} |
|
21 |
+ |
|
22 |
+// GetsizeFull returns the full terminal size description. |
|
23 |
+func GetsizeFull(t *os.File) (size *Winsize, err error) { |
|
24 |
+ var wsz *unix.Winsize |
|
25 |
+ wsz, err = unix.IoctlGetWinsize(int(t.Fd()), TIOCGWINSZ) |
|
26 |
+ |
|
27 |
+ if err != nil { |
|
28 |
+ return nil, err |
|
29 |
+ } else { |
|
30 |
+ return &Winsize{wsz.Row, wsz.Col, wsz.Xpixel, wsz.Ypixel}, nil |
|
31 |
+ } |
|
32 |
+} |
|
33 |
+ |
|
34 |
+// Get Windows Size |
|
35 |
+func Getsize(t *os.File) (rows, cols int, err error) { |
|
36 |
+ var wsz *unix.Winsize |
|
37 |
+ wsz, err = unix.IoctlGetWinsize(int(t.Fd()), TIOCGWINSZ) |
|
38 |
+ |
|
39 |
+ if err != nil { |
|
40 |
+ return 80, 25, err |
|
41 |
+ } else { |
|
42 |
+ return int(wsz.Row), int(wsz.Col), nil |
|
43 |
+ } |
|
44 |
+} |
|
45 |
+ |
|
46 |
+// Setsize resizes t to s. |
|
47 |
+func Setsize(t *os.File, ws *Winsize) error { |
|
48 |
+ wsz := unix.Winsize{ws.Rows, ws.Cols, ws.X, ws.Y} |
|
49 |
+ return unix.IoctlSetWinsize(int(t.Fd()), TIOCSWINSZ, &wsz) |
|
50 |
+} |
0 | 11 |
deleted file mode 100644 |
... | ... |
@@ -1,23 +0,0 @@ |
1 |
-Copyright (c) 2011 Keith Rarick |
|
2 |
- |
|
3 |
-Permission is hereby granted, free of charge, to any person |
|
4 |
-obtaining a copy of this software and associated |
|
5 |
-documentation files (the "Software"), to deal in the |
|
6 |
-Software without restriction, including without limitation |
|
7 |
-the rights to use, copy, modify, merge, publish, distribute, |
|
8 |
-sublicense, and/or sell copies of the Software, and to |
|
9 |
-permit persons to whom the Software is furnished to do so, |
|
10 |
-subject to the following conditions: |
|
11 |
- |
|
12 |
-The above copyright notice and this permission notice shall |
|
13 |
-be included in all copies or substantial portions of the |
|
14 |
-Software. |
|
15 |
- |
|
16 |
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
|
17 |
-KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|
18 |
-WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
19 |
-PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS |
|
20 |
-OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
|
21 |
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
22 |
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
23 |
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
24 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,100 +0,0 @@ |
1 |
-# pty |
|
2 |
- |
|
3 |
-Pty is a Go package for using unix pseudo-terminals. |
|
4 |
- |
|
5 |
-## Install |
|
6 |
- |
|
7 |
- go get github.com/kr/pty |
|
8 |
- |
|
9 |
-## Example |
|
10 |
- |
|
11 |
-### Command |
|
12 |
- |
|
13 |
-```go |
|
14 |
-package main |
|
15 |
- |
|
16 |
-import ( |
|
17 |
- "github.com/kr/pty" |
|
18 |
- "io" |
|
19 |
- "os" |
|
20 |
- "os/exec" |
|
21 |
-) |
|
22 |
- |
|
23 |
-func main() { |
|
24 |
- c := exec.Command("grep", "--color=auto", "bar") |
|
25 |
- f, err := pty.Start(c) |
|
26 |
- if err != nil { |
|
27 |
- panic(err) |
|
28 |
- } |
|
29 |
- |
|
30 |
- go func() { |
|
31 |
- f.Write([]byte("foo\n")) |
|
32 |
- f.Write([]byte("bar\n")) |
|
33 |
- f.Write([]byte("baz\n")) |
|
34 |
- f.Write([]byte{4}) // EOT |
|
35 |
- }() |
|
36 |
- io.Copy(os.Stdout, f) |
|
37 |
-} |
|
38 |
-``` |
|
39 |
- |
|
40 |
-### Shell |
|
41 |
- |
|
42 |
-```go |
|
43 |
-package main |
|
44 |
- |
|
45 |
-import ( |
|
46 |
- "io" |
|
47 |
- "log" |
|
48 |
- "os" |
|
49 |
- "os/exec" |
|
50 |
- "os/signal" |
|
51 |
- "syscall" |
|
52 |
- |
|
53 |
- "github.com/kr/pty" |
|
54 |
- "golang.org/x/crypto/ssh/terminal" |
|
55 |
-) |
|
56 |
- |
|
57 |
-func test() error { |
|
58 |
- // Create arbitrary command. |
|
59 |
- c := exec.Command("bash") |
|
60 |
- |
|
61 |
- // Start the command with a pty. |
|
62 |
- ptmx, err := pty.Start(c) |
|
63 |
- if err != nil { |
|
64 |
- return err |
|
65 |
- } |
|
66 |
- // Make sure to close the pty at the end. |
|
67 |
- defer func() { _ = ptmx.Close() }() // Best effort. |
|
68 |
- |
|
69 |
- // Handle pty size. |
|
70 |
- ch := make(chan os.Signal, 1) |
|
71 |
- signal.Notify(ch, syscall.SIGWINCH) |
|
72 |
- go func() { |
|
73 |
- for range ch { |
|
74 |
- if err := pty.InheritSize(os.Stdin, ptmx); err != nil { |
|
75 |
- log.Printf("error resizing pty: %s", err) |
|
76 |
- } |
|
77 |
- } |
|
78 |
- }() |
|
79 |
- ch <- syscall.SIGWINCH // Initial resize. |
|
80 |
- |
|
81 |
- // Set stdin in raw mode. |
|
82 |
- oldState, err := terminal.MakeRaw(int(os.Stdin.Fd())) |
|
83 |
- if err != nil { |
|
84 |
- panic(err) |
|
85 |
- } |
|
86 |
- defer func() { _ = terminal.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort. |
|
87 |
- |
|
88 |
- // Copy stdin to the pty and the pty to stdout. |
|
89 |
- go func() { _, _ = io.Copy(ptmx, os.Stdin) }() |
|
90 |
- _, _ = io.Copy(os.Stdout, ptmx) |
|
91 |
- |
|
92 |
- return nil |
|
93 |
-} |
|
94 |
- |
|
95 |
-func main() { |
|
96 |
- if err := test(); err != nil { |
|
97 |
- log.Fatal(err) |
|
98 |
- } |
|
99 |
-} |
|
100 |
-``` |
101 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,16 +0,0 @@ |
1 |
-// Package pty provides functions for working with Unix terminals. |
|
2 |
-package pty |
|
3 |
- |
|
4 |
-import ( |
|
5 |
- "errors" |
|
6 |
- "os" |
|
7 |
-) |
|
8 |
- |
|
9 |
-// ErrUnsupported is returned if a function is not |
|
10 |
-// available on the current platform. |
|
11 |
-var ErrUnsupported = errors.New("unsupported") |
|
12 |
- |
|
13 |
-// Opens a pty and its corresponding tty. |
|
14 |
-func Open() (pty, tty *os.File, err error) { |
|
15 |
- return open() |
|
16 |
-} |
14 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,39 +0,0 @@ |
1 |
-// +build darwin dragonfly freebsd netbsd openbsd |
|
2 |
- |
|
3 |
-package pty |
|
4 |
- |
|
5 |
-// from <sys/ioccom.h> |
|
6 |
-const ( |
|
7 |
- _IOC_VOID uintptr = 0x20000000 |
|
8 |
- _IOC_OUT uintptr = 0x40000000 |
|
9 |
- _IOC_IN uintptr = 0x80000000 |
|
10 |
- _IOC_IN_OUT uintptr = _IOC_OUT | _IOC_IN |
|
11 |
- _IOC_DIRMASK = _IOC_VOID | _IOC_OUT | _IOC_IN |
|
12 |
- |
|
13 |
- _IOC_PARAM_SHIFT = 13 |
|
14 |
- _IOC_PARAM_MASK = (1 << _IOC_PARAM_SHIFT) - 1 |
|
15 |
-) |
|
16 |
- |
|
17 |
-func _IOC_PARM_LEN(ioctl uintptr) uintptr { |
|
18 |
- return (ioctl >> 16) & _IOC_PARAM_MASK |
|
19 |
-} |
|
20 |
- |
|
21 |
-func _IOC(inout uintptr, group byte, ioctl_num uintptr, param_len uintptr) uintptr { |
|
22 |
- return inout | (param_len&_IOC_PARAM_MASK)<<16 | uintptr(group)<<8 | ioctl_num |
|
23 |
-} |
|
24 |
- |
|
25 |
-func _IO(group byte, ioctl_num uintptr) uintptr { |
|
26 |
- return _IOC(_IOC_VOID, group, ioctl_num, 0) |
|
27 |
-} |
|
28 |
- |
|
29 |
-func _IOR(group byte, ioctl_num uintptr, param_len uintptr) uintptr { |
|
30 |
- return _IOC(_IOC_OUT, group, ioctl_num, param_len) |
|
31 |
-} |
|
32 |
- |
|
33 |
-func _IOW(group byte, ioctl_num uintptr, param_len uintptr) uintptr { |
|
34 |
- return _IOC(_IOC_IN, group, ioctl_num, param_len) |
|
35 |
-} |
|
36 |
- |
|
37 |
-func _IOWR(group byte, ioctl_num uintptr, param_len uintptr) uintptr { |
|
38 |
- return _IOC(_IOC_IN_OUT, group, ioctl_num, param_len) |
|
39 |
-} |
40 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,65 +0,0 @@ |
1 |
-package pty |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "errors" |
|
5 |
- "os" |
|
6 |
- "syscall" |
|
7 |
- "unsafe" |
|
8 |
-) |
|
9 |
- |
|
10 |
-func open() (pty, tty *os.File, err error) { |
|
11 |
- pFD, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_CLOEXEC, 0) |
|
12 |
- if err != nil { |
|
13 |
- return nil, nil, err |
|
14 |
- } |
|
15 |
- p := os.NewFile(uintptr(pFD), "/dev/ptmx") |
|
16 |
- // In case of error after this point, make sure we close the ptmx fd. |
|
17 |
- defer func() { |
|
18 |
- if err != nil { |
|
19 |
- _ = p.Close() // Best effort. |
|
20 |
- } |
|
21 |
- }() |
|
22 |
- |
|
23 |
- sname, err := ptsname(p) |
|
24 |
- if err != nil { |
|
25 |
- return nil, nil, err |
|
26 |
- } |
|
27 |
- |
|
28 |
- if err := grantpt(p); err != nil { |
|
29 |
- return nil, nil, err |
|
30 |
- } |
|
31 |
- |
|
32 |
- if err := unlockpt(p); err != nil { |
|
33 |
- return nil, nil, err |
|
34 |
- } |
|
35 |
- |
|
36 |
- t, err := os.OpenFile(sname, os.O_RDWR, 0) |
|
37 |
- if err != nil { |
|
38 |
- return nil, nil, err |
|
39 |
- } |
|
40 |
- return p, t, nil |
|
41 |
-} |
|
42 |
- |
|
43 |
-func ptsname(f *os.File) (string, error) { |
|
44 |
- n := make([]byte, _IOC_PARM_LEN(syscall.TIOCPTYGNAME)) |
|
45 |
- |
|
46 |
- err := ioctl(f.Fd(), syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0]))) |
|
47 |
- if err != nil { |
|
48 |
- return "", err |
|
49 |
- } |
|
50 |
- |
|
51 |
- for i, c := range n { |
|
52 |
- if c == 0 { |
|
53 |
- return string(n[:i]), nil |
|
54 |
- } |
|
55 |
- } |
|
56 |
- return "", errors.New("TIOCPTYGNAME string not NUL-terminated") |
|
57 |
-} |
|
58 |
- |
|
59 |
-func grantpt(f *os.File) error { |
|
60 |
- return ioctl(f.Fd(), syscall.TIOCPTYGRANT, 0) |
|
61 |
-} |
|
62 |
- |
|
63 |
-func unlockpt(f *os.File) error { |
|
64 |
- return ioctl(f.Fd(), syscall.TIOCPTYUNLK, 0) |
|
65 |
-} |
66 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,80 +0,0 @@ |
1 |
-package pty |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "errors" |
|
5 |
- "os" |
|
6 |
- "strings" |
|
7 |
- "syscall" |
|
8 |
- "unsafe" |
|
9 |
-) |
|
10 |
- |
|
11 |
-// same code as pty_darwin.go |
|
12 |
-func open() (pty, tty *os.File, err error) { |
|
13 |
- p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) |
|
14 |
- if err != nil { |
|
15 |
- return nil, nil, err |
|
16 |
- } |
|
17 |
- // In case of error after this point, make sure we close the ptmx fd. |
|
18 |
- defer func() { |
|
19 |
- if err != nil { |
|
20 |
- _ = p.Close() // Best effort. |
|
21 |
- } |
|
22 |
- }() |
|
23 |
- |
|
24 |
- sname, err := ptsname(p) |
|
25 |
- if err != nil { |
|
26 |
- return nil, nil, err |
|
27 |
- } |
|
28 |
- |
|
29 |
- if err := grantpt(p); err != nil { |
|
30 |
- return nil, nil, err |
|
31 |
- } |
|
32 |
- |
|
33 |
- if err := unlockpt(p); err != nil { |
|
34 |
- return nil, nil, err |
|
35 |
- } |
|
36 |
- |
|
37 |
- t, err := os.OpenFile(sname, os.O_RDWR, 0) |
|
38 |
- if err != nil { |
|
39 |
- return nil, nil, err |
|
40 |
- } |
|
41 |
- return p, t, nil |
|
42 |
-} |
|
43 |
- |
|
44 |
-func grantpt(f *os.File) error { |
|
45 |
- _, err := isptmaster(f.Fd()) |
|
46 |
- return err |
|
47 |
-} |
|
48 |
- |
|
49 |
-func unlockpt(f *os.File) error { |
|
50 |
- _, err := isptmaster(f.Fd()) |
|
51 |
- return err |
|
52 |
-} |
|
53 |
- |
|
54 |
-func isptmaster(fd uintptr) (bool, error) { |
|
55 |
- err := ioctl(fd, syscall.TIOCISPTMASTER, 0) |
|
56 |
- return err == nil, err |
|
57 |
-} |
|
58 |
- |
|
59 |
-var ( |
|
60 |
- emptyFiodgnameArg fiodgnameArg |
|
61 |
- ioctl_FIODNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg)) |
|
62 |
-) |
|
63 |
- |
|
64 |
-func ptsname(f *os.File) (string, error) { |
|
65 |
- name := make([]byte, _C_SPECNAMELEN) |
|
66 |
- fa := fiodgnameArg{Name: (*byte)(unsafe.Pointer(&name[0])), Len: _C_SPECNAMELEN, Pad_cgo_0: [4]byte{0, 0, 0, 0}} |
|
67 |
- |
|
68 |
- err := ioctl(f.Fd(), ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa))) |
|
69 |
- if err != nil { |
|
70 |
- return "", err |
|
71 |
- } |
|
72 |
- |
|
73 |
- for i, c := range name { |
|
74 |
- if c == 0 { |
|
75 |
- s := "/dev/" + string(name[:i]) |
|
76 |
- return strings.Replace(s, "ptm", "pts", -1), nil |
|
77 |
- } |
|
78 |
- } |
|
79 |
- return "", errors.New("TIOCPTYGNAME string not NUL-terminated") |
|
80 |
-} |
81 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,78 +0,0 @@ |
1 |
-package pty |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "errors" |
|
5 |
- "os" |
|
6 |
- "syscall" |
|
7 |
- "unsafe" |
|
8 |
-) |
|
9 |
- |
|
10 |
-func posixOpenpt(oflag int) (fd int, err error) { |
|
11 |
- r0, _, e1 := syscall.Syscall(syscall.SYS_POSIX_OPENPT, uintptr(oflag), 0, 0) |
|
12 |
- fd = int(r0) |
|
13 |
- if e1 != 0 { |
|
14 |
- err = e1 |
|
15 |
- } |
|
16 |
- return fd, err |
|
17 |
-} |
|
18 |
- |
|
19 |
-func open() (pty, tty *os.File, err error) { |
|
20 |
- fd, err := posixOpenpt(syscall.O_RDWR | syscall.O_CLOEXEC) |
|
21 |
- if err != nil { |
|
22 |
- return nil, nil, err |
|
23 |
- } |
|
24 |
- p := os.NewFile(uintptr(fd), "/dev/pts") |
|
25 |
- // In case of error after this point, make sure we close the pts fd. |
|
26 |
- defer func() { |
|
27 |
- if err != nil { |
|
28 |
- _ = p.Close() // Best effort. |
|
29 |
- } |
|
30 |
- }() |
|
31 |
- |
|
32 |
- sname, err := ptsname(p) |
|
33 |
- if err != nil { |
|
34 |
- return nil, nil, err |
|
35 |
- } |
|
36 |
- |
|
37 |
- t, err := os.OpenFile("/dev/"+sname, os.O_RDWR, 0) |
|
38 |
- if err != nil { |
|
39 |
- return nil, nil, err |
|
40 |
- } |
|
41 |
- return p, t, nil |
|
42 |
-} |
|
43 |
- |
|
44 |
-func isptmaster(fd uintptr) (bool, error) { |
|
45 |
- err := ioctl(fd, syscall.TIOCPTMASTER, 0) |
|
46 |
- return err == nil, err |
|
47 |
-} |
|
48 |
- |
|
49 |
-var ( |
|
50 |
- emptyFiodgnameArg fiodgnameArg |
|
51 |
- ioctlFIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg)) |
|
52 |
-) |
|
53 |
- |
|
54 |
-func ptsname(f *os.File) (string, error) { |
|
55 |
- master, err := isptmaster(f.Fd()) |
|
56 |
- if err != nil { |
|
57 |
- return "", err |
|
58 |
- } |
|
59 |
- if !master { |
|
60 |
- return "", syscall.EINVAL |
|
61 |
- } |
|
62 |
- |
|
63 |
- const n = _C_SPECNAMELEN + 1 |
|
64 |
- var ( |
|
65 |
- buf = make([]byte, n) |
|
66 |
- arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))} |
|
67 |
- ) |
|
68 |
- if err := ioctl(f.Fd(), ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil { |
|
69 |
- return "", err |
|
70 |
- } |
|
71 |
- |
|
72 |
- for i, c := range buf { |
|
73 |
- if c == 0 { |
|
74 |
- return string(buf[:i]), nil |
|
75 |
- } |
|
76 |
- } |
|
77 |
- return "", errors.New("FIODGNAME string not NUL-terminated") |
|
78 |
-} |
79 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,51 +0,0 @@ |
1 |
-package pty |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "os" |
|
5 |
- "strconv" |
|
6 |
- "syscall" |
|
7 |
- "unsafe" |
|
8 |
-) |
|
9 |
- |
|
10 |
-func open() (pty, tty *os.File, err error) { |
|
11 |
- p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) |
|
12 |
- if err != nil { |
|
13 |
- return nil, nil, err |
|
14 |
- } |
|
15 |
- // In case of error after this point, make sure we close the ptmx fd. |
|
16 |
- defer func() { |
|
17 |
- if err != nil { |
|
18 |
- _ = p.Close() // Best effort. |
|
19 |
- } |
|
20 |
- }() |
|
21 |
- |
|
22 |
- sname, err := ptsname(p) |
|
23 |
- if err != nil { |
|
24 |
- return nil, nil, err |
|
25 |
- } |
|
26 |
- |
|
27 |
- if err := unlockpt(p); err != nil { |
|
28 |
- return nil, nil, err |
|
29 |
- } |
|
30 |
- |
|
31 |
- t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) |
|
32 |
- if err != nil { |
|
33 |
- return nil, nil, err |
|
34 |
- } |
|
35 |
- return p, t, nil |
|
36 |
-} |
|
37 |
- |
|
38 |
-func ptsname(f *os.File) (string, error) { |
|
39 |
- var n _C_uint |
|
40 |
- err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) |
|
41 |
- if err != nil { |
|
42 |
- return "", err |
|
43 |
- } |
|
44 |
- return "/dev/pts/" + strconv.Itoa(int(n)), nil |
|
45 |
-} |
|
46 |
- |
|
47 |
-func unlockpt(f *os.File) error { |
|
48 |
- var u _C_int |
|
49 |
- // use TIOCSPTLCK with a pointer to zero to clear the lock |
|
50 |
- return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) |
|
51 |
-} |
52 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,33 +0,0 @@ |
1 |
-package pty |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "os" |
|
5 |
- "syscall" |
|
6 |
- "unsafe" |
|
7 |
-) |
|
8 |
- |
|
9 |
-func open() (pty, tty *os.File, err error) { |
|
10 |
- /* |
|
11 |
- * from ptm(4): |
|
12 |
- * The PTMGET command allocates a free pseudo terminal, changes its |
|
13 |
- * ownership to the caller, revokes the access privileges for all previous |
|
14 |
- * users, opens the file descriptors for the pty and tty devices and |
|
15 |
- * returns them to the caller in struct ptmget. |
|
16 |
- */ |
|
17 |
- |
|
18 |
- p, err := os.OpenFile("/dev/ptm", os.O_RDWR|syscall.O_CLOEXEC, 0) |
|
19 |
- if err != nil { |
|
20 |
- return nil, nil, err |
|
21 |
- } |
|
22 |
- defer p.Close() |
|
23 |
- |
|
24 |
- var ptm ptmget |
|
25 |
- if err := ioctl(p.Fd(), uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil { |
|
26 |
- return nil, nil, err |
|
27 |
- } |
|
28 |
- |
|
29 |
- pty = os.NewFile(uintptr(ptm.Cfd), "/dev/ptm") |
|
30 |
- tty = os.NewFile(uintptr(ptm.Sfd), "/dev/ptm") |
|
31 |
- |
|
32 |
- return pty, tty, nil |
|
33 |
-} |
12 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,56 +0,0 @@ |
1 |
-// +build !windows |
|
2 |
- |
|
3 |
-package pty |
|
4 |
- |
|
5 |
-import ( |
|
6 |
- "os" |
|
7 |
- "os/exec" |
|
8 |
- "syscall" |
|
9 |
-) |
|
10 |
- |
|
11 |
-// Start assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, |
|
12 |
-// and c.Stderr, calls c.Start, and returns the File of the tty's |
|
13 |
-// corresponding pty. |
|
14 |
-func Start(c *exec.Cmd) (pty *os.File, err error) { |
|
15 |
- return StartWithSize(c, nil) |
|
16 |
-} |
|
17 |
- |
|
18 |
-// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, |
|
19 |
-// and c.Stderr, calls c.Start, and returns the File of the tty's |
|
20 |
-// corresponding pty. |
|
21 |
-// |
|
22 |
-// This will resize the pty to the specified size before starting the command |
|
23 |
-func StartWithSize(c *exec.Cmd, sz *Winsize) (pty *os.File, err error) { |
|
24 |
- pty, tty, err := Open() |
|
25 |
- if err != nil { |
|
26 |
- return nil, err |
|
27 |
- } |
|
28 |
- defer tty.Close() |
|
29 |
- if sz != nil { |
|
30 |
- err = Setsize(pty, sz) |
|
31 |
- if err != nil { |
|
32 |
- pty.Close() |
|
33 |
- return nil, err |
|
34 |
- } |
|
35 |
- } |
|
36 |
- if c.Stdout == nil { |
|
37 |
- c.Stdout = tty |
|
38 |
- } |
|
39 |
- if c.Stderr == nil { |
|
40 |
- c.Stderr = tty |
|
41 |
- } |
|
42 |
- if c.Stdin == nil { |
|
43 |
- c.Stdin = tty |
|
44 |
- } |
|
45 |
- if c.SysProcAttr == nil { |
|
46 |
- c.SysProcAttr = &syscall.SysProcAttr{} |
|
47 |
- } |
|
48 |
- c.SysProcAttr.Setctty = true |
|
49 |
- c.SysProcAttr.Setsid = true |
|
50 |
- err = c.Start() |
|
51 |
- if err != nil { |
|
52 |
- pty.Close() |
|
53 |
- return nil, err |
|
54 |
- } |
|
55 |
- return pty, err |
|
56 |
-} |
57 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,64 +0,0 @@ |
1 |
-// +build !windows |
|
2 |
- |
|
3 |
-package pty |
|
4 |
- |
|
5 |
-import ( |
|
6 |
- "os" |
|
7 |
- "syscall" |
|
8 |
- "unsafe" |
|
9 |
-) |
|
10 |
- |
|
11 |
-// InheritSize applies the terminal size of pty to tty. This should be run |
|
12 |
-// in a signal handler for syscall.SIGWINCH to automatically resize the tty when |
|
13 |
-// the pty receives a window size change notification. |
|
14 |
-func InheritSize(pty, tty *os.File) error { |
|
15 |
- size, err := GetsizeFull(pty) |
|
16 |
- if err != nil { |
|
17 |
- return err |
|
18 |
- } |
|
19 |
- err = Setsize(tty, size) |
|
20 |
- if err != nil { |
|
21 |
- return err |
|
22 |
- } |
|
23 |
- return nil |
|
24 |
-} |
|
25 |
- |
|
26 |
-// Setsize resizes t to s. |
|
27 |
-func Setsize(t *os.File, ws *Winsize) error { |
|
28 |
- return windowRectCall(ws, t.Fd(), syscall.TIOCSWINSZ) |
|
29 |
-} |
|
30 |
- |
|
31 |
-// GetsizeFull returns the full terminal size description. |
|
32 |
-func GetsizeFull(t *os.File) (size *Winsize, err error) { |
|
33 |
- var ws Winsize |
|
34 |
- err = windowRectCall(&ws, t.Fd(), syscall.TIOCGWINSZ) |
|
35 |
- return &ws, err |
|
36 |
-} |
|
37 |
- |
|
38 |
-// Getsize returns the number of rows (lines) and cols (positions |
|
39 |
-// in each line) in terminal t. |
|
40 |
-func Getsize(t *os.File) (rows, cols int, err error) { |
|
41 |
- ws, err := GetsizeFull(t) |
|
42 |
- return int(ws.Rows), int(ws.Cols), err |
|
43 |
-} |
|
44 |
- |
|
45 |
-// Winsize describes the terminal size. |
|
46 |
-type Winsize struct { |
|
47 |
- Rows uint16 // ws_row: Number of rows (in cells) |
|
48 |
- Cols uint16 // ws_col: Number of columns (in cells) |
|
49 |
- X uint16 // ws_xpixel: Width in pixels |
|
50 |
- Y uint16 // ws_ypixel: Height in pixels |
|
51 |
-} |
|
52 |
- |
|
53 |
-func windowRectCall(ws *Winsize, fd, a2 uintptr) error { |
|
54 |
- _, _, errno := syscall.Syscall( |
|
55 |
- syscall.SYS_IOCTL, |
|
56 |
- fd, |
|
57 |
- a2, |
|
58 |
- uintptr(unsafe.Pointer(ws)), |
|
59 |
- ) |
|
60 |
- if errno != 0 { |
|
61 |
- return syscall.Errno(errno) |
|
62 |
- } |
|
63 |
- return nil |
|
64 |
-} |