mirror of
https://github.com/golang/go
synced 2024-11-22 00:34:40 -07:00
os: implement new Process api
Fixes #1004. Fixes #1460. R=mattn, r, niemeyer, rog, rsc CC=golang-dev https://golang.org/cl/4029053
This commit is contained in:
parent
8b9d6e38be
commit
4ecebfea53
@ -32,10 +32,11 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
||||
if err != nil {
|
||||
fatal("%s", err)
|
||||
}
|
||||
pid, err := os.ForkExec(cmd, argv, os.Environ(), "", []*os.File{r0, w1, w2})
|
||||
p, err := os.StartProcess(cmd, argv, os.Environ(), "", []*os.File{r0, w1, w2})
|
||||
if err != nil {
|
||||
fatal("%s", err)
|
||||
}
|
||||
defer p.Release()
|
||||
r0.Close()
|
||||
w1.Close()
|
||||
w2.Close()
|
||||
@ -55,7 +56,7 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
||||
<-c
|
||||
<-c
|
||||
|
||||
w, err := os.Wait(pid, 0)
|
||||
w, err := p.Wait(0)
|
||||
if err != nil {
|
||||
fatal("%s", err)
|
||||
}
|
||||
|
@ -83,20 +83,21 @@ func exec(rw http.ResponseWriter, args []string) (status int) {
|
||||
if *verbose {
|
||||
log.Printf("executing %v", args)
|
||||
}
|
||||
pid, err := os.ForkExec(bin, args, os.Environ(), *goroot, fds)
|
||||
p, err := os.StartProcess(bin, args, os.Environ(), *goroot, fds)
|
||||
defer r.Close()
|
||||
w.Close()
|
||||
if err != nil {
|
||||
log.Printf("os.ForkExec(%q): %v", bin, err)
|
||||
log.Printf("os.StartProcess(%q): %v", bin, err)
|
||||
return 2
|
||||
}
|
||||
defer p.Release()
|
||||
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
wait, err := os.Wait(pid, 0)
|
||||
wait, err := p.Wait(0)
|
||||
if err != nil {
|
||||
os.Stderr.Write(buf.Bytes())
|
||||
log.Printf("os.Wait(%d, 0): %v", pid, err)
|
||||
log.Printf("os.Wait(%d, 0): %v", p.Pid, err)
|
||||
return 2
|
||||
}
|
||||
status = wait.ExitStatus()
|
||||
|
@ -22,12 +22,12 @@ const (
|
||||
// Stdin, Stdout, and Stderr are Files representing pipes
|
||||
// connected to the running command's standard input, output, and error,
|
||||
// or else nil, depending on the arguments to Run.
|
||||
// Pid is the running command's operating system process ID.
|
||||
// Process represents the underlying operating system process.
|
||||
type Cmd struct {
|
||||
Stdin *os.File
|
||||
Stdout *os.File
|
||||
Stderr *os.File
|
||||
Pid int
|
||||
Process *os.Process
|
||||
}
|
||||
|
||||
// PathError records the name of a binary that was not
|
||||
@ -88,24 +88,24 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
|
||||
// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
|
||||
// of the returned Cmd is the other end of the pipe.
|
||||
// Otherwise the field in Cmd is nil.
|
||||
func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
|
||||
p = new(Cmd)
|
||||
func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (c *Cmd, err os.Error) {
|
||||
c = new(Cmd)
|
||||
var fd [3]*os.File
|
||||
|
||||
if fd[0], p.Stdin, err = modeToFiles(stdin, 0); err != nil {
|
||||
if fd[0], c.Stdin, err = modeToFiles(stdin, 0); err != nil {
|
||||
goto Error
|
||||
}
|
||||
if fd[1], p.Stdout, err = modeToFiles(stdout, 1); err != nil {
|
||||
if fd[1], c.Stdout, err = modeToFiles(stdout, 1); err != nil {
|
||||
goto Error
|
||||
}
|
||||
if stderr == MergeWithStdout {
|
||||
fd[2] = fd[1]
|
||||
} else if fd[2], p.Stderr, err = modeToFiles(stderr, 2); err != nil {
|
||||
} else if fd[2], c.Stderr, err = modeToFiles(stderr, 2); err != nil {
|
||||
goto Error
|
||||
}
|
||||
|
||||
// Run command.
|
||||
p.Pid, err = os.ForkExec(name, argv, envv, dir, fd[0:])
|
||||
c.Process, err = os.StartProcess(name, argv, envv, dir, fd[0:])
|
||||
if err != nil {
|
||||
goto Error
|
||||
}
|
||||
@ -118,7 +118,7 @@ func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int
|
||||
if fd[2] != os.Stderr && fd[2] != fd[1] {
|
||||
fd[2].Close()
|
||||
}
|
||||
return p, nil
|
||||
return c, nil
|
||||
|
||||
Error:
|
||||
if fd[0] != os.Stdin && fd[0] != nil {
|
||||
@ -130,63 +130,67 @@ Error:
|
||||
if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] {
|
||||
fd[2].Close()
|
||||
}
|
||||
if p.Stdin != nil {
|
||||
p.Stdin.Close()
|
||||
if c.Stdin != nil {
|
||||
c.Stdin.Close()
|
||||
}
|
||||
if p.Stdout != nil {
|
||||
p.Stdout.Close()
|
||||
if c.Stdout != nil {
|
||||
c.Stdout.Close()
|
||||
}
|
||||
if p.Stderr != nil {
|
||||
p.Stderr.Close()
|
||||
if c.Stderr != nil {
|
||||
c.Stderr.Close()
|
||||
}
|
||||
if c.Process != nil {
|
||||
c.Process.Release()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Wait waits for the running command p,
|
||||
// returning the Waitmsg returned by os.Wait and an error.
|
||||
// The options are passed through to os.Wait.
|
||||
// Setting options to 0 waits for p to exit;
|
||||
// Wait waits for the running command c,
|
||||
// returning the Waitmsg returned when the process exits.
|
||||
// The options are passed to the process's Wait method.
|
||||
// Setting options to 0 waits for c to exit;
|
||||
// other options cause Wait to return for other
|
||||
// process events; see package os for details.
|
||||
func (p *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
|
||||
if p.Pid <= 0 {
|
||||
func (c *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
|
||||
if c.Process == nil {
|
||||
return nil, os.ErrorString("exec: invalid use of Cmd.Wait")
|
||||
}
|
||||
w, err := os.Wait(p.Pid, options)
|
||||
w, err := c.Process.Wait(options)
|
||||
if w != nil && (w.Exited() || w.Signaled()) {
|
||||
p.Pid = -1
|
||||
c.Process.Release()
|
||||
c.Process = nil
|
||||
}
|
||||
return w, err
|
||||
}
|
||||
|
||||
// Close waits for the running command p to exit,
|
||||
// Close waits for the running command c to exit,
|
||||
// if it hasn't already, and then closes the non-nil file descriptors
|
||||
// p.Stdin, p.Stdout, and p.Stderr.
|
||||
func (p *Cmd) Close() os.Error {
|
||||
if p.Pid > 0 {
|
||||
// c.Stdin, c.Stdout, and c.Stderr.
|
||||
func (c *Cmd) Close() os.Error {
|
||||
if c.Process != nil {
|
||||
// Loop on interrupt, but
|
||||
// ignore other errors -- maybe
|
||||
// caller has already waited for pid.
|
||||
_, err := p.Wait(0)
|
||||
_, err := c.Wait(0)
|
||||
for err == os.EINTR {
|
||||
_, err = p.Wait(0)
|
||||
_, err = c.Wait(0)
|
||||
}
|
||||
}
|
||||
|
||||
// Close the FDs that are still open.
|
||||
var err os.Error
|
||||
if p.Stdin != nil && p.Stdin.Fd() >= 0 {
|
||||
if err1 := p.Stdin.Close(); err1 != nil {
|
||||
if c.Stdin != nil && c.Stdin.Fd() >= 0 {
|
||||
if err1 := c.Stdin.Close(); err1 != nil {
|
||||
err = err1
|
||||
}
|
||||
}
|
||||
if p.Stdout != nil && p.Stdout.Fd() >= 0 {
|
||||
if err1 := p.Stdout.Close(); err1 != nil && err != nil {
|
||||
if c.Stdout != nil && c.Stdout.Fd() >= 0 {
|
||||
if err1 := c.Stdout.Close(); err1 != nil && err != nil {
|
||||
err = err1
|
||||
}
|
||||
}
|
||||
if p.Stderr != nil && p.Stderr != p.Stdout && p.Stderr.Fd() >= 0 {
|
||||
if err1 := p.Stderr.Close(); err1 != nil && err != nil {
|
||||
if c.Stderr != nil && c.Stderr != c.Stdout && c.Stderr.Fd() >= 0 {
|
||||
if err1 := c.Stderr.Close(); err1 != nil && err != nil {
|
||||
err = err1
|
||||
}
|
||||
}
|
||||
|
@ -99,15 +99,16 @@ func DateServer(rw http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(rw, "pipe: %s\n", err)
|
||||
return
|
||||
}
|
||||
pid, err := os.ForkExec("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w})
|
||||
p, err := os.StartProcess("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w})
|
||||
defer r.Close()
|
||||
w.Close()
|
||||
if err != nil {
|
||||
fmt.Fprintf(rw, "fork/exec: %s\n", err)
|
||||
return
|
||||
}
|
||||
defer p.Release()
|
||||
io.Copy(rw, r)
|
||||
wait, err := os.Wait(pid, 0)
|
||||
wait, err := p.Wait(0)
|
||||
if err != nil {
|
||||
fmt.Fprintf(rw, "wait: %s\n", err)
|
||||
return
|
||||
|
@ -22,21 +22,25 @@ GOFILES_freebsd=\
|
||||
env_unix.go\
|
||||
file_unix.go\
|
||||
sys_bsd.go\
|
||||
exec_unix.go\
|
||||
|
||||
GOFILES_darwin=\
|
||||
env_unix.go\
|
||||
file_unix.go\
|
||||
sys_bsd.go\
|
||||
exec_unix.go\
|
||||
|
||||
GOFILES_linux=\
|
||||
env_unix.go\
|
||||
file_unix.go\
|
||||
sys_linux.go\
|
||||
exec_unix.go\
|
||||
|
||||
GOFILES_windows=\
|
||||
env_windows.go\
|
||||
file_windows.go\
|
||||
sys_windows.go\
|
||||
exec_windows.go\
|
||||
|
||||
GOFILES+=$(GOFILES_$(GOOS))
|
||||
|
||||
|
@ -5,17 +5,29 @@
|
||||
package os
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ForkExec forks the current process and invokes Exec with the program, arguments,
|
||||
// and environment specified by name, argv, and envv. It returns the process
|
||||
// id of the forked process and an Error, if any. The fd array specifies the
|
||||
// Process stores the information about a process created by StartProcess.
|
||||
type Process struct {
|
||||
Pid int
|
||||
handle int
|
||||
}
|
||||
|
||||
func newProcess(pid, handle int) *Process {
|
||||
p := &Process{pid, handle}
|
||||
runtime.SetFinalizer(p, (*Process).Release)
|
||||
return p
|
||||
}
|
||||
|
||||
// StartProcess starts a new process with the program, arguments,
|
||||
// and environment specified by name, argv, and envv. The fd array specifies the
|
||||
// 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.
|
||||
// If dir is not empty, the child chdirs into the directory before execing the program.
|
||||
func ForkExec(name string, argv []string, envv []string, dir string, fd []*File) (pid int, err Error) {
|
||||
func StartProcess(name string, argv []string, envv []string, dir string, fd []*File) (p *Process, err Error) {
|
||||
if envv == nil {
|
||||
envv = Environ()
|
||||
}
|
||||
@ -29,17 +41,17 @@ func ForkExec(name string, argv []string, envv []string, dir string, fd []*File)
|
||||
}
|
||||
}
|
||||
|
||||
p, e := syscall.ForkExec(name, argv, envv, dir, intfd)
|
||||
pid, h, e := syscall.StartProcess(name, argv, envv, dir, intfd)
|
||||
if e != 0 {
|
||||
return 0, &PathError{"fork/exec", name, Errno(e)}
|
||||
return nil, &PathError{"fork/exec", name, Errno(e)}
|
||||
}
|
||||
return p, nil
|
||||
return newProcess(pid, h), nil
|
||||
}
|
||||
|
||||
// Exec replaces the current process with an execution of the
|
||||
// named binary, with arguments argv and environment envv.
|
||||
// If successful, Exec never returns. If it fails, it returns an Error.
|
||||
// ForkExec is almost always a better way to execute a program.
|
||||
// StartProcess is almost always a better way to execute a program.
|
||||
func Exec(name string, argv []string, envv []string) Error {
|
||||
if envv == nil {
|
||||
envv = Environ()
|
||||
@ -65,37 +77,18 @@ type Waitmsg struct {
|
||||
Rusage *syscall.Rusage // System-dependent resource usage info.
|
||||
}
|
||||
|
||||
// Options for Wait.
|
||||
const (
|
||||
WNOHANG = syscall.WNOHANG // Don't wait if no process has exited.
|
||||
WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported.
|
||||
WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED.
|
||||
WRUSAGE = 1 << 20 // Record resource usage.
|
||||
)
|
||||
|
||||
// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
|
||||
// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
|
||||
// the options
|
||||
|
||||
// Wait waits for process pid to exit or stop, and then returns a
|
||||
// Waitmsg describing its status and an Error, if any. The options
|
||||
// (WNOHANG etc.) affect the behavior of the Wait call.
|
||||
// Wait is equivalent to calling FindProcess and then Wait
|
||||
// and Release on the result.
|
||||
func Wait(pid int, options int) (w *Waitmsg, err Error) {
|
||||
var status syscall.WaitStatus
|
||||
var rusage *syscall.Rusage
|
||||
if options&WRUSAGE != 0 {
|
||||
rusage = new(syscall.Rusage)
|
||||
options ^= WRUSAGE
|
||||
p, e := FindProcess(pid)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
pid1, e := syscall.Wait4(pid, &status, options, rusage)
|
||||
if e != 0 {
|
||||
return nil, NewSyscallError("wait", e)
|
||||
}
|
||||
w = new(Waitmsg)
|
||||
w.Pid = pid1
|
||||
w.WaitStatus = status
|
||||
w.Rusage = rusage
|
||||
return w, nil
|
||||
defer p.Release()
|
||||
return p.Wait(options)
|
||||
}
|
||||
|
||||
// Convert i to decimal string.
|
||||
|
63
src/pkg/os/exec_unix.go
Normal file
63
src/pkg/os/exec_unix.go
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Options for Wait.
|
||||
const (
|
||||
WNOHANG = syscall.WNOHANG // Don't wait if no process has exited.
|
||||
WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported.
|
||||
WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED.
|
||||
WRUSAGE = 1 << 20 // Record resource usage.
|
||||
)
|
||||
|
||||
// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
|
||||
// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
|
||||
// the options
|
||||
|
||||
// Wait waits for the Process to exit or stop, and then returns a
|
||||
// Waitmsg describing its status and an Error, if any. The options
|
||||
// (WNOHANG etc.) affect the behavior of the Wait call.
|
||||
func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
|
||||
if p.Pid == -1 {
|
||||
return nil, EINVAL
|
||||
}
|
||||
var status syscall.WaitStatus
|
||||
var rusage *syscall.Rusage
|
||||
if options&WRUSAGE != 0 {
|
||||
rusage = new(syscall.Rusage)
|
||||
options ^= WRUSAGE
|
||||
}
|
||||
pid1, e := syscall.Wait4(p.Pid, &status, options, rusage)
|
||||
if e != 0 {
|
||||
return nil, NewSyscallError("wait", e)
|
||||
}
|
||||
w = new(Waitmsg)
|
||||
w.Pid = pid1
|
||||
w.WaitStatus = status
|
||||
w.Rusage = rusage
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Release releases any resources associated with the Process.
|
||||
func (p *Process) Release() Error {
|
||||
// NOOP for unix.
|
||||
p.Pid = -1
|
||||
// no need for a finalizer anymore
|
||||
runtime.SetFinalizer(p, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindProcess looks for a running process by its pid.
|
||||
// The Process it returns can be used to obtain information
|
||||
// about the underlying operating system process.
|
||||
func FindProcess(pid int) (p *Process, err Error) {
|
||||
// NOOP for unix.
|
||||
return newProcess(pid, 0), nil
|
||||
}
|
50
src/pkg/os/exec_windows.go
Normal file
50
src/pkg/os/exec_windows.go
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
|
||||
s, e := syscall.WaitForSingleObject(int32(p.handle), syscall.INFINITE)
|
||||
switch s {
|
||||
case syscall.WAIT_OBJECT_0:
|
||||
break
|
||||
case syscall.WAIT_FAILED:
|
||||
return nil, NewSyscallError("WaitForSingleObject", e)
|
||||
default:
|
||||
return nil, ErrorString("os: unexpected result from WaitForSingleObject")
|
||||
}
|
||||
var ec uint32
|
||||
if ok, e := syscall.GetExitCodeProcess(uint32(p.handle), &ec); !ok {
|
||||
return nil, NewSyscallError("GetExitCodeProcess", e)
|
||||
}
|
||||
return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
|
||||
}
|
||||
|
||||
func (p *Process) Release() Error {
|
||||
if p.handle == -1 {
|
||||
return EINVAL
|
||||
}
|
||||
if ok, e := syscall.CloseHandle(int32(p.handle)); !ok {
|
||||
return NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
p.handle = -1
|
||||
// no need for a finalizer anymore
|
||||
runtime.SetFinalizer(p, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func FindProcess(pid int) (p *Process, err Error) {
|
||||
const da = syscall.STANDARD_RIGHTS_READ |
|
||||
syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
|
||||
h, e := syscall.OpenProcess(da, false, uint32(pid))
|
||||
if e != 0 {
|
||||
return nil, NewSyscallError("OpenProcess", e)
|
||||
}
|
||||
return newProcess(pid, int(h)), nil
|
||||
}
|
@ -427,10 +427,11 @@ func TestForkExec(t *testing.T) {
|
||||
adir = "/"
|
||||
expect = "/\n"
|
||||
}
|
||||
pid, err := ForkExec(cmd, args, nil, adir, []*File{nil, w, Stderr})
|
||||
p, err := StartProcess(cmd, args, nil, adir, []*File{nil, w, Stderr})
|
||||
if err != nil {
|
||||
t.Fatalf("ForkExec: %v", err)
|
||||
t.Fatalf("StartProcess: %v", err)
|
||||
}
|
||||
defer p.Release()
|
||||
w.Close()
|
||||
|
||||
var b bytes.Buffer
|
||||
@ -440,7 +441,7 @@ func TestForkExec(t *testing.T) {
|
||||
args[0] = cmd
|
||||
t.Errorf("exec %q returned %q wanted %q", strings.Join(args, " "), output, expect)
|
||||
}
|
||||
Wait(pid, 0)
|
||||
p.Wait(0)
|
||||
}
|
||||
|
||||
func checkMode(t *testing.T, path string, mode uint32) {
|
||||
@ -750,15 +751,16 @@ func run(t *testing.T, cmd []string) string {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pid, err := ForkExec("/bin/hostname", []string{"hostname"}, nil, "/", []*File{nil, w, Stderr})
|
||||
p, err := StartProcess("/bin/hostname", []string{"hostname"}, nil, "/", []*File{nil, w, Stderr})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer p.Release()
|
||||
w.Close()
|
||||
|
||||
var b bytes.Buffer
|
||||
io.Copy(&b, r)
|
||||
Wait(pid, 0)
|
||||
p.Wait(0)
|
||||
output := b.String()
|
||||
if n := len(output); n > 0 && output[n-1] == '\n' {
|
||||
output = output[0 : n-1]
|
||||
|
@ -310,3 +310,9 @@ func Exec(argv0 string, argv []string, envv []string) (err int) {
|
||||
uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0])))
|
||||
return int(err1)
|
||||
}
|
||||
|
||||
// StartProcess wraps ForkExec for package os.
|
||||
func StartProcess(argv0 string, argv []string, envv []string, dir string, fd []int) (pid, handle int, err int) {
|
||||
pid, err = forkExec(argv0, argv, envv, false, dir, fd)
|
||||
return pid, 0, err
|
||||
}
|
||||
|
@ -117,13 +117,9 @@ func SetNonblock(fd int, nonblocking bool) (errno int) {
|
||||
|
||||
// TODO(kardia): Add trace
|
||||
//The command and arguments are passed via the Command line parameter.
|
||||
func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) {
|
||||
if traceme == true {
|
||||
return 0, EWINDOWS
|
||||
}
|
||||
|
||||
func StartProcess(argv0 string, argv []string, envv []string, dir string, fd []int) (pid, handle int, err int) {
|
||||
if len(fd) > 3 {
|
||||
return 0, EWINDOWS
|
||||
return 0, 0, EWINDOWS
|
||||
}
|
||||
|
||||
//CreateProcess will throw an error if the dir is not set to a valid dir
|
||||
@ -153,19 +149,19 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri
|
||||
var currentProc, _ = GetCurrentProcess()
|
||||
if len(fd) > 0 && fd[0] > 0 {
|
||||
if ok, err := DuplicateHandle(currentProc, int32(fd[0]), currentProc, &startupInfo.StdInput, 0, true, DUPLICATE_SAME_ACCESS); !ok {
|
||||
return 0, err
|
||||
return 0, 0, err
|
||||
}
|
||||
defer CloseHandle(int32(startupInfo.StdInput))
|
||||
}
|
||||
if len(fd) > 1 && fd[1] > 0 {
|
||||
if ok, err := DuplicateHandle(currentProc, int32(fd[1]), currentProc, &startupInfo.StdOutput, 0, true, DUPLICATE_SAME_ACCESS); !ok {
|
||||
return 0, err
|
||||
return 0, 0, err
|
||||
}
|
||||
defer CloseHandle(int32(startupInfo.StdOutput))
|
||||
}
|
||||
if len(fd) > 2 && fd[2] > 0 {
|
||||
if ok, err := DuplicateHandle(currentProc, int32(fd[2]), currentProc, &startupInfo.StdErr, 0, true, DUPLICATE_SAME_ACCESS); !ok {
|
||||
return 0, err
|
||||
return 0, 0, err
|
||||
}
|
||||
defer CloseHandle(int32(startupInfo.StdErr))
|
||||
}
|
||||
@ -188,21 +184,12 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri
|
||||
|
||||
if ok {
|
||||
pid = int(processInfo.ProcessId)
|
||||
CloseHandle(processInfo.Process)
|
||||
handle = int(processInfo.Process)
|
||||
CloseHandle(processInfo.Thread)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
|
||||
return forkExec(argv0, argv, envv, false, dir, fd)
|
||||
}
|
||||
|
||||
// PtraceForkExec is like ForkExec, but starts the child in a traced state.
|
||||
func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
|
||||
return forkExec(argv0, argv, envv, true, dir, fd)
|
||||
}
|
||||
|
||||
// Ordinary exec.
|
||||
func Exec(argv0 string, argv []string, envv []string) (err int) {
|
||||
return EWINDOWS
|
||||
|
@ -136,6 +136,8 @@ func NewCallback(fn interface{}) uintptr
|
||||
//sys GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int)
|
||||
//sys CancelIo(s uint32) (ok bool, errno int)
|
||||
//sys CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (ok bool, errno int) = CreateProcessW
|
||||
//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int)
|
||||
//sys GetExitCodeProcess(handle uint32, exitcode *uint32) (ok bool, errno int)
|
||||
//sys GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) = GetStartupInfoW
|
||||
//sys GetCurrentProcess() (pseudoHandle int32, errno int)
|
||||
//sys DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (ok bool, errno int)
|
||||
@ -146,8 +148,6 @@ func NewCallback(fn interface{}) uintptr
|
||||
//sys CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (ok bool, errno int) = advapi32.CryptAcquireContextW
|
||||
//sys CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) = advapi32.CryptReleaseContext
|
||||
//sys CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno int) = advapi32.CryptGenRandom
|
||||
//sys OpenProcess(da uint32,b int, pid uint32) (handle uint32, errno int)
|
||||
//sys GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int)
|
||||
//sys GetEnvironmentStrings() (envs *uint16, errno int) [failretval==nil] = kernel32.GetEnvironmentStringsW
|
||||
//sys FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) = kernel32.FreeEnvironmentStringsW
|
||||
//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) = kernel32.GetEnvironmentVariableW
|
||||
@ -672,6 +672,32 @@ func WSASendto(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
|
||||
return
|
||||
}
|
||||
|
||||
// Invented structures to support what package os expects.
|
||||
type Rusage struct{}
|
||||
|
||||
type WaitStatus struct {
|
||||
Status uint32
|
||||
ExitCode uint32
|
||||
}
|
||||
|
||||
func (w WaitStatus) Exited() bool { return true }
|
||||
|
||||
func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) }
|
||||
|
||||
func (w WaitStatus) Signal() int { return -1 }
|
||||
|
||||
func (w WaitStatus) CoreDump() bool { return false }
|
||||
|
||||
func (w WaitStatus) Stopped() bool { return false }
|
||||
|
||||
func (w WaitStatus) Continued() bool { return false }
|
||||
|
||||
func (w WaitStatus) StopSignal() int { return -1 }
|
||||
|
||||
func (w WaitStatus) Signaled() bool { return true }
|
||||
|
||||
func (w WaitStatus) TrapCause() int { return -1 }
|
||||
|
||||
// TODO(brainman): fix all needed for net
|
||||
|
||||
func Accept(fd int) (nfd int, sa Sockaddr, errno int) { return 0, nil, EWINDOWS }
|
||||
@ -735,67 +761,3 @@ const (
|
||||
SYS_EXIT
|
||||
SYS_READ
|
||||
)
|
||||
|
||||
type Rusage struct {
|
||||
Utime Timeval
|
||||
Stime Timeval
|
||||
Maxrss int32
|
||||
Ixrss int32
|
||||
Idrss int32
|
||||
Isrss int32
|
||||
Minflt int32
|
||||
Majflt int32
|
||||
Nswap int32
|
||||
Inblock int32
|
||||
Oublock int32
|
||||
Msgsnd int32
|
||||
Msgrcv int32
|
||||
Nsignals int32
|
||||
Nvcsw int32
|
||||
Nivcsw int32
|
||||
}
|
||||
|
||||
type WaitStatus struct {
|
||||
Status uint32
|
||||
ExitCode uint32
|
||||
}
|
||||
|
||||
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
|
||||
const da = STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | SYNCHRONIZE
|
||||
handle, errno := OpenProcess(da, 0, uint32(pid))
|
||||
if errno != 0 {
|
||||
return 0, errno
|
||||
}
|
||||
defer CloseHandle(int32(handle))
|
||||
e, errno := WaitForSingleObject(int32(handle), INFINITE)
|
||||
var c uint32
|
||||
if ok, errno := GetExitCodeProcess(handle, &c); !ok {
|
||||
return 0, errno
|
||||
}
|
||||
*wstatus = WaitStatus{e, c}
|
||||
return pid, 0
|
||||
}
|
||||
|
||||
|
||||
func (w WaitStatus) Exited() bool { return w.Status == WAIT_OBJECT_0 }
|
||||
|
||||
func (w WaitStatus) ExitStatus() int {
|
||||
if w.Status == WAIT_OBJECT_0 {
|
||||
return int(w.ExitCode)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (WaitStatus) Signal() int { return -1 }
|
||||
|
||||
func (WaitStatus) CoreDump() bool { return false }
|
||||
|
||||
func (WaitStatus) Stopped() bool { return false }
|
||||
|
||||
func (WaitStatus) Continued() bool { return false }
|
||||
|
||||
func (WaitStatus) StopSignal() int { return -1 }
|
||||
|
||||
func (w WaitStatus) Signaled() bool { return w.Status == WAIT_OBJECT_0 }
|
||||
|
||||
func (WaitStatus) TrapCause() int { return -1 }
|
||||
|
@ -45,6 +45,8 @@ var (
|
||||
procGetQueuedCompletionStatus = getSysProcAddr(modkernel32, "GetQueuedCompletionStatus")
|
||||
procCancelIo = getSysProcAddr(modkernel32, "CancelIo")
|
||||
procCreateProcessW = getSysProcAddr(modkernel32, "CreateProcessW")
|
||||
procOpenProcess = getSysProcAddr(modkernel32, "OpenProcess")
|
||||
procGetExitCodeProcess = getSysProcAddr(modkernel32, "GetExitCodeProcess")
|
||||
procGetStartupInfoW = getSysProcAddr(modkernel32, "GetStartupInfoW")
|
||||
procGetCurrentProcess = getSysProcAddr(modkernel32, "GetCurrentProcess")
|
||||
procDuplicateHandle = getSysProcAddr(modkernel32, "DuplicateHandle")
|
||||
@ -55,8 +57,6 @@ var (
|
||||
procCryptAcquireContextW = getSysProcAddr(modadvapi32, "CryptAcquireContextW")
|
||||
procCryptReleaseContext = getSysProcAddr(modadvapi32, "CryptReleaseContext")
|
||||
procCryptGenRandom = getSysProcAddr(modadvapi32, "CryptGenRandom")
|
||||
procOpenProcess = getSysProcAddr(modkernel32, "OpenProcess")
|
||||
procGetExitCodeProcess = getSysProcAddr(modkernel32, "GetExitCodeProcess")
|
||||
procGetEnvironmentStringsW = getSysProcAddr(modkernel32, "GetEnvironmentStringsW")
|
||||
procFreeEnvironmentStringsW = getSysProcAddr(modkernel32, "FreeEnvironmentStringsW")
|
||||
procGetEnvironmentVariableW = getSysProcAddr(modkernel32, "GetEnvironmentVariableW")
|
||||
@ -550,6 +550,42 @@ func CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, thr
|
||||
return
|
||||
}
|
||||
|
||||
func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int) {
|
||||
var _p0 uint32
|
||||
if inheritHandle {
|
||||
_p0 = 1
|
||||
} else {
|
||||
_p0 = 0
|
||||
}
|
||||
r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(_p0), uintptr(pid))
|
||||
handle = uint32(r0)
|
||||
if handle == 0 {
|
||||
if e1 != 0 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = EINVAL
|
||||
}
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetExitCodeProcess(handle uint32, exitcode *uint32) (ok bool, errno int) {
|
||||
r0, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
|
||||
ok = bool(r0 != 0)
|
||||
if !ok {
|
||||
if e1 != 0 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = EINVAL
|
||||
}
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) {
|
||||
r0, _, e1 := Syscall(procGetStartupInfoW, 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
|
||||
ok = bool(r0 != 0)
|
||||
@ -706,36 +742,6 @@ func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno
|
||||
return
|
||||
}
|
||||
|
||||
func OpenProcess(da uint32, b int, pid uint32) (handle uint32, errno int) {
|
||||
r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(b), uintptr(pid))
|
||||
handle = uint32(r0)
|
||||
if handle == 0 {
|
||||
if e1 != 0 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = EINVAL
|
||||
}
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int) {
|
||||
r0, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(h), uintptr(unsafe.Pointer(c)), 0)
|
||||
ok = bool(r0 != 0)
|
||||
if !ok {
|
||||
if e1 != 0 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = EINVAL
|
||||
}
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetEnvironmentStrings() (envs *uint16, errno int) {
|
||||
r0, _, e1 := Syscall(procGetEnvironmentStringsW, 0, 0, 0, 0)
|
||||
envs = (*uint16)(unsafe.Pointer(r0))
|
||||
|
Loading…
Reference in New Issue
Block a user