forked from hyperhq/runv
/
tty.go
112 lines (97 loc) · 2.19 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
package main
import (
"fmt"
"net"
"os"
"os/signal"
"syscall"
"github.com/hyperhq/runv/hypervisor"
"github.com/hyperhq/runv/lib/term"
)
type tty struct {
root string
container string
tag string
termFd uintptr
terminal bool
}
type ttyWinSize struct {
Tag string
Height int
Width int
}
// stdin/stdout <-> conn
func containerTtySplice(root, container string, conn net.Conn, isContainer bool) (int, error) {
tag, err := runvGetTag(conn)
if err != nil {
return -1, err
}
fmt.Printf("tag=%s\n", tag)
outFd, isTerminalOut := term.GetFdInfo(os.Stdout)
newTty(root, container, tag, outFd, isTerminalOut).monitorTtySize()
_, err = term.TtySplice(conn)
if err != nil {
return -1, err
}
cmd := &ttyTagCmd{Root: root, Container: "", Tag: tag}
if isContainer {
cmd.Container = container
}
conn, err = runvRequest(root, container, RUNV_EXITSTATUS, cmd)
if err != nil {
fmt.Printf("runvRequest failed: %v\n", err)
return -1, err
}
defer conn.Close()
msg, err := hypervisor.ReadVmMessage(conn.(*net.UnixConn))
if err != nil {
fmt.Printf("read runv server data failed: %v\n", err)
return -1, err
}
if msg.Code != RUNV_EXITSTATUS {
return -1, fmt.Errorf("unexpected respond code")
}
return int(msg.Message[0]), nil
}
func newTty(root, container, tag string, termFd uintptr, terminal bool) *tty {
return &tty{
root: root,
container: container,
tag: tag,
termFd: termFd,
terminal: terminal,
}
}
func (tty *tty) resizeTty() {
if !tty.terminal {
return
}
height, width := getTtySize(tty.termFd)
ttyCmd := &ttyWinSize{Tag: tty.tag, Height: height, Width: width}
conn, err := runvRequest(tty.root, tty.container, RUNV_WINSIZE, ttyCmd)
if err != nil {
fmt.Printf("Failed to reset winsize")
return
}
conn.Close()
}
func (tty *tty) monitorTtySize() {
tty.resizeTty()
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, syscall.SIGWINCH)
go func() {
for range sigchan {
tty.resizeTty()
}
}()
}
func getTtySize(termFd uintptr) (int, int) {
ws, err := term.GetWinsize(termFd)
if err != nil {
fmt.Printf("Error getting size: %s", err.Error())
if ws == nil {
return 0, 0
}
}
return int(ws.Height), int(ws.Width)
}