mirror of
https://github.com/golang/go
synced 2024-11-21 21:04:41 -07:00
exp/ssh: Add Start(cmd string) and Signal(sig string) to Session. Rename Exec to Run.
Exec() has been renamed to Run() in keeping with the os/exec API. Added func (*Session) Start(cmd string) which starts a remote process but unlike Run() doesn't wait for it to finish before returning. Run() has been refactored to use Start internally. Its really just a refactoring, no new code but some extra functionality was won. Also added func (*Session) Signal(sig signal) which sends a UNIX signal to a remote process. This is espcially useful in conjunction with Start() as the two allow you to start a remote process, monitor its stdout/stderr, and send it a TERM/HUP/etc signal when you want it to close. R=dave, rsc, agl, bradfitz, n13m3y3r, gustavo CC=golang-dev https://golang.org/cl/5437058
This commit is contained in:
parent
175e60a2ad
commit
c6691d1fb4
@ -92,9 +92,9 @@ Each ClientConn can support multiple interactive sessions, represented by a Sess
|
|||||||
session, err := client.NewSession()
|
session, err := client.NewSession()
|
||||||
|
|
||||||
Once a Session is created, you can execute a single command on the remote side
|
Once a Session is created, you can execute a single command on the remote side
|
||||||
using the Exec method.
|
using the Run method.
|
||||||
|
|
||||||
if err := session.Exec("/usr/bin/whoami"); err != nil {
|
if err := session.Run("/usr/bin/whoami"); err != nil {
|
||||||
panic("Failed to exec: " + err.String())
|
panic("Failed to exec: " + err.String())
|
||||||
}
|
}
|
||||||
reader := bufio.NewReader(session.Stdin)
|
reader := bufio.NewReader(session.Stdin)
|
||||||
|
@ -15,6 +15,25 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type signal string
|
||||||
|
|
||||||
|
// POSIX signals as listed in RFC 4254 Section 6.10.
|
||||||
|
const (
|
||||||
|
SIGABRT signal = "ABRT"
|
||||||
|
SIGALRM signal = "ALRM"
|
||||||
|
SIGFPE signal = "FPE"
|
||||||
|
SIGHUP signal = "HUP"
|
||||||
|
SIGILL signal = "ILL"
|
||||||
|
SIGINT signal = "INT"
|
||||||
|
SIGKILL signal = "KILL"
|
||||||
|
SIGPIPE signal = "PIPE"
|
||||||
|
SIGQUIT signal = "QUIT"
|
||||||
|
SIGSEGV signal = "SEGV"
|
||||||
|
SIGTERM signal = "TERM"
|
||||||
|
SIGUSR1 signal = "USR1"
|
||||||
|
SIGUSR2 signal = "USR2"
|
||||||
|
)
|
||||||
|
|
||||||
// A Session represents a connection to a remote command or shell.
|
// A Session represents a connection to a remote command or shell.
|
||||||
type Session struct {
|
type Session struct {
|
||||||
// Stdin specifies the remote process's standard input.
|
// Stdin specifies the remote process's standard input.
|
||||||
@ -35,7 +54,7 @@ type Session struct {
|
|||||||
|
|
||||||
*clientChan // the channel backing this session
|
*clientChan // the channel backing this session
|
||||||
|
|
||||||
started bool // true once a Shell or Exec is invoked.
|
started bool // true once a Shell or Run is invoked.
|
||||||
copyFuncs []func() error
|
copyFuncs []func() error
|
||||||
errch chan error // one send per copyFunc
|
errch chan error // one send per copyFunc
|
||||||
}
|
}
|
||||||
@ -50,7 +69,7 @@ type setenvRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setenv sets an environment variable that will be applied to any
|
// Setenv sets an environment variable that will be applied to any
|
||||||
// command executed by Shell or Exec.
|
// command executed by Shell or Run.
|
||||||
func (s *Session) Setenv(name, value string) error {
|
func (s *Session) Setenv(name, value string) error {
|
||||||
req := setenvRequest{
|
req := setenvRequest{
|
||||||
PeersId: s.peersId,
|
PeersId: s.peersId,
|
||||||
@ -100,6 +119,26 @@ func (s *Session) RequestPty(term string, h, w int) error {
|
|||||||
return s.waitForResponse()
|
return s.waitForResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RFC 4254 Section 6.9.
|
||||||
|
type signalMsg struct {
|
||||||
|
PeersId uint32
|
||||||
|
Request string
|
||||||
|
WantReply bool
|
||||||
|
Signal string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal sends the given signal to the remote process.
|
||||||
|
// sig is one of the SIG* constants.
|
||||||
|
func (s *Session) Signal(sig signal) error {
|
||||||
|
req := signalMsg{
|
||||||
|
PeersId: s.peersId,
|
||||||
|
Request: "signal",
|
||||||
|
WantReply: false,
|
||||||
|
Signal: string(sig),
|
||||||
|
}
|
||||||
|
return s.writePacket(marshal(msgChannelRequest, req))
|
||||||
|
}
|
||||||
|
|
||||||
// RFC 4254 Section 6.5.
|
// RFC 4254 Section 6.5.
|
||||||
type execMsg struct {
|
type execMsg struct {
|
||||||
PeersId uint32
|
PeersId uint32
|
||||||
@ -108,10 +147,10 @@ type execMsg struct {
|
|||||||
Command string
|
Command string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec runs cmd on the remote host. Typically, the remote
|
// Start runs cmd on the remote host. Typically, the remote
|
||||||
// server passes cmd to the shell for interpretation.
|
// server passes cmd to the shell for interpretation.
|
||||||
// A Session only accepts one call to Exec or Shell.
|
// A Session only accepts one call to Run, Start or Shell.
|
||||||
func (s *Session) Exec(cmd string) error {
|
func (s *Session) Start(cmd string) error {
|
||||||
if s.started {
|
if s.started {
|
||||||
return errors.New("ssh: session already started")
|
return errors.New("ssh: session already started")
|
||||||
}
|
}
|
||||||
@ -127,14 +166,23 @@ func (s *Session) Exec(cmd string) error {
|
|||||||
if err := s.waitForResponse(); err != nil {
|
if err := s.waitForResponse(); err != nil {
|
||||||
return fmt.Errorf("ssh: could not execute command %s: %v", cmd, err)
|
return fmt.Errorf("ssh: could not execute command %s: %v", cmd, err)
|
||||||
}
|
}
|
||||||
if err := s.start(); err != nil {
|
return s.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs cmd on the remote host and waits for it to terminate.
|
||||||
|
// Typically, the remote server passes cmd to the shell for
|
||||||
|
// interpretation. A Session only accepts one call to Run,
|
||||||
|
// Start or Shell.
|
||||||
|
func (s *Session) Run(cmd string) error {
|
||||||
|
err := s.Start(cmd)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return s.Wait()
|
return s.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shell starts a login shell on the remote host. A Session only
|
// Shell starts a login shell on the remote host. A Session only
|
||||||
// accepts one call to Exec or Shell.
|
// accepts one call to Run, Start or Shell.
|
||||||
func (s *Session) Shell() error {
|
func (s *Session) Shell() error {
|
||||||
if s.started {
|
if s.started {
|
||||||
return errors.New("ssh: session already started")
|
return errors.New("ssh: session already started")
|
||||||
|
Loading…
Reference in New Issue
Block a user