46 static const char * const format = "%s error=%d, %s";
47 static const char * const fallbackFormat = "%s failed, error=%d";
48 char buf[256];
49 char errmsg[sizeof(buf) + 100];
50 const int errnum = GetLastError();
51 const int n = JVM_GetLastErrorString(buf, sizeof(buf));
52 if (n > 0)
53 sprintf(errmsg, format, functionName, errnum, buf);
54 else
55 sprintf(errmsg, fallbackFormat, functionName, errnum);
56 JNU_ThrowIOException(env, errmsg);
57 }
58
59 static void
60 closeSafely(HANDLE handle)
61 {
62 if (handle != INVALID_HANDLE_VALUE)
63 CloseHandle(handle);
64 }
65
66 JNIEXPORT jlong JNICALL
67 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
68 jstring cmd,
69 jstring envBlock,
70 jstring dir,
71 jlongArray stdHandles,
72 jboolean redirectErrorStream)
73 {
74 HANDLE inRead = INVALID_HANDLE_VALUE;
75 HANDLE inWrite = INVALID_HANDLE_VALUE;
76 HANDLE outRead = INVALID_HANDLE_VALUE;
77 HANDLE outWrite = INVALID_HANDLE_VALUE;
78 HANDLE errRead = INVALID_HANDLE_VALUE;
79 HANDLE errWrite = INVALID_HANDLE_VALUE;
80 SECURITY_ATTRIBUTES sa;
81 PROCESS_INFORMATION pi;
82 STARTUPINFOW si;
83 const jchar* pcmd = NULL;
84 const jchar* pdir = NULL;
85 const jchar* penvBlock = NULL;
86 jlong *handles = NULL;
87 jlong ret = 0;
88 DWORD processFlag;
89
90 assert(cmd != NULL);
91 pcmd = (*env)->GetStringChars(env, cmd, NULL);
92 if (pcmd == NULL) goto Catch;
93
94 if (dir != 0) {
95 pdir = (*env)->GetStringChars(env, dir, NULL);
96 if (pdir == NULL) goto Catch;
97 }
98 if (envBlock != NULL) {
99 penvBlock = ((*env)->GetStringChars(env, envBlock, NULL));
100 if (penvBlock == NULL) goto Catch;
101 }
102 assert(stdHandles != NULL);
103 handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
104 if (handles == NULL) goto Catch;
105
106 memset(&si, 0, sizeof(si));
107 si.cb = sizeof(si);
108 si.dwFlags = STARTF_USESTDHANDLES;
109
110 sa.nLength = sizeof(sa);
111 sa.lpSecurityDescriptor = 0;
112 sa.bInheritHandle = TRUE;
113
114 if (handles[0] != (jlong) -1) {
115 si.hStdInput = (HANDLE) handles[0];
116 handles[0] = (jlong) -1;
117 } else {
118 if (! CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE)) {
119 win32Error(env, "CreatePipe");
120 goto Catch;
121 }
122 si.hStdInput = inRead;
123 SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0);
124 handles[0] = (jlong) inWrite;
125 }
126 SetHandleInformation(si.hStdInput,
127 HANDLE_FLAG_INHERIT,
128 HANDLE_FLAG_INHERIT);
129
130 if (handles[1] != (jlong) -1) {
131 si.hStdOutput = (HANDLE) handles[1];
132 handles[1] = (jlong) -1;
133 } else {
134 if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) {
135 win32Error(env, "CreatePipe");
136 goto Catch;
137 }
138 si.hStdOutput = outWrite;
139 SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0);
140 handles[1] = (jlong) outRead;
141 }
142 SetHandleInformation(si.hStdOutput,
143 HANDLE_FLAG_INHERIT,
144 HANDLE_FLAG_INHERIT);
145
146 if (redirectErrorStream) {
147 si.hStdError = si.hStdOutput;
148 handles[2] = (jlong) -1;
149 } else if (handles[2] != (jlong) -1) {
150 si.hStdError = (HANDLE) handles[2];
151 handles[2] = (jlong) -1;
152 } else {
153 if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) {
154 win32Error(env, "CreatePipe");
155 goto Catch;
156 }
157 si.hStdError = errWrite;
158 SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0);
159 handles[2] = (jlong) errRead;
160 }
161 SetHandleInformation(si.hStdError,
162 HANDLE_FLAG_INHERIT,
163 HANDLE_FLAG_INHERIT);
164
165 processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
166 ret = CreateProcessW(0, /* executable name */
167 (LPWSTR)pcmd, /* command line */
168 0, /* process security attribute */
169 0, /* thread security attribute */
170 TRUE, /* inherits system handles */
171 processFlag, /* selected based on exe type */
172 (LPVOID)penvBlock,/* environment block */
173 (LPCWSTR)pdir, /* change to the new current directory */
174 &si, /* (in) startup information */
175 &pi); /* (out) process information */
176 if (!ret) {
177 win32Error(env, "CreateProcess");
178 goto Catch;
179 }
180
181 CloseHandle(pi.hThread);
182 ret = (jlong)pi.hProcess;
183
184 Finally:
185 /* Always clean up the child's side of the pipes */
186 closeSafely(inRead);
187 closeSafely(outWrite);
188 closeSafely(errWrite);
189
190 if (pcmd != NULL)
191 (*env)->ReleaseStringChars(env, cmd, pcmd);
192 if (pdir != NULL)
193 (*env)->ReleaseStringChars(env, dir, pdir);
194 if (penvBlock != NULL)
195 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
196 if (handles != NULL)
197 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
198 return ret;
199
200 Catch:
201 /* Clean up the parent's side of the pipes in case of failure only */
202 closeSafely(inWrite);
203 closeSafely(outRead);
204 closeSafely(errRead);
205 goto Finally;
206 }
207
208 JNIEXPORT jint JNICALL
209 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
210 {
211 DWORD exit_code;
212 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
213 win32Error(env, "GetExitCodeProcess");
214 return exit_code;
215 }
216
217 JNIEXPORT jint JNICALL
218 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
219 {
220 return STILL_ACTIVE;
221 }
222
223 JNIEXPORT void JNICALL
224 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
225 {
246 events[0] = (HANDLE) handle;
247 events[1] = JVM_GetThreadInterruptEvent();
248 result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
249 FALSE, /* Wait for ANY event */
250 dwTimeout); /* Wait for dwTimeout */
251
252 if (result == WAIT_FAILED)
253 win32Error(env, "WaitForMultipleObjects");
254 }
255
256 JNIEXPORT void JNICALL
257 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
258 {
259 TerminateProcess((HANDLE) handle, 1);
260 }
261
262 JNIEXPORT jboolean JNICALL
263 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
264 {
265 DWORD dwExitStatus;
266 GetExitCodeProcess(handle, &dwExitStatus);
267 return dwExitStatus == STILL_ACTIVE;
268 }
269
270 JNIEXPORT jboolean JNICALL
271 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
272 {
273 return CloseHandle((HANDLE) handle);
274 }
275
276 /**
277 * Returns a copy of the Unicode characters of a string. Fow now this
278 * function doesn't handle long path names and other issues.
279 */
280 static WCHAR* getPath(JNIEnv *env, jstring ps) {
281 WCHAR *pathbuf = NULL;
282 const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
283 if (chars != NULL) {
284 size_t pathlen = wcslen(chars);
285 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
286 if (pathbuf == NULL) {
|
46 static const char * const format = "%s error=%d, %s";
47 static const char * const fallbackFormat = "%s failed, error=%d";
48 char buf[256];
49 char errmsg[sizeof(buf) + 100];
50 const int errnum = GetLastError();
51 const int n = JVM_GetLastErrorString(buf, sizeof(buf));
52 if (n > 0)
53 sprintf(errmsg, format, functionName, errnum, buf);
54 else
55 sprintf(errmsg, fallbackFormat, functionName, errnum);
56 JNU_ThrowIOException(env, errmsg);
57 }
58
59 static void
60 closeSafely(HANDLE handle)
61 {
62 if (handle != INVALID_HANDLE_VALUE)
63 CloseHandle(handle);
64 }
65
66 static BOOL hasInheritFlag(HANDLE handle)
67 {
68 DWORD mask;
69 if (GetHandleInformation(handle, &mask)) {
70 return mask & HANDLE_FLAG_INHERIT;
71 }
72 return FALSE;
73 }
74
75 #define HANDLE_STORAGE_SIZE 6
76 #define OFFSET_READ 0
77 #define OFFSET_WRITE 1
78 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
79
80 typedef struct _STDHOLDER {
81 HANDLE pipe[2];
82 int offset;
83 } STDHOLDER;
84
85 static BOOL initHolder(
86 JNIEnv *env,
87 STDHOLDER *pHolder,
88 jlong *pjhandles,
89 HANDLE *phStd)
90 {
91 if (*pjhandles != (jlong) -1) {
92 *phStd = (HANDLE) *pjhandles;
93 *pjhandles = (jlong) -1;
94 } else {
95 if (!CreatePipe(
96 &pHolder->pipe[OFFSET_READ],
97 &pHolder->pipe[OFFSET_WRITE],
98 NULL, /* we would like to inherit
99 default process access,
100 instead of 'Everybody' access */
101 PIPE_SIZE))
102 {
103 win32Error(env, "CreatePipe");
104 return FALSE;
105 } else {
106 /* [thisProcessEnd] has no the inherit flag.
107 the [lpPipeAttributes] param had the NULL value. */
108 HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
109 *phStd = pHolder->pipe[pHolder->offset];
110 *pjhandles = (jlong) thisProcessEnd;
111 }
112 }
113 /* Pipe handle will be closed in the [releaseHolder] call,
114 file handle will be closed in Java.
115 The long-live handle need to restore the inherit flag,
116 we do it later in the [prepareIOEHandleState] call. */
117 SetHandleInformation(
118 *phStd,
119 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
120 return TRUE;
121 }
122
123 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
124 closeSafely(pHolder->pipe[pHolder->offset]);
125 if (complete) {
126 /* Error occur, close this process pipe end */
127 closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
128 }
129 }
130
131 static void prepareIOEHandleState(
132 HANDLE *stdIOE,
133 BOOL *inherit)
134 {
135 int i;
136 for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
137 HANDLE hstd = stdIOE[i];
138 if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
139 /* FALSE by default */
140 inherit[i] = TRUE;
141 /* Java does not need implicit inheritance for IOE handles,
142 so we drop inherit flag that probably was installed by
143 previous CreateProcess call that launched current process.
144 We will return the handle state back after CreateProcess call.
145 By clearing inherit flag we prevent "greedy grandchild" birth.
146 The explicit inheritance for child process IOE handles is
147 supported in the [initHolder] call. */
148 SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
149 }
150 }
151 }
152
153 static void restoreIOEHandleState(
154 const HANDLE *stdIOE,
155 const BOOL *inherit)
156 {
157 /* The set of current process standard IOE handles and
158 the set of child process IOE handles can intersect.
159 To restore the inherit flag right, we use backward
160 array iteration. */
161 int i;
162 for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
163 if (INVALID_HANDLE_VALUE != stdIOE[i]) {
164 /* Restore inherit flag for any case.
165 The handle can be changed by explicit inheritance.*/
166 SetHandleInformation(stdIOE[i],
167 HANDLE_FLAG_INHERIT,
168 inherit[i] ? HANDLE_FLAG_INHERIT : 0);
169 }
170 }
171
172 /* Please, read about the MS inheritance problem
173 http://support.microsoft.com/kb/315939
174 and critical section/synchronized block solution. */
175 static jlong processCreate(
176 JNIEnv *env,
177 const jchar *pcmd,
178 const jchar *penvBlock,
179 const jchar *pdir,
180 jlong *handles,
181 jboolean redirectErrorStream)
182 {
183 jlong ret = 0L;
184 STARTUPINFOW si = {sizeof(si)};
185
186 /* Handles for which the inheritance flag must be restored. */
187 HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
188 /* Current process standard IOE handles: JDK-7147084 */
189 INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
190 /* Child process IOE handles: JDK-6921885 */
191 (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
192 BOOL inherit[HANDLE_STORAGE_SIZE] = {
193 FALSE, FALSE, FALSE,
194 FALSE, FALSE, FALSE};
195
196 {
197 /* Extraction of current process standard IOE handles */
198 DWORD idsIOE[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
199 int i;
200 for (i = 0; i < 3; ++i)
201 /* Should not be closed by CloseHandle! */
202 stdIOE[i] = GetStdHandle(idsIOE[i]);
203 }
204
205 prepareIOEHandleState(stdIOE, inherit);
206 {
207 /* Input */
208 STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
209 if (initHolder(env, &holderIn, &handles[0], &si.hStdInput)) {
210
211 /* Output */
212 STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
213 if (initHolder(env, &holderOut, &handles[1], &si.hStdOutput)) {
214
215 /* Error */
216 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
217 BOOL success;
218 if (redirectErrorStream) {
219 si.hStdError = si.hStdOutput;
220 handles[2] = (jlong) -1;
221 success = TRUE;
222 } else {
223 success = initHolder(env, &holderErr, &handles[2], &si.hStdError);
224 }
225
226 if (success) {
227 PROCESS_INFORMATION pi;
228 DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
229
230 si.dwFlags = STARTF_USESTDHANDLES;
231 if (!CreateProcessW(
232 NULL, /* executable name */
233 (LPWSTR)pcmd, /* command line */
234 NULL, /* process security attribute */
235 NULL, /* thread security attribute */
236 TRUE, /* inherits system handles */
237 processFlag, /* selected based on exe type */
238 (LPVOID)penvBlock,/* environment block */
239 (LPCWSTR)pdir, /* change to the new current directory */
240 &si, /* (in) startup information */
241 &pi)) /* (out) process information */
242 {
243 win32Error(env, "CreateProcess");
244 } else {
245 closeSafely(pi.hThread);
246 ret = (jlong)pi.hProcess;
247 }
248 }
249 releaseHolder(ret == 0, &holderErr);
250 releaseHolder(ret == 0, &holderOut);
251 }
252 releaseHolder(ret == 0, &holderIn);
253 }
254 }
255 restoreIOEHandleState(stdIOE, inherit);
256
257 return ret;
258 }
259
260 JNIEXPORT jlong JNICALL
261 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
262 jstring cmd,
263 jstring envBlock,
264 jstring dir,
265 jlongArray stdHandles,
266 jboolean redirectErrorStream)
267 {
268 jlong ret = 0;
269 if (cmd != NULL
270 && stdHandles != NULL)
271 {
272 const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
273 if (pcmd != NULL) {
274 const jchar *penvBlock = (envBlock != NULL)
275 ? (*env)->GetStringChars(env, envBlock, NULL)
276 : NULL;
277 const jchar *pdir = (dir != NULL)
278 ? (*env)->GetStringChars(env, dir, NULL)
279 : NULL;
280 jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
281 if (handles != NULL) {
282 ret = processCreate(
283 env,
284 pcmd,
285 penvBlock,
286 pdir,
287 handles,
288 redirectErrorStream);
289 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
290 }
291 if (pdir != NULL)
292 (*env)->ReleaseStringChars(env, dir, pdir);
293 if (penvBlock != NULL)
294 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
295 (*env)->ReleaseStringChars(env, cmd, pcmd);
296 }
297 }
298 return ret;
299 }
300
301 JNIEXPORT jint JNICALL
302 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
303 {
304 DWORD exit_code;
305 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
306 win32Error(env, "GetExitCodeProcess");
307 return exit_code;
308 }
309
310 JNIEXPORT jint JNICALL
311 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
312 {
313 return STILL_ACTIVE;
314 }
315
316 JNIEXPORT void JNICALL
317 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
318 {
339 events[0] = (HANDLE) handle;
340 events[1] = JVM_GetThreadInterruptEvent();
341 result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
342 FALSE, /* Wait for ANY event */
343 dwTimeout); /* Wait for dwTimeout */
344
345 if (result == WAIT_FAILED)
346 win32Error(env, "WaitForMultipleObjects");
347 }
348
349 JNIEXPORT void JNICALL
350 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
351 {
352 TerminateProcess((HANDLE) handle, 1);
353 }
354
355 JNIEXPORT jboolean JNICALL
356 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
357 {
358 DWORD dwExitStatus;
359 GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
360 return dwExitStatus == STILL_ACTIVE;
361 }
362
363 JNIEXPORT jboolean JNICALL
364 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
365 {
366 return CloseHandle((HANDLE) handle);
367 }
368
369 /**
370 * Returns a copy of the Unicode characters of a string. Fow now this
371 * function doesn't handle long path names and other issues.
372 */
373 static WCHAR* getPath(JNIEnv *env, jstring ps) {
374 WCHAR *pathbuf = NULL;
375 const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
376 if (chars != NULL) {
377 size_t pathlen = wcslen(chars);
378 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
379 if (pathbuf == NULL) {
|