Here’s a simple code snippet of running a bash script in a PTY:
pty-test.go
package main
import (
"bytes"
"fmt"
"io"
"os"
"os/exec"
"path"
"sync"
"syscall"
"github.com/kr/pty"
)
func main() {
wd, _ := os.Getwd()
c := exec.Command(path.Join(wd, "pty-test.sh"))
c.Dir = wd
c.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
f, err := pty.Start(c)
if err != nil {
panic(err)
}
var wg sync.WaitGroup
wg.Add(1)
var buffer bytes.Buffer
go func() {
_, err = io.Copy(&buffer, f)
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
}
wg.Done()
}()
c.Wait()
wg.Wait()
fmt.Printf(buffer.String())
}
pty-test.sh
#!/bin/bash
echo "Oh hai there!"
–
If you build this program on OSX:
GOOS=linux GOARCH=amd64 go build -o pty-test pty-test.go
Then run it on Ubuntu, you get:
$ ./pty-test
Oh hai there!
If you build it directly on Ubuntu, or run it there via go run, you get:
$ go run pty-test.go
panic: fork/exec /root/pty-test.sh: operation not permitted
goroutine 1 [running]:
main.main()
/root/pty-test.go:24 +0x229
exit status 2
If you remove the c.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} line, it all works as expected…
Can anyone give me any pointers of what I may be doing wrong?
Hey Dave, to confirm you’re saying the same code compiles and works for you on ubuntu 14.04/amd64? I’m running the same as you:
$ go version
go version go1.5.1 linux/amd64
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.3 LTS
Release: 14.04
Codename: trusty
$ go run pty-test.go
panic: fork/exec /root/pty-test.sh: operation not permitted
goroutine 1 [running]:
main.main()
/root/pty-test.go:24 +0x229
exit status 2
Yeah, I double checked. Did you see something in the strace to suggest otherwise? I didn’t have $GOROOT set (I did a fresh Ubuntu to make sure it wasn’t my machine).
$ which go
/usr/local/go/bin/go
$ echo $GOROOT
/usr/local/go
$ go version
go version go1.5.1 linux/amd64
I’m running as root if that makes any difference? I ran the test again with $GOROOT but had the same error.
(Sorry about the link problem. Brand new users have some restrictions to prevent spam but they only last for the first ~10 minutes on the site and across the first 5 topics. Either way, I’ve bumped you up so you should be able to post links now.)
Cool, I didn’t set it in my initial test anyway. Is there any other debugging information I can provide? I just set this up on a fresh Digital Ocean VM (it’s got nothing on it aside from this test). Happy to give you access if you wanted to poke around.
Heh, all good Dave. Thanks so much for taking a look though! It’s just so weird that it’s working for you and not the fresh machine I just provisioned! Are you running the same Ubuntu release as me?