Ejemplo n.º 1
0
// run command from basedir and print output to stdout.
func runCmd(baseDir string, env []string, command string, args ...string) error {
	cmd := exec.Command(command, args...)
	if baseDir != "" {
		cmd.Dir = baseDir
	}
	cmd.Env = env

	// print command being run
	fmt.Println("$", strings.Join(cmd.Args, " "))

	tty, err := pty.Start(cmd)
	if err != nil {
		return err
	}

	scanner := bufio.NewScanner(tty)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		for scanner.Scan() {
			out := scanner.Text()
			fmt.Printf("%s\n", fmtOutput(out))
		}
	}()

	err = cmd.Wait()
	if err != nil {
		return err
	}

	wg.Wait()

	return nil
}
Ejemplo n.º 2
0
func (this *DockerServer) Run() {
	f, err := pty.Start(this.cmd)
	if err != nil {
		panic(err)
	}
	io.Copy(os.Stdout, f)
}
Ejemplo n.º 3
0
func establishPty(session *SessionConfig) error {
	defer trace.End(trace.Begin("initializing pty handling for session " + session.ID))

	// TODO: if we want to allow raw output to the log so that subsequent tty enabled
	// processing receives the control characters then we should be binding the PTY
	// during attach, and using the same path we have for non-tty here
	session.wait = &sync.WaitGroup{}

	var err error
	session.Pty, err = pty.Start(&session.Cmd)
	if session.Pty != nil {
		session.wait.Add(1)

		// TODO: do we need to ensure all reads have completed before calling Wait on the process?
		// it frees up all resources - does that mean it frees the output buffers?
		go func() {
			_, gerr := io.Copy(session.Outwriter, session.Pty)
			log.Debugf("PTY stdout copy: %s", gerr)

			session.wait.Done()
		}()
		go func() {
			_, gerr := io.Copy(session.Pty, session.Reader)
			log.Debugf("PTY stdin copy: %s", gerr)
		}()
	}

	return err
}
Ejemplo n.º 4
0
func (r *Reporter) execHost(req xfer.Request) xfer.Response {
	cmd := exec.Command(r.hostShellCmd[0], r.hostShellCmd[1:]...)
	cmd.Env = []string{"TERM=xterm"}
	ptyPipe, err := pty.Start(cmd)
	if err != nil {
		return xfer.ResponseError(err)
	}

	id, pipe, err := controls.NewPipeFromEnds(nil, ptyPipe, r.pipes, req.AppID)
	if err != nil {
		return xfer.ResponseError(err)
	}
	pipe.OnClose(func() {
		if err := cmd.Process.Kill(); err != nil {
			log.Errorf("Error stopping host shell: %v", err)
		}
		if err := ptyPipe.Close(); err != nil {
			log.Errorf("Error closing host shell's pty: %v", err)
		}
		log.Info("Host shell closed.")
	})
	go func() {
		if err := cmd.Wait(); err != nil {
			log.Errorf("Error waiting on host shell: %v", err)
		}
		pipe.Close()
	}()

	return xfer.Response{
		Pipe:   id,
		RawTTY: true,
	}
}
Ejemplo n.º 5
0
func (sshConfig *SSHConfig) Login() string {
	// beego.Debug(sshConfig.Agent.LoginName, sshConfig.Agent.Host)
	var err error
	sshConfig.WsPty.Cmd = exec.Command("ssh", "-o", "StrictHostKeyChecking=no", sshConfig.Agent.LoginName+"@"+sshConfig.Agent.Host)
	sshConfig.WsPty.Pty, err = pty.Start(sshConfig.WsPty.Cmd)
	if err != nil {
		beego.Error("Failed to start command: %s\n", err)
	}

	i := 0
	for {
		if i >= 10 {
			beego.Error("login error")
			sshConfig.WsPty.Pty.Close()
			return "login error"
		}
		buf := make([]byte, 1024)
		size, err := sshConfig.WsPty.Pty.Read(buf)
		if err != nil {
			beego.Error("login Read error")
		}

		if !strings.Contains(string([]byte(buf[:size])), "password") {
			i++
			continue
		}

		_, err = sshConfig.WsPty.Pty.Write([]byte(sshConfig.Agent.LoginPass + "\n"))
		if err != nil {
			beego.Error("login Write error")
		}
		return ""
	}
}
Ejemplo n.º 6
0
// Start will create start cmd and return a PTY wrapping it. The PTY implements
// ReadWriteCloser and must be closed when execution is done.
//
// Note: This will overwrite stdio for cmd.
func Start(cmd *exec.Cmd) (*PTY, error) {
	f, err := pty.Start(cmd)
	if err != nil {
		return nil, err
	}
	return &PTY{f}, nil
}
// regression test for #12546
func (s *DockerSuite) TestExecInteractiveStdinClose(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-itd", "busybox", "/bin/cat")
	contID := strings.TrimSpace(out)

	cmd := exec.Command(dockerBinary, "exec", "-i", contID, "echo", "-n", "hello")
	p, err := pty.Start(cmd)
	if err != nil {
		c.Fatal(err)
	}

	b := bytes.NewBuffer(nil)
	go io.Copy(b, p)

	ch := make(chan error)
	go func() { ch <- cmd.Wait() }()

	select {
	case err := <-ch:
		if err != nil {
			c.Errorf("cmd finished with error %v", err)
		}
		if output := b.String(); strings.TrimSpace(output) != "hello" {
			c.Fatalf("Unexpected output %s", output)
		}
	case <-time.After(1 * time.Second):
		c.Fatal("timed out running docker exec")
	}
}
Ejemplo n.º 8
0
func (app *App) handleWS(w http.ResponseWriter, r *http.Request) {
	log.Printf("New client connected: %s", r.RemoteAddr)

	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	conn, err := app.upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("Failed to upgrade connection")
		return
	}

	cmd := exec.Command(app.options.Command[0], app.options.Command[1:]...)
	ptyIo, err := pty.Start(cmd)
	if err != nil {
		log.Print("Failed to execute command")
		return
	}
	log.Printf("Command is running for client %s with PID %d", r.RemoteAddr, cmd.Process.Pid)

	context := &clientContext{
		app:        app,
		request:    r,
		connection: conn,
		command:    cmd,
		pty:        ptyIo,
	}

	context.goHandleClient()
}
Ejemplo n.º 9
0
func ptyExec(test *testing.T, mux *pat.Router) {
	mux.Post("/exec", func(res http.ResponseWriter, req *http.Request) {
		test.Log("got exec")
		conn, rw, err := res.(http.Hijacker).Hijack()
		if err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			res.Write([]byte(err.Error()))
			return
		}
		defer conn.Close()
		script := req.FormValue("cmd")
		if script == "" {
			test.Log("missing script")
			test.FailNow()
		}
		test.Log("executing", script)
		cmd := exec.Command("/bin/bash", "-c", script)
		file, err := pty.Start(cmd)
		if err != nil {
			test.Log(err)
			test.FailNow()
		}
		test.Log("copying from pty")
		go io.Copy(file, rw)
		io.Copy(conn, file)
		test.Log("finished running")
	})
}
Ejemplo n.º 10
0
/**
Expect:
 - all of the input to come back out, because terminals default to echo mode.
 - then the grep'd string should come out, because the command recieved it and matched.
 - the grep'd string should come out surrounded by the escape codes for color, since grep's auto mode should detect that we're in a terminal.
*/
func TestPtySanity(t *testing.T) {
	assert := assrt.NewAssert(t)

	c := exec.Command("grep", "--color=auto", "bar")
	f, err := pty.Start(c)
	if err != nil {
		t.Fatal(err)
	}

	go func() {
		f.Write([]byte("foo\nbar\nbaz\n"))
		/*
			All of the input must be written in a single call to prevent this test from occationally failing nondeterministically, because:
			grep operates stream-wise and will start printing output before it has all of its input,
			and 3/4ths of the output lines are actually from the terminal operating in echo mode on the same channel.
			So there's actually a race between the terminal itself (somewhere down in kernel land I suppose?) and the output of grep.
		*/
		f.Write([]byte{4}) // EOT
	}()

	outBuffer := new(bytes.Buffer)
	io.Copy(outBuffer, f)
	out := string(outBuffer.Bytes())

	expected := // I have no idea where the CR characters come from.
		"foo\r\n" +
			"bar\r\n" +
			"baz\r\n" +
			"bar\r\n"

	assert.Equal(
		expected,
		out,
	)
}
Ejemplo n.º 11
0
func (this *SSH_Config) Login() error {
	var err error
	this.Command = exec.Command("ssh", "-o", "StrictHostKeyChecking=no", this.Username+"@"+this.Ip)
	this.Pty, err = pty.Start(this.Command)
	if err != nil {
		return err
	}
	i := 0
	for {
		if i >= 10 {

			return errors.New("login error")
		}
		buf := make([]byte, 1024)
		size, err2 := this.Pty.Read(buf)
		if err2 != nil {
			return err
		}

		if !strings.Contains(string([]byte(buf[:size])), "password") {
			i++
			continue
		}
		this.Pty.Write([]byte(this.Password + "\n"))
		if err != nil {
			panic(err)
		}
		if err != nil {
			return errors.New("login error")
		}
		return nil
	}
}
Ejemplo n.º 12
0
func (s *RunVSuite) TestStartWithTty(c *check.C) {
	ctrName := "TestStartWithTty"
	spec := defaultTestSpec
	spec.Process.Terminal = true
	spec.Process.Args = []string{"sh"}
	c.Assert(s.addSpec(&spec), checker.IsNil)

	cmdArgs := []string{"--kernel", s.kernelPath, "--initrd", s.initrdPath}
	cmdArgs = append(cmdArgs, "start", "--bundle", s.bundlePath, ctrName)
	cmd := exec.Command(s.binaryPath, cmdArgs...)
	tty, err := pty.Start(cmd)
	c.Assert(err, checker.IsNil)
	defer tty.Close()

	_, err = tty.Write([]byte("uname && sleep 2 && exit\n"))
	c.Assert(err, checker.IsNil)

	chErr := make(chan error)
	go func() {
		chErr <- cmd.Wait()
	}()
	select {
	case err := <-chErr:
		c.Assert(err, checker.IsNil)
	case <-time.After(15 * time.Second):
		c.Fatal("timeout waiting for start to exit")
	}

	buf := make([]byte, 256)
	n, err := tty.Read(buf)
	c.Assert(err, checker.IsNil)
	c.Assert(bytes.Contains(buf, []byte("Linux")), checker.Equals, true, check.Commentf(string(buf[:n])))
}
Ejemplo n.º 13
0
func (s *DockerSuite) TestExecTTY(c *check.C) {
	testRequires(c, DaemonIsLinux, SameHostDaemon)
	dockerCmd(c, "run", "-d", "--name=test", "busybox", "sh", "-c", "echo hello > /foo && top")

	cmd := exec.Command(dockerBinary, "exec", "-it", "test", "sh")
	p, err := pty.Start(cmd)
	c.Assert(err, checker.IsNil)
	defer p.Close()

	_, err = p.Write([]byte("cat /foo && exit\n"))
	c.Assert(err, checker.IsNil)

	chErr := make(chan error)
	go func() {
		chErr <- cmd.Wait()
	}()
	select {
	case err := <-chErr:
		c.Assert(err, checker.IsNil)
	case <-time.After(3 * time.Second):
		c.Fatal("timeout waiting for exec to exit")
	}

	buf := make([]byte, 256)
	read, err := p.Read(buf)
	c.Assert(err, checker.IsNil)
	c.Assert(bytes.Contains(buf, []byte("hello")), checker.Equals, true, check.Commentf(string(buf[:read])))
}
Ejemplo n.º 14
0
func pipePty(cmd *exec.Cmd, handler *interactive.ShellHandler) error {
	// Start the shell as TTY
	f, err := pty.Start(cmd)
	if err == nil {
		// Connect pipes (close stderr as tty only has two streams)
		go ioext.CopyAndClose(f, handler.StdinPipe())
		go ioext.CopyAndClose(handler.StdoutPipe(), f)
		go handler.StderrPipe().Close()

		// Start communication
		handler.Communicate(func(cols, rows uint16) error {
			return setTTYSize(f, cols, rows)
		}, func() error {
			if cmd.Process != nil {
				return cmd.Process.Kill()
			}
			return nil
		})
	}
	// If pty wasn't supported for some reason we fall back to normal execution
	if err == pty.ErrUnsupported {
		return pipeCommand(cmd, handler)
	}
	if err != nil {
		handler.Communicate(nil, func() error {
			// If cmd.Start() failed, then we don't have a process, but we start
			// the communication flow anyways.
			if cmd.Process != nil {
				return cmd.Process.Kill()
			}
			return nil
		})
	}
	return err
}
Ejemplo n.º 15
0
func NewPty(cmd *exec.Cmd) (*Pty, error) {
	cmdPty, err := pty.Start(cmd)
	if err != nil {
		return nil, err
	}
	return &Pty{cmdPty}, nil
}
Ejemplo n.º 16
0
func startProcess(command string, stdin <-chan rune, stdout chan<- rune) {
	tty, _ := pty.Start(stringToCmd(command))

	input, _ := os.Create("/tmp/nutsh-input")
	output, _ := os.Create("/tmp/nutsh-output")

	go func() {
		for {
			r, ok := <-stdin
			if !ok {
				return
			}
			input.Write([]byte(string(r)))
			tty.Write([]byte(string(r)))
		}
	}()

	go func() {
		reader := bufio.NewReader(tty)
		for {
			r, _, err := reader.ReadRune()
			if err != nil {
				close(stdout)
				return
			}
			output.Write([]byte(string(r)))
			stdout <- r
		}
	}()
}
Ejemplo n.º 17
0
// FIXME find out why it fails with "inappropriate ioctl for device"
func (s *RunSuite) TestRun(c *C) {
	p := s.RandomProject()
	cmd := exec.Command(s.command, "-f", "./assets/run/docker-compose.yml", "-p", p, "run", "hello", "echo", "test")
	var b bytes.Buffer
	wbuf := bufio.NewWriter(&b)

	tty, err := pty.Start(cmd)

	_, err = io.Copy(wbuf, tty)
	if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
		// We can safely ignore this error, because it's just
		// the PTY telling us that it closed successfully.
		// See:
		// https://github.com/buildkite/agent/pull/34#issuecomment-46080419
		err = nil
	}
	c.Assert(cmd.Wait(), IsNil)
	output := string(b.Bytes())

	c.Assert(err, IsNil, Commentf("%s", output))

	name := fmt.Sprintf("%s_%s_run_1", p, "hello")
	cn := s.GetContainerByName(c, name)
	c.Assert(cn, NotNil)

	lines := strings.Split(output, "\r\n")
	lastLine := lines[len(lines)-2 : len(lines)-1][0]

	c.Assert(cn.State.Running, Equals, false)
	c.Assert(lastLine, Equals, "test")
}
Ejemplo n.º 18
0
// StartBash starts up a new bash subprocess for use in completions.
func StartBash() (b *Bash, err error) {
	f, err := ioutil.TempFile("", "smash-inputrc")
	if err != nil {
		return nil, err
	}
	io.WriteString(f, inputrc)
	f.Close()
	defer os.Remove(f.Name())

	b = &Bash{}
	b.cmd = exec.Command("bash", "-i")
	b.cmd.Env = append(b.cmd.Env, fmt.Sprintf("INPUTRC=%s", f.Name()))
	if b.pty, err = pty.Start(b.cmd); err != nil {
		return nil, err
	}
	b.lines = bufio.NewScanner(b.pty)
	if err = b.disableEcho(); err != nil {
		return nil, err
	}
	if err = b.setNarrow(); err != nil {
		return nil, err
	}
	if err = b.setupPrompt(); err != nil {
		return nil, err
	}
	return
}
Ejemplo n.º 19
0
func main() {
	fmt.Print("hello from winmux\n")

	//	log.Print("hello!")

	// take a window id from the command line
	// I suppose it could come from the environment too

	//	log.Print(os.Args[0])

	var q Q
	var err error

	// Actually make this correspond to the real syntax.
	var window_id = flag.Int("id", -1, "Acme window id")
	var window_name = flag.String("name", "", "Acme window name")
	flag.Parse()

	cmd := "/usr/local/plan9/bin/rc"
	// cmd := "/usr/local/plan9/bin/cat"	// Safer for now.
	if args := flag.Args(); len(args) == 1 {
		cmd = args[0]
	} else if len(args) > 1 {
		log.Fatal(usage)
	}

	// TODO(rjkroege): look up a window by name if an argument is provided
	// and connect to it.
	// Hunt down an acme window
	log.Printf("asked for window %s\n", *window_name)
	if *window_id == -1 {
		q.Win, err = acme.New()
	} /* else open the named window. */
	if err != nil {
		log.Fatal("can't open the window? ", err.Error())
	}

	q.Win.Name("winmux-%s", cmd)
	q.Win.Fprintf("body", "hi rob\n")

	// TODO(rjkroege): start the function that receives from the pty and inserts into acme
	c := exec.Command(cmd)
	f, err := pty.Start(c)
	if err != nil {
		log.Fatalf("failed to start pty up: %s", err.Error())
	}

	echo := ttypair.Makecho()
	q.Tty = ttypair.New(f, echo)

	// A goroutine to read the output
	go childtoacme(&q, f, echo)

	// Read from the acme and send to child. (Rename?)
	acmetowin(&q, f, echo)

	q.Win.CloseFiles()
	fmt.Print("bye\n")
}
Ejemplo n.º 20
0
// NewIPset starts ipset specified with path in interactive mode (ipset - ) and returns a new IPset.
func NewIPset(path string) *IPset {
	cmd := exec.Command(path, "-")
	f, _ := pty.Start(cmd)
	ipset := &IPset{pty: f, stdin: bufio.NewWriter(f), stdout: bufio.NewReader(f)}
	buf := make([]byte, 1000)
	ipset.stdout.Read(buf)
	return ipset
}
Ejemplo n.º 21
0
// TODO: Add support for opening a console when the app is scaled to 0.
func (this *Server) Console(conn net.Conn, applicationName string) error {
	err := this.WithApplication(applicationName, func(app *Application, cfg *Config) error {
		process := "web"
		// Find a host running the latest version.
		runningDynos, err := this.getRunningDynos(app.Name, process)
		if err != nil {
			return err
		}
		if len(runningDynos) == 0 {
			return fmt.Errorf("No running web processes found, operation aborted.")
		}

		host := runningDynos[0].Host

		Logf(conn, "Opening SSH session to %v\n", host)
		Send(conn, Message{Hijack, ""})

		e := Executor{conn}

		tempName := applicationName + DYNO_DELIMITER + process + DYNO_DELIMITER + "console"

		err = e.Run("ssh", DEFAULT_NODE_USERNAME+"@"+host, "sudo", "/bin/bash", "-c",
			`"lxc-clone -B btrfs -s -o `+runningDynos[0].Application+` -n `+tempName+` && lxc-start -n `+tempName+` -d"`,
		)
		if err != nil {
			return err
		}
		defer e.Run("ssh", DEFAULT_NODE_USERNAME+"@"+host, "sudo", "/bin/bash", "-c",
			`"lxc-stop -k -n `+tempName+`; lxc-destroy -n `+tempName+`"`,
		)

		// Setup a pseudo terminal
		c := exec.Command("ssh", "-t", DEFAULT_NODE_USERNAME+"@"+host, "--", "sudo", "lxc-console", "-n", tempName, "-t", "2")
		f, err := pty.Start(c)
		if err != nil {
			return err
		}
		defer f.Close()

		ec := make(chan error, 1)

		// Read the output
		go func() {
			_, err := io.Copy(conn, f)
			ec <- err
		}()
		// Send the input
		go func() {
			_, err := io.Copy(f, conn)
			ec <- err
		}()

		// Wait for either end to complete
		<-ec
		return nil
	})
	return err
}
Ejemplo n.º 22
0
func (wp *wsPty) Start() {
	var err error
	args := flag.Args()
	wp.Cmd = exec.Command(cmdFlag, args...)
	wp.Pty, err = pty.Start(wp.Cmd)
	if err != nil {
		log.Fatalf("Failed to start command: %s\n", err)
	}
}
Ejemplo n.º 23
0
func (wp *wsPty) Start() {
	var err error
	args := flag.Args()
	wp.Cmd = exec.Command(cmdFlag, args...)
	wp.Pty, err = pty.Start(wp.Cmd)
	if err != nil {
		revel.ERROR.Println("Failed to start command: %s\n", err)
	}
}
Ejemplo n.º 24
0
func NewIPsetExtra(path string, args ...string) *IPset {
	args = append(args, "-")
	cmd := exec.Command(path, args...)
	f, _ := pty.Start(cmd)
	ipset := &IPset{pty: f, stdin: bufio.NewWriter(f), stdout: bufio.NewReader(f)}
	buf := make([]byte, 1000)
	ipset.stdout.Read(buf)
	return ipset
}
Ejemplo n.º 25
0
func _start(expect *ExpectSubprocess) (*ExpectSubprocess, error) {
	f, err := pty.Start(expect.Cmd)
	if err != nil {
		return nil, err
	}
	expect.buf.f = f

	return expect, nil
}
Ejemplo n.º 26
0
func newMongoStateHolder(mongoPath string) (*mongoStateHolder, error) {
	ms := mongoState{mongo: exec.Command(mongoPath, "--nodb")}
	var err error
	ms.mongoPty, err = pty.Start(ms.mongo)
	if err != nil {
		return nil, err
	}
	return &mongoStateHolder{noDB: &ms, stateMap: make(map[backupUID]*mongoState), nextPort: 27017}, nil
}
Ejemplo n.º 27
0
// newStartedMongoState takes a term argument to have a context for printing
func (msh *mongoStateHolder) newStartedMongoState(replicaID, backupID, mongodPath, mongoPath, mountPath string,
	term *terminal.Terminal, driver *strata.Driver) (*mongoState, error) {

	mongoState := mongoState{}
	var err error
	mongoState.dbpath, err = ioutil.TempDir("", "mongoq_")
	if err != nil {
		return &mongoState, err
	}

	if err := driver.RestoreReadOnly(replicaID, backupID, mountPath, mongoState.dbpath); err != nil {
		return &mongoState, err
	}

	// Try to start mongod
	// Look for output text to determine success
	// If output text indicates that port is already in use, try another port
	for mongoState.mongod == nil {
		mongoState.mongod = exec.Command(mongodPath, "--port="+strconv.Itoa(msh.nextPort),
			"--dbpath="+mongoState.dbpath, "--storageEngine=rocksdb", "--rocksdbConfigString=max_open_files=10")

		mongodOut, err := mongoState.mongod.StdoutPipe()
		if err != nil {
			return &mongoState, err
		}
		defer mongodOut.Close()
		if err := mongoState.mongod.Start(); err != nil {
			return &mongoState, err
		}
		// Wait until mongod is ready to accept a connection
		for {
			buf := make([]byte, 10000)
			n, _ := mongodOut.Read(buf)
			term.Write(buf[:n]) // If there is a problem starting mongod, the user should see it and kill process
			rec := string(buf[:n])
			if strings.Contains(rec, "waiting for connections on port") {
				mongodOut.Close()
				break
			} else if strings.Contains(rec, "Address already in use for socket") {
				mongodOut.Close()
				if err := mongoState.mongod.Process.Kill(); err != nil {
					return &mongoState, err
				}
				mongoState.mongod = nil
				term.Write([]byte("MONGOQ Trying to start mongod again on another port\n"))
				msh.nextPort++
				break
			}
		}
	}

	mongoState.mongo = exec.Command(mongoPath, "--port="+strconv.Itoa(msh.nextPort))
	msh.nextPort++
	mongoState.mongoPty, err = pty.Start(mongoState.mongo)
	return &mongoState, err
}
Ejemplo n.º 28
0
func handleChannel(c ssh.NewChannel) {
	if t := c.ChannelType(); t != "session" {
		log.Println("rejected unknown channel type:", t)
		c.Reject(ssh.UnknownChannelType, "unknown channel type")
	}
	connection, requests, err := c.Accept()
	if err != nil {
		log.Println("channel not accepted:", err)
		return
	}
	bash := exec.Command("/bin/bash")
	close := func() {
		connection.Close()
		_, err := bash.Process.Wait()
		if err != nil {
			log.Println("bash not exited:", err)
		}
		log.Println("session closed")
	}
	bashf, err := pty.Start(bash)
	if err != nil {
		log.Println("pty not started:", err)
		close()
		return
	}
	var once sync.Once
	go func() {
		io.Copy(connection, bashf)
		once.Do(close)
	}()
	go func() {
		io.Copy(bashf, connection)
		once.Do(close)
	}()
	go func() {
		for req := range requests {
			log.Println("got request:", req.Type, "want reply:", req.WantReply)
			switch req.Type {
			case "shell":
				if len(req.Payload) == 0 {
					req.Reply(true, nil)
				}
			case "pty-req":
				termLen := req.Payload[3]
				w, h := parseDims(req.Payload[termLen+4:])
				SetWinsize(bashf.Fd(), w, h)
				req.Reply(true, nil)
			case "window-change":
				w, h := parseDims(req.Payload)
				SetWinsize(bashf.Fd(), w, h)
			}
		}
	}()
}
Ejemplo n.º 29
0
func _start(expect *ExpectSubprocess) (*ExpectSubprocess, error) {
	f, err := pty.Start(expect.Cmd)
	if err != nil {
		return nil, err
	}
	expect.buf = new(buffer)
	expect.buf.f = f
	expect.buf.output = expect.Output

	return expect, nil
}
Ejemplo n.º 30
0
// Create an Expect instance from a command.
// Effectively the same as Create(pty.Start(exec.Command(name, args...)))
func Spawn(name string, args ...string) (*Expect, error) {
	cmd := exec.Command(name, args...)
	pty, err := pty.Start(cmd)
	if err != nil {
		return nil, err
	}
	killer := func() {
		cmd.Process.Kill()
	}
	return Create(pty, killer), nil
}