Back to index

lightning-sunbird  0.9+nobinonly
os2misc.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Davide Bresolin <davide@teamos2.it>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040  * os2misc.c
00041  *
00042  */
00043 #include <string.h>
00044 #include "primpl.h"
00045 
00046 extern int   _CRT_init(void);
00047 extern void  _CRT_term(void);
00048 extern void __ctordtorInit(int flag);
00049 extern void __ctordtorTerm(int flag);
00050 
00051 char *
00052 _PR_MD_GET_ENV(const char *name)
00053 {
00054     return getenv(name);
00055 }
00056 
00057 PRIntn
00058 _PR_MD_PUT_ENV(const char *name)
00059 {
00060     return putenv(name);
00061 }
00062 
00063 
00064 /*
00065  **************************************************************************
00066  **************************************************************************
00067  **
00068  **     Date and time routines
00069  **
00070  **************************************************************************
00071  **************************************************************************
00072  */
00073 
00074 #include <sys/timeb.h>
00075 /*
00076  *-----------------------------------------------------------------------
00077  *
00078  * PR_Now --
00079  *
00080  *     Returns the current time in microseconds since the epoch.
00081  *     The epoch is midnight January 1, 1970 GMT.
00082  *     The implementation is machine dependent.  This is the
00083  *     implementation for OS/2.
00084  *     Cf. time_t time(time_t *tp)
00085  *
00086  *-----------------------------------------------------------------------
00087  */
00088 
00089 PR_IMPLEMENT(PRTime)
00090 PR_Now(void)
00091 {
00092     PRInt64 s, ms, ms2us, s2us;
00093     struct timeb b;
00094 
00095     ftime(&b);
00096     LL_I2L(ms2us, PR_USEC_PER_MSEC);
00097     LL_I2L(s2us, PR_USEC_PER_SEC);
00098     LL_I2L(s, b.time);
00099     LL_I2L(ms, b.millitm);
00100     LL_MUL(ms, ms, ms2us);
00101     LL_MUL(s, s, s2us);
00102     LL_ADD(s, s, ms);
00103     return s;       
00104 }
00105 
00106 
00107 /*
00108  ***********************************************************************
00109  ***********************************************************************
00110  *
00111  * Process creation routines
00112  *
00113  ***********************************************************************
00114  ***********************************************************************
00115  */
00116 
00117 /*
00118  * Assemble the command line by concatenating the argv array.
00119  * On success, this function returns 0 and the resulting command
00120  * line is returned in *cmdLine.  On failure, it returns -1.
00121  */
00122 static int assembleCmdLine(char *const *argv, char **cmdLine)
00123 {
00124     char *const *arg;
00125     int cmdLineSize;
00126 
00127     /*
00128      * Find out how large the command line buffer should be.
00129      */
00130     cmdLineSize = 1; /* final null */
00131     for (arg = argv+1; *arg; arg++) {
00132         cmdLineSize += strlen(*arg) + 1; /* space in between */
00133     }
00134     *cmdLine = PR_MALLOC(cmdLineSize);
00135     if (*cmdLine == NULL) {
00136         return -1;
00137     }
00138 
00139     (*cmdLine)[0] = '\0';
00140 
00141     for (arg = argv+1; *arg; arg++) {
00142         if (arg > argv +1) {
00143             strcat(*cmdLine, " ");
00144         }
00145         strcat(*cmdLine, *arg);
00146     } 
00147     return 0;
00148 }
00149 
00150 /*
00151  * Assemble the environment block by concatenating the envp array
00152  * (preserving the terminating null byte in each array element)
00153  * and adding a null byte at the end.
00154  *
00155  * Returns 0 on success.  The resulting environment block is returned
00156  * in *envBlock.  Note that if envp is NULL, a NULL pointer is returned
00157  * in *envBlock.  Returns -1 on failure.
00158  */
00159 static int assembleEnvBlock(char **envp, char **envBlock)
00160 {
00161     char *p;
00162     char *q;
00163     char **env;
00164     char *curEnv;
00165     char *cwdStart, *cwdEnd;
00166     int envBlockSize;
00167 
00168     PPIB ppib = NULL;
00169     PTIB ptib = NULL;
00170 
00171     if (envp == NULL) {
00172         *envBlock = NULL;
00173         return 0;
00174     }
00175 
00176     if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR)
00177        return -1;
00178 
00179     curEnv = ppib->pib_pchenv;
00180 
00181     cwdStart = curEnv;
00182     while (*cwdStart) {
00183         if (cwdStart[0] == '=' && cwdStart[1] != '\0'
00184                 && cwdStart[2] == ':' && cwdStart[3] == '=') {
00185             break;
00186         }
00187         cwdStart += strlen(cwdStart) + 1;
00188     }
00189     cwdEnd = cwdStart;
00190     if (*cwdEnd) {
00191         cwdEnd += strlen(cwdEnd) + 1;
00192         while (*cwdEnd) {
00193             if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
00194                     || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
00195                 break;
00196             }
00197             cwdEnd += strlen(cwdEnd) + 1;
00198         }
00199     }
00200     envBlockSize = cwdEnd - cwdStart;
00201 
00202     for (env = envp; *env; env++) {
00203         envBlockSize += strlen(*env) + 1;
00204     }
00205     envBlockSize++;
00206 
00207     p = *envBlock = PR_MALLOC(envBlockSize);
00208     if (p == NULL) {
00209         return -1;
00210     }
00211 
00212     q = cwdStart;
00213     while (q < cwdEnd) {
00214         *p++ = *q++;
00215     }
00216 
00217     for (env = envp; *env; env++) {
00218         q = *env;
00219         while (*q) {
00220             *p++ = *q++;
00221         }
00222         *p++ = '\0';
00223     }
00224     *p = '\0';
00225     return 0;
00226 }
00227 
00228 /*
00229  * For qsort.  We sort (case-insensitive) the environment strings
00230  * before generating the environment block.
00231  */
00232 static int compare(const void *arg1, const void *arg2)
00233 {
00234     return stricmp(* (char**)arg1, * (char**)arg2);
00235 }
00236 
00237 PRProcess * _PR_CreateOS2Process(
00238     const char *path,
00239     char *const *argv,
00240     char *const *envp,
00241     const PRProcessAttr *attr)
00242 {
00243     PRProcess *proc = NULL;
00244     char *cmdLine = NULL;
00245     char **newEnvp = NULL;
00246     char *envBlock = NULL;
00247    
00248     STARTDATA startData = {0};
00249     APIRET    rc;
00250     ULONG     ulAppType = 0;
00251     PID       pid = 0;
00252     char     *pEnvWPS = NULL;
00253     char     *pszComSpec;
00254     char      pszEXEName[CCHMAXPATH] = "";
00255     char      pszFormatString[CCHMAXPATH];
00256     char      pszObjectBuffer[CCHMAXPATH];
00257     char     *pszFormatResult = NULL;
00258 
00259     /*
00260      * Variables for DosExecPgm
00261      */
00262     char szFailed[CCHMAXPATH];
00263     char *pszCmdLine = NULL;
00264     RESULTCODES procInfo;
00265     HFILE hStdIn  = 0,
00266           hStdOut = 0,
00267           hStdErr = 0;
00268     HFILE hStdInSave  = -1,
00269           hStdOutSave = -1,
00270           hStdErrSave = -1;
00271 
00272     proc = PR_NEW(PRProcess);
00273     if (!proc) {
00274         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00275         goto errorExit;
00276     }
00277    
00278     if (assembleCmdLine(argv, &cmdLine) == -1) {
00279         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00280         goto errorExit;
00281     }
00282    
00283     if (envp == NULL) {
00284         newEnvp = NULL;
00285     } else {
00286         int i;
00287         int numEnv = 0;
00288         while (envp[numEnv]) {
00289             numEnv++;
00290         }
00291         newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *));
00292         for (i = 0; i <= numEnv; i++) {
00293             newEnvp[i] = envp[i];
00294         }
00295         qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare);
00296     }
00297     if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
00298         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00299         goto errorExit;
00300     }
00301   
00302     rc = DosQueryAppType(path, &ulAppType);
00303     if (rc != NO_ERROR) {
00304        char *pszDot = strrchr(path, '.');
00305        if (pszDot) {
00306           /* If it is a CMD file, launch the users command processor */
00307           if (!stricmp(pszDot, ".cmd")) {
00308              rc = DosScanEnv("COMSPEC", &pszComSpec);
00309              if (!rc) {
00310                 strcpy(pszFormatString, "/C %s %s");
00311                 strcpy(pszEXEName, pszComSpec);
00312                 ulAppType = FAPPTYP_WINDOWCOMPAT;
00313              }
00314           }
00315        }
00316     }
00317     if (ulAppType == 0) {
00318        PR_SetError(PR_UNKNOWN_ERROR, 0);
00319        goto errorExit;
00320     }
00321  
00322     if ((ulAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) {
00323         startData.SessionType = SSF_TYPE_PM;
00324     }
00325     else if (ulAppType & FAPPTYP_WINDOWCOMPAT) {
00326         startData.SessionType = SSF_TYPE_WINDOWABLEVIO;
00327     }
00328     else {
00329         startData.SessionType = SSF_TYPE_DEFAULT;
00330     }
00331  
00332     if (ulAppType & (FAPPTYP_WINDOWSPROT31 | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSREAL))
00333     {
00334         strcpy(pszEXEName, "WINOS2.COM");
00335         startData.SessionType = PROG_31_STDSEAMLESSVDM;
00336         strcpy(pszFormatString, "/3 %s %s");
00337     }
00338  
00339     startData.InheritOpt = SSF_INHERTOPT_SHELL;
00340  
00341     if (pszEXEName[0]) {
00342         pszFormatResult = PR_MALLOC(strlen(pszFormatString)+strlen(path)+strlen(cmdLine));
00343         sprintf(pszFormatResult, pszFormatString, path, cmdLine);
00344         startData.PgmInputs = pszFormatResult;
00345     } else {
00346         strcpy(pszEXEName, path);
00347         startData.PgmInputs = cmdLine;
00348     }
00349     startData.PgmName = pszEXEName;
00350  
00351     startData.Length = sizeof(startData);
00352     startData.Related = SSF_RELATED_INDEPENDENT;
00353     startData.ObjectBuffer = pszObjectBuffer;
00354     startData.ObjectBuffLen = CCHMAXPATH;
00355     startData.Environment = envBlock;
00356  
00357     if (attr) {
00358         /* On OS/2, there is really no way to pass file handles for stdin,
00359          * stdout, and stderr to a new process.  Instead, we can make it
00360          * a child process and make the given file handles a copy of our
00361          * stdin, stdout, and stderr.  The child process then inherits
00362          * ours, and we set ours back.  Twisted and gross I know. If you
00363          * know a better way, please use it.
00364          */
00365         if (attr->stdinFd) {
00366             hStdIn = 0;
00367             DosDupHandle(hStdIn, &hStdInSave);
00368             DosDupHandle((HFILE) attr->stdinFd->secret->md.osfd, &hStdIn);
00369         }
00370 
00371         if (attr->stdoutFd) {
00372             hStdOut = 1;
00373             DosDupHandle(hStdOut, &hStdOutSave);
00374             DosDupHandle((HFILE) attr->stdoutFd->secret->md.osfd, &hStdOut);
00375         }
00376 
00377         if (attr->stderrFd) {
00378             hStdErr = 2;
00379             DosDupHandle(hStdErr, &hStdErrSave);
00380             DosDupHandle((HFILE) attr->stderrFd->secret->md.osfd, &hStdErr);
00381         }
00382         /*
00383          * Build up the Command Line for DosExecPgm
00384          */
00385         pszCmdLine = PR_MALLOC(strlen(pszEXEName) +
00386                                strlen(startData.PgmInputs) + 3);
00387         sprintf(pszCmdLine, "%s%c%s%c", pszEXEName, '\0',
00388                 startData.PgmInputs, '\0');
00389         rc = DosExecPgm(szFailed,
00390                         CCHMAXPATH,
00391                         EXEC_ASYNCRESULT,
00392                         pszCmdLine,
00393                         envBlock,
00394                         &procInfo,
00395                         pszEXEName);
00396         PR_DELETE(pszCmdLine);
00397 
00398         /* Restore our old values.  Hope this works */
00399         if (hStdInSave != -1) {
00400             DosDupHandle(hStdInSave, &hStdIn);
00401             DosClose(hStdInSave);
00402         }
00403 
00404         if (hStdOutSave != -1) {
00405             DosDupHandle(hStdOutSave, &hStdOut);
00406             DosClose(hStdOutSave);
00407         }
00408 
00409         if (hStdErrSave != -1) {
00410             DosDupHandle(hStdErrSave, &hStdErr);
00411             DosClose(hStdErrSave);
00412         }
00413 
00414         if (rc != NO_ERROR) {
00415             /* XXX what error code? */
00416             PR_SetError(PR_UNKNOWN_ERROR, rc);
00417             goto errorExit;
00418         }
00419 
00420         proc->md.pid = procInfo.codeTerminate;
00421     } else {  
00422         /*
00423          * If no STDIN/STDOUT redirection is not needed, use DosStartSession
00424          * to create a new, independent session
00425          */
00426         rc = DosStartSession(&startData, &ulAppType, &pid);
00427 
00428         if ((rc != NO_ERROR) && (rc != ERROR_SMG_START_IN_BACKGROUND)) {
00429             PR_SetError(PR_UNKNOWN_ERROR, rc);
00430             goto errorExit;
00431         }
00432  
00433         proc->md.pid = pid;
00434     }
00435 
00436     if (pszFormatResult) {
00437         PR_DELETE(pszFormatResult);
00438     }
00439 
00440     PR_DELETE(cmdLine);
00441     if (newEnvp) {
00442         PR_DELETE(newEnvp);
00443     }
00444     if (envBlock) {
00445         PR_DELETE(envBlock);
00446     }
00447     return proc;
00448 
00449 errorExit:
00450     if (cmdLine) {
00451         PR_DELETE(cmdLine);
00452     }
00453     if (newEnvp) {
00454         PR_DELETE(newEnvp);
00455     }
00456     if (envBlock) {
00457         PR_DELETE(envBlock);
00458     }
00459     if (proc) {
00460         PR_DELETE(proc);
00461     }
00462     return NULL;
00463 }  /* _PR_CreateOS2Process */
00464 
00465 PRStatus _PR_DetachOS2Process(PRProcess *process)
00466 {
00467     /* On OS/2, a process is either created as a child or not. 
00468      * You can't 'detach' it later on.
00469      */
00470     PR_DELETE(process);
00471     return PR_SUCCESS;
00472 }
00473 
00474 /*
00475  * XXX: This will currently only work on a child process.
00476  */
00477 PRStatus _PR_WaitOS2Process(PRProcess *process,
00478     PRInt32 *exitCode)
00479 {
00480     ULONG ulRetVal;
00481     RESULTCODES results;
00482     PID pidEnded = 0;
00483 
00484     ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, 
00485                             &results,
00486                             &pidEnded, process->md.pid);
00487 
00488     if (ulRetVal != NO_ERROR) {
00489        printf("\nDosWaitChild rc = %lu\n", ulRetVal);
00490         PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
00491         return PR_FAILURE;
00492     }
00493     PR_DELETE(process);
00494     return PR_SUCCESS;
00495 }
00496 
00497 PRStatus _PR_KillOS2Process(PRProcess *process)
00498 {
00499    ULONG ulRetVal;
00500     if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) {
00501        return PR_SUCCESS;
00502     }
00503     PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
00504     return PR_FAILURE;
00505 }
00506 
00507 PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen)
00508 {
00509     PRIntn rv;
00510 
00511     rv = gethostname(name, (PRInt32) namelen);
00512     if (0 == rv) {
00513         return PR_SUCCESS;
00514     }
00515        _PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno());
00516     return PR_FAILURE;
00517 }
00518 
00519 void
00520 _PR_MD_WAKEUP_CPUS( void )
00521 {
00522     return;
00523 }    
00524 
00525 
00526 /*
00527  **********************************************************************
00528  *
00529  * Memory-mapped files are not supported on OS/2 (or Win16).
00530  *
00531  **********************************************************************
00532  */
00533 
00534 PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
00535 {
00536     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00537     return PR_FAILURE;
00538 }
00539 
00540 PRInt32 _MD_GetMemMapAlignment(void)
00541 {
00542     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00543     return -1;
00544 }
00545 
00546 void * _MD_MemMap(
00547     PRFileMap *fmap,
00548     PROffset64 offset,
00549     PRUint32 len)
00550 {
00551     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00552     return NULL;
00553 }
00554 
00555 PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
00556 {
00557     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00558     return PR_FAILURE;
00559 }
00560 
00561 PRStatus _MD_CloseFileMap(PRFileMap *fmap)
00562 {
00563     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00564     return PR_FAILURE;
00565 }
00566