aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustav Paul <gustav.paul@gmail.com>2011-11-29 12:26:39 -0500
committerAdam Langley <agl@golang.org>2011-11-29 12:26:39 -0500
commitc6691d1fb4e59ba620dd7f4fdb3ea24e8a0ab404 (patch)
tree722419cdd46969286f45f4dad7e5f553200d4c7c
parent175e60a2ad47f477e5e3bfed83beaa9fe6a5ac85 (diff)
downloadgo-c6691d1fb4e59ba620dd7f4fdb3ea24e8a0ab404.tar.gz
go-c6691d1fb4e59ba620dd7f4fdb3ea24e8a0ab404.zip
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
-rw-r--r--src/pkg/exp/ssh/doc.go4
-rw-r--r--src/pkg/exp/ssh/session.go64
2 files changed, 58 insertions, 10 deletions
diff --git a/src/pkg/exp/ssh/doc.go b/src/pkg/exp/ssh/doc.go
index 248b2fec4f..480f877191 100644
--- a/src/pkg/exp/ssh/doc.go
+++ b/src/pkg/exp/ssh/doc.go
@@ -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)
diff --git a/src/pkg/exp/ssh/session.go b/src/pkg/exp/ssh/session.go
index cafa38cf50..dab0113f4b 100644
--- a/src/pkg/exp/ssh/session.go
+++ b/src/pkg/exp/ssh/session.go
@@ -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")