Left: | ||
Right: |
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 "utf16" | |
11 ) | 12 ) |
12 | 13 |
13 // 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. |
14 // However, the kernel32 CreateProcess does a good job with | 15 // However, the kernel32 CreateProcess does a good job with |
15 // ForkExec. | 16 // ForkExec. |
16 | 17 |
17 var ForkLock sync.RWMutex | 18 var ForkLock sync.RWMutex |
18 | 19 |
19 // Joins an array of string with sep | 20 // Joins an array of string with sep |
20 // From the "strings" package. Modified. | 21 // From the "strings" package. Modified. |
(...skipping 22 matching lines...) Expand all Loading... | |
43 s = sep | 44 s = sep |
44 for j := 0; j < len(s); j++ { | 45 for j := 0; j < len(s); j++ { |
45 b[bp] = s[j] | 46 b[bp] = s[j] |
46 bp++ | 47 bp++ |
47 } | 48 } |
48 } | 49 } |
49 } | 50 } |
50 return string(b) | 51 return string(b) |
51 } | 52 } |
52 | 53 |
54 //Env block is a sequence of null terminated strings followed by a null. | |
55 //Last bytes are two unicode nulls, or four null bytes. | |
56 func createEnvBlock(envv []string) *uint16 { | |
57 if len(envv) == 0 { | |
58 return &utf16.Encode([]int("\x00\x00"))[0] | |
59 } | |
60 length := 0 | |
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] | |
77 } | |
78 | |
53 type escapeFunc func(s string) string | 79 type escapeFunc func(s string) string |
54 | 80 |
55 //escapes quotes by " -> "" | 81 //escapes quotes by " -> "" |
56 //Also string -> "string" | 82 //Also string -> "string" |
57 func escapeAddQuotes(s string) string { | 83 func escapeAddQuotes(s string) string { |
58 //normal ascii char, one byte wide | 84 //normal ascii char, one byte wide |
59 rune := byte('"') | 85 rune := byte('"') |
60 l := len(s) | 86 l := len(s) |
61 n := 0 | 87 n := 0 |
62 for i := 0; i < l; i++ { | 88 for i := 0; i < l; i++ { |
(...skipping 19 matching lines...) Expand all Loading... | |
82 | 108 |
83 func CloseOnExec(fd int) { | 109 func CloseOnExec(fd int) { |
84 return | 110 return |
85 } | 111 } |
86 | 112 |
87 func SetNonblock(fd int, nonblocking bool) (errno int) { | 113 func SetNonblock(fd int, nonblocking bool) (errno int) { |
88 return 0 | 114 return 0 |
89 } | 115 } |
90 | 116 |
91 | 117 |
92 // TODO(kardia): Add trace, env, and fd | 118 // TODO(kardia): Add trace |
93 // Windows requires a valid dir. Maybe detect empty | 119 //The command and arguments are passed via the Command line parameter. |
94 // string and use current dir if it is. | 120 //Thus, repeating the exec name in the first argument is unneeded. |
95 // The command and arguments are passed via the Command line parameter. | |
96 // Thus, repeating the exec name in the first argument is unneeded. | |
97 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) { |
98 if traceme == true { | 122 if traceme == true { |
99 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 } | |
100 } | 136 } |
101 | 137 |
102 startupInfo := new(StartupInfo) | 138 startupInfo := new(StartupInfo) |
brainman
2010/06/09 09:18:34
Aren't you supposed to at lease set startupInfo.Cb
| |
103 processInfo := new(ProcessInformation) | 139 processInfo := new(ProcessInformation) |
104 | 140 |
105 GetStartupInfo(startupInfo) | 141 GetStartupInfo(startupInfo) |
106 | 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 | |
107 // argv0 must not be longer then 256 chars | 165 // argv0 must not be longer then 256 chars |
108 // 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) |
109 » // 0x00000400 = UNICODE env | 167 » ok, err := CreateProcess( |
brainman
2010/06/09 09:18:34
Instead of the comment, I would have const:
CREAT
| |
110 » _, err = CreateProcess(0, | 168 » » nil, |
111 StringToUTF16Ptr(escapeAddQuotes(argv0)+" "+stringJoin(argv, " " , escapeAddQuotes)), | 169 StringToUTF16Ptr(escapeAddQuotes(argv0)+" "+stringJoin(argv, " " , escapeAddQuotes)), |
112 » » 0, 0, 0, | 170 » » nil, //ptr to struct lpProcessAttributes |
113 » » 0x00000400, | 171 » » nil, //ptr to struct lpThreadAttributes |
114 » » 0, //env block, NULL uses parent env | 172 » » true, //bInheritHandles |
173 » » CREATE_UNICODE_ENVIRONMENT, //Flags | |
174 » » createEnvBlock(envv), //env block, NULL uses parent env | |
115 StringToUTF16Ptr(dir), | 175 StringToUTF16Ptr(dir), |
116 startupInfo, | 176 startupInfo, |
117 processInfo) | 177 processInfo) |
118 | 178 |
119 » if err == 0 { | 179 » if ok { |
120 » » pid = int(processInfo.Pid) | 180 » » pid = int(processInfo.ProcessId) |
121 » » CloseHandle(processInfo.ProcessHandle) | 181 » » CloseHandle(processInfo.Process) |
122 » » CloseHandle(processInfo.ThreadHandle) | 182 » » CloseHandle(processInfo.Thread) |
123 } | 183 } |
124 return | 184 return |
125 } | 185 } |
126 | 186 |
127 // Combination of fork and exec, careful to be thread safe. | |
128 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) { |
129 return forkExec(argv0, argv, envv, false, dir, fd) | 188 return forkExec(argv0, argv, envv, false, dir, fd) |
130 } | 189 } |
131 | 190 |
132 // 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. |
133 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) { |
134 return forkExec(argv0, argv, envv, true, dir, fd) | 193 return forkExec(argv0, argv, envv, true, dir, fd) |
135 } | 194 } |
136 | 195 |
137 // Ordinary exec. | 196 // Ordinary exec. |
138 func Exec(argv0 string, argv []string, envv []string) (err int) { | 197 func Exec(argv0 string, argv []string, envv []string) (err int) { |
139 return EWINDOWS | 198 return EWINDOWS |
140 } | 199 } |
LEFT | RIGHT |