summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Theophanes <kardianos@gmail.com>2010-07-26 09:43:35 +1000
committerDaniel Theophanes <kardianos@gmail.com>2010-07-26 09:43:35 +1000
commit5fea9348b7a4023e1618ec26693d9c3b7184eaba (patch)
tree96ea1bf77bc0a08581372476da9cd776046b0f80
parenta59af702763edf3d51b75b855e467526770e9897 (diff)
downloadgo-5fea9348b7a4023e1618ec26693d9c3b7184eaba.tar.gz
syscall: add ForkExec, Syscall12 on Windows
R=brainman, rsc CC=golang-dev http://codereview.appspot.com/1578041 Committer: Alex Brainman <alex.brainman@gmail.com>
-rw-r--r--src/pkg/runtime/windows/os.h2
-rw-r--r--src/pkg/runtime/windows/syscall.goc23
-rw-r--r--src/pkg/runtime/windows/thread.c2
-rw-r--r--src/pkg/syscall/Makefile8
-rw-r--r--src/pkg/syscall/exec_unix.go (renamed from src/pkg/syscall/exec.go)0
-rw-r--r--src/pkg/syscall/exec_windows.go199
-rwxr-xr-xsrc/pkg/syscall/mksyscall_windows.sh9
-rw-r--r--src/pkg/syscall/syscall_windows.go6
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go74
-rw-r--r--src/pkg/syscall/ztypes_windows_386.go38
10 files changed, 356 insertions, 5 deletions
diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h
index 931f4991c..68cdd7ca4 100644
--- a/src/pkg/runtime/windows/os.h
+++ b/src/pkg/runtime/windows/os.h
@@ -34,7 +34,7 @@ typedef struct StdcallParams StdcallParams;
struct StdcallParams
{
void *fn;
- uintptr args[9];
+ uintptr args[12];
uintptr r;
uintptr err;
};
diff --git a/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/windows/syscall.goc
index 362217e6b..8287e7041 100644
--- a/src/pkg/runtime/windows/syscall.goc
+++ b/src/pkg/runtime/windows/syscall.goc
@@ -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;
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
index c65f665b1..5dd013f48 100644
--- a/src/pkg/runtime/windows/thread.c
+++ b/src/pkg/runtime/windows/thread.c
@@ -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;
}
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile
index 3ac99bad9..363eb601e 100644
--- a/src/pkg/syscall/Makefile
+++ b/src/pkg/syscall/Makefile
@@ -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\
diff --git a/src/pkg/syscall/exec.go b/src/pkg/syscall/exec_unix.go
index c7f7893e7..c7f7893e7 100644
--- a/src/pkg/syscall/exec.go
+++ b/src/pkg/syscall/exec_unix.go
diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go
new file mode 100644
index 000000000..1ac84a3d2
--- /dev/null
+++ b/src/pkg/syscall/exec_windows.go
@@ -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
+}
diff --git a/src/pkg/syscall/mksyscall_windows.sh b/src/pkg/syscall/mksyscall_windows.sh
index f9b4584fc..ea35ba2b4 100755
--- a/src/pkg/syscall/mksyscall_windows.sh
+++ b/src/pkg/syscall/mksyscall_windows.sh
@@ -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";
}
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 6aef0ded0..159b9d6b1 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -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
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index 55f26734d..7c75d2b77 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -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)
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
index 4d3507868..3f50480e4 100644
--- a/src/pkg/syscall/ztypes_windows_386.go
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -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