1103 lines
29 KiB
C
1103 lines
29 KiB
C
/* OpenDoors Online Software Programming Toolkit
|
|
* (C) Copyright 1991 - 1999 by Brian Pirie.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*
|
|
* File: ODSpawn.c
|
|
*
|
|
* Description: Implements the od_spawn...() functions for suspending this
|
|
* program and executing a sub-program. Can be called by the
|
|
* user explicitly, or invoked for sysop OS shell.
|
|
*
|
|
* Revisions: Date Ver Who Change
|
|
* ---------------------------------------------------------------
|
|
* Oct 13, 1994 6.00 BP New file header format.
|
|
* Oct 21, 1994 6.00 BP Further isolated com routines.
|
|
* Dec 09, 1994 6.00 BP Use new directory access functions.
|
|
* Dec 13, 1994 6.00 BP Standardized coding style.
|
|
* Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
|
|
* Jan 01, 1995 6.00 BP _waitdrain -> ODWaitDrain()
|
|
* Aug 19, 1995 6.00 BP 32-bit portability.
|
|
* Nov 11, 1995 6.00 BP Removed register keyword.
|
|
* Nov 14, 1995 6.00 BP Added include of odscrn.h.
|
|
* Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
|
|
* Nov 17, 1995 6.00 BP Use new input queue mechanism.
|
|
* Nov 21, 1995 6.00 BP Ported to Win32.
|
|
* Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
|
|
* Jan 23, 1996 6.00 BP Finished port to Win32.
|
|
* Feb 19, 1996 6.00 BP Changed version number to 6.00.
|
|
* Feb 23, 1996 6.00 BP Enable and test under Win32.
|
|
* Feb 27, 1996 6.00 BP Store screen info in our own struct.
|
|
* Mar 03, 1996 6.10 BP Begin version 6.10.
|
|
* Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
|
|
* Aug 10, 2003 6.23 SH *nix support - some functions not supported (Yet)
|
|
*/
|
|
|
|
#define BUILDING_OPENDOORS
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
|
|
#include "OpenDoor.h"
|
|
#ifdef ODPLAT_NIX
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
#include "ODCore.h"
|
|
#include "ODGen.h"
|
|
#include "ODCom.h"
|
|
#include "ODPlat.h"
|
|
#include "ODScrn.h"
|
|
#include "ODInQue.h"
|
|
#include "ODInEx.h"
|
|
#include "ODUtil.h"
|
|
#include "ODKrnl.h"
|
|
#include "ODSwap.h"
|
|
|
|
#ifdef ODPLAT_WIN32
|
|
#include "ODFrame.h"
|
|
#endif /* ODPLAT_WIN32 */
|
|
|
|
#if defined(ODPLAT_WIN32) && defined(_MSC_VER)
|
|
#undef P_WAIT
|
|
#undef P_NOWAIT
|
|
#include <process.h>
|
|
#endif /* ODPLAT_WIN32 && _MSC_VER */
|
|
|
|
#ifdef ODPLAT_DOS
|
|
|
|
/* Local and global variables for memory swapping spawn routines. */
|
|
|
|
int _swap = 0; /* if 0, do swap */
|
|
char *_swappath = NULL; /* swap path */
|
|
int _useems = 0; /* if 0, use EMS */
|
|
int _required = 0; /* child memory requirement in K */
|
|
static long swapsize; /* swap size requirement in bytes */
|
|
static int ems = 2; /* if 0, EMS is available */
|
|
static int mapsize; /* size of page map information */
|
|
static unsigned int tempno = 1; /* tempfile number */
|
|
static char errtab[] = /* error table */
|
|
{
|
|
0,
|
|
EINVAL,
|
|
ENOENT,
|
|
ENOENT,
|
|
EMFILE,
|
|
EACCES,
|
|
EBADF,
|
|
ENOMEM,
|
|
ENOMEM,
|
|
ENOMEM,
|
|
E2BIG,
|
|
ENOEXEC,
|
|
EINVAL,
|
|
EINVAL,
|
|
-1,
|
|
EXDEV,
|
|
EACCES,
|
|
EXDEV,
|
|
ENOENT,
|
|
-1
|
|
};
|
|
|
|
static VECTOR vectab1[]=
|
|
{
|
|
0, 1, 0, 0,
|
|
1, 1, 0, 0,
|
|
2, 1, 0, 0,
|
|
3, 1, 0, 0,
|
|
0x1B, 1, 0, 0,
|
|
0x23, 1, 0, 0,
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 2, 0, 0, /* free record */
|
|
0, 3, 0, 0 /* end record */
|
|
};
|
|
|
|
static VECTOR vectab2[(sizeof vectab1)/(sizeof vectab1[0])];
|
|
|
|
/* Location function prototypes. */
|
|
int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[],
|
|
char *papszEnviron[]);
|
|
int _spawnve(int nModeFlag, char *pszPath, char *papszArgs[],
|
|
char * papszEnviron[]);
|
|
static void savevect(void);
|
|
|
|
|
|
#endif /* ODPLAT_DOS */
|
|
|
|
#ifdef ODPLAT_NIX
|
|
/* Location function prototypes. */
|
|
int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[],
|
|
char *papszEnviron[]);
|
|
#endif /* ODPLAT_NIX */
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* od_spawn()
|
|
*
|
|
* Executes the specified command line, suspending OpenDoors operations while
|
|
* the spawned-to program is running.
|
|
*
|
|
* Parameters: pszCommandLine - Command to execute along with any parameters.
|
|
*
|
|
* Return: TRUE on success, or FALSE on failure.
|
|
*/
|
|
ODAPIDEF BOOL ODCALL od_spawn(const char *pszCommandLine)
|
|
{
|
|
#ifdef ODPLAT_DOS
|
|
char *apszArgs[4];
|
|
INT16 nReturnCode;
|
|
|
|
/* Log function entry if running in trace mode. */
|
|
TRACE(TRACE_API, "od_spawn()");
|
|
|
|
*apszArgs=getenv("COMSPEC");
|
|
|
|
apszArgs[1] = "/c";
|
|
apszArgs[2] = pszCommandLine;
|
|
apszArgs[3] = NULL;
|
|
|
|
if(*apszArgs != NULL)
|
|
{
|
|
if((nReturnCode = od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL)) != -1
|
|
|| errno != ENOENT)
|
|
{
|
|
return(nReturnCode != -1);
|
|
}
|
|
}
|
|
|
|
*apszArgs = "command.com";
|
|
|
|
return(od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL) != -1);
|
|
#endif /* ODPLAT_DOS */
|
|
|
|
#ifdef ODPLAT_WIN32
|
|
char *pch;
|
|
char *apszArgs[3];
|
|
char szProgName[80];
|
|
|
|
/* Build command and arguments list. */
|
|
/* Build program name. */
|
|
ODStringCopy(szProgName, pszCommandLine, sizeof(szProgName));
|
|
pch = strchr(szProgName, ' ');
|
|
if(pch != NULL) *pch = '\0';
|
|
apszArgs[0] = szProgName;
|
|
|
|
/* Build arguments. */
|
|
pch = strchr(pszCommandLine, ' ');
|
|
if(pch == NULL)
|
|
{
|
|
apszArgs[1] = NULL;
|
|
}
|
|
else
|
|
{
|
|
apszArgs[1] = pch + 1;
|
|
apszArgs[2] = NULL;
|
|
}
|
|
|
|
/* Now, call od_spawnvpe(). */
|
|
return(od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL) != -1);
|
|
#endif /* ODPLAT_WIN32 */
|
|
|
|
#ifdef ODPLAT_NIX
|
|
sigset_t block;
|
|
int retval;
|
|
|
|
/* Suspend kernel */
|
|
sigemptyset(&block);
|
|
sigaddset(&block,SIGALRM);
|
|
sigprocmask(SIG_BLOCK,&block,NULL);
|
|
retval=system(pszCommandLine);
|
|
|
|
/* Restore kernel */
|
|
sigemptyset(&block);
|
|
sigaddset(&block,SIGALRM);
|
|
sigprocmask(SIG_UNBLOCK,&block,NULL);
|
|
|
|
return(retval!=-1 && retval != 127);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* od_spawnvpe()
|
|
*
|
|
* Executes the specified program, using the specified arguments and
|
|
* environment variables, optionally suspending OpenDoors operations while
|
|
* the spawned-to program is running.
|
|
*
|
|
* Parameters: nModeFlag - P_WAIT to for OpenDoors operations to be suspended
|
|
* while the spawned-to program is running, or
|
|
* P_NOWAIT if the calling program should continue to
|
|
* run while the spawned-to program is running. In
|
|
* non-multitasking environments, the only valid value
|
|
* of this parameters is P_WAIT.
|
|
*
|
|
* pszPath - Complete path and filename of the program to
|
|
* exectute.
|
|
*
|
|
* papszArg - Array of string pointers to command line arguments.
|
|
*
|
|
* papszEnv - Array of string pointers to environment variables.
|
|
*
|
|
* Return: -1 on failure or the spawned-to program's return value on
|
|
* success.
|
|
*/
|
|
ODAPIDEF INT16 ODCALL od_spawnvpe(INT16 nModeFlag, char *pszPath,
|
|
char *papszArg[], char *papszEnv[])
|
|
{
|
|
INT16 nToReturn;
|
|
time_t nStartUnixTime;
|
|
DWORD dwQuotient;
|
|
#ifdef ODPLAT_WIN32
|
|
void *pWindow;
|
|
#endif /* ODPLAT_WIN32 */
|
|
#ifdef ODPLAT_DOS
|
|
char *pszDir;
|
|
BYTE *abtScreenBuffer;
|
|
INT nDrive;
|
|
tODScrnTextInfo TextInfo;
|
|
#endif /* ODPLAT_DOS */
|
|
|
|
/* Log function entry if running in trace mode. */
|
|
TRACE(TRACE_API, "od_spawnvpe()");
|
|
|
|
/* Initialize OpenDoors if it hasn't already been done. */
|
|
if(!bODInitialized) od_init();
|
|
|
|
#ifdef ODPLAT_DOS
|
|
/* Ensure the nModeFlag is P_WAIT, which is the only valid value for */
|
|
/* the MS-DOS version of OpenDoors. */
|
|
if(nModeFlag != P_WAIT)
|
|
{
|
|
od_control.od_error = ERR_PARAMETER;
|
|
return(-1);
|
|
}
|
|
|
|
/* Store current screen contents. */
|
|
if((abtScreenBuffer = malloc(4000)) == NULL)
|
|
{
|
|
od_control.od_error = ERR_MEMORY;
|
|
return(-1);
|
|
}
|
|
if((pszDir = malloc(256)) == NULL)
|
|
{
|
|
od_control.od_error = ERR_MEMORY;
|
|
free(abtScreenBuffer);
|
|
return(-1);
|
|
}
|
|
|
|
/* Store current display settings. */
|
|
ODScrnGetTextInfo(&TextInfo);
|
|
|
|
/* Set current output area to the full screen. */
|
|
ODScrnSetBoundary(1,1,80,25);
|
|
|
|
/* Store contents of entire screen. */
|
|
ODScrnGetText(1, 1, 80, 25, (char *)abtScreenBuffer);
|
|
|
|
/* Set the current display colour to grey on black. */
|
|
ODScrnSetAttribute(0x07);
|
|
|
|
/* Clear the screen if required. Otherwise, move the cursor to the */
|
|
/* upper left corner of the screen. */
|
|
if(od_control.od_clear_on_exit)
|
|
{
|
|
ODScrnClear();
|
|
}
|
|
else
|
|
{
|
|
ODScrnSetCursorPos(1, 1);
|
|
}
|
|
|
|
/* Store current directory. */
|
|
strcpy(pszDir, "X:\\");
|
|
pszDir[0] = 'A' + (nDrive = _getdrv());
|
|
_getcd(0, (char *)pszDir + 3);
|
|
#endif /* ODPLAT_DOS */
|
|
|
|
/* Remember when spawned to program was executed. */
|
|
nStartUnixTime = time(NULL);
|
|
|
|
if(nModeFlag == P_WAIT)
|
|
{
|
|
/* Display the spawn message box under Win32. */
|
|
#ifdef ODPLAT_WIN32
|
|
pWindow = ODScrnShowMessage("Running sub-program...", 0);
|
|
#endif /* ODPLAT_WIN32 */
|
|
|
|
/* Wait for up to ten seconds for outbound buffer to drain. */
|
|
ODWaitDrain(10000);
|
|
|
|
#ifdef OD_MULTITHREADED
|
|
/* Mutlithreaded versions of OpenDoors must shutdown the kernel */
|
|
/* before closing the serial port. */
|
|
ODKrnlShutdown();
|
|
#endif /* OD_MULTITHREADED */
|
|
|
|
/* Close serial port. */
|
|
if(od_control.baud != 0)
|
|
{
|
|
#ifdef ODPLAT_WIN32
|
|
/* Disable DTR response by the modem before closing the serial */
|
|
/* port, if this is required. */
|
|
ODInExDisableDTR();
|
|
#endif /* ODPLAT_WIN32 */
|
|
ODComClose(hSerialPort);
|
|
}
|
|
}
|
|
|
|
/* Execute specified program with the specified arguments. */
|
|
nToReturn = _spawnvpe(nModeFlag, pszPath, papszArg, papszEnv);
|
|
|
|
if(nModeFlag == P_WAIT)
|
|
{
|
|
/* Re-open serial port. */
|
|
if(od_control.baud != 0)
|
|
{
|
|
ODComOpen(hSerialPort);
|
|
}
|
|
|
|
#ifdef OD_MULTITHREADED
|
|
/* Mutlithreaded versions of OpenDoors must shutdown the kernel */
|
|
/* before closing the serial port, so reinitialize the kernel now. */
|
|
ODKrnlInitialize();
|
|
#endif /* OD_MULTITHREADED */
|
|
|
|
if(!(bIsShell || od_control.od_spawn_freeze_time))
|
|
{
|
|
ODDWordDivide(&dwQuotient, NULL, time(NULL) - nStartUnixTime, 60L);
|
|
od_control.user_timelimit -= (int)dwQuotient;
|
|
}
|
|
else
|
|
{
|
|
nNextTimeDeductTime += time(NULL) - nStartUnixTime;
|
|
}
|
|
|
|
/* Reset the time of the last input activity to the current time. */
|
|
/* This will prevent an immediate inactity timeout, regardless of */
|
|
/* how long the spawned-to program was active. */
|
|
ODInQueueResetLastActivity(hODInputQueue);
|
|
|
|
/* Clear inbound buffer. */
|
|
od_clear_keybuffer();
|
|
|
|
/* Remove the spawn message box under Win32. */
|
|
#ifdef ODPLAT_WIN32
|
|
ODScrnRemoveMessage(pWindow);
|
|
#endif /* ODPLAT_WIN32 */
|
|
}
|
|
|
|
#ifdef ODPLAT_DOS
|
|
/* Redisplay the door screen. */
|
|
ODScrnPutText(1, 1, 80, 25, (char *)abtScreenBuffer);
|
|
|
|
/* Restore cursor to old position. */
|
|
ODScrnSetBoundary(TextInfo.winleft, TextInfo.wintop,
|
|
TextInfo.winright, TextInfo.winbottom);
|
|
ODScrnSetAttribute(TextInfo.attribute);
|
|
ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury);
|
|
|
|
_setdrvcd(nDrive, pszDir);
|
|
|
|
/* Free allocated space. */
|
|
free(abtScreenBuffer);
|
|
free(pszDir);
|
|
#endif /* ODPLAT_DOS */
|
|
|
|
/* Return appropriate value. */
|
|
return(nToReturn);
|
|
}
|
|
|
|
|
|
#ifdef ODPLAT_DOS
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* _spawnvpe() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Executes a child program in the MS-DOS environment, swapping the calling
|
|
* program out of memory if enabled.
|
|
*
|
|
* Parameters: nModeFlag - Must be P_WAIT.
|
|
*
|
|
* pszPath - Name of program to execute.
|
|
*
|
|
* papszArgs - Array of command-line arguments.
|
|
*
|
|
* papszEnviron - Array of environment variables.
|
|
*
|
|
* Return: -1 on failure or the spawned-to program's return value on
|
|
* success.
|
|
*/
|
|
int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[],
|
|
char *papszEnviron[])
|
|
{
|
|
char *e;
|
|
char *p;
|
|
char buf[80];
|
|
int nReturnCode;
|
|
|
|
|
|
_swappath = (char *)(strlen(od_control.od_swapping_path) == 0 ? NULL
|
|
: (char *)od_control.od_swapping_path);
|
|
_useems = od_control.od_swapping_noems;
|
|
_swap = od_control.od_swapping_disable;
|
|
|
|
if((nReturnCode=_spawnve(nModeFlag, pszPath, papszArgs, papszEnviron))!=-1
|
|
|| errno!=ENOENT || *pszPath=='\\' || *pszPath=='/'
|
|
|| *pszPath && *(pszPath+1)==':' || (e=getenv("PATH"))==NULL)
|
|
{
|
|
return(nReturnCode);
|
|
}
|
|
|
|
for (;;e++)
|
|
{
|
|
if((p=strchr(e,';'))!=NULL)
|
|
{
|
|
if(p-e > 66)
|
|
{
|
|
e=p;
|
|
continue;
|
|
}
|
|
}
|
|
else if(strlen(e)>66)
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
p=buf;
|
|
|
|
while(*e && *e!=';') *p++=*e++;
|
|
|
|
if(p>buf)
|
|
{
|
|
if(*(p-1)!='\\' && *(p-1)!='/') *p++ = '\\';
|
|
strcpy(p,pszPath);
|
|
|
|
if((nReturnCode=_spawnve(nModeFlag,buf,papszArgs,papszEnviron))!=-1 || errno!=ENOENT)
|
|
{
|
|
return(nReturnCode);
|
|
}
|
|
}
|
|
if(*e=='\0') return(-1);
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* addvect() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Adds a vector to the vector table.
|
|
*
|
|
* Parameters: number - The vector number.
|
|
*
|
|
* opcode - Vector flags.
|
|
*
|
|
* Return: -1 on failure, or 0 on success.
|
|
*/
|
|
int addvect(int number, int opcode)
|
|
{
|
|
VECTOR *vect = vectab1;
|
|
|
|
if ( number < 0 || number > 0xFF ||
|
|
( opcode != IRET && opcode != CURRENT ))
|
|
{
|
|
errno = EINVAL;
|
|
return( -1 );
|
|
}
|
|
|
|
/* see if number is already in table */
|
|
while ( vect->flag != 3 && ( vect->flag == 2 ||
|
|
vect->number != ( char )number ))
|
|
{
|
|
vect++;
|
|
}
|
|
|
|
if ( vect->flag == 3 )
|
|
{
|
|
/* look for a free record */
|
|
vect = vectab1;
|
|
while ( vect->flag == CURRENT || vect->flag == IRET )
|
|
vect++;
|
|
}
|
|
|
|
if ( vect->flag != 3 )
|
|
{
|
|
vect->number = ( char )number;
|
|
vect->flag = ( char )opcode;
|
|
if ( opcode == CURRENT )
|
|
_getvect( number, &vect->vseg, &vect->voff );
|
|
return( 0 );
|
|
}
|
|
|
|
errno = ENOMEM;
|
|
return( -1 );
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* savevect() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Saves current vector in vector table.
|
|
*
|
|
* Parameters: none
|
|
*
|
|
* Return: void
|
|
*/
|
|
static void savevect(void)
|
|
{
|
|
VECTOR *vect1 = vectab1;
|
|
VECTOR *vect2 = vectab2;
|
|
|
|
while ( vect1->flag != 3 )
|
|
{
|
|
if ( vect1->flag != 2 )
|
|
{
|
|
vect2->number = vect1->number;
|
|
vect2->flag = CURRENT;
|
|
_getvect( vect1->number, &vect2->vseg, &vect2->voff );
|
|
}
|
|
else
|
|
vect2->flag = 2; /* free */
|
|
vect1++;
|
|
vect2++;
|
|
}
|
|
vect2->flag = 3; /* end */
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* testfile() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Tests swap file.
|
|
*
|
|
* Parameters: p - Path.
|
|
*
|
|
* file - File name.
|
|
*
|
|
* handle - File handle.
|
|
*
|
|
* Return: 1 on failure.
|
|
*/
|
|
static int testfile(char *p, char *file, int *handle)
|
|
{
|
|
unsigned int startno = tempno;
|
|
int nDrive = ( *file | 32 ) - 96; /* a = 1, b = 2, etc. */
|
|
int root;
|
|
unsigned int bytes; /* bytes per cluster */
|
|
unsigned int clusters; /* free clusters */
|
|
int need; /* clusters needed for swap file */
|
|
int nReturnCode; /* return code */
|
|
unsigned long dwQuotient;
|
|
unsigned long remainder;
|
|
|
|
if ( file + 2 == p )
|
|
{
|
|
*p++ = '\\';
|
|
if ( _getcd( nDrive, p )) /* get current directory */
|
|
return( 1 ); /* invalid drive */
|
|
p = file + strlen( file );
|
|
}
|
|
else
|
|
{
|
|
*p = '\0';
|
|
if ( ODFileAccessMode( file, 0 ))
|
|
return( 1 ); /* path does not exist */
|
|
}
|
|
if ( *( p - 1 ) != '\\' && *( p - 1 ) != '/' )
|
|
*p++ = '\\';
|
|
if ( p - file == 3 )
|
|
root = 1; /* is root directory */
|
|
else
|
|
root = 0; /* is not root directory */
|
|
strcpy( p, "swp" );
|
|
p += 3;
|
|
|
|
if ( _dskspace( nDrive, &bytes, &clusters ) != 0 )
|
|
return( 1 ); /* invalid drive */
|
|
|
|
|
|
|
|
ODDWordDivide(&dwQuotient, &remainder, swapsize, bytes);
|
|
need = (int)dwQuotient;
|
|
|
|
if ( remainder )
|
|
need++;
|
|
if ( root == 0 ) /* if subdirectory */
|
|
need++; /* in case the directory needs space */
|
|
if ( clusters < ( unsigned int )need )
|
|
return( 1 ); /* insufficient free disk space */
|
|
|
|
do
|
|
{
|
|
again: tempno = ( ++tempno ) ? tempno : 1;
|
|
if ( tempno == startno )
|
|
return( 1 ); /* extremely unlikely */
|
|
ltoa(( long )tempno, p, 10 );
|
|
}
|
|
while ( !ODFileAccessMode( file, 0 ));
|
|
|
|
/*
|
|
* The return code from _create will equal 80 if the user is running DOS 3.0
|
|
* or above and the file was created by another program between the access
|
|
* call and the _create call.
|
|
*/
|
|
|
|
if (( nReturnCode = _create( file, handle )) == 80 )
|
|
goto again;
|
|
return( nReturnCode );
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* tempfile() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Creates a temporary swap file.
|
|
*
|
|
* Parameters: file - Filename
|
|
*
|
|
* handle - Handle to file.
|
|
*
|
|
* Return: 0 on success, or 1 on failure.
|
|
*/
|
|
static int tempfile(char *file, int *handle)
|
|
{
|
|
char *s = _swappath;
|
|
char *p = file;
|
|
|
|
if ( s )
|
|
{
|
|
for ( ;; s++ )
|
|
{
|
|
while ( *s && *s != ';' )
|
|
*p++ = *s++;
|
|
if ( p > file )
|
|
{
|
|
if ( p == file + 1 || file[ 1 ] != ':' )
|
|
{
|
|
memmove( file + 2, file, ( int )( p - file ));
|
|
*file = ( char )( _getdrv() + 'a' );
|
|
file[ 1 ] = ':';
|
|
p += 2;
|
|
}
|
|
if ( testfile( p, file, handle ) == 0 )
|
|
return( 0 );
|
|
p = file;
|
|
}
|
|
if ( *s == '\0' )
|
|
break;
|
|
}
|
|
}
|
|
else /* try the current directory */
|
|
{
|
|
*p++ = ( char )( _getdrv() + 'a' );
|
|
*p++ = ':';
|
|
if ( testfile( p, file, handle ) == 0 )
|
|
return( 0 );
|
|
}
|
|
|
|
errno = EACCES;
|
|
return( 1 );
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* cmdenv() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Constructs environment.
|
|
*
|
|
* Parameters: papszArgs - Array of arguments.
|
|
*
|
|
* papszEnviron - Array of environment variables to add.
|
|
*
|
|
* command - The command specified.
|
|
*
|
|
* env - Pointer to environment.
|
|
*
|
|
* memory - Allocated memory.
|
|
*
|
|
* Return: Environment length.
|
|
*/
|
|
static int cmdenv(char **papszArgs, char **papszEnviron, char *command,
|
|
char **env, char **memory)
|
|
{
|
|
char **vp;
|
|
unsigned int elen = 0; /* environment length */
|
|
char *p;
|
|
int cnt;
|
|
int len;
|
|
|
|
/* construct environment */
|
|
|
|
if ( papszEnviron == NULL )
|
|
{
|
|
char far *parent_env;
|
|
char far *env_ptr;
|
|
int nul_count;
|
|
|
|
ASM mov ah, 0x62
|
|
ASM int 0x21
|
|
ASM push es
|
|
ASM mov es, bx
|
|
ASM mov ax, es:[0x2c]
|
|
ASM pop es
|
|
ASM mov word ptr parent_env, 0
|
|
ASM mov word ptr parent_env + 2, ax
|
|
|
|
env_ptr = parent_env;
|
|
nul_count = 0;
|
|
while(nul_count < 2)
|
|
{
|
|
if(*env_ptr)
|
|
{
|
|
nul_count = 0;
|
|
}
|
|
else
|
|
{
|
|
++nul_count;
|
|
}
|
|
|
|
++env_ptr;
|
|
++elen;
|
|
}
|
|
|
|
if ( elen > 32766 ) /* 32K - 2 */
|
|
{
|
|
errno = E2BIG;
|
|
return( -1 );
|
|
}
|
|
|
|
if (( p = malloc(elen + 15 )) == NULL )
|
|
{
|
|
errno = ENOMEM;
|
|
return( -1 );
|
|
}
|
|
*memory = p;
|
|
|
|
*( unsigned int * )&p = *( unsigned int * )&p + 15 & ~15;
|
|
*env = p;
|
|
|
|
len = elen;
|
|
while(len--)
|
|
{
|
|
*p++ = *parent_env++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( vp = papszEnviron; *vp; vp++ )
|
|
{
|
|
elen += strlen( *vp ) + 1;
|
|
if ( elen > 32766 ) /* 32K - 2 */
|
|
{
|
|
errno = E2BIG;
|
|
return( -1 );
|
|
}
|
|
}
|
|
|
|
if (( p = malloc( ++elen + 15 )) == NULL )
|
|
{
|
|
errno = ENOMEM;
|
|
return( -1 );
|
|
}
|
|
*memory = p;
|
|
|
|
*( unsigned int * )&p = *( unsigned int * )&p + 15 & ~15;
|
|
*env = p;
|
|
|
|
for ( vp = papszEnviron; *vp; vp++ )
|
|
p = strchr( strcpy( p, *vp ), '\0' ) + 1;
|
|
|
|
*p = '\0'; /* final element */
|
|
}
|
|
|
|
|
|
/* construct command-line */
|
|
|
|
vp = papszArgs;
|
|
p = command + 1;
|
|
cnt = 0;
|
|
|
|
if (vp!=NULL && *vp )
|
|
{
|
|
while ( *++vp )
|
|
{
|
|
*p++ = ' ';
|
|
cnt++;
|
|
len = strlen( *vp );
|
|
if ( cnt + len > 125 )
|
|
{
|
|
errno = E2BIG;
|
|
free( *memory );
|
|
return( -1 );
|
|
}
|
|
strcpy( p, *vp );
|
|
p += len;
|
|
cnt += len;
|
|
}
|
|
}
|
|
|
|
*p = '\r';
|
|
*command = ( char )cnt;
|
|
|
|
return(( int )elen ); /* return environment length */
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* doxspawn() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Performs spawn using memory swapping.
|
|
*
|
|
* Parameters: pszPath - Path to command to exectute.
|
|
*
|
|
* papszArg - Array of arugments.
|
|
*
|
|
* papszEnviron - Pointer to the environment.
|
|
*
|
|
* Return: 0 on success, or -1 on failure.
|
|
*/
|
|
static int doxspawn(char *pszPath, char *papszArgs[], char *papszEnviron[])
|
|
{
|
|
int nReturnCode = 0; /* assume do xspawn */
|
|
int doswap = 0; /* assume do swap */
|
|
int elen; /* environment length */
|
|
char *memory;
|
|
char *env; /* environment */
|
|
char command[ 128 ]; /* command-line */
|
|
long totalsize; /* parent and free memory in bytes */
|
|
int handle;
|
|
int pages;
|
|
char file[ 79 ];
|
|
char *mapbuf = NULL; /* buffer for map information */
|
|
|
|
/* construct the command-line and the environment */
|
|
if (( elen = cmdenv( papszArgs, papszEnviron, command, &env, &memory )) == -1 )
|
|
return( -1 );
|
|
|
|
if ( _swap == 0 )
|
|
{
|
|
if ( _useems == 0 )
|
|
{
|
|
if ( ems == 2 )
|
|
ems = _chkems( "EMMXXXX0", &mapsize );
|
|
if ( ems == 0 && ( mapbuf = malloc( mapsize )) == NULL )
|
|
{
|
|
errno = ENOMEM;
|
|
free( memory );
|
|
return( -1 );
|
|
}
|
|
}
|
|
if (( nReturnCode = _xsize( _psp, &swapsize, &totalsize )) == 0 )
|
|
{
|
|
if ( _required == 0 || totalsize - swapsize - 272
|
|
< (long)ODDWordShiftLeft(( long )_required , 10 ))
|
|
{
|
|
if ( ems == 0 && _useems == 0 )
|
|
{
|
|
pages = ( int )ODDWordShiftRight( swapsize , 14);
|
|
if ((long)ODDWordShiftLeft(( long )pages , 14 ) < swapsize )
|
|
pages++;
|
|
if ( _savemap( mapbuf ) == 0 &&
|
|
_getems( pages, &handle ) == 0 )
|
|
*file = '\0'; /* use EMS */
|
|
else if ( tempfile( file, &handle ) != 0 )
|
|
nReturnCode = -1; /* don't do xspawn */
|
|
}
|
|
else if ( tempfile( file, &handle ) != 0 )
|
|
nReturnCode = -1; /* don't do xspawn */
|
|
}
|
|
else
|
|
doswap = 1; /* don't do swap */
|
|
}
|
|
else
|
|
{
|
|
errno = errtab[ nReturnCode ];
|
|
nReturnCode = -1; /* don't do xspawn */
|
|
}
|
|
}
|
|
else
|
|
doswap = 1; /* don't do swap */
|
|
|
|
if ( nReturnCode == 0 )
|
|
{
|
|
savevect(); /* save current vectors */
|
|
nReturnCode = _xspawn( pszPath, command, env, vectab1, doswap, elen, file,
|
|
handle );
|
|
_setvect( vectab2 ); /* restore saved vectors */
|
|
if ( nReturnCode == 0 )
|
|
nReturnCode = _getrc(); /* get child return code */
|
|
else
|
|
{
|
|
errno = errtab[ nReturnCode ];
|
|
nReturnCode = -1;
|
|
}
|
|
/*
|
|
* If EMS was used, restore the page-mapping state of the expanded
|
|
* memory hardware.
|
|
*/
|
|
if ( doswap == 0 && *file == '\0' && _restmap( mapbuf ) != 0 )
|
|
{
|
|
errno = EACCES;
|
|
nReturnCode = -1;
|
|
}
|
|
}
|
|
|
|
if ( mapbuf )
|
|
free( mapbuf );
|
|
free( memory );
|
|
return( nReturnCode );
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* _spawnve() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Performs a spawn.
|
|
*
|
|
* Parameters: nModeFlag - Must be P_WAIT
|
|
*
|
|
* pszPath - Command to execute.
|
|
*
|
|
* papszArgs - Command line arguments.
|
|
*
|
|
* papszEnviron - Pointer to environment.
|
|
*
|
|
* Return: void
|
|
*/
|
|
int _spawnve(int nModeFlag, char *pszPath, char *papszArgs[],
|
|
char * papszEnviron[])
|
|
{
|
|
char *p;
|
|
char *s;
|
|
int nReturnCode = -1;
|
|
char buf[ 80 ];
|
|
|
|
if ( nModeFlag != P_WAIT )
|
|
{
|
|
errno = EINVAL;
|
|
return( -1 );
|
|
}
|
|
|
|
p = strrchr( pszPath, '\\' );
|
|
s = strrchr( pszPath, '/' );
|
|
if ( p == NULL && s == NULL )
|
|
p = pszPath;
|
|
else if ( p == NULL || s > p )
|
|
p = s;
|
|
|
|
if ( strchr( p, '.' ))
|
|
{
|
|
if ( !ODFileAccessMode( pszPath, 0 ))
|
|
nReturnCode = doxspawn( pszPath, papszArgs, papszEnviron );
|
|
/* If file not found, access will have set errno to ENOENT. */
|
|
}
|
|
else
|
|
{
|
|
strcpy( buf, pszPath );
|
|
strcat( buf, ".com" );
|
|
if ( !ODFileAccessMode( buf, 0 ))
|
|
nReturnCode = doxspawn( buf, papszArgs, papszEnviron );
|
|
else
|
|
{
|
|
strcpy( strrchr( buf, '.' ), ".exe" );
|
|
if ( !ODFileAccessMode( buf, 0 ))
|
|
nReturnCode = doxspawn( buf, papszArgs, papszEnviron );
|
|
/* If file not found, access will have set errno to ENOENT. */
|
|
}
|
|
}
|
|
|
|
return( nReturnCode );
|
|
}
|
|
|
|
#endif /* ODPLAT_DOS */
|
|
|
|
#ifdef ODPLAT_NIX
|
|
/* ----------------------------------------------------------------------------
|
|
* _spawnvpe() *** PRIVATE FUNCTION ***
|
|
*
|
|
* Executes a child program in the *nix environment.
|
|
*
|
|
* Parameters: nModeFlag - Must be P_WAIT or P_NOWAIT
|
|
*
|
|
* pszPath - Name of program to execute.
|
|
*
|
|
* papszArgs - Array of command-line arguments.
|
|
*
|
|
* papszEnviron - Array of environment variables.
|
|
*
|
|
* Return: -1 on failure or the spawned-to program's return value on
|
|
* success.
|
|
*/
|
|
int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[],
|
|
char *papszEnviron[])
|
|
{
|
|
pid_t child;
|
|
int status;
|
|
pid_t wret;
|
|
struct sigaction act;
|
|
|
|
|
|
child=fork();
|
|
|
|
if(nModeFlag == P_WAIT) {
|
|
/* require wait for child */
|
|
act.sa_handler=SIG_IGN;
|
|
sigemptyset(&(act.sa_mask));
|
|
act.sa_flags=SA_NOCLDSTOP;
|
|
sigaction(SIGCHLD,&act,NULL);
|
|
}
|
|
else {
|
|
/* Ignore SIGCHLD for backgrounded spawned processes */
|
|
act.sa_handler=SIG_IGN;
|
|
sigemptyset(&(act.sa_mask));
|
|
act.sa_flags=SA_NOCLDSTOP|SA_NOCLDWAIT;
|
|
sigaction(SIGCHLD,&act,NULL);
|
|
}
|
|
|
|
if(!child) {
|
|
/* Do the exec stuff here */
|
|
execve(pszPath,papszArgs,papszEnviron);
|
|
exit(-1); /* this should never happen! */
|
|
}
|
|
if(nModeFlag == P_WAIT) {
|
|
wret=waitpid(child,&status,0);
|
|
if(WIFEXITED(status)) {
|
|
return(WEXITSTATUS(status));
|
|
}
|
|
return(-1);
|
|
}
|
|
return(0);
|
|
}
|
|
#endif /* ODPLAT_NIX */
|