home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / spawnve.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  11KB  |  314 lines

  1. /***
  2. *spawnve.c - Low level routine eventually called by all _spawnXX routines
  3. *       also contains all code for _execve, called by _execXX routines
  4. *
  5. *       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  6. *
  7. *Purpose:
  8. *
  9. *       This is the low level routine which is eventually invoked by all the
  10. *       _spawnXX routines.
  11. *
  12. *       This is also the low-level routine which is eventually invoked by
  13. *       all of the _execXX routines.
  14. *
  15. *******************************************************************************/
  16.  
  17. #include <cruntime.h>
  18. #include <io.h>
  19. #include <process.h>
  20. #include <errno.h>
  21. #include <msdos.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <internal.h>
  25. #include <mbstring.h>
  26. #include <tchar.h>
  27. #include <dbgint.h>
  28.  
  29. #define SLASHCHAR   _T('\\')
  30. #define XSLASHCHAR  _T('/')
  31.  
  32. #ifndef EXECVE
  33. #ifdef WPRFLAG
  34. static int __cdecl wcomexecmd(int mode, const wchar_t * name,
  35.         const wchar_t * const * argv, const wchar_t * const * envp);
  36. #else  /* WPRFLAG */
  37. static int __cdecl comexecmd(int mode, const char * name,
  38.         const char * const * argv, const char * const * envp);
  39. #endif  /* WPRFLAG */
  40. #else  /* EXECVE */
  41. #ifdef WPRFLAG
  42. static int __cdecl wcomexecmd(const wchar_t * name,
  43.         const wchar_t * const * argv, const wchar_t * const * envp);
  44. #else  /* WPRFLAG */
  45. static int __cdecl comexecmd(const char * name,
  46.         const char * const * argv, const char * const * envp);
  47. #endif  /* WPRFLAG */
  48. #endif  /* EXECVE */
  49.  
  50. /***
  51. *static int comexecmd(mode, name, argv, envp) - do the exec
  52. *       or spawn after name fixup
  53. *
  54. *Purpose:
  55. *       Spawns a child process with given parameters and environment.  Either
  56. *       overlays current process or loads in free memory while parent process
  57. *       waits.  If the named file is a .cmd file, modifies the calling sequence
  58. *       and prepends the /c and filename arguments into the command string
  59. *
  60. *       Exec doesn't take a mode; instead, the parent process goes away as
  61. *       the child process is brought in.
  62. *
  63. *Entry:
  64. *       int mode - mode to spawn (WAIT, NOWAIT, or OVERLAY)
  65. *                   only WAIT and OVERLAY currently supported
  66. *
  67. *           ****  mode is only used in the spawnve() version  ****
  68. *
  69. *       _TSCHAR *name - pathname of file to spawn.  Includes the extension
  70. *       _TSCHAR **argv - vector of parameter strings
  71. *       _TSCHAR **envp - vector of environment variables
  72. *
  73. *Exit:
  74. *       returns exit code of child process
  75. *       if fails, returns -1
  76. *
  77. *Exceptions:
  78. *       Returns a value of (-1) to indicate an error in exec'ing the child
  79. *       process.  errno may be set to:
  80. *
  81. *       E2BIG   = failed in argument/environment processing (_cenvarg)
  82. *                 argument list or environment too big;
  83. *       EACCESS = locking or sharing violation on file;
  84. *       EMFILE  = too many files open;
  85. *       ENOENT  = failed to find program name - no such file or directory;
  86. *       ENOEXEC = failed in exec - bad executable format;
  87. *       ENOMEM  = failed in memory allocation (during malloc, or in
  88. *                 setting up memory for executing child process).
  89. *
  90. *******************************************************************************/
  91.  
  92. #ifdef WPRFLAG
  93. static int __cdecl wcomexecmd (
  94. #else  /* WPRFLAG */
  95. static int __cdecl comexecmd (
  96. #endif  /* WPRFLAG */
  97.  
  98. #ifndef EXECVE
  99.         REG3 int mode,
  100. #endif  /* EXECVE */
  101.  
  102.         REG2 const _TSCHAR *name,
  103.         const _TSCHAR * const *argv,
  104.         const _TSCHAR * const *envp
  105.         )
  106. {
  107.         _TSCHAR *argblk;
  108.         _TSCHAR *envblk;
  109.         REG4 int rc;
  110.  
  111. #ifdef WPRFLAG
  112.         if (_wcenvarg(argv, envp, &argblk, &envblk, name) == -1)
  113. #else  /* WPRFLAG */
  114.         if (_cenvarg(argv, envp, &argblk, &envblk, name) == -1)
  115. #endif  /* WPRFLAG */
  116.                 return -1;
  117.  
  118. #ifndef EXECVE
  119. #ifdef WPRFLAG
  120.         rc = _wdospawn(mode, name, argblk, envblk);
  121. #else  /* WPRFLAG */
  122.         rc = _dospawn(mode, name, argblk, envblk);
  123. #endif  /* WPRFLAG */
  124. #else  /* EXECVE */
  125. #ifdef WPRFLAG
  126.         rc = _wdospawn(_P_OVERLAY, name, argblk, envblk);
  127. #else  /* WPRFLAG */
  128.         rc = _dospawn(_P_OVERLAY, name, argblk, envblk);
  129. #endif  /* WPRFLAG */
  130. #endif  /* EXECVE */
  131.         /* free memory */
  132.  
  133.         _free_crt(argblk);
  134.         _free_crt(envblk);
  135.  
  136.         return rc;
  137. }
  138.  
  139. /***
  140. *int _spawnve(mode, name, argv, envp) - low level _spawnXX library function
  141. *int _execve(name, argv, envp) - low level _execXX library function
  142. *
  143. *Purpose:
  144. *       spawns or execs a child process; takes a single pointer to an argument
  145. *       list as well as a pointer to the environment; unlike _spawnvpe,
  146. *       _spawnve does not search the PATH= list in processing the name
  147. *       parameter; mode specifies the parent's execution mode.
  148. *
  149. *Entry:
  150. *       int mode    - parent process's execution mode:
  151. *                     must be one of _P_OVERLAY, _P_WAIT, _P_NOWAIT;
  152. *                     not used for _execve
  153. *       _TSCHAR *name  - path name of program to spawn;
  154. *       _TSCHAR **argv - pointer to array of pointers to child's arguments;
  155. *       _TSCHAR **envp - pointer to array of pointers to child's environment
  156. *                     settings.
  157. *
  158. *Exit:
  159. *       Returns : (int) a status value whose meaning is as follows:
  160. *               0        = normal termination of child process;
  161. *               positive = exit code of child upon error termination
  162. *                          (abort or exit(nonzero));
  163. *               -1       = child process was not spawned;
  164. *                          errno indicates what kind of error:
  165. *                          (E2BIG, EINVAL, ENOENT, ENOEXEC, ENOMEM).
  166. *
  167. *Exceptions:
  168. *       Returns a value of (-1) to indicate an error in spawning the child
  169. *       process.  errno may be set to:
  170. *
  171. *       E2BIG   = failed in argument/environment processing (_cenvarg) -
  172. *                 argument list or environment too big;
  173. *       EINVAL  = invalid mode argument;
  174. *       ENOENT  = failed to find program name - no such file or directory;
  175. *       ENOEXEC = failed in spawn - bad executable format;
  176. *       ENOMEM  = failed in memory allocation (during malloc, or in
  177. *                 setting up memory for spawning child process).
  178. *
  179. *******************************************************************************/
  180.  
  181. /* Extension array - ordered in search order from right to left.
  182.  
  183.    ext_strings  = array of extensions
  184. */
  185.  
  186. static _TSCHAR *ext_strings[] = { _T(".cmd"), _T(".bat"), _T(".exe"), _T(".com") };
  187. enum {CMD, BAT, EXE, COM, EXTFIRST=CMD, EXTLAST=COM};
  188.  
  189. int __cdecl
  190.  
  191. #ifndef EXECVE
  192.  
  193. _tspawnve (
  194.         REG3 int mode,
  195.  
  196. #else  /* EXECVE */
  197.  
  198. _texecve (
  199.  
  200. #endif  /* EXECVE */
  201.  
  202.         const _TSCHAR *name,
  203.         const _TSCHAR * const *argv,
  204.         const _TSCHAR * const *envp
  205.         )
  206. {
  207.         _TSCHAR *ext;   /* where the extension goes if we have to add one */
  208.         REG1 _TSCHAR *p;
  209.         _TSCHAR *q;
  210.         REG2 _TSCHAR *pathname = (_TSCHAR *)name;
  211.         REG4 int rc;
  212.         REG5 int i;
  213.  
  214.         p = _tcsrchr(pathname, SLASHCHAR);
  215.         q = _tcsrchr(pathname, XSLASHCHAR);
  216.  
  217.         /* ensure that pathname is an absolute or relative pathname. also,
  218.          * position p to point at the filename portion of pathname (i.e., just
  219.          * after the last occurence of a colon, slash or backslash character */
  220.  
  221.         if (!q) {
  222.                 if (!p)
  223.                         if (!(p = _tcschr(pathname, _T(':')))) {
  224.  
  225.                                 /* pathname is a filename only, force it to be
  226.                                  * a relative pathname. note that an extra byte
  227.                                  * is malloc-ed just in case pathname is NULL,
  228.                                  * to keep the heap from being trashed by
  229.                                  * strcpy */
  230.                                 if (!(pathname = _malloc_crt((_tcslen(pathname) + 3) * sizeof(_TSCHAR))))
  231.                                         return(-1);
  232.  
  233.                                 _tcscpy(pathname, _T(".\\"));
  234.                                 _tcscat(pathname, name);
  235.  
  236.                                 /* set p to point to the start of the filename
  237.                                  * (i.e., past the ".\\" prefix) */
  238.                                 p = pathname + 2;
  239.                         }
  240.                         /* else pathname has drive specifier prefix and p is
  241.                          * is pointing to the ':' */
  242.         }
  243.         else if (!p || q > p)   /* p == NULL or q > p */
  244.                 p = q;
  245.  
  246.  
  247.         rc = -1;        /* init to error value */
  248.  
  249.         if (ext = _tcsrchr(p, _T('.')))  {
  250.  
  251.                 /* extension given; only do filename */
  252.  
  253.                 if (_taccess(pathname, 0) != -1) {
  254.  
  255. #ifndef EXECVE
  256.  
  257. #ifdef WPRFLAG
  258.                         rc = wcomexecmd(mode, pathname, argv, envp);
  259. #else  /* WPRFLAG */
  260.                         rc = comexecmd(mode, pathname, argv, envp);
  261. #endif  /* WPRFLAG */
  262.  
  263. #else  /* EXECVE */
  264.  
  265. #ifdef WPRFLAG
  266.                         rc = wcomexecmd(pathname, argv, envp);
  267. #else  /* WPRFLAG */
  268.                         rc = comexecmd(pathname, argv, envp);
  269. #endif  /* WPRFLAG */
  270.  
  271. #endif  /* EXECVE */
  272.                 }
  273.  
  274.         }
  275.         else    {
  276.  
  277.                 /* no extension; try .cmd/.bat, then .com and .exe */
  278.  
  279.                 if (!(p = _malloc_crt((_tcslen(pathname) + 5) * sizeof(_TSCHAR))))
  280.                         return(-1);
  281.  
  282.                 _tcscpy(p, pathname);
  283.                 ext = p + _tcslen(pathname);
  284.  
  285.                 for (i = EXTLAST; i >= EXTFIRST; --i) {
  286.                         _tcscpy(ext, ext_strings[i]);
  287.  
  288.                         if (_taccess(p, 0) != -1) {
  289.  
  290. #ifndef EXECVE
  291. #ifdef WPRFLAG
  292.                                 rc = wcomexecmd(mode, p, argv, envp);
  293. #else  /* WPRFLAG */
  294.                                 rc = comexecmd(mode, p, argv, envp);
  295. #endif  /* WPRFLAG */
  296. #else  /* EXECVE */
  297. #ifdef WPRFLAG
  298.                                 rc = wcomexecmd(p, argv, envp);
  299. #else  /* WPRFLAG */
  300.                                 rc = comexecmd(p, argv, envp);
  301. #endif  /* WPRFLAG */
  302. #endif  /* EXECVE */
  303.                                 break;
  304.                         }
  305.                 }
  306.                 _free_crt(p);
  307.         }
  308.  
  309.         if (pathname != name)
  310.                 _free_crt(pathname);
  311.  
  312.         return rc;
  313. }
  314.