// file descriptors to be set up in the new process: fd[0] will be Unix file
// descriptor 0 (standard input), fd[1] descriptor 1, and so on. A nil entry
// will cause the child to have no open file descriptor with that index.
-func ForkExec(argv0 string, argv []string, envv []string, fd []*File)
+// If dir is not empty, the child chdirs into the directory before execing the program.
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*File)
(pid int, err Error)
{
// Create array of integer (system) fds.
}
}
- p, e := syscall.ForkExec(argv0, argv, envv, intfd);
+ p, e := syscall.ForkExec(argv0, argv, envv, dir, intfd);
return int(p), ErrnoToError(e);
}
import (
"fmt";
+ "io";
"os";
"testing";
)
t.Fatalf("after symlink %q != %q", r, s);
}
}
+
+func TestForkExec(t *testing.T) {
+ r, w, err := Pipe();
+ if err != nil {
+ t.Fatalf("Pipe: %v", err);
+ }
+ pid, err := ForkExec("/bin/pwd", []string{"pwd"}, nil, "/", []*File{nil, w, os.Stderr});
+ if err != nil {
+ t.Fatalf("ForkExec: %v", err);
+ }
+ w.Close();
+
+ var b io.ByteBuffer;
+ io.Copy(r, &b);
+ output := string(b.Data());
+ expect := "/\n";
+ if output != expect {
+ t.Errorf("exec /bin/pwd returned %q wanted %q", output, expect);
+ }
+ Wait(pid, 0);
+}
// no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack.
-func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, fd []int64, pipe int64)
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd []int64, pipe int64)
(pid int64, err int64)
{
// Declare all variables at top in case any
// Fork succeeded, now in child.
+ // Chdir
+ if dir != nil {
+ r1, r2, err = RawSyscall(SYS_CHDIR, int64(uintptr(unsafe.Pointer(dir))), 0, 0);
+ if err != 0 {
+ goto childerror;
+ }
+ }
+
// Pass 1: look for fd[i] < i and move those up above len(fd)
// so that pass 2 won't stomp on an fd it needs later.
nextfd = int64(len(fd));
}
// Combination of fork and exec, careful to be thread safe.
-func ForkExec(argv0 string, argv []string, envv []string, fd []int64)
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int64)
(pid int64, err int64)
{
var p [2]int64;
argv0p := StringBytePtr(argv0);
argvp := StringArrayPtr(argv);
envvp := StringArrayPtr(envv);
+ var dirp *byte;
+ if len(dir) > 0 {
+ dirp = StringBytePtr(dir);
+ }
// Acquire the fork lock so that no other threads
// create new fds that are not yet close-on-exec
}
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvp, fd, p[1]);
+ pid, err = forkAndExecInChild(argv0p, argvp, envvp, dirp, fd, p[1]);
if err != 0 {
error:
if p[0] >= 0 {