ODSpawn.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. /* OpenDoors Online Software Programming Toolkit
  2. * (C) Copyright 1991 - 1999 by Brian Pirie.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *
  19. * File: ODSpawn.c
  20. *
  21. * Description: Implements the od_spawn...() functions for suspending this
  22. * program and executing a sub-program. Can be called by the
  23. * user explicitly, or invoked for sysop OS shell.
  24. *
  25. * Revisions: Date Ver Who Change
  26. * ---------------------------------------------------------------
  27. * Oct 13, 1994 6.00 BP New file header format.
  28. * Oct 21, 1994 6.00 BP Further isolated com routines.
  29. * Dec 09, 1994 6.00 BP Use new directory access functions.
  30. * Dec 13, 1994 6.00 BP Standardized coding style.
  31. * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
  32. * Jan 01, 1995 6.00 BP _waitdrain -> ODWaitDrain()
  33. * Aug 19, 1995 6.00 BP 32-bit portability.
  34. * Nov 11, 1995 6.00 BP Removed register keyword.
  35. * Nov 14, 1995 6.00 BP Added include of odscrn.h.
  36. * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
  37. * Nov 17, 1995 6.00 BP Use new input queue mechanism.
  38. * Nov 21, 1995 6.00 BP Ported to Win32.
  39. * Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
  40. * Jan 23, 1996 6.00 BP Finished port to Win32.
  41. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  42. * Feb 23, 1996 6.00 BP Enable and test under Win32.
  43. * Feb 27, 1996 6.00 BP Store screen info in our own struct.
  44. * Mar 03, 1996 6.10 BP Begin version 6.10.
  45. * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
  46. * Aug 10, 2003 6.23 SH *nix support - some functions not supported (Yet)
  47. */
  48. #define BUILDING_OPENDOORS
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <stdio.h>
  52. #include <ctype.h>
  53. #include <time.h>
  54. #include <errno.h>
  55. #include "OpenDoor.h"
  56. #ifdef ODPLAT_NIX
  57. #include <signal.h>
  58. #include <sys/types.h>
  59. #include <sys/wait.h>
  60. #include <unistd.h>
  61. #endif
  62. #include "ODCore.h"
  63. #include "ODGen.h"
  64. #include "ODCom.h"
  65. #include "ODPlat.h"
  66. #include "ODScrn.h"
  67. #include "ODInQue.h"
  68. #include "ODInEx.h"
  69. #include "ODUtil.h"
  70. #include "ODKrnl.h"
  71. #include "ODSwap.h"
  72. #ifdef ODPLAT_WIN32
  73. #include "ODFrame.h"
  74. #endif /* ODPLAT_WIN32 */
  75. #if defined(ODPLAT_WIN32) && defined(_MSC_VER)
  76. #undef P_WAIT
  77. #undef P_NOWAIT
  78. #include <process.h>
  79. #endif /* ODPLAT_WIN32 && _MSC_VER */
  80. #ifdef ODPLAT_DOS
  81. /* Local and global variables for memory swapping spawn routines. */
  82. int _swap = 0; /* if 0, do swap */
  83. char *_swappath = NULL; /* swap path */
  84. int _useems = 0; /* if 0, use EMS */
  85. int _required = 0; /* child memory requirement in K */
  86. static long swapsize; /* swap size requirement in bytes */
  87. static int ems = 2; /* if 0, EMS is available */
  88. static int mapsize; /* size of page map information */
  89. static unsigned int tempno = 1; /* tempfile number */
  90. static char errtab[] = /* error table */
  91. {
  92. 0,
  93. EINVAL,
  94. ENOENT,
  95. ENOENT,
  96. EMFILE,
  97. EACCES,
  98. EBADF,
  99. ENOMEM,
  100. ENOMEM,
  101. ENOMEM,
  102. E2BIG,
  103. ENOEXEC,
  104. EINVAL,
  105. EINVAL,
  106. -1,
  107. EXDEV,
  108. EACCES,
  109. EXDEV,
  110. ENOENT,
  111. -1
  112. };
  113. static VECTOR vectab1[]=
  114. {
  115. 0, 1, 0, 0,
  116. 1, 1, 0, 0,
  117. 2, 1, 0, 0,
  118. 3, 1, 0, 0,
  119. 0x1B, 1, 0, 0,
  120. 0x23, 1, 0, 0,
  121. 0, 2, 0, 0, /* free record */
  122. 0, 2, 0, 0, /* free record */
  123. 0, 2, 0, 0, /* free record */
  124. 0, 2, 0, 0, /* free record */
  125. 0, 2, 0, 0, /* free record */
  126. 0, 2, 0, 0, /* free record */
  127. 0, 2, 0, 0, /* free record */
  128. 0, 2, 0, 0, /* free record */
  129. 0, 2, 0, 0, /* free record */
  130. 0, 2, 0, 0, /* free record */
  131. 0, 2, 0, 0, /* free record */
  132. 0, 2, 0, 0, /* free record */
  133. 0, 2, 0, 0, /* free record */
  134. 0, 2, 0, 0, /* free record */
  135. 0, 3, 0, 0 /* end record */
  136. };
  137. static VECTOR vectab2[(sizeof vectab1)/(sizeof vectab1[0])];
  138. /* Location function prototypes. */
  139. int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[],
  140. char *papszEnviron[]);
  141. int _spawnve(int nModeFlag, char *pszPath, char *papszArgs[],
  142. char * papszEnviron[]);
  143. static void savevect(void);
  144. #endif /* ODPLAT_DOS */
  145. #ifdef ODPLAT_NIX
  146. /* Location function prototypes. */
  147. int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[],
  148. char *papszEnviron[]);
  149. #endif /* ODPLAT_NIX */
  150. /* ----------------------------------------------------------------------------
  151. * od_spawn()
  152. *
  153. * Executes the specified command line, suspending OpenDoors operations while
  154. * the spawned-to program is running.
  155. *
  156. * Parameters: pszCommandLine - Command to execute along with any parameters.
  157. *
  158. * Return: TRUE on success, or FALSE on failure.
  159. */
  160. ODAPIDEF BOOL ODCALL od_spawn(const char *pszCommandLine)
  161. {
  162. #ifdef ODPLAT_DOS
  163. char *apszArgs[4];
  164. INT16 nReturnCode;
  165. /* Log function entry if running in trace mode. */
  166. TRACE(TRACE_API, "od_spawn()");
  167. *apszArgs=getenv("COMSPEC");
  168. apszArgs[1] = "/c";
  169. apszArgs[2] = pszCommandLine;
  170. apszArgs[3] = NULL;
  171. if(*apszArgs != NULL)
  172. {
  173. if((nReturnCode = od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL)) != -1
  174. || errno != ENOENT)
  175. {
  176. return(nReturnCode != -1);
  177. }
  178. }
  179. *apszArgs = "command.com";
  180. return(od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL) != -1);
  181. #endif /* ODPLAT_DOS */
  182. #ifdef ODPLAT_WIN32
  183. char *pch;
  184. char *apszArgs[3];
  185. char szProgName[80];
  186. /* Build command and arguments list. */
  187. /* Build program name. */
  188. ODStringCopy(szProgName, pszCommandLine, sizeof(szProgName));
  189. pch = strchr(szProgName, ' ');
  190. if(pch != NULL) *pch = '\0';
  191. apszArgs[0] = szProgName;
  192. /* Build arguments. */
  193. pch = strchr(pszCommandLine, ' ');
  194. if(pch == NULL)
  195. {
  196. apszArgs[1] = NULL;
  197. }
  198. else
  199. {
  200. apszArgs[1] = pch + 1;
  201. apszArgs[2] = NULL;
  202. }
  203. /* Now, call od_spawnvpe(). */
  204. return(od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL) != -1);
  205. #endif /* ODPLAT_WIN32 */
  206. #ifdef ODPLAT_NIX
  207. sigset_t block;
  208. int retval;
  209. /* Suspend kernel */
  210. sigemptyset(&block);
  211. sigaddset(&block,SIGALRM);
  212. sigprocmask(SIG_BLOCK,&block,NULL);
  213. retval=system(pszCommandLine);
  214. /* Restore kernel */
  215. sigemptyset(&block);
  216. sigaddset(&block,SIGALRM);
  217. sigprocmask(SIG_UNBLOCK,&block,NULL);
  218. return(retval!=-1 && retval != 127);
  219. #endif
  220. }
  221. /* ----------------------------------------------------------------------------
  222. * od_spawnvpe()
  223. *
  224. * Executes the specified program, using the specified arguments and
  225. * environment variables, optionally suspending OpenDoors operations while
  226. * the spawned-to program is running.
  227. *
  228. * Parameters: nModeFlag - P_WAIT to for OpenDoors operations to be suspended
  229. * while the spawned-to program is running, or
  230. * P_NOWAIT if the calling program should continue to
  231. * run while the spawned-to program is running. In
  232. * non-multitasking environments, the only valid value
  233. * of this parameters is P_WAIT.
  234. *
  235. * pszPath - Complete path and filename of the program to
  236. * exectute.
  237. *
  238. * papszArg - Array of string pointers to command line arguments.
  239. *
  240. * papszEnv - Array of string pointers to environment variables.
  241. *
  242. * Return: -1 on failure or the spawned-to program's return value on
  243. * success.
  244. */
  245. ODAPIDEF INT16 ODCALL od_spawnvpe(INT16 nModeFlag, char *pszPath,
  246. char *papszArg[], char *papszEnv[])
  247. {
  248. INT16 nToReturn;
  249. time_t nStartUnixTime;
  250. DWORD dwQuotient;
  251. #ifdef ODPLAT_WIN32
  252. void *pWindow;
  253. #endif /* ODPLAT_WIN32 */
  254. #ifdef ODPLAT_DOS
  255. char *pszDir;
  256. BYTE *abtScreenBuffer;
  257. INT nDrive;
  258. tODScrnTextInfo TextInfo;
  259. #endif /* ODPLAT_DOS */
  260. /* Log function entry if running in trace mode. */
  261. TRACE(TRACE_API, "od_spawnvpe()");
  262. /* Initialize OpenDoors if it hasn't already been done. */
  263. if(!bODInitialized) od_init();
  264. #ifdef ODPLAT_DOS
  265. /* Ensure the nModeFlag is P_WAIT, which is the only valid value for */
  266. /* the MS-DOS version of OpenDoors. */
  267. if(nModeFlag != P_WAIT)
  268. {
  269. od_control.od_error = ERR_PARAMETER;
  270. return(-1);
  271. }
  272. /* Store current screen contents. */
  273. if((abtScreenBuffer = malloc(4000)) == NULL)
  274. {
  275. od_control.od_error = ERR_MEMORY;
  276. return(-1);
  277. }
  278. if((pszDir = malloc(256)) == NULL)
  279. {
  280. od_control.od_error = ERR_MEMORY;
  281. free(abtScreenBuffer);
  282. return(-1);
  283. }
  284. /* Store current display settings. */
  285. ODScrnGetTextInfo(&TextInfo);
  286. /* Set current output area to the full screen. */
  287. ODScrnSetBoundary(1,1,80,25);
  288. /* Store contents of entire screen. */
  289. ODScrnGetText(1, 1, 80, 25, (char *)abtScreenBuffer);
  290. /* Set the current display colour to grey on black. */
  291. ODScrnSetAttribute(0x07);
  292. /* Clear the screen if required. Otherwise, move the cursor to the */
  293. /* upper left corner of the screen. */
  294. if(od_control.od_clear_on_exit)
  295. {
  296. ODScrnClear();
  297. }
  298. else
  299. {
  300. ODScrnSetCursorPos(1, 1);
  301. }
  302. /* Store current directory. */
  303. strcpy(pszDir, "X:\\");
  304. pszDir[0] = 'A' + (nDrive = _getdrv());
  305. _getcd(0, (char *)pszDir + 3);
  306. #endif /* ODPLAT_DOS */
  307. /* Remember when spawned to program was executed. */
  308. nStartUnixTime = time(NULL);
  309. if(nModeFlag == P_WAIT)
  310. {
  311. /* Display the spawn message box under Win32. */
  312. #ifdef ODPLAT_WIN32
  313. pWindow = ODScrnShowMessage("Running sub-program...", 0);
  314. #endif /* ODPLAT_WIN32 */
  315. /* Wait for up to ten seconds for outbound buffer to drain. */
  316. ODWaitDrain(10000);
  317. #ifdef OD_MULTITHREADED
  318. /* Mutlithreaded versions of OpenDoors must shutdown the kernel */
  319. /* before closing the serial port. */
  320. ODKrnlShutdown();
  321. #endif /* OD_MULTITHREADED */
  322. /* Close serial port. */
  323. if(od_control.baud != 0)
  324. {
  325. #ifdef ODPLAT_WIN32
  326. /* Disable DTR response by the modem before closing the serial */
  327. /* port, if this is required. */
  328. ODInExDisableDTR();
  329. #endif /* ODPLAT_WIN32 */
  330. ODComClose(hSerialPort);
  331. }
  332. }
  333. /* Execute specified program with the specified arguments. */
  334. nToReturn = _spawnvpe(nModeFlag, pszPath, papszArg, papszEnv);
  335. if(nModeFlag == P_WAIT)
  336. {
  337. /* Re-open serial port. */
  338. if(od_control.baud != 0)
  339. {
  340. ODComOpen(hSerialPort);
  341. }
  342. #ifdef OD_MULTITHREADED
  343. /* Mutlithreaded versions of OpenDoors must shutdown the kernel */
  344. /* before closing the serial port, so reinitialize the kernel now. */
  345. ODKrnlInitialize();
  346. #endif /* OD_MULTITHREADED */
  347. if(!(bIsShell || od_control.od_spawn_freeze_time))
  348. {
  349. ODDWordDivide(&dwQuotient, NULL, time(NULL) - nStartUnixTime, 60L);
  350. od_control.user_timelimit -= (int)dwQuotient;
  351. }
  352. else
  353. {
  354. nNextTimeDeductTime += time(NULL) - nStartUnixTime;
  355. }
  356. /* Reset the time of the last input activity to the current time. */
  357. /* This will prevent an immediate inactity timeout, regardless of */
  358. /* how long the spawned-to program was active. */
  359. ODInQueueResetLastActivity(hODInputQueue);
  360. /* Clear inbound buffer. */
  361. od_clear_keybuffer();
  362. /* Remove the spawn message box under Win32. */
  363. #ifdef ODPLAT_WIN32
  364. ODScrnRemoveMessage(pWindow);
  365. #endif /* ODPLAT_WIN32 */
  366. }
  367. #ifdef ODPLAT_DOS
  368. /* Redisplay the door screen. */
  369. ODScrnPutText(1, 1, 80, 25, (char *)abtScreenBuffer);
  370. /* Restore cursor to old position. */
  371. ODScrnSetBoundary(TextInfo.winleft, TextInfo.wintop,
  372. TextInfo.winright, TextInfo.winbottom);
  373. ODScrnSetAttribute(TextInfo.attribute);
  374. ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury);
  375. _setdrvcd(nDrive, pszDir);
  376. /* Free allocated space. */
  377. free(abtScreenBuffer);
  378. free(pszDir);
  379. #endif /* ODPLAT_DOS */
  380. /* Return appropriate value. */
  381. return(nToReturn);
  382. }
  383. #ifdef ODPLAT_DOS
  384. /* ----------------------------------------------------------------------------
  385. * _spawnvpe() *** PRIVATE FUNCTION ***
  386. *
  387. * Executes a child program in the MS-DOS environment, swapping the calling
  388. * program out of memory if enabled.
  389. *
  390. * Parameters: nModeFlag - Must be P_WAIT.
  391. *
  392. * pszPath - Name of program to execute.
  393. *
  394. * papszArgs - Array of command-line arguments.
  395. *
  396. * papszEnviron - Array of environment variables.
  397. *
  398. * Return: -1 on failure or the spawned-to program's return value on
  399. * success.
  400. */
  401. int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[],
  402. char *papszEnviron[])
  403. {
  404. char *e;
  405. char *p;
  406. char buf[80];
  407. int nReturnCode;
  408. _swappath = (char *)(strlen(od_control.od_swapping_path) == 0 ? NULL
  409. : (char *)od_control.od_swapping_path);
  410. _useems = od_control.od_swapping_noems;
  411. _swap = od_control.od_swapping_disable;
  412. if((nReturnCode=_spawnve(nModeFlag, pszPath, papszArgs, papszEnviron))!=-1
  413. || errno!=ENOENT || *pszPath=='\\' || *pszPath=='/'
  414. || *pszPath && *(pszPath+1)==':' || (e=getenv("PATH"))==NULL)
  415. {
  416. return(nReturnCode);
  417. }
  418. for (;;e++)
  419. {
  420. if((p=strchr(e,';'))!=NULL)
  421. {
  422. if(p-e > 66)
  423. {
  424. e=p;
  425. continue;
  426. }
  427. }
  428. else if(strlen(e)>66)
  429. {
  430. return( -1 );
  431. }
  432. p=buf;
  433. while(*e && *e!=';') *p++=*e++;
  434. if(p>buf)
  435. {
  436. if(*(p-1)!='\\' && *(p-1)!='/') *p++ = '\\';
  437. strcpy(p,pszPath);
  438. if((nReturnCode=_spawnve(nModeFlag,buf,papszArgs,papszEnviron))!=-1 || errno!=ENOENT)
  439. {
  440. return(nReturnCode);
  441. }
  442. }
  443. if(*e=='\0') return(-1);
  444. }
  445. }
  446. /* ----------------------------------------------------------------------------
  447. * addvect() *** PRIVATE FUNCTION ***
  448. *
  449. * Adds a vector to the vector table.
  450. *
  451. * Parameters: number - The vector number.
  452. *
  453. * opcode - Vector flags.
  454. *
  455. * Return: -1 on failure, or 0 on success.
  456. */
  457. int addvect(int number, int opcode)
  458. {
  459. VECTOR *vect = vectab1;
  460. if ( number < 0 || number > 0xFF ||
  461. ( opcode != IRET && opcode != CURRENT ))
  462. {
  463. errno = EINVAL;
  464. return( -1 );
  465. }
  466. /* see if number is already in table */
  467. while ( vect->flag != 3 && ( vect->flag == 2 ||
  468. vect->number != ( char )number ))
  469. {
  470. vect++;
  471. }
  472. if ( vect->flag == 3 )
  473. {
  474. /* look for a free record */
  475. vect = vectab1;
  476. while ( vect->flag == CURRENT || vect->flag == IRET )
  477. vect++;
  478. }
  479. if ( vect->flag != 3 )
  480. {
  481. vect->number = ( char )number;
  482. vect->flag = ( char )opcode;
  483. if ( opcode == CURRENT )
  484. _getvect( number, &vect->vseg, &vect->voff );
  485. return( 0 );
  486. }
  487. errno = ENOMEM;
  488. return( -1 );
  489. }
  490. /* ----------------------------------------------------------------------------
  491. * savevect() *** PRIVATE FUNCTION ***
  492. *
  493. * Saves current vector in vector table.
  494. *
  495. * Parameters: none
  496. *
  497. * Return: void
  498. */
  499. static void savevect(void)
  500. {
  501. VECTOR *vect1 = vectab1;
  502. VECTOR *vect2 = vectab2;
  503. while ( vect1->flag != 3 )
  504. {
  505. if ( vect1->flag != 2 )
  506. {
  507. vect2->number = vect1->number;
  508. vect2->flag = CURRENT;
  509. _getvect( vect1->number, &vect2->vseg, &vect2->voff );
  510. }
  511. else
  512. vect2->flag = 2; /* free */
  513. vect1++;
  514. vect2++;
  515. }
  516. vect2->flag = 3; /* end */
  517. }
  518. /* ----------------------------------------------------------------------------
  519. * testfile() *** PRIVATE FUNCTION ***
  520. *
  521. * Tests swap file.
  522. *
  523. * Parameters: p - Path.
  524. *
  525. * file - File name.
  526. *
  527. * handle - File handle.
  528. *
  529. * Return: 1 on failure.
  530. */
  531. static int testfile(char *p, char *file, int *handle)
  532. {
  533. unsigned int startno = tempno;
  534. int nDrive = ( *file | 32 ) - 96; /* a = 1, b = 2, etc. */
  535. int root;
  536. unsigned int bytes; /* bytes per cluster */
  537. unsigned int clusters; /* free clusters */
  538. int need; /* clusters needed for swap file */
  539. int nReturnCode; /* return code */
  540. unsigned long dwQuotient;
  541. unsigned long remainder;
  542. if ( file + 2 == p )
  543. {
  544. *p++ = '\\';
  545. if ( _getcd( nDrive, p )) /* get current directory */
  546. return( 1 ); /* invalid drive */
  547. p = file + strlen( file );
  548. }
  549. else
  550. {
  551. *p = '\0';
  552. if ( ODFileAccessMode( file, 0 ))
  553. return( 1 ); /* path does not exist */
  554. }
  555. if ( *( p - 1 ) != '\\' && *( p - 1 ) != '/' )
  556. *p++ = '\\';
  557. if ( p - file == 3 )
  558. root = 1; /* is root directory */
  559. else
  560. root = 0; /* is not root directory */
  561. strcpy( p, "swp" );
  562. p += 3;
  563. if ( _dskspace( nDrive, &bytes, &clusters ) != 0 )
  564. return( 1 ); /* invalid drive */
  565. ODDWordDivide(&dwQuotient, &remainder, swapsize, bytes);
  566. need = (int)dwQuotient;
  567. if ( remainder )
  568. need++;
  569. if ( root == 0 ) /* if subdirectory */
  570. need++; /* in case the directory needs space */
  571. if ( clusters < ( unsigned int )need )
  572. return( 1 ); /* insufficient free disk space */
  573. do
  574. {
  575. again: tempno = ( ++tempno ) ? tempno : 1;
  576. if ( tempno == startno )
  577. return( 1 ); /* extremely unlikely */
  578. ltoa(( long )tempno, p, 10 );
  579. }
  580. while ( !ODFileAccessMode( file, 0 ));
  581. /*
  582. * The return code from _create will equal 80 if the user is running DOS 3.0
  583. * or above and the file was created by another program between the access
  584. * call and the _create call.
  585. */
  586. if (( nReturnCode = _create( file, handle )) == 80 )
  587. goto again;
  588. return( nReturnCode );
  589. }
  590. /* ----------------------------------------------------------------------------
  591. * tempfile() *** PRIVATE FUNCTION ***
  592. *
  593. * Creates a temporary swap file.
  594. *
  595. * Parameters: file - Filename
  596. *
  597. * handle - Handle to file.
  598. *
  599. * Return: 0 on success, or 1 on failure.
  600. */
  601. static int tempfile(char *file, int *handle)
  602. {
  603. char *s = _swappath;
  604. char *p = file;
  605. if ( s )
  606. {
  607. for ( ;; s++ )
  608. {
  609. while ( *s && *s != ';' )
  610. *p++ = *s++;
  611. if ( p > file )
  612. {
  613. if ( p == file + 1 || file[ 1 ] != ':' )
  614. {
  615. memmove( file + 2, file, ( int )( p - file ));
  616. *file = ( char )( _getdrv() + 'a' );
  617. file[ 1 ] = ':';
  618. p += 2;
  619. }
  620. if ( testfile( p, file, handle ) == 0 )
  621. return( 0 );
  622. p = file;
  623. }
  624. if ( *s == '\0' )
  625. break;
  626. }
  627. }
  628. else /* try the current directory */
  629. {
  630. *p++ = ( char )( _getdrv() + 'a' );
  631. *p++ = ':';
  632. if ( testfile( p, file, handle ) == 0 )
  633. return( 0 );
  634. }
  635. errno = EACCES;
  636. return( 1 );
  637. }
  638. /* ----------------------------------------------------------------------------
  639. * cmdenv() *** PRIVATE FUNCTION ***
  640. *
  641. * Constructs environment.
  642. *
  643. * Parameters: papszArgs - Array of arguments.
  644. *
  645. * papszEnviron - Array of environment variables to add.
  646. *
  647. * command - The command specified.
  648. *
  649. * env - Pointer to environment.
  650. *
  651. * memory - Allocated memory.
  652. *
  653. * Return: Environment length.
  654. */
  655. static int cmdenv(char **papszArgs, char **papszEnviron, char *command,
  656. char **env, char **memory)
  657. {
  658. char **vp;
  659. unsigned int elen = 0; /* environment length */
  660. char *p;
  661. int cnt;
  662. int len;
  663. /* construct environment */
  664. if ( papszEnviron == NULL )
  665. {
  666. char far *parent_env;
  667. char far *env_ptr;
  668. int nul_count;
  669. ASM mov ah, 0x62
  670. ASM int 0x21
  671. ASM push es
  672. ASM mov es, bx
  673. ASM mov ax, es:[0x2c]
  674. ASM pop es
  675. ASM mov word ptr parent_env, 0
  676. ASM mov word ptr parent_env + 2, ax
  677. env_ptr = parent_env;
  678. nul_count = 0;
  679. while(nul_count < 2)
  680. {
  681. if(*env_ptr)
  682. {
  683. nul_count = 0;
  684. }
  685. else
  686. {
  687. ++nul_count;
  688. }
  689. ++env_ptr;
  690. ++elen;
  691. }
  692. if ( elen > 32766 ) /* 32K - 2 */
  693. {
  694. errno = E2BIG;
  695. return( -1 );
  696. }
  697. if (( p = malloc(elen + 15 )) == NULL )
  698. {
  699. errno = ENOMEM;
  700. return( -1 );
  701. }
  702. *memory = p;
  703. *( unsigned int * )&p = *( unsigned int * )&p + 15 & ~15;
  704. *env = p;
  705. len = elen;
  706. while(len--)
  707. {
  708. *p++ = *parent_env++;
  709. }
  710. }
  711. else
  712. {
  713. for ( vp = papszEnviron; *vp; vp++ )
  714. {
  715. elen += strlen( *vp ) + 1;
  716. if ( elen > 32766 ) /* 32K - 2 */
  717. {
  718. errno = E2BIG;
  719. return( -1 );
  720. }
  721. }
  722. if (( p = malloc( ++elen + 15 )) == NULL )
  723. {
  724. errno = ENOMEM;
  725. return( -1 );
  726. }
  727. *memory = p;
  728. *( unsigned int * )&p = *( unsigned int * )&p + 15 & ~15;
  729. *env = p;
  730. for ( vp = papszEnviron; *vp; vp++ )
  731. p = strchr( strcpy( p, *vp ), '\0' ) + 1;
  732. *p = '\0'; /* final element */
  733. }
  734. /* construct command-line */
  735. vp = papszArgs;
  736. p = command + 1;
  737. cnt = 0;
  738. if (vp!=NULL && *vp )
  739. {
  740. while ( *++vp )
  741. {
  742. *p++ = ' ';
  743. cnt++;
  744. len = strlen( *vp );
  745. if ( cnt + len > 125 )
  746. {
  747. errno = E2BIG;
  748. free( *memory );
  749. return( -1 );
  750. }
  751. strcpy( p, *vp );
  752. p += len;
  753. cnt += len;
  754. }
  755. }
  756. *p = '\r';
  757. *command = ( char )cnt;
  758. return(( int )elen ); /* return environment length */
  759. }
  760. /* ----------------------------------------------------------------------------
  761. * doxspawn() *** PRIVATE FUNCTION ***
  762. *
  763. * Performs spawn using memory swapping.
  764. *
  765. * Parameters: pszPath - Path to command to exectute.
  766. *
  767. * papszArg - Array of arugments.
  768. *
  769. * papszEnviron - Pointer to the environment.
  770. *
  771. * Return: 0 on success, or -1 on failure.
  772. */
  773. static int doxspawn(char *pszPath, char *papszArgs[], char *papszEnviron[])
  774. {
  775. int nReturnCode = 0; /* assume do xspawn */
  776. int doswap = 0; /* assume do swap */
  777. int elen; /* environment length */
  778. char *memory;
  779. char *env; /* environment */
  780. char command[ 128 ]; /* command-line */
  781. long totalsize; /* parent and free memory in bytes */
  782. int handle;
  783. int pages;
  784. char file[ 79 ];
  785. char *mapbuf = NULL; /* buffer for map information */
  786. /* construct the command-line and the environment */
  787. if (( elen = cmdenv( papszArgs, papszEnviron, command, &env, &memory )) == -1 )
  788. return( -1 );
  789. if ( _swap == 0 )
  790. {
  791. if ( _useems == 0 )
  792. {
  793. if ( ems == 2 )
  794. ems = _chkems( "EMMXXXX0", &mapsize );
  795. if ( ems == 0 && ( mapbuf = malloc( mapsize )) == NULL )
  796. {
  797. errno = ENOMEM;
  798. free( memory );
  799. return( -1 );
  800. }
  801. }
  802. if (( nReturnCode = _xsize( _psp, &swapsize, &totalsize )) == 0 )
  803. {
  804. if ( _required == 0 || totalsize - swapsize - 272
  805. < (long)ODDWordShiftLeft(( long )_required , 10 ))
  806. {
  807. if ( ems == 0 && _useems == 0 )
  808. {
  809. pages = ( int )ODDWordShiftRight( swapsize , 14);
  810. if ((long)ODDWordShiftLeft(( long )pages , 14 ) < swapsize )
  811. pages++;
  812. if ( _savemap( mapbuf ) == 0 &&
  813. _getems( pages, &handle ) == 0 )
  814. *file = '\0'; /* use EMS */
  815. else if ( tempfile( file, &handle ) != 0 )
  816. nReturnCode = -1; /* don't do xspawn */
  817. }
  818. else if ( tempfile( file, &handle ) != 0 )
  819. nReturnCode = -1; /* don't do xspawn */
  820. }
  821. else
  822. doswap = 1; /* don't do swap */
  823. }
  824. else
  825. {
  826. errno = errtab[ nReturnCode ];
  827. nReturnCode = -1; /* don't do xspawn */
  828. }
  829. }
  830. else
  831. doswap = 1; /* don't do swap */
  832. if ( nReturnCode == 0 )
  833. {
  834. savevect(); /* save current vectors */
  835. nReturnCode = _xspawn( pszPath, command, env, vectab1, doswap, elen, file,
  836. handle );
  837. _setvect( vectab2 ); /* restore saved vectors */
  838. if ( nReturnCode == 0 )
  839. nReturnCode = _getrc(); /* get child return code */
  840. else
  841. {
  842. errno = errtab[ nReturnCode ];
  843. nReturnCode = -1;
  844. }
  845. /*
  846. * If EMS was used, restore the page-mapping state of the expanded
  847. * memory hardware.
  848. */
  849. if ( doswap == 0 && *file == '\0' && _restmap( mapbuf ) != 0 )
  850. {
  851. errno = EACCES;
  852. nReturnCode = -1;
  853. }
  854. }
  855. if ( mapbuf )
  856. free( mapbuf );
  857. free( memory );
  858. return( nReturnCode );
  859. }
  860. /* ----------------------------------------------------------------------------
  861. * _spawnve() *** PRIVATE FUNCTION ***
  862. *
  863. * Performs a spawn.
  864. *
  865. * Parameters: nModeFlag - Must be P_WAIT
  866. *
  867. * pszPath - Command to execute.
  868. *
  869. * papszArgs - Command line arguments.
  870. *
  871. * papszEnviron - Pointer to environment.
  872. *
  873. * Return: void
  874. */
  875. int _spawnve(int nModeFlag, char *pszPath, char *papszArgs[],
  876. char * papszEnviron[])
  877. {
  878. char *p;
  879. char *s;
  880. int nReturnCode = -1;
  881. char buf[ 80 ];
  882. if ( nModeFlag != P_WAIT )
  883. {
  884. errno = EINVAL;
  885. return( -1 );
  886. }
  887. p = strrchr( pszPath, '\\' );
  888. s = strrchr( pszPath, '/' );
  889. if ( p == NULL && s == NULL )
  890. p = pszPath;
  891. else if ( p == NULL || s > p )
  892. p = s;
  893. if ( strchr( p, '.' ))
  894. {
  895. if ( !ODFileAccessMode( pszPath, 0 ))
  896. nReturnCode = doxspawn( pszPath, papszArgs, papszEnviron );
  897. /* If file not found, access will have set errno to ENOENT. */
  898. }
  899. else
  900. {
  901. strcpy( buf, pszPath );
  902. strcat( buf, ".com" );
  903. if ( !ODFileAccessMode( buf, 0 ))
  904. nReturnCode = doxspawn( buf, papszArgs, papszEnviron );
  905. else
  906. {
  907. strcpy( strrchr( buf, '.' ), ".exe" );
  908. if ( !ODFileAccessMode( buf, 0 ))
  909. nReturnCode = doxspawn( buf, papszArgs, papszEnviron );
  910. /* If file not found, access will have set errno to ENOENT. */
  911. }
  912. }
  913. return( nReturnCode );
  914. }
  915. #endif /* ODPLAT_DOS */
  916. #ifdef ODPLAT_NIX
  917. /* ----------------------------------------------------------------------------
  918. * _spawnvpe() *** PRIVATE FUNCTION ***
  919. *
  920. * Executes a child program in the *nix environment.
  921. *
  922. * Parameters: nModeFlag - Must be P_WAIT or P_NOWAIT
  923. *
  924. * pszPath - Name of program to execute.
  925. *
  926. * papszArgs - Array of command-line arguments.
  927. *
  928. * papszEnviron - Array of environment variables.
  929. *
  930. * Return: -1 on failure or the spawned-to program's return value on
  931. * success.
  932. */
  933. int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[],
  934. char *papszEnviron[])
  935. {
  936. pid_t child;
  937. int status;
  938. pid_t wret;
  939. struct sigaction act;
  940. child=fork();
  941. if(nModeFlag == P_WAIT) {
  942. /* require wait for child */
  943. act.sa_handler=SIG_IGN;
  944. sigemptyset(&(act.sa_mask));
  945. act.sa_flags=SA_NOCLDSTOP;
  946. sigaction(SIGCHLD,&act,NULL);
  947. }
  948. else {
  949. /* Ignore SIGCHLD for backgrounded spawned processes */
  950. act.sa_handler=SIG_IGN;
  951. sigemptyset(&(act.sa_mask));
  952. act.sa_flags=SA_NOCLDSTOP|SA_NOCLDWAIT;
  953. sigaction(SIGCHLD,&act,NULL);
  954. }
  955. if(!child) {
  956. /* Do the exec stuff here */
  957. execve(pszPath,papszArgs,papszEnviron);
  958. exit(-1); /* this should never happen! */
  959. }
  960. if(nModeFlag == P_WAIT) {
  961. wret=waitpid(child,&status,0);
  962. if(WIFEXITED(status)) {
  963. return(WEXITSTATUS(status));
  964. }
  965. return(-1);
  966. }
  967. return(0);
  968. }
  969. #endif /* ODPLAT_NIX */