This repository has been archived by the owner on Jan 25, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 37
/
wirer.go
81 lines (64 loc) · 1.88 KB
/
wirer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package iodaemon
import (
"os"
"os/exec"
"github.com/kr/pty"
)
type Wirer struct {
WithTty bool
WindowColumns int
WindowRows int
}
func (w *Wirer) Wire(cmd *exec.Cmd) (*os.File, *os.File, *os.File, *os.File, error) {
extraFdR, extraFdW, err := os.Pipe()
if err != nil {
return nil, nil, nil, nil, err
}
cmd.ExtraFiles = []*os.File{extraFdR}
var stdinW, stdoutR, stderrR *os.File
if w.WithTty {
cmd.Stdin, stdinW, stdoutR, cmd.Stdout, stderrR, cmd.Stderr, err = createTtyPty(w.WindowColumns, w.WindowRows)
cmd.SysProcAttr.Setctty = true
cmd.SysProcAttr.Setsid = true
} else {
cmd.Stdin, stdinW, stdoutR, cmd.Stdout, stderrR, cmd.Stderr, err = createPipes()
}
return stdinW, stdoutR, stderrR, extraFdW, nil
}
func createPipes() (stdinR, stdinW, stdoutR, stdoutW, stderrR, stderrW *os.File, err error) {
// stderr will not be assigned in the case of a tty, so make
// a dummy pipe to send across instead
stderrR, stderrW, err = os.Pipe()
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
stdinR, stdinW, err = os.Pipe()
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
stdoutR, stdoutW, err = os.Pipe()
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
return
}
func createTtyPty(windowColumns int, windowRows int) (stdinR, stdinW, stdoutR, stdoutW, stderrR, stderrW *os.File, err error) {
// stderr will not be assigned in the case of a tty, so ensure it will return EOF on read
stderrR, err = os.Open("/dev/null")
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
pty, tty, err := pty.Open()
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
// do NOT assign stderrR to pty; the receiving end should only receive one
// pty output stream, as they're both the same fd
stdinW = pty
stdoutR = pty
stdinR = tty
stdoutW = tty
stderrW = tty
setWinSize(stdinW, windowColumns, windowRows)
return
}