1
0
mirror of https://github.com/golang/go synced 2024-11-25 22:17:58 -07:00

add directory argument to os.ForkExec

R=iant
DELTA=41  (35 added, 0 deleted, 6 changed)
OCL=28892
CL=28895
This commit is contained in:
Russ Cox 2009-05-15 10:32:05 -07:00
parent a854c7f993
commit b725e32c99
4 changed files with 41 additions and 6 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 {