func configureSessionIO(session *ssh.Session) error { fmt.Println("Requesting Pseudo Terminal") if err := session.RequestPty("xterm", 80, 40, modes); err != nil { fmt.Println("Unable to request Pseudo Terminal") fmt.Println("Error : ", err.Error()) return err } fmt.Println("Setting up STDIN") stdin, err := session.StdinPipe() if err != nil { fmt.Println("Unable to setup STDIN") fmt.Println("Error : ", err.Error()) return err } go io.Copy(stdin, os.Stdin) fmt.Println("Setting up STDOUT") stdout, err := session.StdoutPipe() if err != nil { fmt.Println("Unable to setup STDOUT") fmt.Println("Error : ", err.Error()) return err } go io.Copy(os.Stdout, stdout) fmt.Println("Setting up STDERR") stderr, err := session.StderrPipe() if err != nil { fmt.Println("Unable to setup STDERR") fmt.Println("Error : ", err.Error()) return err } go io.Copy(os.Stderr, stderr) return nil }
// NewClient creates a new SFTP client on top of an already created // ssh.Session. func NewClient(s *ssh.Session) (*Client, error) { stdin, err := s.StdinPipe() if err != nil { return nil, err } stdout, err := s.StdoutPipe() if err != nil { return nil, err } stderr, err := s.StderrPipe() if err != nil { return nil, err } if err := s.RequestSubsystem("sftp"); err != nil { return nil, err } sftp := &Client{ stdin: stdin, stdout: stdout, stderr: stderr, chans: &fxpChanList{}, session: s, } if err := sftp.init(); err != nil { return nil, err } return sftp, nil }
func logSession(session *ssh.Session) { { r, err := session.StdoutPipe() if err != nil { exitf("failed to get stdoutPipe: %s", err) } go io.Copy(os.Stdout, r) } { r, err := session.StderrPipe() if err != nil { exitf("failed to get StderrPipe: %s", err) } go io.Copy(os.Stderr, r) } }
func tailFile(session *ssh.Session, file string, sudo bool, linec chan<- string) error { var command string if sudo { command = fmt.Sprintf("sudo /usr/bin/env tail -F %s", file) } else { command = fmt.Sprintf("/usr/bin/env tail -F %s", file) } var wg sync.WaitGroup errc := make(chan error, 3) consumeStream := func(r io.Reader) { defer wg.Done() scan := bufio.NewScanner(r) scan.Split(bufio.ScanLines) for scan.Scan() { linec <- scan.Text() } if err := scan.Err(); err != nil { errc <- err } } stderr, err := session.StderrPipe() if err != nil { return fmt.Errorf("opening stderr: %v", err) } stdout, err := session.StdoutPipe() if err != nil { return fmt.Errorf("opening stdout: %v", err) } wg.Add(1) go consumeStream(stderr) go consumeStream(stdout) if err := session.Start(command); err != nil { return err } wg.Add(1) go func() { if err := session.Wait(); err != nil { errc <- err } }() go func() { wg.Wait() close(errc) }() return <-errc }
// Get stdin, stdout, and stderr from the SSH session. func sessionStreams(session *ssh.Session) (stdin io.WriteCloser, stdout io.Reader, stderr io.Reader, err error) { stdin, err = session.StdinPipe() if err != nil { return } stdout, err = session.StdoutPipe() if err != nil { return } stderr, err = session.StderrPipe() if err != nil { return } return }
func (client *SSHClient) prepareCommand(session *ssh.Session, cmd *SSHCommand) error { for _, env := range cmd.Env { variable := strings.Split(env, "=") if len(variable) != 2 { continue } if err := session.Setenv(variable[0], variable[1]); err != nil { return err } } if cmd.Stdin != nil { stdin, err := session.StdinPipe() if err != nil { return fmt.Errorf("Unable to setup stdin for session: %v", err) } go io.Copy(stdin, cmd.Stdin) } if cmd.Stdout != nil { stdout, err := session.StdoutPipe() if err != nil { return fmt.Errorf("Unable to setup stdout for session: %v", err) } go io.Copy(cmd.Stdout, stdout) } if cmd.Stderr != nil { stderr, err := session.StderrPipe() if err != nil { return fmt.Errorf("Unable to setup stderr for session: %v", err) } go io.Copy(cmd.Stderr, stderr) } return nil }
/** InitIOPipes binds session IO streams to the output @Deprecated */ func (client *Client) InitIOPipes(session *ssh.Session) error { stdin, err := session.StdinPipe() if err != nil { return fmt.Errorf("Unable to setup stdin for session: %v", err) } go io.Copy(stdin, os.Stdin) stdout, err := session.StdoutPipe() if err != nil { return fmt.Errorf("Unable to setup stdout for session: %v", err) } go io.Copy(os.Stdout, stdout) stderr, err := session.StderrPipe() if err != nil { return fmt.Errorf("Unable to setup stderr for session: %v", err) } go io.Copy(os.Stderr, stderr) return nil }
func stream(command string, session *ssh.Session) (output chan string, done chan bool, err error) { outReader, err := session.StdoutPipe() Ω(err).ShouldNot(HaveOccurred()) errReader, err := session.StderrPipe() Ω(err).ShouldNot(HaveOccurred()) outputReader := io.MultiReader(outReader, errReader) err = session.Start(command) Ω(err).ShouldNot(HaveOccurred()) scanner := bufio.NewScanner(outputReader) outputChan := make(chan string) done = make(chan bool) go func(scanner *bufio.Scanner, out chan string, done chan bool) { defer close(outputChan) defer close(done) for scanner.Scan() { outputChan <- scanner.Text() } done <- true session.Close() }(scanner, outputChan, done) return outputChan, done, err }
// handleDownload handles message parsing to and from the session. func (c *Client) handleUpload(session *ssh.Session, localPath string) { var err error c.scpStdinPipe, err = session.StdinPipe() if err != nil { c.addError(err) return } defer c.scpStdinPipe.Close() r, err := session.StdoutPipe() if err != nil { c.addError(err) return } // Wrapper to support cancellation c.scpStdoutPipe = &readCanceller{ Reader: bufio.NewReader(r), cancel: make(chan struct{}, 1), } // This has already been used in the cmd call below // so it can be reused for 'end of directory' message handling c.DestinationPath = []string{} err = filepath.Walk(localPath, c.handleItem) if err != nil { c.addError(err) return } // End transfer paths := strings.Split(c.DestinationPath[0], "/") for range paths { c.sendEndOfDirectoryMessage(c.scpStdinPipe) } }
} Eventually(connectionFinished).Should(BeClosed()) }) Context("when a session is opened", func() { var session *ssh.Session BeforeEach(func() { var sessionErr error session, sessionErr = client.NewSession() Expect(sessionErr).NotTo(HaveOccurred()) }) It("can use the session to execute a command with stdout and stderr", func() { stdout, err := session.StdoutPipe() Expect(err).NotTo(HaveOccurred()) stderr, err := session.StderrPipe() Expect(err).NotTo(HaveOccurred()) err = session.Run("/bin/echo -n Hello; /bin/echo -n Goodbye >&2") Expect(err).NotTo(HaveOccurred()) stdoutBytes, err := ioutil.ReadAll(stdout) Expect(err).NotTo(HaveOccurred()) Expect(stdoutBytes).To(Equal([]byte("Hello"))) stderrBytes, err := ioutil.ReadAll(stderr) Expect(err).NotTo(HaveOccurred()) Expect(stderrBytes).To(Equal([]byte("Goodbye")))
// handleDownload handles message parsing to and from the session. func (c *Client) handleDownload(session *ssh.Session) { var err error c.scpStdinPipe, err = session.StdinPipe() if err != nil { c.addError(err) return } defer c.scpStdinPipe.Close() r, err := session.StdoutPipe() if err != nil { c.addError(err) return } // Initialize transfer c.sendAck(c.scpStdinPipe) // Wrapper to support cancellation c.scpStdoutPipe = &readCanceller{ Reader: bufio.NewReader(r), cancel: make(chan struct{}, 1), } for { c.outputInfo("Reading message from source") msg, err := c.scpStdoutPipe.ReadString('\n') if err != nil { if err != io.EOF { c.addError(err) } return } // Strip nulls and new lines msg = strings.TrimSpace(strings.Trim(msg, "\x00")) c.outputInfo(fmt.Sprintf("Received: %s", msg)) // Confirm message c.sendAck(c.scpStdinPipe) switch { case c.isFileCopyMsg(msg): // Handle incoming file err := c.file(msg) if err != nil { c.addError(err) return } case c.isDirCopyMsg(msg): // Handling incoming directory err := c.directory(msg) if err != nil { c.addError(err) return } case msg == endDir: // Directory finished, go up a directory c.upDirectory() case c.isWarningMsg(msg): c.addError(fmt.Errorf("Warning message: [%q]\n", msg)) return case c.isErrorMsg(msg): c.addError(fmt.Errorf("Error message: [%q]\n", msg)) return default: c.addError(fmt.Errorf("Unhandled message: [%q]\n", msg)) return } // Confirm message c.sendAck(c.scpStdinPipe) } }
func pipe(ch ssh.Channel, client *ssh.Client, session *ssh.Session, command string) (int, error) { targetStderr, err := session.StderrPipe() if err != nil { return -1, errors.New("fail to pipe stderr: " + err.Error()) } targetStdout, err := session.StdoutPipe() if err != nil { return -1, errors.New("fail to pipe stdout: " + err.Error()) } targetStdin, err := session.StdinPipe() if err != nil { return -1, errors.New("fail to pipe stdin: " + err.Error()) } go io.Copy(targetStdin, ch) go io.Copy(ch.Stderr(), targetStderr) go io.Copy(ch, targetStdout) err = session.Start(command) if err != nil { ch.Write([]byte("Error when starting '" + command + "': " + err.Error())) ch.Close() } err = session.Wait() if err != nil { if err, ok := err.(*ssh.ExitError); ok { return err.ExitStatus(), nil } else { return -1, errors.New("failed to wait ssh command: " + err.Error()) } } return 0, nil }