From b725e32c993219d93567c77ee43b7156c3d880c4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 15 May 2009 10:32:05 -0700 Subject: [PATCH] add directory argument to os.ForkExec R=iant DELTA=41 (35 added, 0 deleted, 6 changed) OCL=28892 CL=28895 --- src/lib/exec/exec.go | 2 +- src/lib/os/exec.go | 5 +++-- src/lib/os/os_test.go | 22 ++++++++++++++++++++++ src/lib/syscall/exec.go | 18 +++++++++++++++--- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/lib/exec/exec.go b/src/lib/exec/exec.go index c13bad3e07b..29f25df651b 100644 --- a/src/lib/exec/exec.go +++ b/src/lib/exec/exec.go @@ -96,7 +96,7 @@ func Run(argv0 string, argv, envv []string, stdin, stdout, stderr int) (p *Cmd, } // Run command. - p.Pid, err = os.ForkExec(argv0, argv, envv, &fd); + p.Pid, err = os.ForkExec(argv0, argv, envv, "", &fd); if err != nil { goto Error; } diff --git a/src/lib/os/exec.go b/src/lib/os/exec.go index 6c0b3557858..1fbd7e7aae2 100644 --- a/src/lib/os/exec.go +++ b/src/lib/os/exec.go @@ -15,7 +15,8 @@ import ( // 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. @@ -28,7 +29,7 @@ func ForkExec(argv0 string, argv []string, envv []string, fd []*File) } } - p, e := syscall.ForkExec(argv0, argv, envv, intfd); + p, e := syscall.ForkExec(argv0, argv, envv, dir, intfd); return int(p), ErrnoToError(e); } diff --git a/src/lib/os/os_test.go b/src/lib/os/os_test.go index e1e2d4b4b39..7c503bfe625 100644 --- a/src/lib/os/os_test.go +++ b/src/lib/os/os_test.go @@ -6,6 +6,7 @@ package os import ( "fmt"; + "io"; "os"; "testing"; ) @@ -299,3 +300,24 @@ func TestLongSymlink(t *testing.T) { 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); +} diff --git a/src/lib/syscall/exec.go b/src/lib/syscall/exec.go index 809cd8c578d..63d7821089a 100644 --- a/src/lib/syscall/exec.go +++ b/src/lib/syscall/exec.go @@ -99,7 +99,7 @@ func Wait4(pid int64, wstatus *WaitStatus, options int64, rusage *Rusage) // 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 @@ -132,6 +132,14 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, fd []int64, pip // 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)); @@ -210,7 +218,7 @@ childerror: } // 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; @@ -225,6 +233,10 @@ func ForkExec(argv0 string, argv []string, envv []string, fd []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 @@ -243,7 +255,7 @@ func ForkExec(argv0 string, argv []string, envv []string, fd []int64) } // 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 {