Commit c6691d1f authored by Gustav Paul's avatar Gustav Paul Committed by Adam Langley

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
parent 175e60a2
......@@ -92,9 +92,9 @@ Each ClientConn can support multiple interactive sessions, represented by a Sess
session, err := client.NewSession()
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())
}
reader := bufio.NewReader(session.Stdin)
......
......@@ -15,6 +15,25 @@ import (
"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.
type Session struct {
// Stdin specifies the remote process's standard input.
......@@ -35,7 +54,7 @@ type Session struct {
*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
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
// command executed by Shell or Exec.
// command executed by Shell or Run.
func (s *Session) Setenv(name, value string) error {
req := setenvRequest{
PeersId: s.peersId,
......@@ -100,6 +119,26 @@ func (s *Session) RequestPty(term string, h, w int) error {
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.
type execMsg struct {
PeersId uint32
......@@ -108,10 +147,10 @@ type execMsg struct {
Command string
}
// Exec runs cmd on the remote host. Typically, the remote
// server passes cmd to the shell for interpretation.
// A Session only accepts one call to Exec or Shell.
func (s *Session) Exec(cmd string) error {
// Start runs cmd on the remote host. 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) Start(cmd string) error {
if s.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 {
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 s.Wait()
}
// 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 {
if s.started {
return errors.New("ssh: session already started")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment