nsprpub/pr/src/md/os2/os2misc.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7  * os2misc.c
     8  *
     9  */
    11 #ifdef MOZ_OS2_HIGH_MEMORY
    12 /* os2safe.h has to be included before os2.h, needed for high mem */
    13 #include <os2safe.h>
    14 #endif
    16 #include <string.h>
    17 #include "primpl.h"
    19 extern int   _CRT_init(void);
    20 extern void  _CRT_term(void);
    21 extern void __ctordtorInit(int flag);
    22 extern void __ctordtorTerm(int flag);
    24 char *
    25 _PR_MD_GET_ENV(const char *name)
    26 {
    27     return getenv(name);
    28 }
    30 PRIntn
    31 _PR_MD_PUT_ENV(const char *name)
    32 {
    33     return putenv(name);
    34 }
    37 /*
    38  **************************************************************************
    39  **************************************************************************
    40  **
    41  **     Date and time routines
    42  **
    43  **************************************************************************
    44  **************************************************************************
    45  */
    47 #include <sys/timeb.h>
    48 /*
    49  *-----------------------------------------------------------------------
    50  *
    51  * PR_Now --
    52  *
    53  *     Returns the current time in microseconds since the epoch.
    54  *     The epoch is midnight January 1, 1970 GMT.
    55  *     The implementation is machine dependent.  This is the
    56  *     implementation for OS/2.
    57  *     Cf. time_t time(time_t *tp)
    58  *
    59  *-----------------------------------------------------------------------
    60  */
    62 PR_IMPLEMENT(PRTime)
    63 PR_Now(void)
    64 {
    65     PRInt64 s, ms, ms2us, s2us;
    66     struct timeb b;
    68     ftime(&b);
    69     LL_I2L(ms2us, PR_USEC_PER_MSEC);
    70     LL_I2L(s2us, PR_USEC_PER_SEC);
    71     LL_I2L(s, b.time);
    72     LL_I2L(ms, b.millitm);
    73     LL_MUL(ms, ms, ms2us);
    74     LL_MUL(s, s, s2us);
    75     LL_ADD(s, s, ms);
    76     return s;       
    77 }
    80 /*
    81  ***********************************************************************
    82  ***********************************************************************
    83  *
    84  * Process creation routines
    85  *
    86  ***********************************************************************
    87  ***********************************************************************
    88  */
    90 /*
    91  * Assemble the command line by concatenating the argv array.
    92  * Special characters intentionally do not get escaped, and it is
    93  * expected that the caller wraps arguments in quotes if needed
    94  * (e.g. for filename with spaces).
    95  *
    96  * On success, this function returns 0 and the resulting command
    97  * line is returned in *cmdLine.  On failure, it returns -1.
    98  */
    99 static int assembleCmdLine(char *const *argv, char **cmdLine)
   100 {
   101     char *const *arg;
   102     int cmdLineSize;
   104     /*
   105      * Find out how large the command line buffer should be.
   106      */
   107     cmdLineSize = 1; /* final null */
   108     for (arg = argv+1; *arg; arg++) {
   109         cmdLineSize += strlen(*arg) + 1; /* space in between */
   110     }
   111     *cmdLine = PR_MALLOC(cmdLineSize);
   112     if (*cmdLine == NULL) {
   113         return -1;
   114     }
   116     (*cmdLine)[0] = '\0';
   118     for (arg = argv+1; *arg; arg++) {
   119         if (arg > argv +1) {
   120             strcat(*cmdLine, " ");
   121         }
   122         strcat(*cmdLine, *arg);
   123     } 
   124     return 0;
   125 }
   127 /*
   128  * Assemble the environment block by concatenating the envp array
   129  * (preserving the terminating null byte in each array element)
   130  * and adding a null byte at the end.
   131  *
   132  * Returns 0 on success.  The resulting environment block is returned
   133  * in *envBlock.  Note that if envp is NULL, a NULL pointer is returned
   134  * in *envBlock.  Returns -1 on failure.
   135  */
   136 static int assembleEnvBlock(char **envp, char **envBlock)
   137 {
   138     char *p;
   139     char *q;
   140     char **env;
   141     char *curEnv;
   142     char *cwdStart, *cwdEnd;
   143     int envBlockSize;
   145     PPIB ppib = NULL;
   146     PTIB ptib = NULL;
   148     if (envp == NULL) {
   149         *envBlock = NULL;
   150         return 0;
   151     }
   153     if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR)
   154        return -1;
   156     curEnv = ppib->pib_pchenv;
   158     cwdStart = curEnv;
   159     while (*cwdStart) {
   160         if (cwdStart[0] == '=' && cwdStart[1] != '\0'
   161                 && cwdStart[2] == ':' && cwdStart[3] == '=') {
   162             break;
   163         }
   164         cwdStart += strlen(cwdStart) + 1;
   165     }
   166     cwdEnd = cwdStart;
   167     if (*cwdEnd) {
   168         cwdEnd += strlen(cwdEnd) + 1;
   169         while (*cwdEnd) {
   170             if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
   171                     || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
   172                 break;
   173             }
   174             cwdEnd += strlen(cwdEnd) + 1;
   175         }
   176     }
   177     envBlockSize = cwdEnd - cwdStart;
   179     for (env = envp; *env; env++) {
   180         envBlockSize += strlen(*env) + 1;
   181     }
   182     envBlockSize++;
   184     p = *envBlock = PR_MALLOC(envBlockSize);
   185     if (p == NULL) {
   186         return -1;
   187     }
   189     q = cwdStart;
   190     while (q < cwdEnd) {
   191         *p++ = *q++;
   192     }
   194     for (env = envp; *env; env++) {
   195         q = *env;
   196         while (*q) {
   197             *p++ = *q++;
   198         }
   199         *p++ = '\0';
   200     }
   201     *p = '\0';
   202     return 0;
   203 }
   205 /*
   206  * For qsort.  We sort (case-insensitive) the environment strings
   207  * before generating the environment block.
   208  */
   209 static int compare(const void *arg1, const void *arg2)
   210 {
   211     return stricmp(* (char**)arg1, * (char**)arg2);
   212 }
   214 PRProcess * _PR_CreateOS2Process(
   215     const char *path,
   216     char *const *argv,
   217     char *const *envp,
   218     const PRProcessAttr *attr)
   219 {
   220     PRProcess *proc = NULL;
   221     char *cmdLine = NULL;
   222     char **newEnvp = NULL;
   223     char *envBlock = NULL;
   225     STARTDATA startData = {0};
   226     APIRET    rc;
   227     ULONG     ulAppType = 0;
   228     PID       pid = 0;
   229     char     *pszComSpec;
   230     char      pszEXEName[CCHMAXPATH] = "";
   231     char      pszFormatString[CCHMAXPATH];
   232     char      pszObjectBuffer[CCHMAXPATH];
   233     char     *pszFormatResult = NULL;
   235     /*
   236      * Variables for DosExecPgm
   237      */
   238     char szFailed[CCHMAXPATH];
   239     char *pszCmdLine = NULL;
   240     RESULTCODES procInfo;
   241     HFILE hStdIn  = 0,
   242           hStdOut = 0,
   243           hStdErr = 0;
   244     HFILE hStdInSave  = -1,
   245           hStdOutSave = -1,
   246           hStdErrSave = -1;
   248     proc = PR_NEW(PRProcess);
   249     if (!proc) {
   250         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   251         goto errorExit;
   252     }
   254     if (assembleCmdLine(argv, &cmdLine) == -1) {
   255         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   256         goto errorExit;
   257     }
   259 #ifdef MOZ_OS2_HIGH_MEMORY
   260     /*
   261      * DosQueryAppType() fails if path (the char* in the first argument) is in
   262      * high memory. If that is the case, the following moves it to low memory.
   263      */ 
   264     if ((ULONG)path >= 0x20000000) {
   265         size_t len = strlen(path) + 1;
   266         char *copy = (char *)alloca(len);
   267         memcpy(copy, path, len);
   268         path = copy;
   269     }
   270 #endif
   272     if (envp == NULL) {
   273         newEnvp = NULL;
   274     } else {
   275         int i;
   276         int numEnv = 0;
   277         while (envp[numEnv]) {
   278             numEnv++;
   279         }
   280         newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *));
   281         for (i = 0; i <= numEnv; i++) {
   282             newEnvp[i] = envp[i];
   283         }
   284         qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare);
   285     }
   286     if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
   287         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   288         goto errorExit;
   289     }
   291     rc = DosQueryAppType(path, &ulAppType);
   292     if (rc != NO_ERROR) {
   293        char *pszDot = strrchr(path, '.');
   294        if (pszDot) {
   295           /* If it is a CMD file, launch the users command processor */
   296           if (!stricmp(pszDot, ".cmd")) {
   297              rc = DosScanEnv("COMSPEC", (PSZ *)&pszComSpec);
   298              if (!rc) {
   299                 strcpy(pszFormatString, "/C %s %s");
   300                 strcpy(pszEXEName, pszComSpec);
   301                 ulAppType = FAPPTYP_WINDOWCOMPAT;
   302              }
   303           }
   304        }
   305     }
   306     if (ulAppType == 0) {
   307        PR_SetError(PR_UNKNOWN_ERROR, 0);
   308        goto errorExit;
   309     }
   311     if ((ulAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) {
   312         startData.SessionType = SSF_TYPE_PM;
   313     }
   314     else if (ulAppType & FAPPTYP_WINDOWCOMPAT) {
   315         startData.SessionType = SSF_TYPE_WINDOWABLEVIO;
   316     }
   317     else {
   318         startData.SessionType = SSF_TYPE_DEFAULT;
   319     }
   321     if (ulAppType & (FAPPTYP_WINDOWSPROT31 | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSREAL))
   322     {
   323         strcpy(pszEXEName, "WINOS2.COM");
   324         startData.SessionType = PROG_31_STDSEAMLESSVDM;
   325         strcpy(pszFormatString, "/3 %s %s");
   326     }
   328     startData.InheritOpt = SSF_INHERTOPT_SHELL;
   330     if (pszEXEName[0]) {
   331         pszFormatResult = PR_MALLOC(strlen(pszFormatString)+strlen(path)+strlen(cmdLine));
   332         sprintf(pszFormatResult, pszFormatString, path, cmdLine);
   333         startData.PgmInputs = pszFormatResult;
   334     } else {
   335         strcpy(pszEXEName, path);
   336         startData.PgmInputs = cmdLine;
   337     }
   338     startData.PgmName = pszEXEName;
   340     startData.Length = sizeof(startData);
   341     startData.Related = SSF_RELATED_INDEPENDENT;
   342     startData.ObjectBuffer = pszObjectBuffer;
   343     startData.ObjectBuffLen = CCHMAXPATH;
   344     startData.Environment = envBlock;
   346     if (attr) {
   347         /* On OS/2, there is really no way to pass file handles for stdin,
   348          * stdout, and stderr to a new process.  Instead, we can make it
   349          * a child process and make the given file handles a copy of our
   350          * stdin, stdout, and stderr.  The child process then inherits
   351          * ours, and we set ours back.  Twisted and gross I know. If you
   352          * know a better way, please use it.
   353          */
   354         if (attr->stdinFd) {
   355             hStdIn = 0;
   356             DosDupHandle(hStdIn, &hStdInSave);
   357             DosDupHandle((HFILE) attr->stdinFd->secret->md.osfd, &hStdIn);
   358         }
   360         if (attr->stdoutFd) {
   361             hStdOut = 1;
   362             DosDupHandle(hStdOut, &hStdOutSave);
   363             DosDupHandle((HFILE) attr->stdoutFd->secret->md.osfd, &hStdOut);
   364         }
   366         if (attr->stderrFd) {
   367             hStdErr = 2;
   368             DosDupHandle(hStdErr, &hStdErrSave);
   369             DosDupHandle((HFILE) attr->stderrFd->secret->md.osfd, &hStdErr);
   370         }
   371         /*
   372          * Build up the Command Line for DosExecPgm
   373          */
   374         pszCmdLine = PR_MALLOC(strlen(pszEXEName) +
   375                                strlen(startData.PgmInputs) + 3);
   376         sprintf(pszCmdLine, "%s%c%s%c", pszEXEName, '\0',
   377                 startData.PgmInputs, '\0');
   378         rc = DosExecPgm(szFailed,
   379                         CCHMAXPATH,
   380                         EXEC_ASYNCRESULT,
   381                         pszCmdLine,
   382                         envBlock,
   383                         &procInfo,
   384                         pszEXEName);
   385         PR_DELETE(pszCmdLine);
   387         /* Restore our old values.  Hope this works */
   388         if (hStdInSave != -1) {
   389             DosDupHandle(hStdInSave, &hStdIn);
   390             DosClose(hStdInSave);
   391         }
   393         if (hStdOutSave != -1) {
   394             DosDupHandle(hStdOutSave, &hStdOut);
   395             DosClose(hStdOutSave);
   396         }
   398         if (hStdErrSave != -1) {
   399             DosDupHandle(hStdErrSave, &hStdErr);
   400             DosClose(hStdErrSave);
   401         }
   403         if (rc != NO_ERROR) {
   404             /* XXX what error code? */
   405             PR_SetError(PR_UNKNOWN_ERROR, rc);
   406             goto errorExit;
   407         }
   409         proc->md.pid = procInfo.codeTerminate;
   410     } else {	
   411         /*
   412          * If no STDIN/STDOUT redirection is not needed, use DosStartSession
   413          * to create a new, independent session
   414          */
   415         rc = DosStartSession(&startData, &ulAppType, &pid);
   417         if ((rc != NO_ERROR) && (rc != ERROR_SMG_START_IN_BACKGROUND)) {
   418             PR_SetError(PR_UNKNOWN_ERROR, rc);
   419             goto errorExit;
   420         }
   422         proc->md.pid = pid;
   423     }
   425     if (pszFormatResult) {
   426         PR_DELETE(pszFormatResult);
   427     }
   429     PR_DELETE(cmdLine);
   430     if (newEnvp) {
   431         PR_DELETE(newEnvp);
   432     }
   433     if (envBlock) {
   434         PR_DELETE(envBlock);
   435     }
   436     return proc;
   438 errorExit:
   439     if (cmdLine) {
   440         PR_DELETE(cmdLine);
   441     }
   442     if (newEnvp) {
   443         PR_DELETE(newEnvp);
   444     }
   445     if (envBlock) {
   446         PR_DELETE(envBlock);
   447     }
   448     if (proc) {
   449         PR_DELETE(proc);
   450     }
   451     return NULL;
   452 }  /* _PR_CreateOS2Process */
   454 PRStatus _PR_DetachOS2Process(PRProcess *process)
   455 {
   456     /* On OS/2, a process is either created as a child or not. 
   457      * You can't 'detach' it later on.
   458      */
   459     PR_DELETE(process);
   460     return PR_SUCCESS;
   461 }
   463 /*
   464  * XXX: This will currently only work on a child process.
   465  */
   466 PRStatus _PR_WaitOS2Process(PRProcess *process,
   467     PRInt32 *exitCode)
   468 {
   469     ULONG ulRetVal;
   470     RESULTCODES results;
   471     PID pidEnded = 0;
   473     ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, 
   474                             &results,
   475                             &pidEnded, process->md.pid);
   477     if (ulRetVal != NO_ERROR) {
   478        printf("\nDosWaitChild rc = %lu\n", ulRetVal);
   479         PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
   480         return PR_FAILURE;
   481     }
   482     PR_DELETE(process);
   483     return PR_SUCCESS;
   484 }
   486 PRStatus _PR_KillOS2Process(PRProcess *process)
   487 {
   488    ULONG ulRetVal;
   489     if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) {
   490 	return PR_SUCCESS;
   491     }
   492     PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
   493     return PR_FAILURE;
   494 }
   496 PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen)
   497 {
   498     PRIntn rv;
   500     rv = gethostname(name, (PRInt32) namelen);
   501     if (0 == rv) {
   502         return PR_SUCCESS;
   503     }
   504 	_PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno());
   505     return PR_FAILURE;
   506 }
   508 void
   509 _PR_MD_WAKEUP_CPUS( void )
   510 {
   511     return;
   512 }    
   514 /*
   515  **********************************************************************
   516  *
   517  * Memory-mapped files
   518  *
   519  * A credible emulation of memory-mapped i/o on OS/2 would require
   520  * an exception-handler on each thread that might access the mapped
   521  * memory.  In the Mozilla environment, that would be impractical.
   522  * Instead, the following simulates those modes which don't modify
   523  * the mapped file.  It reads the entire mapped file segment at once
   524  * when MemMap is called, and frees it on MemUnmap.  CreateFileMap
   525  * only does sanity-checks, while CloseFileMap does almost nothing.
   526  *
   527  **********************************************************************
   528  */
   530 PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
   531 {
   532     PRFileInfo64 info;
   534     /* assert on PR_PROT_READWRITE which modifies the underlying file */
   535     PR_ASSERT(fmap->prot == PR_PROT_READONLY ||
   536               fmap->prot == PR_PROT_WRITECOPY);
   537     if (fmap->prot != PR_PROT_READONLY &&
   538         fmap->prot != PR_PROT_WRITECOPY) {
   539         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   540         return PR_FAILURE;
   541     }
   542     if (PR_GetOpenFileInfo64(fmap->fd, &info) == PR_FAILURE) {
   543         return PR_FAILURE;
   544     }
   545     /* reject zero-byte mappings & zero-byte files */
   546     if (!size || !info.size) {
   547         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   548         return PR_FAILURE;
   549     }
   550     /* file size rounded up to the next page boundary */
   551     fmap->md.maxExtent = (info.size + 0xfff) & ~(0xfff);
   553     return PR_SUCCESS;
   554 }
   556 PRInt32 _MD_GetMemMapAlignment(void)
   557 {
   558     /* OS/2 pages are 4k */
   559     return 0x1000;
   560 }
   562 void * _MD_MemMap(PRFileMap *fmap, PROffset64 offset, PRUint32 len)
   563 {
   564     PRUint32 rv;
   565     void *addr;
   567     /* prevent mappings beyond EOF + remainder of page */
   568     if (offset + len > fmap->md.maxExtent) {
   569         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   570         return NULL;
   571     }
   572     if (PR_Seek64(fmap->fd, offset, PR_SEEK_SET) == -1) {
   573         return NULL;
   574     }
   575     /* try for high memory, fall back to low memory if hi-mem fails */
   576     rv = DosAllocMem(&addr, len, OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE);
   577     if (rv) {
   578         rv = DosAllocMem(&addr, len, PAG_COMMIT | PAG_READ | PAG_WRITE);
   579         if (rv) {
   580             PR_SetError(PR_OUT_OF_MEMORY_ERROR, rv);
   581             return NULL;
   582         }
   583     }
   584     if (PR_Read(fmap->fd, addr, len) == -1) {
   585         DosFreeMem(addr);
   586         return NULL;
   587     }
   588     /* don't permit writes if readonly */
   589     if (fmap->prot == PR_PROT_READONLY) {
   590         rv = DosSetMem(addr, len, PAG_READ);
   591         if (rv) {
   592             DosFreeMem(addr);
   593             PR_SetError(PR_UNKNOWN_ERROR, rv);
   594             return NULL;
   595         }
   596     }
   597     return addr;
   598 }
   600 PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
   601 {
   602     PRUint32 rv;
   604     /* we just have to trust that addr & len are those used by MemMap */
   605     rv = DosFreeMem(addr);
   606     if (rv) {
   607         PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv);
   608         return PR_FAILURE;
   609     }
   610     return PR_SUCCESS;
   611 }
   613 PRStatus _MD_CloseFileMap(PRFileMap *fmap)
   614 {
   615     /* nothing to do except free the PRFileMap struct */
   616     PR_Free(fmap);
   617     return PR_SUCCESS;
   618 }

mercurial