// details.
func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
sysattr := &syscall.ProcAttr{
- Dir: attr.Dir,
- Env: attr.Env,
- Ptrace: true,
+ Dir: attr.Dir,
+ Env: attr.Env,
+ Sys: &syscall.SysProcAttr{
+ Ptrace: true,
+ },
}
p := newProcess(-1)
"io"
"os"
"strconv"
+ "syscall"
)
// Error records the name of a binary that failed to be be executed
Stdout io.Writer
Stderr io.Writer
+ // SysProcAttr holds optional, operating system-specific attributes.
+ // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
+ SysProcAttr *syscall.SysProcAttr
+
// Process is the underlying process, once started.
Process *os.Process
Dir: c.Dir,
Files: c.childFiles,
Env: c.envv(),
+ Sys: c.SysProcAttr,
})
if err != nil {
return err
// depending on the underlying operating system. A nil entry corresponds
// to that file being closed when the process starts.
Files []*File
+
+ // Operating system-specific process creation attributes.
+ // Note that setting this field means that your program
+ // may not execute properly or even compile on some
+ // operating systems.
+ Sys *syscall.SysProcAttr
}
// Getpid returns the process id of the caller.
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
+ Sys: attr.Sys,
}
// Create array of integer (system) fds.
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
+ Sys: attr.Sys,
}
if sysattr.Env == nil {
sysattr.Env = Environ()
// 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 []envItem, chroot, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int) (pid int, err Error) {
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err Error) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., errbuf).
var (
// About to call fork.
// No more allocation or calls of non-assembly functions.
- r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv), 0, 0)
+ r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0)
if r1 != 0 {
if int(r1) == -1 {
}
type ProcAttr struct {
- Dir string // Current working directory.
- Env []string // Environment.
- Files []int // File descriptors.
- Chroot string // Chroot.
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []int // File descriptors.
+ Sys *SysProcAttr
}
-var zeroAttributes ProcAttr
+type SysProcAttr struct {
+ Rfork int // additional flags to pass to rfork
+}
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
var (
)
if attr == nil {
- attr = &zeroAttributes
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
}
p[0] = -1
argv0p := StringBytePtr(argv0)
argvp := StringSlicePtr(argv)
- var chroot *byte
- if attr.Chroot != "" {
- chroot = StringBytePtr(attr.Chroot)
- }
var dir *byte
if attr.Dir != "" {
dir = StringBytePtr(attr.Dir)
fdsToClose = append(fdsToClose, p[0])
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, chroot, dir, attr, fdsToClose, p[1])
+ pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, fdsToClose, p[1], sys.Rfork)
if err != nil {
if p[0] >= 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, envv []*byte, chroot, dir *byte, attr *ProcAttr, pipe int) (pid int, err int) {
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err int) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., err1).
var r1, r2, err1 uintptr
// Fork succeeded, now in child.
// Enable tracing if requested.
- if attr.Ptrace {
+ if sys.Ptrace {
_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
if err1 != 0 {
goto childerror
}
// Session ID
- if attr.Setsid {
+ if sys.Setsid {
_, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
if err1 != 0 {
goto childerror
}
// User and groups
- if attr.Credential != nil {
- ngroups := uintptr(len(attr.Credential.Groups))
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
groups := uintptr(0)
if ngroups > 0 {
- groups = uintptr(unsafe.Pointer(&attr.Credential.Groups[0]))
+ groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
}
_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
if err1 != 0 {
goto childerror
}
- _, _, err1 = RawSyscall(SYS_SETGID, uintptr(attr.Credential.Gid), 0, 0)
+ _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
if err1 != 0 {
goto childerror
}
- _, _, err1 = RawSyscall(SYS_SETUID, uintptr(attr.Credential.Uid), 0, 0)
+ _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
if err1 != 0 {
goto childerror
}
}
type ProcAttr struct {
- Setsid bool // Create session.
- Ptrace bool // Enable tracing.
- Dir string // Current working directory.
- Env []string // Environment.
- Files []int // File descriptors.
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []int // File descriptors.
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
Chroot string // Chroot.
Credential *Credential // Credential.
+ Ptrace bool // Enable tracing.
+ Setsid bool // Create session.
}
-var zeroAttributes ProcAttr
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var p [2]int
var wstatus WaitStatus
if attr == nil {
- attr = &zeroAttributes
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
}
p[0] = -1
}
var chroot *byte
- if attr.Chroot != "" {
- chroot = StringBytePtr(attr.Chroot)
+ if sys.Chroot != "" {
+ chroot = StringBytePtr(sys.Chroot)
}
var dir *byte
if attr.Dir != "" {
}
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, p[1])
+ pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
if err != 0 {
error:
if p[0] >= 0 {
}
type ProcAttr struct {
- Dir string
- Env []string
- Files []int
+ Dir string
+ Env []string
+ Files []int
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
HideWindow bool
CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
}
-var zeroAttributes ProcAttr
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
if len(argv0) == 0 {
return 0, 0, EWINDOWS
}
if attr == nil {
- attr = &zeroAttributes
+ attr = &zeroProcAttr
}
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
+ }
+
if len(attr.Files) > 3 {
return 0, 0, EWINDOWS
}
// Windows CreateProcess takes the command line as a single string:
// use attr.CmdLine if set, else build the command line by escaping
// and joining each argument with spaces
- if attr.CmdLine != "" {
- cmdline = attr.CmdLine
+ if sys.CmdLine != "" {
+ cmdline = sys.CmdLine
} else {
cmdline = makeCmdLine(argv)
}
si := new(StartupInfo)
si.Cb = uint32(unsafe.Sizeof(*si))
si.Flags = STARTF_USESTDHANDLES
- if attr.HideWindow {
+ if sys.HideWindow {
si.Flags |= STARTF_USESHOWWINDOW
si.ShowWindow = SW_HIDE
}