1 /* 2 * Copyright (c) 1997, 2012, 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 23 * questions. 24 */ 25 26 #include <assert.h> 27 #include "java_lang_ProcessImpl.h" 28 29 #include "jni.h" 30 #include "jvm.h" 31 #include "jni_util.h" 32 #include "io_util.h" 33 #include <windows.h> 34 #include <io.h> 35 36 /* We try to make sure that we can read and write 4095 bytes (the 37 * fixed limit on Linux) to the pipe on all operating systems without 38 * deadlock. Windows 2000 inexplicably appears to need an extra 24 39 * bytes of slop to avoid deadlock. 40 */ 41 #define PIPE_SIZE (4096+24) 42 43 static void 44 win32Error(JNIEnv *env, const char *functionName) 45 { 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 { 226 HANDLE events[2]; 227 events[0] = (HANDLE) handle; 228 events[1] = JVM_GetThreadInterruptEvent(); 229 230 if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, 231 FALSE, /* Wait for ANY event */ 232 INFINITE) /* Wait forever */ 233 == WAIT_FAILED) 234 win32Error(env, "WaitForMultipleObjects"); 235 } 236 237 JNIEXPORT void JNICALL 238 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env, 239 jclass ignored, 240 jlong handle, 241 jlong timeout) 242 { 243 HANDLE events[2]; 244 DWORD dwTimeout = (DWORD)timeout; 245 DWORD result; 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) { 287 JNU_ThrowOutOfMemoryError(env, NULL); 288 } else { 289 wcscpy(pathbuf, chars); 290 } 291 (*env)->ReleaseStringChars(env, ps, chars); 292 } 293 return pathbuf; 294 } 295 296 JNIEXPORT jlong JNICALL 297 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path) 298 { 299 const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); 300 const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; 301 const DWORD disposition = OPEN_ALWAYS; 302 const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL; 303 HANDLE h; 304 WCHAR *pathbuf = getPath(env, path); 305 if (pathbuf == NULL) { 306 /* Exception already pending */ 307 return -1; 308 } 309 h = CreateFileW( 310 pathbuf, /* Wide char path name */ 311 access, /* Read and/or write permission */ 312 sharing, /* File sharing flags */ 313 NULL, /* Security attributes */ 314 disposition, /* creation disposition */ 315 flagsAndAttributes, /* flags and attributes */ 316 NULL); 317 free(pathbuf); 318 if (h == INVALID_HANDLE_VALUE) { 319 JNU_ThrowIOExceptionWithLastError(env, "CreateFileW"); 320 } 321 return ptr_to_jlong(h); 322 }