1
0
mirror of https://github.com/golang/go synced 2024-11-20 02:54:39 -07:00

syscall: add ForkExec, Syscall12 on Windows

R=brainman, rsc
CC=golang-dev
https://golang.org/cl/1578041
This commit is contained in:
Daniel Theophanes 2010-07-26 09:43:35 +10:00 committed by Alex Brainman
parent e57657683f
commit 7f9e247489
10 changed files with 356 additions and 5 deletions

View File

@ -34,7 +34,7 @@ typedef struct StdcallParams StdcallParams;
struct StdcallParams
{
void *fn;
uintptr args[9];
uintptr args[12];
uintptr r;
uintptr err;
};

View File

@ -80,6 +80,29 @@ func Syscall9(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 u
lasterr = p.err;
}
func Syscall12(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, lasterr uintptr) {
StdcallParams p;
p.fn = (void*)trap;
p.args[0] = a1;
p.args[1] = a2;
p.args[2] = a3;
p.args[3] = a4;
p.args[4] = a5;
p.args[5] = a6;
p.args[6] = a7;
p.args[7] = a8;
p.args[8] = a9;
p.args[9] = a10;
p.args[10] = a11;
p.args[11] = a12;
·entersyscall();
syscall(&p);
·exitsyscall();
r1 = p.r;
r2 = 0;
lasterr = p.err;
}
func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
StdcallParams p;
p.fn = (void*)trap;

View File

@ -285,7 +285,7 @@ void
call_syscall(void *args)
{
StdcallParams *p = (StdcallParams*)args;
p->r = (uintptr)stdcall_raw((void*)p->fn, p->args[0], p->args[1], p->args[2], p->args[3], p->args[4], p->args[5], p->args[6], p->args[7], p->args[8]);
p->r = (uintptr)stdcall_raw((void*)p->fn, p->args[0], p->args[1], p->args[2], p->args[3], p->args[4], p->args[5], p->args[6], p->args[7], p->args[8], p->args[9], p->args[10], p->args[11]);
p->err = (uintptr)stdcall_raw(GetLastError);
return;
}

View File

@ -7,7 +7,6 @@ include ../../Make.$(GOARCH)
TARG=syscall
GOFILES=\
str.go\
exec.go\
syscall.go\
syscall_$(GOARCH).go\
syscall_$(GOOS).go\
@ -20,16 +19,23 @@ GOFILES=\
GOFILES_freebsd=\
syscall_bsd.go\
syscall_unix.go\
exec_unix.go\
GOFILES_darwin=\
syscall_bsd.go\
syscall_unix.go\
exec_unix.go\
GOFILES_linux=\
syscall_unix.go\
exec_unix.go\
GOFILES_nacl=\
syscall_unix.go\
exec_unix.go\
GOFILES_windows=\
exec_windows.go
OFILES=\
asm_$(GOOS)_$(GOARCH).$O\

View File

@ -0,0 +1,199 @@
// 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.
// Fork, exec, wait, etc.
package syscall
import (
"sync"
"utf16"
)
// Windows doesn't have a good concept of just Exec in the documented API.
// However, the kernel32 CreateProcess does a good job with
// ForkExec.
var ForkLock sync.RWMutex
// Joins an array of string with sep
// From the "strings" package. Modified.
func stringJoin(a []string, sep string, escape escapeFunc) string {
if len(a) == 0 {
return ""
}
if len(a) == 1 {
return a[0]
}
n := len(sep) * (len(a) - 1)
for i := 0; i < len(a); i++ {
a[i] = escape(a[i])
n += len(a[i])
}
b := make([]byte, n)
bp := 0
for i := 0; i < len(a); i++ {
s := a[i]
for j := 0; j < len(s); j++ {
b[bp] = s[j]
bp++
}
if i+1 < len(a) {
s = sep
for j := 0; j < len(s); j++ {
b[bp] = s[j]
bp++
}
}
}
return string(b)
}
//Env block is a sequence of null terminated strings followed by a null.
//Last bytes are two unicode nulls, or four null bytes.
func createEnvBlock(envv []string) *uint16 {
if len(envv) == 0 {
return &utf16.Encode([]int("\x00\x00"))[0]
}
length := 0
for _, s := range envv {
length += len(s) + 1
}
length += 1
b := make([]byte, length)
i := 0
for _, s := range envv {
l := len(s)
copy(b[i:i+l], []byte(s))
copy(b[i+l:i+l+1], []byte{0})
i = i + l + 1
}
copy(b[i:i+1], []byte{0})
return &utf16.Encode([]int(string(b)))[0]
}
type escapeFunc func(s string) string
//escapes quotes by " -> ""
//Also string -> "string"
func escapeAddQuotes(s string) string {
//normal ascii char, one byte wide
rune := byte('"')
l := len(s)
n := 0
for i := 0; i < l; i++ {
if s[i] == rune {
n++
}
}
qs := make([]byte, l+n+2)
qs[0] = rune
j := 1
for i := 0; i < l; i++ {
qs[i+j] = s[i]
if s[i] == rune {
j++
qs[i+j] = rune
}
}
qs[len(qs)-1] = rune
return string(qs)
}
func CloseOnExec(fd int) {
return
}
func SetNonblock(fd int, nonblocking bool) (errno int) {
return 0
}
// TODO(kardia): Add trace
//The command and arguments are passed via the Command line parameter.
//Thus, repeating the exec name in the first argument is unneeded.
func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) {
if traceme == true {
return 0, EWINDOWS
}
if len(fd) > 3 {
return 0, EWINDOWS
}
//CreateProcess will throw an error if the dir is not set to a valid dir
// thus get the working dir if dir is empty.
if len(dir) == 0 {
if wd, ok := Getwd(); ok == 0 {
dir = wd
}
}
startupInfo := new(StartupInfo)
processInfo := new(ProcessInformation)
GetStartupInfo(startupInfo)
startupInfo.Flags = STARTF_USESTDHANDLES
startupInfo.StdInput = 0
startupInfo.StdOutput = 0
startupInfo.StdErr = 0
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
}
}
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
}
}
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
}
}
// argv0 must not be longer then 256 chars
// but the entire cmd line can have up to 32k chars (msdn)
ok, err := CreateProcess(
nil,
StringToUTF16Ptr(escapeAddQuotes(argv0)+" "+stringJoin(argv, " ", escapeAddQuotes)),
nil, //ptr to struct lpProcessAttributes
nil, //ptr to struct lpThreadAttributes
true, //bInheritHandles
CREATE_UNICODE_ENVIRONMENT, //Flags
createEnvBlock(envv), //env block, NULL uses parent env
StringToUTF16Ptr(dir),
startupInfo,
processInfo)
if ok {
pid = int(processInfo.ProcessId)
CloseHandle(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
}

View File

@ -145,6 +145,10 @@ while(<>) {
} else {
push @args, "uintptr($name)", "uintptr($name >> 32)";
}
} elsif($type eq "bool") {
$text .= "\tvar _p$n uint32;\n";
$text .= "\tif $name { _p$n = 1; } else { _p$n = 0;}\n";
push @args, "uintptr(_p$n)";
} else {
push @args, "uintptr($name)";
}
@ -167,6 +171,11 @@ while(<>) {
while(@args < 9) {
push @args, "0";
}
} elsif(@args <= 12) {
$asm = "Syscall12";
while(@args < 12) {
push @args, "0";
}
} else {
print STDERR "$ARGV:$.: too many arguments to system call\n";
}

View File

@ -80,6 +80,7 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
// implemented in ../pkg/runtime/windows/syscall.cgo
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, lasterr uintptr)
func Syscall12(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, lasterr uintptr)
func loadlibraryex(filename uintptr) (handle uint32)
func getprocaddress(handle uint32, procname uintptr) (proc uintptr)
@ -131,6 +132,11 @@ func getSysProcAddr(m uint32, pname string) uintptr {
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) [failretval=0xffffffff]
//sys CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int)
//sys GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout 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 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)
//sys WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) [failretval=0xffffffff]
//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) = GetTempPathW
//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

View File

@ -1,4 +1,4 @@
// mksyscall_windows.sh -l32 syscall_windows.go syscall_windows_386.go
// mksyscall_windows.sh -l32 syscall_windows.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@ -41,6 +41,11 @@ var (
procGetTimeZoneInformation = getSysProcAddr(modkernel32, "GetTimeZoneInformation")
procCreateIoCompletionPort = getSysProcAddr(modkernel32, "CreateIoCompletionPort")
procGetQueuedCompletionStatus = getSysProcAddr(modkernel32, "GetQueuedCompletionStatus")
procCreateProcessW = getSysProcAddr(modkernel32, "CreateProcessW")
procGetStartupInfoW = getSysProcAddr(modkernel32, "GetStartupInfoW")
procGetCurrentProcess = getSysProcAddr(modkernel32, "GetCurrentProcess")
procDuplicateHandle = getSysProcAddr(modkernel32, "DuplicateHandle")
procWaitForSingleObject = getSysProcAddr(modkernel32, "WaitForSingleObject")
procGetTempPathW = getSysProcAddr(modkernel32, "GetTempPathW")
procCryptAcquireContextW = getSysProcAddr(modadvapi32, "CryptAcquireContextW")
procCryptReleaseContext = getSysProcAddr(modadvapi32, "CryptReleaseContext")
@ -380,6 +385,73 @@ func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlap
return
}
func 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) {
var _p0 uint32
if inheritHandles {
_p0 = 1
} else {
_p0 = 0
}
r0, _, e1 := Syscall12(procCreateProcessW, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
ok = bool(r0 != 0)
if !ok {
errno = int(e1)
} else {
errno = 0
}
return
}
func GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) {
r0, _, e1 := Syscall(procGetStartupInfoW, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
ok = bool(r0 != 0)
if !ok {
errno = int(e1)
} else {
errno = 0
}
return
}
func GetCurrentProcess() (pseudoHandle int32, errno int) {
r0, _, e1 := Syscall(procGetCurrentProcess, 0, 0, 0)
pseudoHandle = int32(r0)
if pseudoHandle == 0 {
errno = int(e1)
} else {
errno = 0
}
return
}
func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (ok bool, errno int) {
var _p0 uint32
if bInheritHandle {
_p0 = 1
} else {
_p0 = 0
}
r0, _, e1 := Syscall9(procDuplicateHandle, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
ok = bool(r0 != 0)
if !ok {
errno = int(e1)
} else {
errno = 0
}
return
}
func WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) {
r0, _, e1 := Syscall(procWaitForSingleObject, uintptr(handle), uintptr(waitMilliseconds), 0)
event = uint32(r0)
if event == 0xffffffff {
errno = int(e1)
} else {
errno = 0
}
return
}
func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
r0, _, e1 := Syscall(procGetTempPathW, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
n = uint32(r0)

View File

@ -59,6 +59,10 @@ const (
OPEN_ALWAYS = 4
TRUNCATE_EXISTING = 5
STARTF_USESTDHANDLES = 0x00000100
DUPLICATE_CLOSE_SOURCE = 0x00000001
DUPLICATE_SAME_ACCESS = 0x00000002
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
@ -75,7 +79,8 @@ const (
FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192
FORMAT_MESSAGE_MAX_WIDTH_MASK = 255
MAX_PATH = 260
MAX_PATH = 260
MAX_LONG_PATH = 32768
MAX_COMPUTERNAME_LENGTH = 15
@ -83,9 +88,12 @@ const (
TIME_ZONE_ID_STANDARD = 1
TIME_ZONE_ID_DAYLIGHT = 2
IGNORE = 0
INFINITE = 0xffffffff
WAIT_TIMEOUT = 258
CREATE_UNICODE_ENVIRONMENT = 0x00000400
)
const (
@ -181,6 +189,34 @@ type ByHandleFileInformation struct {
FileIndexLow uint32
}
type StartupInfo struct {
Cb uint32
_ *uint16
Desktop *uint16
Title *uint16
X uint32
Y uint32
XSize uint32
YSize uint32
XCountChars uint32
YCountChars uint32
FillAttribute uint32
Flags uint32
ShowWindow uint16
_ uint16
_ *byte
StdInput int32
StdOutput int32
StdErr int32
}
type ProcessInformation struct {
Process int32
Thread int32
ProcessId uint32
ThreadId uint32
}
// Invented values to support what package os expects.
type Stat_t struct {
Windata Win32finddata