summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c666
1 files changed, 666 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c
new file mode 100644
index 00000000..9ea8df74
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c
@@ -0,0 +1,666 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * os2misc.c
+ *
+ */
+#include <string.h>
+#include "primpl.h"
+
+extern int _CRT_init(void);
+extern void _CRT_term(void);
+extern void __ctordtorInit(int flag);
+extern void __ctordtorTerm(int flag);
+
+char *
+_PR_MD_GET_ENV(const char *name)
+{
+ return getenv(name);
+}
+
+PRIntn
+_PR_MD_PUT_ENV(const char *name)
+{
+ return putenv(name);
+}
+
+
+/* see assembleEnvBlock() below */
+#define USE_DOSALLOCMEM
+
+
+/*
+ **************************************************************************
+ **************************************************************************
+ **
+ ** Date and time routines
+ **
+ **************************************************************************
+ **************************************************************************
+ */
+
+#include <sys/timeb.h>
+/*
+ *-----------------------------------------------------------------------
+ *
+ * PR_Now --
+ *
+ * Returns the current time in microseconds since the epoch.
+ * The epoch is midnight January 1, 1970 GMT.
+ * The implementation is machine dependent. This is the
+ * implementation for OS/2.
+ * Cf. time_t time(time_t *tp)
+ *
+ *-----------------------------------------------------------------------
+ */
+
+PR_IMPLEMENT(PRTime)
+PR_Now(void)
+{
+ PRInt64 s, ms, ms2us, s2us;
+ struct timeb b;
+
+ ftime(&b);
+ LL_I2L(ms2us, PR_USEC_PER_MSEC);
+ LL_I2L(s2us, PR_USEC_PER_SEC);
+ LL_I2L(s, b.time);
+ LL_I2L(ms, b.millitm);
+ LL_MUL(ms, ms, ms2us);
+ LL_MUL(s, s, s2us);
+ LL_ADD(s, s, ms);
+ return s;
+}
+
+
+/*
+ ***********************************************************************
+ ***********************************************************************
+ *
+ * Process creation routines
+ *
+ ***********************************************************************
+ ***********************************************************************
+ */
+
+/*
+ * Assemble the command line by concatenating the argv array.
+ * On success, this function returns 0 and the resulting command
+ * line is returned in *cmdLine. On failure, it returns -1.
+ */
+static int assembleCmdLine(char *const *argv, char **cmdLine)
+{
+ char *const *arg;
+ int cmdLineSize;
+
+ /*
+ * Find out how large the command line buffer should be.
+ */
+ cmdLineSize = 1; /* final null */
+ for (arg = argv+1; *arg; arg++) {
+ cmdLineSize += strlen(*arg) + 1; /* space in between */
+ }
+ *cmdLine = PR_MALLOC(cmdLineSize);
+ if (*cmdLine == NULL) {
+ return -1;
+ }
+
+ (*cmdLine)[0] = '\0';
+
+ for (arg = argv+1; *arg; arg++) {
+ if (arg > argv +1) {
+ strcat(*cmdLine, " ");
+ }
+ strcat(*cmdLine, *arg);
+ }
+ return 0;
+}
+
+/*
+ * Assemble the environment block by concatenating the envp array
+ * (preserving the terminating null byte in each array element)
+ * and adding a null byte at the end.
+ *
+ * Returns 0 on success. The resulting environment block is returned
+ * in *envBlock. Note that if envp is NULL, a NULL pointer is returned
+ * in *envBlock. Returns -1 on failure.
+ */
+static int assembleEnvBlock(char **envp, char **envBlock)
+{
+ char *p;
+ char *q;
+ char **env;
+ char *curEnv;
+ char *cwdStart, *cwdEnd;
+ int envBlockSize;
+
+ PPIB ppib = NULL;
+ PTIB ptib = NULL;
+
+ if (envp == NULL) {
+ *envBlock = NULL;
+ return 0;
+ }
+
+ if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR)
+ return -1;
+
+ curEnv = ppib->pib_pchenv;
+
+ cwdStart = curEnv;
+ while (*cwdStart) {
+ if (cwdStart[0] == '=' && cwdStart[1] != '\0'
+ && cwdStart[2] == ':' && cwdStart[3] == '=') {
+ break;
+ }
+ cwdStart += strlen(cwdStart) + 1;
+ }
+ cwdEnd = cwdStart;
+ if (*cwdEnd) {
+ cwdEnd += strlen(cwdEnd) + 1;
+ while (*cwdEnd) {
+ if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
+ || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
+ break;
+ }
+ cwdEnd += strlen(cwdEnd) + 1;
+ }
+ }
+ envBlockSize = cwdEnd - cwdStart;
+
+ for (env = envp; *env; env++) {
+ envBlockSize += strlen(*env) + 1;
+ }
+ envBlockSize++;
+
+ /* It seems that the Environment parameter of DosStartSession() and/or
+ * DosExecPgm() wants a memory block that is completely within the 64K
+ * memory object; otherwise we will get the environment truncated on the
+ * 64K boundary in the child process. PR_MALLOC() cannot guarantee this,
+ * so use DosAllocMem directly. */
+#ifdef USE_DOSALLOCMEM
+ DosAllocMem((PPVOID) envBlock, envBlockSize, PAG_COMMIT | PAG_READ | PAG_WRITE);
+ p = *envBlock;
+#else
+ p = *envBlock = PR_MALLOC(envBlockSize);
+#endif
+ if (p == NULL) {
+ return -1;
+ }
+
+ q = cwdStart;
+ while (q < cwdEnd) {
+ *p++ = *q++;
+ }
+
+ for (env = envp; *env; env++) {
+ q = *env;
+ while (*q) {
+ *p++ = *q++;
+ }
+ *p++ = '\0';
+ }
+ *p = '\0';
+ return 0;
+}
+
+/*
+ * For qsort. We sort (case-insensitive) the environment strings
+ * before generating the environment block.
+ */
+static int compare(const void *arg1, const void *arg2)
+{
+ return stricmp(* (char**)arg1, * (char**)arg2);
+}
+
+/*
+ * On OS/2, a process can be detached only when it is started -- you cannot
+ * make it detached afterwards. This is why _PR_CreateOS2ProcessEx() is
+ * necessary. This function is called directly from
+ * PR_CreateProcessDetached(). */
+PRProcess * _PR_CreateOS2ProcessEx(
+ const char *path,
+ char *const *argv,
+ char *const *envp,
+ const PRProcessAttr *attr,
+ PRBool detached)
+{
+ PRProcess *proc = NULL;
+ char *cmdLine = NULL;
+ char **newEnvp = NULL;
+ char *envBlock = NULL;
+
+ APIRET rc;
+ ULONG ulAppType = 0;
+ PID pid = 0;
+ char *pEnvWPS = NULL;
+ char *pszComSpec;
+ char pszEXEName[CCHMAXPATH] = "";
+ char pszFormatString[CCHMAXPATH];
+ char pszObjectBuffer[CCHMAXPATH];
+ char *pszFormatResult = NULL;
+ char *pszArg0 = NULL;
+
+ 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;
+ }
+
+ /* the 0th argument to the program (by convention, the program name, as
+ * entered by user) */
+ pszArg0 = argv[0];
+
+ /*
+ * If attr->fdInheritBuffer is not NULL, we need to insert
+ * it into the envp array, so envp cannot be NULL.
+ */
+ if (envp == NULL && attr && attr->fdInheritBuffer) {
+ envp = environ;
+ }
+
+ if (envp != NULL) {
+ int idx;
+ int numEnv;
+ int newEnvpSize;
+
+ numEnv = 0;
+ while (envp[numEnv]) {
+ numEnv++;
+ }
+ newEnvpSize = numEnv + 1; /* terminating null pointer */
+ if (attr && attr->fdInheritBuffer) {
+ newEnvpSize++;
+ }
+ newEnvp = (char **) PR_MALLOC(newEnvpSize * sizeof(char *));
+ for (idx = 0; idx < numEnv; idx++) {
+ newEnvp[idx] = envp[idx];
+ }
+ if (attr && attr->fdInheritBuffer) {
+ newEnvp[idx++] = attr->fdInheritBuffer;
+ }
+ newEnvp[idx] = NULL;
+ qsort((void *) newEnvp, (size_t) (newEnvpSize - 1),
+ sizeof(char *), compare);
+ }
+ if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ goto errorExit;
+ }
+
+ if (attr) {
+ if (attr->stdinFd || attr->stdoutFd || attr->stderrFd)
+ PR_ASSERT(!"Stdin/stdout redirection is not implemented");
+ if (attr->currentDirectory)
+ PR_ASSERT(!"Setting current directory is not implemented");
+ }
+
+ 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", &pszComSpec);
+ if (!rc) {
+ strcpy(pszFormatString, "/C %s %s");
+ strcpy(pszEXEName, pszComSpec);
+ pszArg0 = pszEXEName;
+ ulAppType = FAPPTYP_WINDOWCOMPAT;
+ }
+ }
+ }
+ }
+ if (ulAppType == 0) {
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ goto errorExit;
+ }
+
+ /* We don't want to use DosExecPgm for detached processes because
+ * they won't have stdin/stderr/stdout by default which will hang up
+ * the child process if it tries to write/read from there. Instead,
+ * we will detach console processes by starting them using the PM session
+ * (yes, it requires PM, but the whole XPCOM does so too).
+ */
+#if 0
+ if (detached) {
+ /* we don't care about parent/child process type matching,
+ * DosExecPgm() should complain if there is a mismatch. */
+
+ size_t cbArg0 = strlen(pszArg0);
+ char *pszArgs = NULL;
+
+ if (pszEXEName[0]) {
+ pszFormatResult = PR_MALLOC(cbArg0 + 1 +
+ strlen(pszFormatString) +
+ strlen(path) + strlen(cmdLine) + 1 + 1);
+ if (!pszFormatResult) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ goto errorExit;
+ }
+ pszArgs = pszFormatResult + cbArg0 + 1;
+ sprintf(pszArgs, pszFormatString, path, cmdLine);
+ } else {
+ strcpy(pszEXEName, path);
+ pszFormatResult = PR_MALLOC(cbArg0 + 1 +
+ strlen(cmdLine) + 1 + 1);
+ if (!pszFormatResult) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ goto errorExit;
+ }
+ pszArgs = pszFormatResult + cbArg0 + 1;
+ strcpy(pszArgs, cmdLine);
+ }
+
+ strcpy(pszFormatResult, pszArg0);
+ /* add final NULL */
+ pszArgs[strlen(pszArgs) + 1] = '\0';
+
+ RESULTCODES res = {0};
+ rc = DosExecPgm(pszObjectBuffer, CCHMAXPATH, EXEC_BACKGROUND,
+ pszFormatResult, envBlock, &res, pszEXEName);
+
+ if (rc != NO_ERROR) {
+ PR_SetError(PR_UNKNOWN_ERROR, rc);
+ goto errorExit;
+ }
+
+ /* use 0 to indicate the detached process in the internal
+ * process structure (I believe no process may have pid of 0) */
+ proc->md.pid = 0 /* res.codeTerminate */;
+ }
+ else
+#endif
+ {
+ STARTDATA startData = {0};
+
+ if ((ulAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) {
+ startData.SessionType = SSF_TYPE_PM;
+ }
+ else if (ulAppType & FAPPTYP_WINDOWCOMPAT) {
+ startData.SessionType = detached ? SSF_TYPE_PM
+ : SSF_TYPE_WINDOWABLEVIO;
+ }
+ else if (ulAppType & FAPPTYP_NOTWINDOWCOMPAT) {
+ startData.SessionType = detached ? SSF_TYPE_PM
+ : SSF_TYPE_DEFAULT;
+ }
+ 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_PARENT;
+
+ 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.Related = detached ? SSF_RELATED_INDEPENDENT : SSF_RELATED_CHILD;
+
+ startData.Length = sizeof(startData);
+ startData.ObjectBuffer = pszObjectBuffer;
+ startData.ObjectBuffLen = CCHMAXPATH;
+ startData.Environment = envBlock;
+
+ rc = DosStartSession(&startData, &ulAppType, &pid);
+
+ if ((rc != NO_ERROR) && (rc != ERROR_SMG_START_IN_BACKGROUND)) {
+ PR_SetError(PR_UNKNOWN_ERROR, rc);
+ goto errorExit;
+ }
+
+ /* if Related is SSF_RELATED_INDEPENDENT, we don't get pid of the started
+ * process and use 0 to indicate the detached process in the internal
+ * process structure (I believe no process may have pid of 0).
+ */
+ proc->md.pid = detached ? 0 : pid;
+ }
+
+ if (pszFormatResult) {
+ PR_DELETE(pszFormatResult);
+ }
+ if (cmdLine) {
+ PR_DELETE(cmdLine);
+ }
+ if (newEnvp) {
+ PR_DELETE(newEnvp);
+ }
+ if (envBlock) {
+#ifdef USE_DOSALLOCMEM
+ DosFreeMem(envBlock);
+#else
+ PR_DELETE(envBlock);
+#endif
+ }
+ return proc;
+
+errorExit:
+ if (pszFormatResult) {
+ PR_DELETE(pszFormatResult);
+ }
+ if (cmdLine) {
+ PR_DELETE(cmdLine);
+ }
+ if (newEnvp) {
+ PR_DELETE(newEnvp);
+ }
+ if (envBlock) {
+#ifdef USE_DOSALLOCMEM
+ DosFreeMem(envBlock);
+#else
+ PR_DELETE(envBlock);
+#endif
+ }
+ if (proc) {
+ PR_DELETE(proc);
+ }
+ return NULL;
+} /* _PR_CreateOS2ProcessEx */
+
+PRProcess * _PR_CreateOS2Process(
+ const char *path,
+ char *const *argv,
+ char *const *envp,
+ const PRProcessAttr *attr)
+{
+ return _PR_CreateOS2ProcessEx(path, argv, envp, attr, PR_FALSE);
+}
+
+PRStatus _PR_DetachOS2Process(PRProcess *process)
+{
+ /* On OS/2, a process is either created as a child or not.
+ * You can't 'detach' it later on.
+ */
+ if (process->md.pid == 0) {
+ /* this is a detached process, just free memory */
+ PR_DELETE(process);
+ return PR_SUCCESS;
+ }
+ /* For a normal child process, we can't complete the request. Note that
+ * terminating the parent process w/o calling PR_WaitProcess() on the
+ * child will terminate the child as well (since it is not detached).
+ */
+ PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+/*
+ * XXX: This will currently only work on a child process.
+ */
+PRStatus _PR_WaitOS2Process(PRProcess *process,
+ PRInt32 *exitCode)
+{
+ ULONG ulRetVal;
+ RESULTCODES results;
+ PID pidEnded = 0;
+
+ ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT,
+ &results,
+ &pidEnded, process->md.pid);
+
+ if (ulRetVal != NO_ERROR) {
+ printf("\nDosWaitChild rc = %lu\n", ulRetVal);
+ PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
+ return PR_FAILURE;
+ }
+ PR_DELETE(process);
+ return PR_SUCCESS;
+}
+
+PRStatus _PR_KillOS2Process(PRProcess *process)
+{
+ ULONG ulRetVal;
+ if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) {
+ return PR_SUCCESS;
+ }
+ PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
+ return PR_FAILURE;
+}
+
+PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen)
+{
+ PRIntn rv;
+
+ rv = gethostname(name, (PRInt32) namelen);
+ if (0 == rv) {
+ return PR_SUCCESS;
+ }
+ _PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno());
+ return PR_FAILURE;
+}
+
+void
+_PR_MD_WAKEUP_CPUS( void )
+{
+ return;
+}
+
+
+/*
+ **********************************************************************
+ *
+ * Memory-mapped files are not supported on OS/2 (or Win16).
+ *
+ **********************************************************************
+ */
+
+PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+PRInt32 _MD_GetMemMapAlignment(void)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return -1;
+}
+
+void * _MD_MemMap(
+ PRFileMap *fmap,
+ PROffset64 offset,
+ PRUint32 len)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return NULL;
+}
+
+PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+PRStatus _MD_CloseFileMap(PRFileMap *fmap)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+/*
+ * Automatically set apptype switch for interactive and other
+ * tests that create an invisible plevent window.
+ */
+unsigned long _System _DLL_InitTerm( unsigned long mod_handle, unsigned long flag)
+{
+ unsigned long rc = 0; /* failure */
+
+ if( !flag)
+ {
+ /* init */
+ if( _CRT_init() == 0)
+ {
+ PPIB pPib;
+ PTIB pTib;
+
+ /* probably superfluous, but can't hurt */
+ __ctordtorInit(0);
+
+ DosGetInfoBlocks( &pTib, &pPib);
+ pPib->pib_ultype = 3; /* PM */
+
+ rc = 1;
+ }
+ }
+ else
+ {
+ __ctordtorTerm(0);
+ _CRT_term();
+ rc = 1;
+ }
+
+ return rc;
+}
+