1 /*
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
118 static const char * const format = "%s error=%d, %s";
119 static const char * const fallbackFormat = "%s failed, error=%d";
120 char buf[256];
121 char errmsg[sizeof(buf) + 100];
122 const int errnum = GetLastError();
123 const int n = JVM_GetLastErrorString(buf, sizeof(buf));
124 if (n > 0)
125 sprintf(errmsg, format, functionName, errnum, buf);
126 else
127 sprintf(errmsg, fallbackFormat, functionName, errnum);
128 JNU_ThrowIOException(env, errmsg);
129 }
130
131 static void
132 closeSafely(HANDLE handle)
133 {
134 if (handle != INVALID_HANDLE_VALUE)
135 CloseHandle(handle);
136 }
137
138 JNIEXPORT jlong JNICALL
139 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
140 jstring cmd,
141 jstring envBlock,
142 jstring dir,
143 jlongArray stdHandles,
144 jboolean redirectErrorStream)
145 {
146 HANDLE inRead = INVALID_HANDLE_VALUE;
147 HANDLE inWrite = INVALID_HANDLE_VALUE;
148 HANDLE outRead = INVALID_HANDLE_VALUE;
149 HANDLE outWrite = INVALID_HANDLE_VALUE;
150 HANDLE errRead = INVALID_HANDLE_VALUE;
151 HANDLE errWrite = INVALID_HANDLE_VALUE;
152 SECURITY_ATTRIBUTES sa;
153 PROCESS_INFORMATION pi;
154 STARTUPINFOW si;
155 const jchar* pcmd = NULL;
156 const jchar* pdir = NULL;
157 const jchar* penvBlock = NULL;
158 jlong *handles = NULL;
159 jlong ret = 0;
160 OSVERSIONINFO ver;
161 jboolean onNT = JNI_FALSE;
162 DWORD processFlag;
163
164 ver.dwOSVersionInfoSize = sizeof(ver);
165 GetVersionEx(&ver);
166 if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
167 onNT = JNI_TRUE;
168
169 assert(cmd != NULL);
170 pcmd = (*env)->GetStringChars(env, cmd, NULL);
171 if (pcmd == NULL) goto Catch;
172
173 if (dir != 0) {
174 pdir = (*env)->GetStringChars(env, dir, NULL);
175 if (pdir == NULL) goto Catch;
176 }
177 if (envBlock != NULL) {
178 penvBlock = ((*env)->GetStringChars(env, envBlock, NULL));
179 if (penvBlock == NULL) goto Catch;
180 }
181 assert(stdHandles != NULL);
182 handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
183 if (handles == NULL) goto Catch;
184
185 memset(&si, 0, sizeof(si));
186 si.cb = sizeof(si);
187 si.dwFlags = STARTF_USESTDHANDLES;
188
189 sa.nLength = sizeof(sa);
190 sa.lpSecurityDescriptor = 0;
191 sa.bInheritHandle = TRUE;
192
193 if (handles[0] != (jlong) -1) {
194 si.hStdInput = (HANDLE) handles[0];
195 handles[0] = (jlong) -1;
196 } else {
197 if (! CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE)) {
198 win32Error(env, "CreatePipe");
199 goto Catch;
200 }
201 si.hStdInput = inRead;
202 SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0);
203 handles[0] = (jlong) inWrite;
204 }
205 SetHandleInformation(si.hStdInput,
206 HANDLE_FLAG_INHERIT,
207 HANDLE_FLAG_INHERIT);
208
209 if (handles[1] != (jlong) -1) {
210 si.hStdOutput = (HANDLE) handles[1];
211 handles[1] = (jlong) -1;
212 } else {
213 if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) {
214 win32Error(env, "CreatePipe");
215 goto Catch;
216 }
217 si.hStdOutput = outWrite;
218 SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0);
219 handles[1] = (jlong) outRead;
220 }
221 SetHandleInformation(si.hStdOutput,
222 HANDLE_FLAG_INHERIT,
223 HANDLE_FLAG_INHERIT);
224
225 if (redirectErrorStream) {
226 si.hStdError = si.hStdOutput;
227 handles[2] = (jlong) -1;
228 } else if (handles[2] != (jlong) -1) {
229 si.hStdError = (HANDLE) handles[2];
230 handles[2] = (jlong) -1;
231 } else {
232 if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) {
233 win32Error(env, "CreatePipe");
234 goto Catch;
235 }
236 si.hStdError = errWrite;
237 SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0);
238 handles[2] = (jlong) errRead;
239 }
240 SetHandleInformation(si.hStdError,
241 HANDLE_FLAG_INHERIT,
242 HANDLE_FLAG_INHERIT);
243
244 if (onNT)
245 processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
246 else
247 processFlag = selectProcessFlag(env, cmd) | CREATE_UNICODE_ENVIRONMENT;
248 ret = CreateProcessW(0, /* executable name */
249 (LPWSTR)pcmd, /* command line */
250 0, /* process security attribute */
251 0, /* thread security attribute */
252 TRUE, /* inherits system handles */
253 processFlag, /* selected based on exe type */
254 (LPVOID)penvBlock,/* environment block */
255 (LPCWSTR)pdir, /* change to the new current directory */
256 &si, /* (in) startup information */
257 &pi); /* (out) process information */
258 if (!ret) {
259 win32Error(env, "CreateProcess");
260 goto Catch;
261 }
262
263 CloseHandle(pi.hThread);
264 ret = (jlong)pi.hProcess;
265
266 Finally:
267 /* Always clean up the child's side of the pipes */
268 closeSafely(inRead);
269 closeSafely(outWrite);
270 closeSafely(errWrite);
271
272 if (pcmd != NULL)
273 (*env)->ReleaseStringChars(env, cmd, pcmd);
274 if (pdir != NULL)
275 (*env)->ReleaseStringChars(env, dir, pdir);
276 if (penvBlock != NULL)
277 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
278 if (handles != NULL)
279 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
280 return ret;
281
282 Catch:
283 /* Clean up the parent's side of the pipes in case of failure only */
284 closeSafely(inWrite);
285 closeSafely(outRead);
286 closeSafely(errRead);
287 goto Finally;
288 }
289
290 JNIEXPORT jint JNICALL
291 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
292 {
293 DWORD exit_code;
294 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
295 win32Error(env, "GetExitCodeProcess");
296 return exit_code;
297 }
298
299 JNIEXPORT jint JNICALL
300 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
301 {
302 return STILL_ACTIVE;
303 }
304
305 JNIEXPORT void JNICALL
306 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
307 {
|
1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
118 static const char * const format = "%s error=%d, %s";
119 static const char * const fallbackFormat = "%s failed, error=%d";
120 char buf[256];
121 char errmsg[sizeof(buf) + 100];
122 const int errnum = GetLastError();
123 const int n = JVM_GetLastErrorString(buf, sizeof(buf));
124 if (n > 0)
125 sprintf(errmsg, format, functionName, errnum, buf);
126 else
127 sprintf(errmsg, fallbackFormat, functionName, errnum);
128 JNU_ThrowIOException(env, errmsg);
129 }
130
131 static void
132 closeSafely(HANDLE handle)
133 {
134 if (handle != INVALID_HANDLE_VALUE)
135 CloseHandle(handle);
136 }
137
138 static BOOL hasInheritFlag(HANDLE handle)
139 {
140 DWORD mask;
141 if (GetHandleInformation(handle, &mask)) {
142 return mask & HANDLE_FLAG_INHERIT;
143 }
144 return FALSE;
145 }
146
147 #define HANDLE_STORAGE_SIZE 6
148 #define OFFSET_READ 0
149 #define OFFSET_WRITE 1
150 //long signed version of INVALID_HANDLE_VALUE
151 #define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)
152 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
153
154 /* Pipe holder structure */
155 typedef struct _STDHOLDER {
156 HANDLE pipe[2];
157 int offset;
158 } STDHOLDER;
159
160 /* Responsible for correct initialization of the [pHolder] structure
161 (that is used for handles recycling) if needs,
162 and appropriate setup of IOE handle [phStd] for child process based
163 on created pipe or Java handle. */
164 static BOOL initHolder(
165 JNIEnv *env,
166 jlong *pjhandles, /* IN OUT - the handle form Java,
167 that can be a file, console or undefined */
168 STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe
169 handles */
170 HANDLE *phStd /* OUT - initialized handle for child process */
171 ) {
172 /* Here we test the value from Java against invalid
173 handle value. We are not using INVALID_HANDLE_VALUE macro
174 due to double signed/unsigned and 32/64bit ambiguity.
175 Otherwise it will be easy to get the wrong
176 value 0x00000000FFFFFFFF
177 instead 0xFFFFFFFFFFFFFFFF. */
178 if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
179 /* Java file or console redirection */
180 *phStd = (HANDLE) *pjhandles;
181 /* Here we set the related Java stream (Process.getXXXXStream())
182 to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
183 The initial Java handle [*pjhandles] will be closed in
184 ANY case. It is not a handle leak. */
185 *pjhandles = JAVA_INVALID_HANDLE_VALUE;
186 } else {
187 /* Creation of parent-child pipe */
188 if (!CreatePipe(
189 &pHolder->pipe[OFFSET_READ],
190 &pHolder->pipe[OFFSET_WRITE],
191 NULL, /* we would like to inherit
192 default process access,
193 instead of 'Everybody' access */
194 PIPE_SIZE))
195 {
196 win32Error(env, "CreatePipe");
197 return FALSE;
198 } else {
199 /* [thisProcessEnd] has no the inherit flag because
200 the [lpPipeAttributes] param of [CreatePipe]
201 had the NULL value. */
202 HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
203 *phStd = pHolder->pipe[pHolder->offset];
204 *pjhandles = (jlong) thisProcessEnd;
205 }
206 }
207 /* Pipe handle will be closed in the [releaseHolder] call,
208 file handle will be closed in Java.
209 The long-live handle need to restore the inherit flag,
210 we do it later in the [prepareIOEHandleState] call. */
211 SetHandleInformation(
212 *phStd,
213 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
214 return TRUE;
215 }
216
217 /* Smart recycling of pipe handles in [pHolder]. For the failed
218 create process attempts, both ends of pipe need to be released.
219 The [complete] has the [TRUE] value in the failed attempt. */
220 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
221 closeSafely(pHolder->pipe[pHolder->offset]);
222 if (complete) {
223 /* Error occur, close this process pipe end */
224 closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
225 }
226 }
227
228 /* Stores and drops the inherit flag of handles that should not
229 be shared with the child process by default, but can hold the
230 inherit flag due to MS process birth specific. */
231 static void prepareIOEHandleState(
232 HANDLE *stdIOE,
233 BOOL *inherit)
234 {
235 int i;
236 for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
237 HANDLE hstd = stdIOE[i];
238 if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
239 /* FALSE by default */
240 inherit[i] = TRUE;
241 /* Java does not need implicit inheritance for IOE handles,
242 so we drop inherit flag that probably was installed by
243 previous CreateProcess call that launched current process.
244 We will return the handle state back after CreateProcess call.
245 By clearing inherit flag we prevent "greedy grandchild" birth.
246 The explicit inheritance for child process IOE handles is
247 implemented in the [initHolder] call. */
248 SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
249 }
250 }
251 }
252
253 /* Restores the inheritance flag of handles from stored values. */
254 static void restoreIOEHandleState(
255 const HANDLE *stdIOE,
256 const BOOL *inherit)
257 {
258 /* The set of current process standard IOE handles and
259 the set of child process IOE handles can intersect.
260 To restore the inherit flag right, we use backward
261 array iteration. */
262 int i;
263 for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
264 if (INVALID_HANDLE_VALUE != stdIOE[i]) {
265 /* Restore inherit flag for any case.
266 The handle can be changed by explicit inheritance.*/
267 SetHandleInformation(stdIOE[i],
268 HANDLE_FLAG_INHERIT,
269 inherit[i] ? HANDLE_FLAG_INHERIT : 0);
270 }
271 }
272
273 /* Please, read about the MS inheritance problem
274 http://support.microsoft.com/kb/315939
275 and critical section/synchronized block solution. */
276 static jlong processCreate(
277 JNIEnv *env,
278 const jchar *pcmd,
279 const jchar *penvBlock,
280 const jchar *pdir,
281 jlong *handles,
282 jboolean redirectErrorStream)
283 {
284 jlong ret = 0L;
285 STARTUPINFOW si = {sizeof(si)};
286
287 /* Handles for which the inheritance flag must be restored. */
288 HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
289 /* Current process standard IOE handles: JDK-7147084 */
290 INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
291 /* Child process IOE handles: JDK-6921885 */
292 (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
293 BOOL inherit[HANDLE_STORAGE_SIZE] = {
294 FALSE, FALSE, FALSE,
295 FALSE, FALSE, FALSE};
296
297 {
298 /* Extraction of current process standard IOE handles */
299 DWORD idsIOE[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
300 int i;
301 for (i = 0; i < 3; ++i)
302 /* Should not be closed by CloseHandle! */
303 stdIOE[i] = GetStdHandle(idsIOE[i]);
304 }
305
306 prepareIOEHandleState(stdIOE, inherit);
307 {
308 /* Input */
309 STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
310 if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {
311
312 /* Output */
313 STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
314 if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {
315
316 /* Error */
317 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
318 BOOL success;
319 if (redirectErrorStream) {
320 si.hStdError = si.hStdOutput;
321 /* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]
322 value. That is in accordance with Java Doc for the redirection case.
323 The Java file for the [ handles[2] ] will be closed in ANY case. It is not
324 a handle leak. */
325 handles[2] = JAVA_INVALID_HANDLE_VALUE;
326 success = TRUE;
327 } else {
328 success = initHolder(env, &handles[2], &holderErr, &si.hStdError);
329 }
330
331 if (success) {
332 PROCESS_INFORMATION pi;
333 DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
334
335 si.dwFlags = STARTF_USESTDHANDLES;
336 if (!CreateProcessW(
337 NULL, /* executable name */
338 (LPWSTR)pcmd, /* command line */
339 NULL, /* process security attribute */
340 NULL, /* thread security attribute */
341 TRUE, /* inherits system handles */
342 processFlag, /* selected based on exe type */
343 (LPVOID)penvBlock,/* environment block */
344 (LPCWSTR)pdir, /* change to the new current directory */
345 &si, /* (in) startup information */
346 &pi)) /* (out) process information */
347 {
348 win32Error(env, "CreateProcess");
349 } else {
350 closeSafely(pi.hThread);
351 ret = (jlong)pi.hProcess;
352 }
353 }
354 releaseHolder(ret == 0, &holderErr);
355 releaseHolder(ret == 0, &holderOut);
356 }
357 releaseHolder(ret == 0, &holderIn);
358 }
359 }
360 restoreIOEHandleState(stdIOE, inherit);
361
362 return ret;
363 }
364
365 JNIEXPORT jlong JNICALL
366 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
367 jstring cmd,
368 jstring envBlock,
369 jstring dir,
370 jlongArray stdHandles,
371 jboolean redirectErrorStream)
372 {
373 jlong ret = 0;
374 if (cmd != NULL && stdHandles != NULL) {
375 const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
376 if (pcmd != NULL) {
377 const jchar *penvBlock = (envBlock != NULL)
378 ? (*env)->GetStringChars(env, envBlock, NULL)
379 : NULL;
380 const jchar *pdir = (dir != NULL)
381 ? (*env)->GetStringChars(env, dir, NULL)
382 : NULL;
383 jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
384 if (handles != NULL) {
385 ret = processCreate(
386 env,
387 pcmd,
388 penvBlock,
389 pdir,
390 handles,
391 redirectErrorStream);
392 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
393 }
394 if (pdir != NULL)
395 (*env)->ReleaseStringChars(env, dir, pdir);
396 if (penvBlock != NULL)
397 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
398 (*env)->ReleaseStringChars(env, cmd, pcmd);
399 }
400 }
401 return ret;
402 }
403
404 JNIEXPORT jint JNICALL
405 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
406 {
407 DWORD exit_code;
408 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
409 win32Error(env, "GetExitCodeProcess");
410 return exit_code;
411 }
412
413 JNIEXPORT jint JNICALL
414 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
415 {
416 return STILL_ACTIVE;
417 }
418
419 JNIEXPORT void JNICALL
420 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
421 {
|