// 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; }
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 */