1
0
mirror of https://github.com/golang/go synced 2024-11-21 23:34:42 -07:00

syscall, os, exec: introduce *syscall.SysProcAttr field in os.ProcAttr and exec.Cmd

R=r, bradfitz, alex.brainman, borman, vincent.vanackere
CC=golang-dev
https://golang.org/cl/4607046
This commit is contained in:
Russ Cox 2011-06-14 10:49:34 -04:00
parent 371aa14e06
commit 4d0f2e9195
8 changed files with 83 additions and 44 deletions

View File

@ -1284,9 +1284,11 @@ func Attach(pid int) (Process, os.Error) {
// details. // details.
func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) { func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
sysattr := &syscall.ProcAttr{ sysattr := &syscall.ProcAttr{
Dir: attr.Dir, Dir: attr.Dir,
Env: attr.Env, Env: attr.Env,
Ptrace: true, Sys: &syscall.SysProcAttr{
Ptrace: true,
},
} }
p := newProcess(-1) p := newProcess(-1)

View File

@ -12,6 +12,7 @@ import (
"io" "io"
"os" "os"
"strconv" "strconv"
"syscall"
) )
// Error records the name of a binary that failed to be be executed // Error records the name of a binary that failed to be be executed
@ -62,6 +63,10 @@ type Cmd struct {
Stdout io.Writer Stdout io.Writer
Stderr 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 is the underlying process, once started.
Process *os.Process Process *os.Process
@ -225,6 +230,7 @@ func (c *Cmd) Start() os.Error {
Dir: c.Dir, Dir: c.Dir,
Files: c.childFiles, Files: c.childFiles,
Env: c.envv(), Env: c.envv(),
Sys: c.SysProcAttr,
}) })
if err != nil { if err != nil {
return err return err

View File

@ -37,6 +37,12 @@ type ProcAttr struct {
// depending on the underlying operating system. A nil entry corresponds // depending on the underlying operating system. A nil entry corresponds
// to that file being closed when the process starts. // to that file being closed when the process starts.
Files []*File 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. // Getpid returns the process id of the caller.

View File

@ -15,6 +15,7 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
sysattr := &syscall.ProcAttr{ sysattr := &syscall.ProcAttr{
Dir: attr.Dir, Dir: attr.Dir,
Env: attr.Env, Env: attr.Env,
Sys: attr.Sys,
} }
// Create array of integer (system) fds. // Create array of integer (system) fds.

View File

@ -30,6 +30,7 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
sysattr := &syscall.ProcAttr{ sysattr := &syscall.ProcAttr{
Dir: attr.Dir, Dir: attr.Dir,
Env: attr.Env, Env: attr.Env,
Sys: attr.Sys,
} }
if sysattr.Env == nil { if sysattr.Env == nil {
sysattr.Env = Environ() sysattr.Env = Environ()

View File

@ -169,7 +169,7 @@ func init() {
// no rescheduling, no malloc calls, and no new stack segments. // no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly // The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack. // 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 // Declare all variables at top in case any
// declarations require heap allocation (e.g., errbuf). // declarations require heap allocation (e.g., errbuf).
var ( var (
@ -190,7 +190,7 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, chroot, dir *
// About to call fork. // About to call fork.
// No more allocation or calls of non-assembly functions. // 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 r1 != 0 {
if int(r1) == -1 { if int(r1) == -1 {
@ -338,14 +338,18 @@ type envItem struct {
} }
type ProcAttr struct { type ProcAttr struct {
Dir string // Current working directory. Dir string // Current working directory.
Env []string // Environment. Env []string // Environment.
Files []int // File descriptors. Files []int // File descriptors.
Chroot string // Chroot. 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) { func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
var ( var (
@ -356,7 +360,11 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
) )
if attr == nil { if attr == nil {
attr = &zeroAttributes attr = &zeroProcAttr
}
sys := attr.Sys
if sys == nil {
sys = &zeroSysProcAttr
} }
p[0] = -1 p[0] = -1
@ -366,10 +374,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
argv0p := StringBytePtr(argv0) argv0p := StringBytePtr(argv0)
argvp := StringSlicePtr(argv) argvp := StringSlicePtr(argv)
var chroot *byte
if attr.Chroot != "" {
chroot = StringBytePtr(attr.Chroot)
}
var dir *byte var dir *byte
if attr.Dir != "" { if attr.Dir != "" {
dir = StringBytePtr(attr.Dir) dir = StringBytePtr(attr.Dir)
@ -439,7 +443,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
fdsToClose = append(fdsToClose, p[0]) fdsToClose = append(fdsToClose, p[0])
// Kick off child. // 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 err != nil {
if p[0] >= 0 { if p[0] >= 0 {

View File

@ -96,7 +96,7 @@ func SetNonblock(fd int, nonblocking bool) (errno int) {
// no rescheduling, no malloc calls, and no new stack segments. // no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly // The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack. // 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 // Declare all variables at top in case any
// declarations require heap allocation (e.g., err1). // declarations require heap allocation (e.g., err1).
var r1, r2, err1 uintptr var r1, r2, err1 uintptr
@ -131,7 +131,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Fork succeeded, now in child. // Fork succeeded, now in child.
// Enable tracing if requested. // Enable tracing if requested.
if attr.Ptrace { if sys.Ptrace {
_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0) _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
if err1 != 0 { if err1 != 0 {
goto childerror goto childerror
@ -139,7 +139,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
} }
// Session ID // Session ID
if attr.Setsid { if sys.Setsid {
_, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0) _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
if err1 != 0 { if err1 != 0 {
goto childerror goto childerror
@ -155,21 +155,21 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
} }
// User and groups // User and groups
if attr.Credential != nil { if cred := sys.Credential; cred != nil {
ngroups := uintptr(len(attr.Credential.Groups)) ngroups := uintptr(len(cred.Groups))
groups := uintptr(0) groups := uintptr(0)
if ngroups > 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) _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
if err1 != 0 { if err1 != 0 {
goto childerror goto childerror
} }
_, _, err1 = RawSyscall(SYS_SETGID, uintptr(attr.Credential.Gid), 0, 0) _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
if err1 != 0 { if err1 != 0 {
goto childerror goto childerror
} }
_, _, err1 = RawSyscall(SYS_SETUID, uintptr(attr.Credential.Uid), 0, 0) _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
if err1 != 0 { if err1 != 0 {
goto childerror goto childerror
} }
@ -267,16 +267,21 @@ type Credential struct {
} }
type ProcAttr struct { type ProcAttr struct {
Setsid bool // Create session. Dir string // Current working directory.
Ptrace bool // Enable tracing. Env []string // Environment.
Dir string // Current working directory. Files []int // File descriptors.
Env []string // Environment. Sys *SysProcAttr
Files []int // File descriptors.
Chroot string // Chroot.
Credential *Credential // Credential.
} }
var zeroAttributes ProcAttr type SysProcAttr struct {
Chroot string // Chroot.
Credential *Credential // Credential.
Ptrace bool // Enable tracing.
Setsid bool // Create session.
}
var zeroProcAttr ProcAttr
var zeroSysProcAttr SysProcAttr
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) { func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var p [2]int var p [2]int
@ -285,7 +290,11 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var wstatus WaitStatus var wstatus WaitStatus
if attr == nil { if attr == nil {
attr = &zeroAttributes attr = &zeroProcAttr
}
sys := attr.Sys
if sys == nil {
sys = &zeroSysProcAttr
} }
p[0] = -1 p[0] = -1
@ -301,8 +310,8 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
} }
var chroot *byte var chroot *byte
if attr.Chroot != "" { if sys.Chroot != "" {
chroot = StringBytePtr(attr.Chroot) chroot = StringBytePtr(sys.Chroot)
} }
var dir *byte var dir *byte
if attr.Dir != "" { if attr.Dir != "" {
@ -326,7 +335,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
} }
// Kick off child. // 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 { if err != 0 {
error: error:
if p[0] >= 0 { if p[0] >= 0 {

View File

@ -218,22 +218,32 @@ func joinExeDirAndFName(dir, p string) (name string, err int) {
} }
type ProcAttr struct { type ProcAttr struct {
Dir string Dir string
Env []string Env []string
Files []int Files []int
Sys *SysProcAttr
}
type SysProcAttr struct {
HideWindow bool HideWindow bool
CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess 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) { func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
if len(argv0) == 0 { if len(argv0) == 0 {
return 0, 0, EWINDOWS return 0, 0, EWINDOWS
} }
if attr == nil { if attr == nil {
attr = &zeroAttributes attr = &zeroProcAttr
} }
sys := attr.Sys
if sys == nil {
sys = &zeroSysProcAttr
}
if len(attr.Files) > 3 { if len(attr.Files) > 3 {
return 0, 0, EWINDOWS return 0, 0, EWINDOWS
} }
@ -257,8 +267,8 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
// Windows CreateProcess takes the command line as a single string: // Windows CreateProcess takes the command line as a single string:
// use attr.CmdLine if set, else build the command line by escaping // use attr.CmdLine if set, else build the command line by escaping
// and joining each argument with spaces // and joining each argument with spaces
if attr.CmdLine != "" { if sys.CmdLine != "" {
cmdline = attr.CmdLine cmdline = sys.CmdLine
} else { } else {
cmdline = makeCmdLine(argv) cmdline = makeCmdLine(argv)
} }
@ -293,7 +303,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
si := new(StartupInfo) si := new(StartupInfo)
si.Cb = uint32(unsafe.Sizeof(*si)) si.Cb = uint32(unsafe.Sizeof(*si))
si.Flags = STARTF_USESTDHANDLES si.Flags = STARTF_USESTDHANDLES
if attr.HideWindow { if sys.HideWindow {
si.Flags |= STARTF_USESHOWWINDOW si.Flags |= STARTF_USESHOWWINDOW
si.ShowWindow = SW_HIDE si.ShowWindow = SW_HIDE
} }