src/windows/bin/java_md.c
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);
    }
}
/*
 * 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.
 */
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.
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();
    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 (JLI_StrNCaseCmp(jre, path, JLI_StrLen(jre)) == 0)
        return;                 
    JLI_Snprintf(path, sizeof(path), "%s\\bin\\%s.exe", jre, progname);
    {
        char    *cmdline;
        char    *p;
        char    *np;
        char    *ocl;
        char    *ccl;
        char    *unquoted;
        DWORD   exitCode;
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        ocl = GetCommandLine();
        np = ccl = JLI_StringDup(ocl);
        p = nextarg(&np);               
        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) {                
            p = nextarg(&np);
            if (*p != (char)0) {                
                unquoted = unquote(p);
                if (*unquoted == '-') {         
                    if (JLI_StrCmp(unquoted, "-classpath") == 0 ||
                      JLI_StrCmp(unquoted, "-cp") == 0) {       
                        cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p);
                        p = nextarg(&np);
                        if (*p != (char)0)      
                            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 {                        
                    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);
        memset(&si, 0, sizeof(si));
        si.cb =sizeof(STARTUPINFO);
        memset(&pi, 0, sizeof(pi));
        if (!CreateProcess((LPCTSTR)path,       
          (LPTSTR)cmdline,                      
          (LPSECURITY_ATTRIBUTES)NULL,          
          (LPSECURITY_ATTRIBUTES)NULL,          
          (BOOL)TRUE,                           
          (DWORD)0,                             
          (LPVOID)NULL,                         
          (LPCTSTR)NULL,                        
          (LPSTARTUPINFO)&si,                   
          (LPPROCESS_INFORMATION)&pi)) {        
            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);
    }
}
void ExecJRE ( char * jre , char * * argv ) { jint len ; char path [ MAXPATHLEN + 1 ] ; const char * progname = GetProgramName ( ) ; len = GetModuleFileName ( NULL , path , MAXPATHLEN + 1 ) ; if ( len == 0 || len > MAXPATHLEN ) { JLI_ReportErrorMessageSys ( JRE_ERROR9 , progname ) ; exit ( 1 ) ; } JLI_TraceLauncher ( " \n " , path ) ; JLI_TraceLauncher ( " \n " , jre ) ; if ( JLI_StrNCaseCmp ( jre , path , JLI_StrLen ( jre ) ) == 0 ) return ; JLI_Snprintf ( path , sizeof ( path ) , " \\ \\ " , jre , progname ) ; { char * cmdline ; char * p ; char * np ; char * ocl ; char * ccl ; char * unquoted ; DWORD exitCode ; STARTUPINFO si ; PROCESS_INFORMATION pi ; ocl = GetCommandLine ( ) ; np = ccl = JLI_StringDup ( ocl ) ; p = nextarg ( & np ) ; 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 ) { p = nextarg ( & np ) ; if ( * p != ( char ) 0 ) { unquoted = unquote ( p ) ; if ( * unquoted == ' ' ) { if ( JLI_StrCmp ( unquoted , " " ) == 0 || JLI_StrCmp ( unquoted , " " ) == 0 ) { cmdline = JLI_StrCat ( JLI_StrCat ( cmdline , " " ) , p ) ; p = nextarg ( & np ) ; if ( * p != ( char ) 0 ) cmdline = JLI_StrCat ( JLI_StrCat ( cmdline , " " ) , p ) ; } else if ( JLI_StrNCmp ( unquoted , " " , 9 ) != 0 && JLI_StrCmp ( unquoted , " " ) != 0 && JLI_StrCmp ( unquoted , " " ) != 0 ) { cmdline = JLI_StrCat ( JLI_StrCat ( cmdline , " " ) , p ) ; } } else { 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 ( " \n " , path , p ) ; printf ( " \n " , np ) ; JLI_MemFree ( ( void * ) ccl ) ; } ( void ) fflush ( stdout ) ; ( void ) fflush ( stderr ) ; memset ( & si , 0 , sizeof ( si ) ) ; si . cb = sizeof ( STARTUPINFO ) ; memset ( & pi , 0 , sizeof ( pi ) ) ; if ( ! CreateProcess ( ( LPCTSTR ) path , ( LPTSTR ) cmdline , ( LPSECURITY_ATTRIBUTES ) NULL , ( LPSECURITY_ATTRIBUTES ) NULL , ( BOOL ) TRUE , ( DWORD ) 0 , ( LPVOID ) NULL , ( LPCTSTR ) NULL , ( LPSTARTUPINFO ) & si , ( LPPROCESS_INFORMATION ) & pi ) ) { 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 ) ; } }
Given a path to a jre to execute, this routine checks if this process
 is indeed that jre.
Given a path to a jre to execute this routine checks if this process is indeed that jre .
/*
     * Resolve the real path to the currently running launcher.
     */ /*
     * 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.
     */ /* I am the droid you were looking for */ /*
     * If this isn't the selected version, exec the selected version.
     */ /*
     * 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.
     */ /*
         * 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.
         */ /* Discard argv[0] */ /* While more command-line */ /* If a token was isolated */ /* Looks like an option */ /* Unique cp syntax */ /* If a token was isolated */ /* End of options */ /*
         * 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.
         */ /* executable name */ /* command line */ /* process security attr. */ /* thread security attr. */ /* inherits system handles */ /* creation flags */ /* environment block */ /* current directory */ /* (in) startup information */ /* (out) process information */