LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Fork, exec, wait, etc. | 5 // Fork, exec, wait, etc. |
6 | 6 |
7 package syscall | 7 package syscall |
8 | 8 |
9 import ( | 9 import ( |
10 "sync" | 10 "sync" |
11 » //"unsafe" | 11 » "utf16" |
12 » //"utf16" | |
13 ) | 12 ) |
14 | 13 |
15 // Windows doesn't have a good concept of just Exec in the documented API. | 14 // Windows doesn't have a good concept of just Exec in the documented API. |
16 // However, the kernel32 CreateProcess does a good job with | 15 // However, the kernel32 CreateProcess does a good job with |
17 // ForkExec. | 16 // ForkExec. |
18 | 17 |
19 var ForkLock sync.RWMutex | 18 var ForkLock sync.RWMutex |
20 | 19 |
21 // Joins an array of string with sep | 20 // Joins an array of string with sep |
22 // From the "strings" package | 21 // From the "strings" package. Modified. |
23 func stringJoin(a []string, sep string) string { | 22 func stringJoin(a []string, sep string, escape escapeFunc) string { |
24 if len(a) == 0 { | 23 if len(a) == 0 { |
25 return "" | 24 return "" |
26 } | 25 } |
27 if len(a) == 1 { | 26 if len(a) == 1 { |
28 return a[0] | 27 return a[0] |
29 } | 28 } |
30 n := len(sep) * (len(a) - 1) | 29 n := len(sep) * (len(a) - 1) |
31 for i := 0; i < len(a); i++ { | 30 for i := 0; i < len(a); i++ { |
| 31 a[i] = escape(a[i]) |
32 n += len(a[i]) | 32 n += len(a[i]) |
33 } | 33 } |
34 | 34 |
35 b := make([]byte, n) | 35 b := make([]byte, n) |
36 bp := 0 | 36 bp := 0 |
37 for i := 0; i < len(a); i++ { | 37 for i := 0; i < len(a); i++ { |
38 s := a[i] | 38 s := a[i] |
39 for j := 0; j < len(s); j++ { | 39 for j := 0; j < len(s); j++ { |
40 b[bp] = s[j] | 40 b[bp] = s[j] |
41 bp++ | 41 bp++ |
42 } | 42 } |
43 if i+1 < len(a) { | 43 if i+1 < len(a) { |
44 s = sep | 44 s = sep |
45 for j := 0; j < len(s); j++ { | 45 for j := 0; j < len(s); j++ { |
46 b[bp] = s[j] | 46 b[bp] = s[j] |
47 bp++ | 47 bp++ |
48 } | 48 } |
49 } | 49 } |
50 } | 50 } |
51 return string(b) | 51 return string(b) |
52 } | 52 } |
53 | 53 |
54 // Convert array of string to array | 54 //Env block is a sequence of null terminated strings followed by a null. |
55 // of NUL-terminated pointer. | 55 //Last bytes are two unicode nulls, or four null bytes. |
56 func StringArrayPtr(ss []string) []*uint16 { | 56 func createEnvBlock(envv []string) *uint16 { |
57 » bb := make([]*uint16, len(ss)+1) | 57 » if len(envv) == 0 { |
58 » for i := 0; i < len(ss); i++ { | 58 » » return &utf16.Encode([]int("\x00\x00"))[0] |
59 » » bb[i] = StringToUTF16Ptr(ss[i]) | |
60 } | 59 } |
61 » bb[len(ss)] = nil | 60 » length := 0 |
62 » return bb | 61 » for _, s := range envv { |
| 62 » » length += len(s) + 1 |
| 63 » } |
| 64 » length += 1 |
| 65 |
| 66 » b := make([]byte, length) |
| 67 » i := 0 |
| 68 » for _, s := range envv { |
| 69 » » l := len(s) |
| 70 » » copy(b[i:i+l], []byte(s)) |
| 71 » » copy(b[i+l:i+l+1], []byte{0}) |
| 72 » » i = i + l + 1 |
| 73 » } |
| 74 » copy(b[i:i+1], []byte{0}) |
| 75 |
| 76 » return &utf16.Encode([]int(string(b)))[0] |
63 } | 77 } |
64 func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) } | |
65 | 78 |
66 func SetNonblock(fd int, nonblocking bool) (errno int) { | 79 type escapeFunc func(s string) string |
67 » flag, err := fcntl(fd, F_GETFL, 0) | 80 |
68 » if err != 0 { | 81 //escapes quotes by " -> "" |
69 » » return err | 82 //Also string -> "string" |
| 83 func escapeAddQuotes(s string) string { |
| 84 » //normal ascii char, one byte wide |
| 85 » rune := byte('"') |
| 86 » l := len(s) |
| 87 » n := 0 |
| 88 » for i := 0; i < l; i++ { |
| 89 » » if s[i] == rune { |
| 90 » » » n++ |
| 91 » » } |
70 } | 92 } |
71 » if nonblocking { | 93 » qs := make([]byte, l+n+2) |
72 » » flag |= O_NONBLOCK | 94 |
73 » } else { | 95 » qs[0] = rune |
74 » » flag &= ^O_NONBLOCK | 96 » j := 1 |
| 97 » for i := 0; i < l; i++ { |
| 98 » » qs[i+j] = s[i] |
| 99 » » if s[i] == rune { |
| 100 » » » j++ |
| 101 » » » qs[i+j] = rune |
| 102 » » } |
75 } | 103 } |
76 » _, err = fcntl(fd, F_SETFL, flag) | 104 » qs[len(qs)-1] = rune |
77 » return err | 105 » return string(qs) |
78 } | 106 } |
79 | 107 |
80 | 108 |
81 // TODO(kardia): Add trace, env, and fd | 109 func CloseOnExec(fd int) { |
| 110 » return |
| 111 } |
| 112 |
| 113 func SetNonblock(fd int, nonblocking bool) (errno int) { |
| 114 » return 0 |
| 115 } |
| 116 |
| 117 |
| 118 // TODO(kardia): Add trace |
| 119 //The command and arguments are passed via the Command line parameter. |
| 120 //Thus, repeating the exec name in the first argument is unneeded. |
82 func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri
ng, fd []int) (pid int, err int) { | 121 func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri
ng, fd []int) (pid int, err int) { |
83 if traceme == true { | 122 if traceme == true { |
84 return 0, EWINDOWS | 123 return 0, EWINDOWS |
| 124 } |
| 125 |
| 126 if len(fd) > 3 { |
| 127 return 0, EWINDOWS |
| 128 } |
| 129 |
| 130 //CreateProcess will throw an error if the dir is not set to a valid dir |
| 131 // thus get the working dir if dir is empty. |
| 132 if len(dir) == 0 { |
| 133 if wd, ok := Getwd(); ok == 0 { |
| 134 dir = wd |
| 135 } |
85 } | 136 } |
86 | 137 |
87 startupInfo := new(StartupInfo) | 138 startupInfo := new(StartupInfo) |
88 processInfo := new(ProcessInformation) | 139 processInfo := new(ProcessInformation) |
89 | 140 |
90 GetStartupInfo(startupInfo) | 141 GetStartupInfo(startupInfo) |
91 | 142 |
| 143 startupInfo.Flags = STARTF_USESTDHANDLES |
| 144 startupInfo.StdInput = 0 |
| 145 startupInfo.StdOutput = 0 |
| 146 startupInfo.StdErr = 0 |
| 147 |
| 148 var currentProc, _ = GetCurrentProcess() |
| 149 if len(fd) > 0 && fd[0] > 0 { |
| 150 if ok, err := DuplicateHandle(currentProc, int32(fd[0]), current
Proc, &startupInfo.StdInput, 0, true, DUPLICATE_SAME_ACCESS); !ok { |
| 151 return 0, err |
| 152 } |
| 153 } |
| 154 if len(fd) > 1 && fd[1] > 0 { |
| 155 if ok, err := DuplicateHandle(currentProc, int32(fd[1]), current
Proc, &startupInfo.StdOutput, 0, true, DUPLICATE_SAME_ACCESS); !ok { |
| 156 return 0, err |
| 157 } |
| 158 } |
| 159 if len(fd) > 2 && fd[2] > 0 { |
| 160 if ok, err := DuplicateHandle(currentProc, int32(fd[2]), current
Proc, &startupInfo.StdErr, 0, true, DUPLICATE_SAME_ACCESS); !ok { |
| 161 return 0, err |
| 162 } |
| 163 } |
| 164 |
92 // argv0 must not be longer then 256 chars | 165 // argv0 must not be longer then 256 chars |
93 // but the entire cmd line can have up to 32k chars (msdn) | 166 // but the entire cmd line can have up to 32k chars (msdn) |
94 » // 0x00000400 = UNICODE env | 167 » ok, err := CreateProcess( |
95 » _, err = CreateProcess(0, | 168 » » nil, |
96 » » StringToUTF16Ptr("\""+argv0+"\" "+stringJoin(argv, " ")), | 169 » » StringToUTF16Ptr(escapeAddQuotes(argv0)+" "+stringJoin(argv, " "
, escapeAddQuotes)), |
97 » » 0, 0, 0, | 170 » » nil, //ptr to struct lpProcessAttributes |
98 » » 0x00000400, | 171 » » nil, //ptr to struct lpThreadAttributes |
99 » » 0, //env block, NULL uses parent env | 172 » » true, //bInheritHandles |
| 173 » » CREATE_UNICODE_ENVIRONMENT, //Flags |
| 174 » » createEnvBlock(envv), //env block, NULL uses parent env |
100 StringToUTF16Ptr(dir), | 175 StringToUTF16Ptr(dir), |
101 startupInfo, | 176 startupInfo, |
102 processInfo) | 177 processInfo) |
103 | 178 |
104 » if err == 0 { | 179 » if ok { |
105 » » pid = int(processInfo.Pid) | 180 » » pid = int(processInfo.ProcessId) |
106 » » CloseHandle(processInfo.ProcessHandle) | 181 » » CloseHandle(processInfo.Process) |
107 » » CloseHandle(processInfo.ThreadHandle) | 182 » » CloseHandle(processInfo.Thread) |
108 } | 183 } |
109 return | 184 return |
110 } | 185 } |
111 | 186 |
112 // Combination of fork and exec, careful to be thread safe. | |
113 func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int)
(pid int, err int) { | 187 func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int)
(pid int, err int) { |
114 return forkExec(argv0, argv, envv, false, dir, fd) | 188 return forkExec(argv0, argv, envv, false, dir, fd) |
115 } | 189 } |
116 | 190 |
117 // PtraceForkExec is like ForkExec, but starts the child in a traced state. | 191 // PtraceForkExec is like ForkExec, but starts the child in a traced state. |
118 func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd [
]int) (pid int, err int) { | 192 func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd [
]int) (pid int, err int) { |
119 return forkExec(argv0, argv, envv, true, dir, fd) | 193 return forkExec(argv0, argv, envv, true, dir, fd) |
120 } | 194 } |
121 | 195 |
122 // Ordinary exec. | 196 // Ordinary exec. |
123 func Exec(argv0 string, argv []string, envv []string) (err int) { | 197 func Exec(argv0 string, argv []string, envv []string) (err int) { |
124 return EWINDOWS | 198 return EWINDOWS |
125 } | 199 } |
LEFT | RIGHT |