update terminal module

ws
dingjun 4 years ago
parent bcf8b9f481
commit ee91917e00

@ -14,10 +14,10 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/containerd/console"
"github.com/fangdingjun/go-log" "github.com/fangdingjun/go-log"
socks "github.com/fangdingjun/socks-go" socks "github.com/fangdingjun/socks-go"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
) )
// Client is ssh client connection // Client is ssh client connection
@ -147,30 +147,46 @@ func (cc *Client) Shell() error {
return err return err
} }
session.Stdin = os.Stdin
session.Stdout = os.Stdout
session.Stderr = os.Stderr
modes := ssh.TerminalModes{ modes := ssh.TerminalModes{
ssh.ECHO: 1, ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400, ssh.TTY_OP_OSPEED: 14400,
} }
_console := console.Current()
defer _console.Reset()
// this make CTRL+C works // this make CTRL+C works
log.Debugf("turn terminal mode to raw") log.Debugf("turn terminal mode to raw")
_console.SetRaw()
oldState, _ := terminal.MakeRaw(0) ws, _ := _console.Size()
defer func() {
log.Debugf("restore terminal mode")
terminal.Restore(0, oldState)
}()
w, h, _ := terminal.GetSize(0)
log.Debugf("request pty") log.Debugf("request pty")
if err := session.RequestPty("xterm", h, w, modes); err != nil { if err := session.RequestPty("xterm", int(ws.Height), int(ws.Width), modes); err != nil {
log.Errorf("request pty error: %s", err.Error()) log.Errorf("request pty error: %s", err.Error())
return err return err
} }
ch := make(chan os.Signal, 2)
signal.Notify(ch, syscall.SIGWINCH)
go func() {
for {
select {
case <-ch:
ws, _ := _console.Size()
_winCh := windowChange{Rows: uint32(ws.Height), Columns: uint32(ws.Width)}
d := ssh.Marshal(_winCh)
ok, err := session.SendRequest("window-change", true, d)
log.Debugf("send window change request %+v %+v", ok, err)
}
}
}()
session.Stdin = _console
session.Stdout = os.Stdout
session.Stderr = os.Stderr
log.Debugf("request shell") log.Debugf("request shell")
if err := session.Shell(); err != nil { if err := session.Shell(); err != nil {
log.Errorf("start shell error: %s", err.Error()) log.Errorf("start shell error: %s", err.Error())

@ -10,7 +10,7 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/creack/pty" "github.com/containerd/console"
"github.com/fangdingjun/go-log" "github.com/fangdingjun/go-log"
"github.com/pkg/sftp" "github.com/pkg/sftp"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@ -178,7 +178,8 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
var env []string var env []string
var _ptyReq ptyReq var _ptyReq ptyReq
var _windowChange windowChange var _windowChange windowChange
var _pty, _tty *os.File var _console console.Console
var ptsname string
for r := range req { for r := range req {
switch r.Type { switch r.Type {
@ -204,7 +205,7 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
cmd = exec.Command("bash", "-l") cmd = exec.Command("bash", "-l")
} }
cmd.Env = env cmd.Env = env
go handleShell(cmd, ch, _pty, _tty) go handleShell(cmd, ch, _console, ptsname)
case "signal": case "signal":
log.Debugln("got signal") log.Debugln("got signal")
ret = true ret = true
@ -233,26 +234,23 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
} }
log.Debugf("pty req %+v", _ptyReq) log.Debugf("pty req %+v", _ptyReq)
if err == nil && (runtime.GOOS == "unix" || runtime.GOOS == "linux") { if err == nil && (runtime.GOOS == "unix" || runtime.GOOS == "linux") {
_pty, _tty, err = pty.Open() _console, ptsname, err = console.NewPty()
if err != nil { if err == nil {
log.Errorln(err) log.Debugf("allocate pty %s", ptsname)
ret = false env = append(env, fmt.Sprintf("SSH_TTY=%s", ptsname))
} else { ws, err := _console.Size()
env = append(env, fmt.Sprintf("TERM=%s", _ptyReq.Term)) if err != nil {
size, err := pty.GetsizeFull(_pty) log.Errorln(err)
if err == nil { } else {
log.Debugf("term size %+v", size) log.Debugf("current console %+v", ws)
size.Rows = uint16(_ptyReq.Rows) ws.Height = uint16(_ptyReq.Rows)
size.Cols = uint16(_ptyReq.Columns) ws.Width = uint16(_ptyReq.Columns)
if err = pty.Setsize(_pty, size); err != nil { if err = _console.Resize(ws); err != nil {
log.Errorln(err)
}
if err = pty.Setsize(_tty, size); err != nil {
log.Errorln(err) log.Errorln(err)
} }
} else {
log.Errorln(err)
} }
} else {
log.Errorln(err)
} }
} }
case "env": case "env":
@ -272,20 +270,17 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
ret = false ret = false
log.Errorln(err) log.Errorln(err)
} }
if err == nil && _pty != nil { if err == nil && _console != nil {
size, err := pty.GetsizeFull(_pty) ws, err := _console.Size()
if err == nil { if err != nil {
log.Debugf("term size %+v", size) log.Errorln(err)
size.Rows = uint16(_ptyReq.Rows) } else {
size.Cols = uint16(_ptyReq.Columns) log.Debugf("current console %+v", ws)
if err = pty.Setsize(_pty, size); err != nil { ws.Height = uint16(_windowChange.Rows)
log.Errorln(err) ws.Width = uint16(_windowChange.Columns)
} if err = _console.Resize(ws); err != nil {
if err = pty.Setsize(_tty, size); err != nil {
log.Errorln(err) log.Errorln(err)
} }
} else {
log.Errorln(err)
} }
} }
log.Debugf("window change %+v", _windowChange) log.Debugf("window change %+v", _windowChange)
@ -301,12 +296,11 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
} }
} }
func handleShell(cmd *exec.Cmd, ch ssh.Channel, _pty, _tty *os.File) { func handleShell(cmd *exec.Cmd, ch ssh.Channel, _console console.Console, ptsname string) {
defer func() { defer func() {
ch.Close() ch.Close()
if _pty != nil { if _console != nil {
_pty.Close() _console.Close()
_tty.Close()
} }
}() }()
@ -314,7 +308,13 @@ func handleShell(cmd *exec.Cmd, ch ssh.Channel, _pty, _tty *os.File) {
log.Infoln("start shell") log.Infoln("start shell")
if _tty != nil { if _console != nil {
_tty, err := os.OpenFile(ptsname, syscall.O_RDWR|syscall.O_NOCTTY, 0600)
if err != nil {
log.Errorln(err)
return
}
defer _tty.Close()
cmd.Stderr = _tty cmd.Stderr = _tty
cmd.Stdout = _tty cmd.Stdout = _tty
cmd.Stdin = _tty cmd.Stdin = _tty
@ -323,10 +323,10 @@ func handleShell(cmd *exec.Cmd, ch ssh.Channel, _pty, _tty *os.File) {
} }
cmd.SysProcAttr.Setsid = true cmd.SysProcAttr.Setsid = true
cmd.SysProcAttr.Setctty = true cmd.SysProcAttr.Setctty = true
cmd.SysProcAttr.Ctty = int(_tty.Fd()) // cmd.SysProcAttr.Ctty = int(_tty.Fd())
go io.Copy(ch, _pty) go io.Copy(ch, _console)
go io.Copy(_pty, ch) go io.Copy(_console, ch)
} else { } else {
cmd.Stderr = ch cmd.Stderr = ch
cmd.Stdout = ch cmd.Stdout = ch

Loading…
Cancel
Save