forked from gliderlabs/ssh
-
Notifications
You must be signed in to change notification settings - Fork 6
/
pty_windows.go
96 lines (80 loc) · 1.83 KB
/
pty_windows.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
//go:build windows
// +build windows
package ssh
import (
"fmt"
"os"
"os/exec"
"syscall"
"github.com/charmbracelet/x/conpty"
"golang.org/x/crypto/ssh"
"golang.org/x/sys/windows"
)
type impl struct {
Context
*conpty.ConPty
}
func (i *impl) IsZero() bool {
return i.ConPty == nil
}
func (i *impl) Name() string {
return "windows-pty"
}
func (i *impl) Read(p []byte) (n int, err error) {
return i.ConPty.Read(p)
}
func (i *impl) Write(p []byte) (n int, err error) {
return i.ConPty.Write(p)
}
func (i *impl) Resize(w int, h int) error {
return i.ConPty.Resize(w, h)
}
func (i *impl) Close() error {
return i.ConPty.Close()
}
func (i *impl) start(c *exec.Cmd) error {
pid, process, err := i.Spawn(c.Path, c.Args, &syscall.ProcAttr{
Dir: c.Dir,
Env: c.Env,
Sys: c.SysProcAttr,
})
if err != nil {
return err
}
c.Process, err = os.FindProcess(pid)
if err != nil {
// If we can't find the process via os.FindProcess, terminate the
// process as that's what we rely on for all further operations on the
// object.
if tErr := windows.TerminateProcess(windows.Handle(process), 1); tErr != nil {
return fmt.Errorf("failed to terminate process after process not found: %w", tErr)
}
return fmt.Errorf("failed to find process after starting: %w", err)
}
type result struct {
*os.ProcessState
error
}
donec := make(chan result, 1)
go func() {
state, err := c.Process.Wait()
donec <- result{state, err}
}()
go func() {
select {
case <-i.Context.Done():
c.Err = windows.TerminateProcess(windows.Handle(process), 1)
case r := <-donec:
c.ProcessState = r.ProcessState
c.Err = r.error
}
}()
return nil
}
func newPty(ctx Context, _ string, win Window, _ ssh.TerminalModes) (impl, error) {
c, err := conpty.New(win.Width, win.Height, 0)
if err != nil {
return impl{}, err
}
return impl{ctx, c}, nil
}