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 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 char * 44 extractExecutablePath(JNIEnv *env, char *source) 45 { 46 char *p, *r; 47 48 /* If no spaces, then use entire thing */ 49 if ((p = strchr(source, ' ')) == NULL) 50 return source; 51 52 /* If no quotes, or quotes after space, return up to space */ 53 if (((r = strchr(source, '"')) == NULL) || (r > p)) { 54 *p = 0; 55 return source; 56 } 57 58 /* Quotes before space, return up to space after next quotes */ 59 p = strchr(r, '"'); 60 if ((p = strchr(p, ' ')) == NULL) 61 return source; 62 *p = 0; 63 return source; 64 } 65 66 static const char EXE_EXT[] = ".exe"; 67 68 DWORD 69 selectProcessFlag(JNIEnv *env, jstring cmd0) 70 { 71 DWORD newFlag = 0; 72 char *exe = (char *)JNU_GetStringPlatformChars(env, cmd0, 0); 73 if (exe != NULL) { 74 char buf[MAX_PATH]; 75 char *name; 76 DWORD len; 77 exe = extractExecutablePath(env, exe); 78 if (exe != NULL) { 79 /*we are here for Win9x/Me, so the [/] is not the path sep*/ 80 char *p = strrchr(exe, '\\'); 81 if (p == NULL) { 82 len = SearchPath(NULL, exe, EXE_EXT, MAX_PATH, buf, &name); 83 } else { 84 *p = 0; 85 len = SearchPath(exe, p + 1, EXE_EXT, MAX_PATH, buf, &name); 86 } 87 } 88 89 if (len > 0 && len < MAX_PATH) { 90 /*here the [buf] path is null terminated*/ 91 int fd = _open(buf, _O_RDONLY); 92 if (fd != -1) { 93 unsigned char buffer[2]; 94 if (_read(fd, buffer, 2) == 2 95 && buffer[0] == 'M' && buffer[1] == 'Z' 96 && _lseek(fd, 60L, SEEK_SET) == 60L 97 && _read(fd, buffer, 2) == 2) 98 { 99 long headerLoc = (long)buffer[1] << 8 | (long)buffer[0]; 100 if (_lseek(fd, headerLoc, SEEK_SET) == headerLoc 101 && _read(fd, buffer, 2) == 2 102 && buffer[0] == 'P' && buffer[1] == 'E') 103 { 104 newFlag = DETACHED_PROCESS; 105 } 106 } 107 _close(fd); 108 } 109 } 110 JNU_ReleaseStringPlatformChars(env, cmd0, exe); 111 } 112 return newFlag; 113 } 114 115 static void 116 win32Error(JNIEnv *env, const char *functionName) 117 { 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, FALSE); 203 handles[0] = (jlong) inWrite; 204 } 205 SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT, TRUE); 206 207 if (handles[1] != (jlong) -1) { 208 si.hStdOutput = (HANDLE) handles[1]; 209 handles[1] = (jlong) -1; 210 } else { 211 if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) { 212 win32Error(env, "CreatePipe"); 213 goto Catch; 214 } 215 si.hStdOutput = outWrite; 216 SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, FALSE); 217 handles[1] = (jlong) outRead; 218 } 219 SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT, TRUE); 220 221 if (redirectErrorStream) { 222 si.hStdError = si.hStdOutput; 223 handles[2] = (jlong) -1; 224 } else if (handles[2] != (jlong) -1) { 225 si.hStdError = (HANDLE) handles[2]; 226 handles[2] = (jlong) -1; 227 } else { 228 if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) { 229 win32Error(env, "CreatePipe"); 230 goto Catch; 231 } 232 si.hStdError = errWrite; 233 SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, FALSE); 234 handles[2] = (jlong) errRead; 235 } 236 SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT, TRUE); 237 238 if (onNT) 239 processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; 240 else 241 processFlag = selectProcessFlag(env, cmd) | CREATE_UNICODE_ENVIRONMENT; 242 ret = CreateProcessW(0, /* executable name */ 243 (LPWSTR)pcmd, /* command line */ 244 0, /* process security attribute */ 245 0, /* thread security attribute */ 246 TRUE, /* inherits system handles */ 247 processFlag, /* selected based on exe type */ 248 (LPVOID)penvBlock,/* environment block */ 249 (LPCWSTR)pdir, /* change to the new current directory */ 250 &si, /* (in) startup information */ 251 &pi); /* (out) process information */ 252 if (!ret) { 253 win32Error(env, "CreateProcess"); 254 goto Catch; 255 } 256 257 CloseHandle(pi.hThread); 258 ret = (jlong)pi.hProcess; 259 260 Finally: 261 /* Always clean up the child's side of the pipes */ 262 closeSafely(inRead); 263 closeSafely(outWrite); 264 closeSafely(errWrite); 265 266 if (pcmd != NULL) 267 (*env)->ReleaseStringChars(env, cmd, pcmd); 268 if (pdir != NULL) 269 (*env)->ReleaseStringChars(env, dir, pdir); 270 if (penvBlock != NULL) 271 (*env)->ReleaseStringChars(env, envBlock, penvBlock); 272 if (handles != NULL) 273 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0); 274 return ret; 275 276 Catch: 277 /* Clean up the parent's side of the pipes in case of failure only */ 278 closeSafely(inWrite); 279 closeSafely(outRead); 280 closeSafely(errRead); 281 goto Finally; 282 } 283 284 JNIEXPORT jint JNICALL 285 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle) 286 { 287 DWORD exit_code; 288 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0) 289 win32Error(env, "GetExitCodeProcess"); 290 return exit_code; 291 } 292 293 JNIEXPORT jint JNICALL 294 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored) 295 { 296 return STILL_ACTIVE; 297 } 298 299 JNIEXPORT void JNICALL 300 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle) 301 { 302 HANDLE events[2]; 303 events[0] = (HANDLE) handle; 304 events[1] = JVM_GetThreadInterruptEvent(); 305 306 if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, 307 FALSE, /* Wait for ANY event */ 308 INFINITE) /* Wait forever */ 309 == WAIT_FAILED) 310 win32Error(env, "WaitForMultipleObjects"); 311 } 312 313 JNIEXPORT void JNICALL 314 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle) 315 { 316 TerminateProcess((HANDLE) handle, 1); 317 } 318 319 JNIEXPORT jboolean JNICALL 320 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle) 321 { 322 return CloseHandle((HANDLE) handle); 323 } 324 325 /** 326 * Returns a copy of the Unicode characters of a string. Fow now this 327 * function doesn't handle long path names and other issues. 328 */ 329 static WCHAR* getPath(JNIEnv *env, jstring ps) { 330 WCHAR *pathbuf = NULL; 331 const jchar *chars = (*(env))->GetStringChars(env, ps, NULL); 332 if (chars != NULL) { 333 size_t pathlen = wcslen(chars); 334 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); 335 if (pathbuf == NULL) { 336 JNU_ThrowOutOfMemoryError(env, NULL); 337 } else { 338 wcscpy(pathbuf, chars); 339 } 340 (*env)->ReleaseStringChars(env, ps, chars); 341 } 342 return pathbuf; 343 } 344 345 JNIEXPORT jlong JNICALL 346 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path) 347 { 348 const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); 349 const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; 350 const DWORD disposition = OPEN_ALWAYS; 351 const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL; 352 HANDLE h; 353 WCHAR *pathbuf = getPath(env, path); 354 if (pathbuf == NULL) { 355 /* Exception already pending */ 356 return -1; 357 } 358 h = CreateFileW( 359 pathbuf, /* Wide char path name */ 360 access, /* Read and/or write permission */ 361 sharing, /* File sharing flags */ 362 NULL, /* Security attributes */ 363 disposition, /* creation disposition */ 364 flagsAndAttributes, /* flags and attributes */ 365 NULL); 366 free(pathbuf); 367 if (h == INVALID_HANDLE_VALUE) { 368 JNU_ThrowIOExceptionWithLastError(env, "CreateFileW"); 369 } 370 return ptr_to_jlong(h); 371 }