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
This commit is contained in:
Brad Fitzpatrick 2011-10-06 11:00:02 -07:00
parent 029c9bcb8b
commit 155e21cc7f
2 changed files with 49 additions and 0 deletions

View File

@ -63,6 +63,11 @@ type Cmd struct {
Stdout io.Writer Stdout io.Writer
Stderr 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. // SysProcAttr holds optional, operating system-specific attributes.
// Run passes it to os.StartProcess as the os.ProcAttr's Sys field. // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
SysProcAttr *syscall.SysProcAttr SysProcAttr *syscall.SysProcAttr
@ -224,6 +229,7 @@ func (c *Cmd) Start() os.Error {
} }
c.childFiles = append(c.childFiles, fd) c.childFiles = append(c.childFiles, fd)
} }
c.childFiles = append(c.childFiles, c.ExtraFiles...)
var err os.Error var err os.Error
c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{ c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{

View File

@ -9,8 +9,10 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"testing" "testing"
"os" "os"
"runtime"
"strconv" "strconv"
"strings" "strings"
) )
@ -139,6 +141,39 @@ func TestPipes(t *testing.T) {
check("Wait", err) 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 // TestHelperProcess isn't a real test. It's used as a helper process
// for TestParameterRun. // for TestParameterRun.
func TestHelperProcess(*testing.T) { func TestHelperProcess(*testing.T) {
@ -204,6 +239,14 @@ func TestHelperProcess(*testing.T) {
os.Exit(1) 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": case "exit":
n, _ := strconv.Atoi(args[0]) n, _ := strconv.Atoi(args[0])
os.Exit(n) os.Exit(n)