/* * XSPAWN * Version 1.33 * (C) Copyright 1990 Whitney Software, Inc. * All Rights Reserved */ #include #include #include #include #ifdef LATTICE #include #else #include #endif #include "xspawnp.h" typedef struct _vector { char number; /* vector number */ char flag; /* 0-CURRENT, 1-IRET, 2-free, 3-end */ unsigned int vseg; /* vector segment */ unsigned int voff; /* vector offset */ } VECTOR; static void savevect( void ); static int testfile( char *, char *, int * ); static int tempfile( char *, int * ); static int cmdenv( char **, char **, char *, char **, char ** ); static int doxspawn( char *, char **, char ** ); #ifdef LATTICE extern int __xspawn( char *, char *, char *, VECTOR *, int, int, char *, int ); extern int __xsize( unsigned int, long *, long * ); extern int __chkems( char *, int * ); extern int __savemap( char * ); extern int __restmap( char * ); extern int __getems( int, int * ); extern int __dskspace( int, unsigned int *, unsigned int * ); extern int __getrc( void ); extern int __create( char *, int * ); extern int __getcd( int, char * ); extern int __getdrv( void ); extern void __getvect( int, unsigned int *, unsigned int * ); extern void __setvect( VECTOR * ); #else extern int _xspawn( char *, char *, char *, VECTOR *, int, int, char *, int ); extern int _xsize( unsigned int, long *, long * ); extern int _chkems( char *, int * ); extern int _savemap( char * ); extern int _restmap( char * ); extern int _getems( int, int * ); extern int _dskspace( int, unsigned int *, unsigned int * ); extern int _getrc( void ); extern int _create( char *, int * ); extern int _getcd( int, char * ); extern int _getdrv( void ); extern void _getvect( int, unsigned int *, unsigned int * ); extern void _setvect( VECTOR * ); #endif #ifdef LATTICE extern char **environ; #endif 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 ]]; int addvect( number, opcode ) int number; int opcode; { register 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 ) #ifdef LATTICE __getvect( number, &vect->vseg, &vect->voff ); #else _getvect( number, &vect->vseg, &vect->voff ); #endif return( 0 ); } errno = ENOMEM; return( -1 ); } static void savevect() { register VECTOR *vect1 = vectab1; register VECTOR *vect2 = vectab2; while ( vect1->flag != 3 ) { if ( vect1->flag != 2 ) { vect2->number = vect1->number; vect2->flag = CURRENT; #ifdef LATTICE __getvect( vect1->number, &vect2->vseg, &vect2->voff ); #else _getvect( vect1->number, &vect2->vseg, &vect2->voff ); #endif } else vect2->flag = 2; /* free */ vect1++; vect2++; } vect2->flag = 3; /* end */ } static int testfile( p, file, handle ) register char *p; register char *file; int *handle; { unsigned int startno = tempno; int drive = ( *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 rc; /* return code */ if ( file + 2 == p ) { *p++ = '\\'; #ifdef LATTICE if ( __getcd( drive, p )) /* get current directory */ #else if ( _getcd( drive, p )) /* get current directory */ #endif return( 1 ); /* invalid drive */ p = file + strlen( file ); } else { *p = '\0'; if ( access( 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; #ifdef LATTICE if ( __dskspace( drive, &bytes, &clusters ) != 0 ) #else if ( _dskspace( drive, &bytes, &clusters ) != 0 ) #endif return( 1 ); /* invalid drive */ need = ( int )( swapsize / bytes ); if ( swapsize % bytes ) 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 */ #ifdef LATTICE stcu_d( p, tempno ); #else ltoa(( long )tempno, p, 10 ); #endif } while ( !access( 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. */ #ifdef LATTICE if (( rc = __create( file, handle )) == 80 ) #else if (( rc = _create( file, handle )) == 80 ) #endif goto again; return( rc ); } static int tempfile( file, handle ) char *file; int *handle; { register char *s = _swappath; register char *p = file; if ( s ) { for ( ;; s++ ) { while ( *s && *s != ';' ) *p++ = *s++; if ( p > file ) { if ( p == file + 1 || file[ 1 ] != ':' ) { #ifdef MSC4 memcpy( file + 2, file, ( int )( p - file )); #else memmove( file + 2, file, ( int )( p - file )); #endif #ifdef LATTICE *file = ( char )( __getdrv() + 'a' ); #else *file = ( char )( _getdrv() + 'a' ); #endif file[ 1 ] = ':'; p += 2; } if ( testfile( p, file, handle ) == 0 ) return( 0 ); p = file; } if ( *s == '\0' ) break; } } else /* try the current directory */ { #ifdef LATTICE *p++ = ( char )( __getdrv() + 'a' ); #else *p++ = ( char )( _getdrv() + 'a' ); #endif *p++ = ':'; if ( testfile( p, file, handle ) == 0 ) return( 0 ); } errno = EACCES; return( 1 ); } static int cmdenv( argv, envp, command, env, memory ) char **argv; char **envp; char *command; char **env; char **memory; { register char **vp; unsigned int elen = 0; /* environment length */ char *p; int cnt; int len; /* construct environment */ if ( envp == NULL ) envp = environ; if ( envp ) { for ( vp = envp; *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; if ( envp ) { for ( vp = envp; *vp; vp++ ) p = strchr( strcpy( p, *vp ), '\0' ) + 1; } *p = '\0'; /* final element */ /* construct command-line */ vp = argv; p = command + 1; cnt = 0; if ( *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 */ } static int doxspawn( path, argv, envp ) char *path; /* file to be executed */ char *argv[]; /* array of pointers to arguments */ char *envp[]; /* array of pointers to environment strings */ { register int rc = 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( argv, envp, command, &env, &memory )) == -1 ) return( -1 ); if ( _swap == 0 ) { if ( _useems == 0 ) { if ( ems == 2 ) #ifdef LATTICE ems = __chkems( "EMMXXXX0", &mapsize ); #else ems = _chkems( "EMMXXXX0", &mapsize ); #endif if ( ems == 0 && ( mapbuf = malloc( mapsize )) == NULL ) { errno = ENOMEM; free( memory ); return( -1 ); } } #ifdef LATTICE if (( rc = __xsize(( unsigned int )(( unsigned long )_PSP >> 16 ), &swapsize, &totalsize )) == 0 ) #else if (( rc = _xsize( _psp, &swapsize, &totalsize )) == 0 ) #endif { if ( _required == 0 || totalsize - swapsize - 272 < (( long )_required << 10 )) { if ( ems == 0 && _useems == 0 ) { pages = ( int )( swapsize >> 14 ); if ((( long )pages << 14 ) < swapsize ) pages++; #ifdef LATTICE if ( __savemap( mapbuf ) == 0 && __getems( pages, &handle ) == 0 ) #else if ( _savemap( mapbuf ) == 0 && _getems( pages, &handle ) == 0 ) #endif *file = '\0'; /* use EMS */ else if ( tempfile( file, &handle ) != 0 ) rc = -1; /* don't do xspawn */ } else if ( tempfile( file, &handle ) != 0 ) rc = -1; /* don't do xspawn */ } else doswap = 1; /* don't do swap */ } else { errno = errtab[ rc ]; rc = -1; /* don't do xspawn */ } } else doswap = 1; /* don't do swap */ if ( rc == 0 ) { savevect(); /* save current vectors */ #ifdef LATTICE rc = __xspawn( path, command, env, vectab1, doswap, elen, file, handle ); #else rc = _xspawn( path, command, env, vectab1, doswap, elen, file, handle ); #endif #ifdef LATTICE __setvect( vectab2 ); /* restore saved vectors */ #else _setvect( vectab2 ); /* restore saved vectors */ #endif if ( rc == 0 ) #ifdef LATTICE rc = __getrc(); /* get child return code */ #else rc = _getrc(); /* get child return code */ #endif else { errno = errtab[ rc ]; rc = -1; } /* * If EMS was used, restore the page-mapping state of the expanded * memory hardware. */ #ifdef LATTICE if ( doswap == 0 && *file == '\0' && __restmap( mapbuf ) != 0 ) #else if ( doswap == 0 && *file == '\0' && _restmap( mapbuf ) != 0 ) #endif { errno = EACCES; rc = -1; } } if ( mapbuf ) free( mapbuf ); free( memory ); return( rc ); } int xspawnve( modeflag, path, argv, envp ) int modeflag; /* execution mode for parent process */ register char *path; /* file to be executed */ char *argv[]; /* array of pointers to arguments */ char *envp[]; /* array of pointers to environment strings */ { register char *p; char *s; int rc = -1; char buf[ 80 ]; if ( modeflag != P_WAIT ) { errno = EINVAL; return( -1 ); } p = strrchr( path, '\\' ); s = strrchr( path, '/' ); if ( p == NULL && s == NULL ) p = path; else if ( p == NULL || s > p ) p = s; if ( strchr( p, '.' )) { if ( !access( path, 0 )) rc = doxspawn( path, argv, envp ); /* If file not found, access will have set errno to ENOENT. */ } else { strcpy( buf, path ); strcat( buf, ".com" ); if ( !access( buf, 0 )) rc = doxspawn( buf, argv, envp ); else { strcpy( strrchr( buf, '.' ), ".exe" ); if ( !access( buf, 0 )) rc = doxspawn( buf, argv, envp ); /* If file not found, access will have set errno to ENOENT. */ } } return( rc ); }