Esempio n. 1
0
// XXXldb |args| has the wrong const-ness
NS_IMETHODIMP  
nsProcess::Run(PRBool blocking, const char **args, PRUint32 count,
               PRUint32 *pid)
{
    NS_ENSURE_TRUE(mExecutable, NS_ERROR_NOT_INITIALIZED);
    PRStatus status = PR_SUCCESS;

    // make sure that when we allocate we have 1 greater than the
    // count since we need to null terminate the list for the argv to
    // pass into PR_CreateProcess
    char **my_argv = NULL;
    my_argv = (char **)nsMemory::Alloc(sizeof(char *) * (count + 2) );
    if (!my_argv) {
        return NS_ERROR_OUT_OF_MEMORY;
    }

    // copy the args
    PRUint32 i;
    for (i=0; i < count; i++) {
        my_argv[i+1] = NS_CONST_CAST(char*, args[i]);
    }
    // we need to set argv[0] to the program name.
    my_argv[0] = mTargetPath.BeginWriting();
    // null terminate the array
    my_argv[count+1] = NULL;

#if defined(XP_WIN)
    STARTUPINFO startupInfo;
    PROCESS_INFORMATION procInfo;
    BOOL retVal;
    char *cmdLine;

    if (assembleCmdLine(my_argv, &cmdLine) == -1) {
        nsMemory::Free(my_argv);
        return NS_ERROR_FILE_EXECUTION_FAILED;    
    }

    ZeroMemory(&startupInfo, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);

    retVal = CreateProcess(NULL,
                           // NS_CONST_CAST(char*, mTargetPath.get()),
                           cmdLine,
                           NULL,  /* security attributes for the new
                                   * process */
                           NULL,  /* security attributes for the primary
                                   * thread in the new process */
                           FALSE,  /* inherit handles */
                           0,     /* creation flags */
                           NULL,  /* env */
                           NULL,  /* current drive and directory */
                           &startupInfo,
                           &procInfo
                          );
    PR_Free( cmdLine );
    if (blocking) {
 
        // if success, wait for process termination. the early returns and such
        // are a bit ugly but preserving the logic of the nspr code I copied to 
        // minimize our risk abit.

        if ( retVal == TRUE ) {
            DWORD dwRetVal;
            unsigned long exitCode;

            dwRetVal = WaitForSingleObject(procInfo.hProcess, INFINITE);
            if (dwRetVal == WAIT_FAILED) {
                nsMemory::Free(my_argv);
                return NS_ERROR_FAILURE;
            }
            if (GetExitCodeProcess(procInfo.hProcess, &exitCode) == FALSE) {
                mExitValue = exitCode;
                nsMemory::Free(my_argv);
               return NS_ERROR_FAILURE;
            }
            mExitValue = exitCode;
            CloseHandle(procInfo.hProcess);
        }
        else
            status = PR_FAILURE;
    } 
    else {

        // map return value into success code

        if (retVal == TRUE) 
            status = PR_SUCCESS;
        else
            status = PR_FAILURE;
    }

#else // Note, this must not be an #elif ...!

#if defined(XP_MACOSX)
    if (count == 0) {
        FSSpec resolvedSpec;
        OSErr err = noErr;

        nsCOMPtr<nsILocalFileMac> macExecutable =
            do_QueryInterface(mExecutable);
        macExecutable->GetFSSpec(&resolvedSpec);

        LaunchParamBlockRec launchPB;
        launchPB.launchAppSpec = &resolvedSpec;
        launchPB.launchAppParameters = NULL;
        launchPB.launchBlockID = extendedBlock;
        launchPB.launchEPBLength = extendedBlockLen;
        launchPB.launchFileFlags = NULL;
        launchPB.launchControlFlags =
            launchContinue + launchNoFileFlags + launchUseMinimum;
        if (!blocking)
            launchPB.launchControlFlags += launchDontSwitch;

        err = LaunchApplication(&launchPB);

        // NOTE: blocking mode assumes you are running on a thread
        //       other than the UI thread that has the main event loop
        if (blocking && err == noErr) {
            while (1) {
                ProcessInfoRec info;
                info.processInfoLength = sizeof(ProcessInfoRec);
                info.processName = NULL;
                info.processAppSpec = NULL;

                err = GetProcessInformation(&launchPB.launchProcessSN, &info);

                if (err != noErr) {
                    // The process is no longer in the process
                    // manager's internal list, assume the process is
                    // done.
                    err = noErr;

                    break;
                }

                // still running so sleep some more (200 msecs)
                PR_Sleep(200);
            }
        }

        if (err != noErr) {
            status = PR_FAILURE;
        }

        if (blocking) {
            mExitValue = err;
        }
    } else
#endif
    {
        if (blocking) {
            mProcess = PR_CreateProcess(mTargetPath.get(), my_argv, NULL,
                                        NULL);
            if (mProcess)
                status = PR_WaitProcess(mProcess, &mExitValue);
        } else {
            status = PR_CreateProcessDetached(mTargetPath.get(), my_argv, NULL,
                                          NULL);
        }
    }
#endif

    // free up our argv
    nsMemory::Free(my_argv);

    if (status != PR_SUCCESS)
        return NS_ERROR_FILE_EXECUTION_FAILED;

    return NS_OK;
}
Esempio n. 2
0
PRProcess * _PR_CreateOS2Process(
    const char *path,
    char *const *argv,
    char *const *envp,
    const PRProcessAttr *attr)
{
    PRProcess *proc = NULL;
    char *cmdLine = NULL;
    char **newEnvp = NULL;
    char *envBlock = NULL;
   
    STARTDATA startData = {0};
    APIRET    rc;
    ULONG     ulAppType = 0;
    PID       pid = 0;
    char     *pszComSpec;
    char      pszEXEName[CCHMAXPATH] = "";
    char      pszFormatString[CCHMAXPATH];
    char      pszObjectBuffer[CCHMAXPATH];
    char     *pszFormatResult = NULL;

    /*
     * Variables for DosExecPgm
     */
    char szFailed[CCHMAXPATH];
    char *pszCmdLine = NULL;
    RESULTCODES procInfo;
    HFILE hStdIn  = 0,
          hStdOut = 0,
          hStdErr = 0;
    HFILE hStdInSave  = -1,
          hStdOutSave = -1,
          hStdErrSave = -1;

    proc = PR_NEW(PRProcess);
    if (!proc) {
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
        goto errorExit;
    }
   
    if (assembleCmdLine(argv, &cmdLine) == -1) {
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
        goto errorExit;
    }

#ifdef MOZ_OS2_HIGH_MEMORY
    /*
     * DosQueryAppType() fails if path (the char* in the first argument) is in
     * high memory. If that is the case, the following moves it to low memory.
     */ 
    if ((ULONG)path >= 0x20000000) {
        size_t len = strlen(path) + 1;
        char *copy = (char *)alloca(len);
        memcpy(copy, path, len);
        path = copy;
    }
#endif
   
    if (envp == NULL) {
        newEnvp = NULL;
    } else {
        int i;
        int numEnv = 0;
        while (envp[numEnv]) {
            numEnv++;
        }
        newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *));
        for (i = 0; i <= numEnv; i++) {
            newEnvp[i] = envp[i];
        }
        qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare);
    }
    if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
        goto errorExit;
    }
  
    rc = DosQueryAppType(path, &ulAppType);
    if (rc != NO_ERROR) {
       char *pszDot = strrchr(path, '.');
       if (pszDot) {
          /* If it is a CMD file, launch the users command processor */
          if (!stricmp(pszDot, ".cmd")) {
             rc = DosScanEnv("COMSPEC", (PSZ *)&pszComSpec);
             if (!rc) {
                strcpy(pszFormatString, "/C %s %s");
                strcpy(pszEXEName, pszComSpec);
                ulAppType = FAPPTYP_WINDOWCOMPAT;
             }
          }
       }
    }
    if (ulAppType == 0) {
       PR_SetError(PR_UNKNOWN_ERROR, 0);
       goto errorExit;
    }
 
    if ((ulAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) {
        startData.SessionType = SSF_TYPE_PM;
    }
    else if (ulAppType & FAPPTYP_WINDOWCOMPAT) {
        startData.SessionType = SSF_TYPE_WINDOWABLEVIO;
    }
    else {
        startData.SessionType = SSF_TYPE_DEFAULT;
    }
 
    if (ulAppType & (FAPPTYP_WINDOWSPROT31 | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSREAL))
    {
        strcpy(pszEXEName, "WINOS2.COM");
        startData.SessionType = PROG_31_STDSEAMLESSVDM;
        strcpy(pszFormatString, "/3 %s %s");
    }
 
    startData.InheritOpt = SSF_INHERTOPT_SHELL;
 
    if (pszEXEName[0]) {
        pszFormatResult = PR_MALLOC(strlen(pszFormatString)+strlen(path)+strlen(cmdLine));
        sprintf(pszFormatResult, pszFormatString, path, cmdLine);
        startData.PgmInputs = pszFormatResult;
    } else {
        strcpy(pszEXEName, path);
        startData.PgmInputs = cmdLine;
    }
    startData.PgmName = pszEXEName;
 
    startData.Length = sizeof(startData);
    startData.Related = SSF_RELATED_INDEPENDENT;
    startData.ObjectBuffer = pszObjectBuffer;
    startData.ObjectBuffLen = CCHMAXPATH;
    startData.Environment = envBlock;
 
    if (attr) {
        /* On OS/2, there is really no way to pass file handles for stdin,
         * stdout, and stderr to a new process.  Instead, we can make it
         * a child process and make the given file handles a copy of our
         * stdin, stdout, and stderr.  The child process then inherits
         * ours, and we set ours back.  Twisted and gross I know. If you
         * know a better way, please use it.
         */
        if (attr->stdinFd) {
            hStdIn = 0;
            DosDupHandle(hStdIn, &hStdInSave);
            DosDupHandle((HFILE) attr->stdinFd->secret->md.osfd, &hStdIn);
        }

        if (attr->stdoutFd) {
            hStdOut = 1;
            DosDupHandle(hStdOut, &hStdOutSave);
            DosDupHandle((HFILE) attr->stdoutFd->secret->md.osfd, &hStdOut);
        }

        if (attr->stderrFd) {
            hStdErr = 2;
            DosDupHandle(hStdErr, &hStdErrSave);
            DosDupHandle((HFILE) attr->stderrFd->secret->md.osfd, &hStdErr);
        }
        /*
         * Build up the Command Line for DosExecPgm
         */
        pszCmdLine = PR_MALLOC(strlen(pszEXEName) +
                               strlen(startData.PgmInputs) + 3);
        sprintf(pszCmdLine, "%s%c%s%c", pszEXEName, '\0',
                startData.PgmInputs, '\0');
        rc = DosExecPgm(szFailed,
                        CCHMAXPATH,
                        EXEC_ASYNCRESULT,
                        pszCmdLine,
                        envBlock,
                        &procInfo,
                        pszEXEName);
        PR_DELETE(pszCmdLine);

        /* Restore our old values.  Hope this works */
        if (hStdInSave != -1) {
            DosDupHandle(hStdInSave, &hStdIn);
            DosClose(hStdInSave);
        }

        if (hStdOutSave != -1) {
            DosDupHandle(hStdOutSave, &hStdOut);
            DosClose(hStdOutSave);
        }

        if (hStdErrSave != -1) {
            DosDupHandle(hStdErrSave, &hStdErr);
            DosClose(hStdErrSave);
        }

        if (rc != NO_ERROR) {
            /* XXX what error code? */
            PR_SetError(PR_UNKNOWN_ERROR, rc);
            goto errorExit;
        }

        proc->md.pid = procInfo.codeTerminate;
    } else {	
        /*
         * If no STDIN/STDOUT redirection is not needed, use DosStartSession
         * to create a new, independent session
         */
        rc = DosStartSession(&startData, &ulAppType, &pid);

        if ((rc != NO_ERROR) && (rc != ERROR_SMG_START_IN_BACKGROUND)) {
            PR_SetError(PR_UNKNOWN_ERROR, rc);
            goto errorExit;
        }
 
        proc->md.pid = pid;
    }

    if (pszFormatResult) {
        PR_DELETE(pszFormatResult);
    }

    PR_DELETE(cmdLine);
    if (newEnvp) {
        PR_DELETE(newEnvp);
    }
    if (envBlock) {
        PR_DELETE(envBlock);
    }
    return proc;

errorExit:
    if (cmdLine) {
        PR_DELETE(cmdLine);
    }
    if (newEnvp) {
        PR_DELETE(newEnvp);
    }
    if (envBlock) {
        PR_DELETE(envBlock);
    }
    if (proc) {
        PR_DELETE(proc);
    }
    return NULL;
}  /* _PR_CreateOS2Process */