src/java.base/windows/native/libjli/java_md.c

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 35,45 **** #include <wtypes.h> #include <commctrl.h> #include <jni.h> #include "java.h" - #include "version_comp.h" #define JVM_DLL "jvm.dll" #define JAVA_DLL "java.dll" /* --- 35,44 ----
*** 672,1095 **** jboolean ServerClassMachine() { return (GetErgoPolicy() == ALWAYS_SERVER_CLASS) ? JNI_TRUE : JNI_FALSE; } - /* - * Determine if there is an acceptable JRE in the registry directory top_key. - * Upon locating the "best" one, return a fully qualified path to it. - * "Best" is defined as the most advanced JRE meeting the constraints - * contained in the manifest_info. If no JRE in this directory meets the - * constraints, return NULL. - * - * It doesn't matter if we get an error reading the registry, or we just - * don't find anything interesting in the directory. We just return NULL - * in either case. - */ - static char * - ProcessDir(manifest_info* info, HKEY top_key) { - DWORD index = 0; - HKEY ver_key; - char name[MAXNAMELEN]; - int len; - char *best = NULL; - - /* - * Enumerate "<top_key>/SOFTWARE/JavaSoft/Java Runtime Environment" - * searching for the best available version. - */ - while (RegEnumKey(top_key, index, name, MAXNAMELEN) == ERROR_SUCCESS) { - index++; - if (JLI_AcceptableRelease(name, info->jre_version)) - if ((best == NULL) || (JLI_ExactVersionId(name, best) > 0)) { - if (best != NULL) - JLI_MemFree(best); - best = JLI_StringDup(name); - } - } - - /* - * Extract "JavaHome" from the "best" registry directory and return - * that path. If no appropriate version was located, or there is an - * error in extracting the "JavaHome" string, return null. - */ - if (best == NULL) - return (NULL); - else { - if (RegOpenKeyEx(top_key, best, 0, KEY_READ, &ver_key) - != ERROR_SUCCESS) { - JLI_MemFree(best); - if (ver_key != NULL) - RegCloseKey(ver_key); - return (NULL); - } - JLI_MemFree(best); - len = MAXNAMELEN; - if (RegQueryValueEx(ver_key, "JavaHome", NULL, NULL, (LPBYTE)name, &len) - != ERROR_SUCCESS) { - if (ver_key != NULL) - RegCloseKey(ver_key); - return (NULL); - } - if (ver_key != NULL) - RegCloseKey(ver_key); - return (JLI_StringDup(name)); - } - } - - /* - * This is the global entry point. It examines the host for the optimal - * JRE to be used by scanning a set of registry entries. This set of entries - * is hardwired on Windows as "Software\JavaSoft\Java Runtime Environment" - * under the set of roots "{ HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }". - * - * This routine simply opens each of these registry directories before passing - * control onto ProcessDir(). - */ - char * - LocateJRE(manifest_info* info) { - HKEY key = NULL; - char *path; - int key_index; - HKEY root_keys[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; - - for (key_index = 0; key_index <= 1; key_index++) { - if (RegOpenKeyEx(root_keys[key_index], JRE_KEY, 0, KEY_READ, &key) - == ERROR_SUCCESS) - if ((path = ProcessDir(info, key)) != NULL) { - if (key != NULL) - RegCloseKey(key); - return (path); - } - if (key != NULL) - RegCloseKey(key); - } - return NULL; - } - - /* - * Local helper routine to isolate a single token (option or argument) - * from the command line. - * - * This routine accepts a pointer to a character pointer. The first - * token (as defined by MSDN command-line argument syntax) is isolated - * from that string. - * - * Upon return, the input character pointer pointed to by the parameter s - * is updated to point to the remainding, unscanned, portion of the string, - * or to a null character if the entire string has been consummed. - * - * This function returns a pointer to a null-terminated string which - * contains the isolated first token, or to the null character if no - * token could be isolated. - * - * Note the side effect of modifying the input string s by the insertion - * of a null character, making it two strings. - * - * See "Parsing C Command-Line Arguments" in the MSDN Library for the - * parsing rule details. The rule summary from that specification is: - * - * * Arguments are delimited by white space, which is either a space or a tab. - * - * * A string surrounded by double quotation marks is interpreted as a single - * argument, regardless of white space contained within. A quoted string can - * be embedded in an argument. Note that the caret (^) is not recognized as - * an escape character or delimiter. - * - * * A double quotation mark preceded by a backslash, \", is interpreted as a - * literal double quotation mark ("). - * - * * Backslashes are interpreted literally, unless they immediately precede a - * double quotation mark. - * - * * If an even number of backslashes is followed by a double quotation mark, - * then one backslash (\) is placed in the argv array for every pair of - * backslashes (\\), and the double quotation mark (") is interpreted as a - * string delimiter. - * - * * If an odd number of backslashes is followed by a double quotation mark, - * then one backslash (\) is placed in the argv array for every pair of - * backslashes (\\) and the double quotation mark is interpreted as an - * escape sequence by the remaining backslash, causing a literal double - * quotation mark (") to be placed in argv. - */ - static char* - nextarg(char** s) { - char *p = *s; - char *head; - int slashes = 0; - int inquote = 0; - - /* - * Strip leading whitespace, which MSDN defines as only space or tab. - * (Hence, no locale specific "isspace" here.) - */ - while (*p != (char)0 && (*p == ' ' || *p == '\t')) - p++; - head = p; /* Save the start of the token to return */ - - /* - * Isolate a token from the command line. - */ - while (*p != (char)0 && (inquote || !(*p == ' ' || *p == '\t'))) { - if (*p == '\\' && *(p+1) == '"' && slashes % 2 == 0) - p++; - else if (*p == '"') - inquote = !inquote; - slashes = (*p++ == '\\') ? slashes + 1 : 0; - } - - /* - * If the token isolated isn't already terminated in a "char zero", - * then replace the whitespace character with one and move to the - * next character. - */ - if (*p != (char)0) - *p++ = (char)0; - - /* - * Update the parameter to point to the head of the remaining string - * reflecting the command line and return a pointer to the leading - * token which was isolated from the command line. - */ - *s = p; - return (head); - } - - /* - * Local helper routine to return a string equivalent to the input string - * s, but with quotes removed so the result is a string as would be found - * in argv[]. The returned string should be freed by a call to JLI_MemFree(). - * - * The rules for quoting (and escaped quotes) are: - * - * 1 A double quotation mark preceded by a backslash, \", is interpreted as a - * literal double quotation mark ("). - * - * 2 Backslashes are interpreted literally, unless they immediately precede a - * double quotation mark. - * - * 3 If an even number of backslashes is followed by a double quotation mark, - * then one backslash (\) is placed in the argv array for every pair of - * backslashes (\\), and the double quotation mark (") is interpreted as a - * string delimiter. - * - * 4 If an odd number of backslashes is followed by a double quotation mark, - * then one backslash (\) is placed in the argv array for every pair of - * backslashes (\\) and the double quotation mark is interpreted as an - * escape sequence by the remaining backslash, causing a literal double - * quotation mark (") to be placed in argv. - */ - static char* - unquote(const char *s) { - const char *p = s; /* Pointer to the tail of the original string */ - char *un = (char*)JLI_MemAlloc(JLI_StrLen(s) + 1); /* Ptr to unquoted string */ - char *pun = un; /* Pointer to the tail of the unquoted string */ - - while (*p != '\0') { - if (*p == '"') { - p++; - } else if (*p == '\\') { - const char *q = p + JLI_StrSpn(p,"\\"); - if (*q == '"') - do { - *pun++ = '\\'; - p += 2; - } while (*p == '\\' && p < q); - else - while (p < q) - *pun++ = *p++; - } else { - *pun++ = *p++; - } - } - *pun = '\0'; - return un; - } - - /* - * Given a path to a jre to execute, this routine checks if this process - * is indeed that jre. If not, it exec's that jre. - * - * We want to actually check the paths rather than just the version string - * built into the executable, so that given version specification will yield - * the exact same Java environment, regardless of the version of the arbitrary - * launcher we start with. - */ - void - ExecJRE(char *jre, char **argv) { - jint len; - char path[MAXPATHLEN + 1]; - - const char *progname = GetProgramName(); - - /* - * Resolve the real path to the currently running launcher. - */ - len = GetModuleFileName(NULL, path, MAXPATHLEN + 1); - if (len == 0 || len > MAXPATHLEN) { - JLI_ReportErrorMessageSys(JRE_ERROR9, progname); - exit(1); - } - - JLI_TraceLauncher("ExecJRE: old: %s\n", path); - JLI_TraceLauncher("ExecJRE: new: %s\n", jre); - - /* - * If the path to the selected JRE directory is a match to the initial - * portion of the path to the currently executing JRE, we have a winner! - * If so, just return. - */ - if (JLI_StrNCaseCmp(jre, path, JLI_StrLen(jre)) == 0) - return; /* I am the droid you were looking for */ - - /* - * If this isn't the selected version, exec the selected version. - */ - JLI_Snprintf(path, sizeof(path), "%s\\bin\\%s.exe", jre, progname); - - /* - * Although Windows has an execv() entrypoint, it doesn't actually - * overlay a process: it can only create a new process and terminate - * the old process. Therefore, any processes waiting on the initial - * process wake up and they shouldn't. Hence, a chain of pseudo-zombie - * processes must be retained to maintain the proper wait semantics. - * Fortunately the image size of the launcher isn't too large at this - * time. - * - * If it weren't for this semantic flaw, the code below would be ... - * - * execv(path, argv); - * JLI_ReportErrorMessage("Error: Exec of %s failed\n", path); - * exit(1); - * - * The incorrect exec semantics could be addressed by: - * - * exit((int)spawnv(_P_WAIT, path, argv)); - * - * Unfortunately, a bug in Windows spawn/exec impementation prevents - * this from completely working. All the Windows POSIX process creation - * interfaces are implemented as wrappers around the native Windows - * function CreateProcess(). CreateProcess() takes a single string - * to specify command line options and arguments, so the POSIX routine - * wrappers build a single string from the argv[] array and in the - * process, any quoting information is lost. - * - * The solution to this to get the original command line, to process it - * to remove the new multiple JRE options (if any) as was done for argv - * in the common SelectVersion() routine and finally to pass it directly - * to the native CreateProcess() Windows process control interface. - */ - { - char *cmdline; - char *p; - char *np; - char *ocl; - char *ccl; - char *unquoted; - DWORD exitCode; - STARTUPINFO si; - PROCESS_INFORMATION pi; - - /* - * The following code block gets and processes the original command - * line, replacing the argv[0] equivalent in the command line with - * the path to the new executable and removing the appropriate - * Multiple JRE support options. Note that similar logic exists - * in the platform independent SelectVersion routine, but is - * replicated here due to the syntax of CreateProcess(). - * - * The magic "+ 4" characters added to the command line length are - * 2 possible quotes around the path (argv[0]), a space after the - * path and a terminating null character. - */ - ocl = GetCommandLine(); - np = ccl = JLI_StringDup(ocl); - p = nextarg(&np); /* Discard argv[0] */ - cmdline = (char *)JLI_MemAlloc(JLI_StrLen(path) + JLI_StrLen(np) + 4); - if (JLI_StrChr(path, (int)' ') == NULL && JLI_StrChr(path, (int)'\t') == NULL) - cmdline = JLI_StrCpy(cmdline, path); - else - cmdline = JLI_StrCat(JLI_StrCat(JLI_StrCpy(cmdline, "\""), path), "\""); - - while (*np != (char)0) { /* While more command-line */ - p = nextarg(&np); - if (*p != (char)0) { /* If a token was isolated */ - unquoted = unquote(p); - if (*unquoted == '-') { /* Looks like an option */ - if (JLI_StrCmp(unquoted, "-classpath") == 0 || - JLI_StrCmp(unquoted, "-cp") == 0) { /* Unique cp syntax */ - cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); - p = nextarg(&np); - if (*p != (char)0) /* If a token was isolated */ - cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); - } else if (JLI_StrNCmp(unquoted, "-version:", 9) != 0 && - JLI_StrCmp(unquoted, "-jre-restrict-search") != 0 && - JLI_StrCmp(unquoted, "-no-jre-restrict-search") != 0) { - cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); - } - } else { /* End of options */ - cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); - cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), np); - JLI_MemFree((void *)unquoted); - break; - } - JLI_MemFree((void *)unquoted); - } - } - JLI_MemFree((void *)ccl); - - if (JLI_IsTraceLauncher()) { - np = ccl = JLI_StringDup(cmdline); - p = nextarg(&np); - printf("ReExec Command: %s (%s)\n", path, p); - printf("ReExec Args: %s\n", np); - JLI_MemFree((void *)ccl); - } - (void)fflush(stdout); - (void)fflush(stderr); - - /* - * The following code is modeled after a model presented in the - * Microsoft Technical Article "Moving Unix Applications to - * Windows NT" (March 6, 1994) and "Creating Processes" on MSDN - * (Februrary 2005). It approximates UNIX spawn semantics with - * the parent waiting for termination of the child. - */ - memset(&si, 0, sizeof(si)); - si.cb =sizeof(STARTUPINFO); - memset(&pi, 0, sizeof(pi)); - - if (!CreateProcess((LPCTSTR)path, /* executable name */ - (LPTSTR)cmdline, /* command line */ - (LPSECURITY_ATTRIBUTES)NULL, /* process security attr. */ - (LPSECURITY_ATTRIBUTES)NULL, /* thread security attr. */ - (BOOL)TRUE, /* inherits system handles */ - (DWORD)0, /* creation flags */ - (LPVOID)NULL, /* environment block */ - (LPCTSTR)NULL, /* current directory */ - (LPSTARTUPINFO)&si, /* (in) startup information */ - (LPPROCESS_INFORMATION)&pi)) { /* (out) process information */ - JLI_ReportErrorMessageSys(SYS_ERROR1, path); - exit(1); - } - - if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) { - if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE) - exitCode = 1; - } else { - JLI_ReportErrorMessage(SYS_ERROR2); - exitCode = 1; - } - - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - - exit(exitCode); - } - } - /* * Wrapper for platform dependent unsetenv function. */ int UnsetEnv(char *name) --- 671,680 ----