aboutsummaryrefslogtreecommitdiff
path: root/vendor/golang.org/x/crypto/ssh/session.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/session.go')
-rw-r--r--vendor/golang.org/x/crypto/ssh/session.go33
1 files changed, 24 insertions, 9 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go
index 09eb009..17e2aa8 100644
--- a/vendor/golang.org/x/crypto/ssh/session.go
+++ b/vendor/golang.org/x/crypto/ssh/session.go
@@ -9,6 +9,7 @@ package ssh
import (
"bytes"
+ "encoding/binary"
"errors"
"fmt"
"io"
@@ -281,9 +282,10 @@ func (s *Session) Start(cmd string) error {
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
-// If the command fails to run or doesn't complete successfully, the
-// error is of type *ExitError. Other error types may be
-// returned for I/O problems.
+// If the remote server does not send an exit status, an error of type
+// *ExitMissingError is returned. If the command completes
+// unsuccessfully or is interrupted by a signal, the error is of type
+// *ExitError. Other error types may be returned for I/O problems.
func (s *Session) Run(cmd string) error {
err := s.Start(cmd)
if err != nil {
@@ -370,9 +372,10 @@ func (s *Session) start() error {
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
-// If the command fails to run or doesn't complete successfully, the
-// error is of type *ExitError. Other error types may be
-// returned for I/O problems.
+// If the remote server does not send an exit status, an error of type
+// *ExitMissingError is returned. If the command completes
+// unsuccessfully or is interrupted by a signal, the error is of type
+// *ExitError. Other error types may be returned for I/O problems.
func (s *Session) Wait() error {
if !s.started {
return errors.New("ssh: session not started")
@@ -400,8 +403,7 @@ func (s *Session) wait(reqs <-chan *Request) error {
for msg := range reqs {
switch msg.Type {
case "exit-status":
- d := msg.Payload
- wm.status = int(d[0])<<24 | int(d[1])<<16 | int(d[2])<<8 | int(d[3])
+ wm.status = int(binary.BigEndian.Uint32(msg.Payload))
case "exit-signal":
var sigval struct {
Signal string
@@ -431,16 +433,29 @@ func (s *Session) wait(reqs <-chan *Request) error {
if wm.status == -1 {
// exit-status was never sent from server
if wm.signal == "" {
- return errors.New("wait: remote command exited without exit status or exit signal")
+ // signal was not sent either. RFC 4254
+ // section 6.10 recommends against this
+ // behavior, but it is allowed, so we let
+ // clients handle it.
+ return &ExitMissingError{}
}
wm.status = 128
if _, ok := signals[Signal(wm.signal)]; ok {
wm.status += signals[Signal(wm.signal)]
}
}
+
return &ExitError{wm}
}
+// ExitMissingError is returned if a session is torn down cleanly, but
+// the server sends no confirmation of the exit status.
+type ExitMissingError struct{}
+
+func (e *ExitMissingError) Error() string {
+ return "wait: remote command exited without exit status or exit signal"
+}
+
func (s *Session) stdin() {
if s.stdinpipe {
return