diff options
author | Brad Fitzpatrick <bradfitz@golang.org> | 2011-10-06 11:00:02 -0700 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2011-10-06 11:00:02 -0700 |
commit | 155e21cc7f37ade106171ac53fd6826869811001 (patch) | |
tree | 9281c3fe24b61d0c09d00318a174971ca1ae8148 | |
parent | 029c9bcb8bbf4b9dd55293d9b41fc1c16994b3f9 (diff) | |
download | go-155e21cc7f37ade106171ac53fd6826869811001.tar.gz go-155e21cc7f37ade106171ac53fd6826869811001.zip |
exec: add Command.ExtraFiles
Allows passing extra fds to the child process.
Fixes #2329
R=rsc, dsymonds
CC=golang-dev
https://golang.org/cl/5162050
-rw-r--r-- | src/pkg/exec/exec.go | 6 | ||||
-rw-r--r-- | src/pkg/exec/exec_test.go | 43 |
2 files changed, 49 insertions, 0 deletions
diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go index 3b20f2008c..aaad50846e 100644 --- a/src/pkg/exec/exec.go +++ b/src/pkg/exec/exec.go @@ -63,6 +63,11 @@ type Cmd struct { Stdout io.Writer Stderr io.Writer + // ExtraFiles specifies additional open files to be inherited by the + // new process. It does not include standard input, standard output, or + // standard error. If non-nil, entry i becomes file descriptor 3+i. + ExtraFiles []*os.File + // SysProcAttr holds optional, operating system-specific attributes. // Run passes it to os.StartProcess as the os.ProcAttr's Sys field. SysProcAttr *syscall.SysProcAttr @@ -224,6 +229,7 @@ func (c *Cmd) Start() os.Error { } c.childFiles = append(c.childFiles, fd) } + c.childFiles = append(c.childFiles, c.ExtraFiles...) var err os.Error c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{ diff --git a/src/pkg/exec/exec_test.go b/src/pkg/exec/exec_test.go index 242120faab..2b36e2535a 100644 --- a/src/pkg/exec/exec_test.go +++ b/src/pkg/exec/exec_test.go @@ -9,8 +9,10 @@ import ( "bytes" "fmt" "io" + "io/ioutil" "testing" "os" + "runtime" "strconv" "strings" ) @@ -139,6 +141,39 @@ func TestPipes(t *testing.T) { check("Wait", err) } +func TestExtraFiles(t *testing.T) { + if runtime.GOOS == "windows" { + t.Logf("no operating system support; skipping") + return + } + tf, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("TempFile: %v", err) + } + defer os.Remove(tf.Name()) + defer tf.Close() + + const text = "Hello, fd 3!" + _, err = tf.Write([]byte(text)) + if err != nil { + t.Fatalf("Write: %v", err) + } + _, err = tf.Seek(0, os.SEEK_SET) + if err != nil { + t.Fatalf("Seek: %v", err) + } + + c := helperCommand("read3") + c.ExtraFiles = []*os.File{tf} + bs, err := c.CombinedOutput() + if err != nil { + t.Fatalf("CombinedOutput: %v", err) + } + if string(bs) != text { + t.Errorf("got %q; want %q", string(bs), text) + } +} + // TestHelperProcess isn't a real test. It's used as a helper process // for TestParameterRun. func TestHelperProcess(*testing.T) { @@ -204,6 +239,14 @@ func TestHelperProcess(*testing.T) { os.Exit(1) } } + case "read3": // read fd 3 + fd3 := os.NewFile(3, "fd3") + bs, err := ioutil.ReadAll(fd3) + if err != nil { + fmt.Printf("ReadAll from fd 3: %v", err) + os.Exit(1) + } + os.Stderr.Write(bs) case "exit": n, _ := strconv.Atoi(args[0]) os.Exit(n) |