summaryrefslogtreecommitdiffstats
path: root/private/crt32/exec/spawnvpe.c
blob: ffbdbb55a497b72c360e1dd163086589821c75d3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/***
*spawnvpe.c - spawn a child process with given environ (search PATH)
*
*	Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved.
*
*Purpose:
*	defines _spawnvpe() - spawn a child process with given environ (search
*	PATH)
*
*Revision History:
*	04-15-84  DFW	written
*	10-29-85  TC	added spawnvpe capability
*	11-19-86  SKS	handle both kinds of slashes
*	12-01-86  JMB	added Kanji file name support under conditional KANJI
*			switches.  Corrected header info.  Removed bogus check
*			for env = b after call to strncpy
*	12-11-87  JCR	Added "_LOAD_DS" to declaration
*	09-05-88  SKS	Treat EACCES the same as ENOENT -- keep trying
*	10-17-88  GJF	Removed copy of PATH string to local array, changed
*			bbuf to be a malloc-ed buffer. Removed bogus limits
*			on the size of that PATH string.
*	10-25-88  GJF	Don't search PATH when relative pathname is given (per
*			Stevesa). Also, if the name built from PATH component
*			and filename is a UNC name, allow any error.
*	05-17-89  MT	Added "include <jstring.h>" under KANJI switch
*	05-24-89  PHG	Reduce _amblksiz to use minimal memory (DOS only)
*	08-29-89  GJF	Use _getpath() to retrieve PATH components, fixing
*			several problems in handling unusual or bizarre
*			PATH's.
*	11-20-89  GJF	Added const attribute to types of filename, argv and
*			envptr.
*	03-08-90  GJF	Replaced _LOAD_DS with _CALLTYPE1, added #include
*			<cruntime.h> and removed #include <register.h>
*	07-24-90  SBM	Removed redundant includes, replaced <assertm.h> by
*			<assert.h>
*	09-27-90  GJF	New-style function declarator.
*	01-17-91  GJF	ANSI naming.
*	09-25-91  JCR	Changed ifdef "OS2" to "_DOS_" (unused in 32-bit tree)
*	11-30-92  KRS	Port _MBCS code from 16-bit tree.
*
*******************************************************************************/

#include <cruntime.h>
#include <errno.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <internal.h>
#include <process.h>
#include <mbstring.h>

#define SLASH "\\"
#define SLASHCHAR '\\'
#define XSLASHCHAR '/'
#define DELIMITER ";"

#ifdef _MBCS
/* note, the macro below assumes p is to pointer to a single-byte character
 * or the 1st byte of a double-byte character, in a string.
 */
#define ISPSLASH(p)	( ((p) == _mbschr((p), SLASHCHAR)) || ((p) == \
_mbschr((p), XSLASHCHAR)) )
#else
#define ISSLASH(c)	( ((c) == SLASHCHAR) || ((c) == XSLASHCHAR) )
#endif

/***
*_spawnvpe(modeflag, filename, argv, envptr) - spawn a child process
*
*Purpose:
*	Spawns a child process with the given arguments and environ,
*	searches along PATH for given file until found.
*	Formats the parameters and calls _spawnve to do the actual work. The
*	NULL environment pointer indicates that the new process will inherit
*	the parents process's environment.  NOTE - at least one argument must
*	be present.  This argument is always, by convention, the name of the
*	file being spawned.
*
*Entry:
*	int modeflag - defines mode of spawn (WAIT, NOWAIT, or OVERLAY)
*			only WAIT and OVERLAY supported
*	char *filename - name of file to execute
*	char **argv - vector of parameters
*	char **envptr - vector of environment variables
*
*Exit:
*	returns exit code of spawned process
*	if fails, returns -1
*
*Exceptions:
*
*******************************************************************************/

int _CALLTYPE1 _spawnvpe (
	int modeflag,
	REG3 const char *filename,
	const char * const *argv,
	const char * const *envptr
	)
{
	int i;
	REG1 char *env;
	REG2 char *buf = NULL;
	char *pfin;
#ifdef _DOS_
	int tempamblksiz;	   /* old _amblksiz */
#endif
	assert(filename != NULL);
	assert(*filename != '\0');
	assert(argv != NULL);
	assert(*argv != NULL);
	assert(**argv != '\0');

#ifdef _DOS_
	tempamblksiz = _amblksiz;
	_amblksiz = 0x10;	    /* reduce _amblksiz for efficient mallocs */
#endif

	if (
	(i = _spawnve(modeflag, filename, argv, envptr)) != -1
		/* everything worked just fine; return i */

	|| (errno != ENOENT)
		/* couldn't spawn the process, return failure */

	/* In a SBCS build, _mbschr will map to strchr. */

	|| (_mbschr(filename, XSLASHCHAR) != NULL)
		/* filename contains a '/', return failure */

#ifdef _DOS_
	|| (_mbschr(filename,SLASHCHAR) != NULL)
		/* filename contains a '\', return failure */

	|| *filename && *(filename+1) == ':'
		/* drive specification, return failure */
#endif

	|| !(env = getenv("PATH"))
		/* no PATH environment string name, return failure */

	|| ( (buf = (char *)malloc(_MAX_PATH)) == NULL )
		/* cannot allocate buffer to build alternate pathnames, return
		 * failure */
	) {
#ifdef _DOS_
		_amblksiz = tempamblksiz;	/* restore old _amblksiz */
#endif
		goto done;
	}

#ifdef _DOS_
	_amblksiz = tempamblksiz;		/* restore old _amblksiz */
#endif


	/* could not find the file as specified, search PATH. try each
	 * component of the PATH until we get either no error return, or the
	 * error is not ENOENT and the component is not a UNC name, or we run
	 * out of components to try.
	 */

	while ( (env = _getpath(env, buf, _MAX_PATH - 1)) && (*buf) ) {

		pfin = buf + strlen(buf) - 1;

		/* if necessary, append a '/'
		 */
#ifdef _MBCS
		if (*pfin == SLASHCHAR) {
			if (pfin != _mbsrchr(buf,SLASHCHAR))
			/* fin is the second byte of a double-byte char */
				strcat(buf, SLASH );
		}
		else if (*pfin !=XSLASHCHAR)
			strcat(buf, SLASH);
#else
		if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR)
			strcat(buf, SLASH);
#endif
		/* check that the final path will be of legal size. if so,
		 * build it. otherwise, return to the caller (return value
		 * and errno rename set from initial call to _spawnve()).
		 */
		if ( (strlen(buf) + strlen(filename)) < _MAX_PATH )
			strcat(buf, filename);
		else
			break;

		/* try spawning it. if successful, or if errno comes back with a
		 * value other than ENOENT and the pathname is not a UNC name,
		 * return to the caller.
		 */
		if ( (i = _spawnve(modeflag, buf, argv, envptr)) != -1
			|| ((errno != ENOENT)
#ifdef _MBCS
				&& (!ISPSLASH(buf) || !ISPSLASH(buf+1))) )
#else
				&& (!ISSLASH(*buf) || !ISSLASH(*(buf+1)))) )
#endif
			break;

	}

done:
	if (buf != NULL) free(buf);
	return(i);
}