/
tty.go
128 lines (112 loc) · 2.41 KB
/
tty.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package docker
import (
"os"
gosignal "os/signal"
"runtime"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/term"
"github.com/pkg/errors"
)
func resizeTty(c *Container, e *Execution, height, width uint, isExec bool) {
if height == 0 && width == 0 {
return
}
options := types.ResizeOptions{
Height: height,
Width: width,
}
client := c.client
ctx := c.options.context
var err error
if isExec {
err = client.ContainerExecResize(ctx, e.execID, options)
} else {
err = client.ContainerResize(ctx, c.ID, options)
}
if err != nil {
log.WithError(err).Debug("resize error")
}
}
func monitorTtySize(c *Container, e *Execution, isExec bool) error {
stdin := c.client.options.stdin
if isExec && e.Stdin != nil {
if s, ok := e.Stdin.(*InStream); ok {
stdin = s
}
}
if stdin == nil {
return nil
}
if !stdin.IsTerminal() {
log.Debug("unable to monitor tty size, because stdin is not a terminal")
return errors.New("not a terminal")
}
getTtySize := func() (uint, uint) {
ws, err := term.GetWinsize(stdin.FD())
if err != nil {
return 0, 0
}
return uint(ws.Height), uint(ws.Width)
}
doResizeTty := func() {
h, w := getTtySize()
resizeTty(c, e, h, w, isExec)
}
doResizeTty()
if runtime.GOOS == "windows" {
go func() {
prevH, prevW := getTtySize()
for {
time.Sleep(time.Millisecond * 250)
h, w := getTtySize()
if h != prevH || w != prevW {
doResizeTty()
}
prevH, prevW = h, w
}
}()
} else {
sigchan := make(chan os.Signal, 1)
gosignal.Notify(sigchan, signal.SIGWINCH)
go func() {
for range sigchan {
doResizeTty()
}
}()
}
return nil
}
func (c *Container) MonitorTtySize() error {
return monitorTtySize(c, nil, false)
}
func (e *Execution) MonitorTtySize() error {
return monitorTtySize(e.container, e, true)
}
func (c *Container) ForwardAllSignals() chan os.Signal {
sigc := make(chan os.Signal, 128)
signal.CatchAll(sigc)
go func() {
for s := range sigc {
if s == signal.SIGCHLD || s == signal.SIGPIPE {
continue
}
var sig string
for sigStr, sigN := range signal.SignalMap {
if sigN == s {
sig = sigStr
break
}
}
if sig == "" {
log.Errorf("Unsupported signal: %v. Discarding.\n", s)
continue
}
if err := c.killWithSignal(sig); err != nil {
log.WithError(err).Debug("sending signal")
}
}
}()
return sigc
}