xref: /onnv-gate/usr/src/lib/libast/common/comp/omitted.c (revision 4887:feebf9260c2e)
1*4887Schin #pragma prototyped noticed
2*4887Schin 
3*4887Schin /*
4*4887Schin  * workarounds to bring the native interface close to posix and x/open
5*4887Schin  */
6*4887Schin 
7*4887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide)
8*4887Schin __STDPP__directive pragma pp:hide utime utimes
9*4887Schin #else
10*4887Schin #define utime		______utime
11*4887Schin #define utimes		______utimes
12*4887Schin #endif
13*4887Schin 
14*4887Schin #include <ast.h>
15*4887Schin #include <error.h>
16*4887Schin #include <tm.h>
17*4887Schin 
18*4887Schin #include "FEATURE/omitted"
19*4887Schin 
20*4887Schin #undef	OMITTED
21*4887Schin 
22*4887Schin #if _win32_botch
23*4887Schin 
24*4887Schin #define	OMITTED	1
25*4887Schin 
26*4887Schin #include <ls.h>
27*4887Schin #include <utime.h>
28*4887Schin 
29*4887Schin #if __CYGWIN__
30*4887Schin #include <ast_windows.h>
31*4887Schin #if _win32_botch_execve || _lib_spawn_mode
32*4887Schin #define CONVERT		1
33*4887Schin #endif
34*4887Schin #endif
35*4887Schin 
36*4887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide)
37*4887Schin __STDPP__directive pragma pp:nohide utime utimes
38*4887Schin #else
39*4887Schin #undef	utime
40*4887Schin #undef	utimes
41*4887Schin #endif
42*4887Schin 
43*4887Schin #ifndef MAX_PATH
44*4887Schin #define MAX_PATH	PATH_MAX
45*4887Schin #endif
46*4887Schin 
47*4887Schin /*
48*4887Schin  * these workarounds assume each system call foo() has a _foo() entry
49*4887Schin  * which is true for __CYGWIN__ and __EMX__ (both gnu based)
50*4887Schin  *
51*4887Schin  * the workarounds handle:
52*4887Schin  *
53*4887Schin  *	(1) .exe suffix inconsistencies
54*4887Schin  *	(2) /bin/sh reference in execve() and spawnve()
55*4887Schin  *	(3) bogus getpagesize() return values
56*4887Schin  *	(4) a fork() bug that screws up shell fork()+script
57*4887Schin  *
58*4887Schin  * NOTE: Not all workarounds can be handled by unix syscall intercepts.
59*4887Schin  *	 In particular, { ksh nmake } have workarounds for case-ignorant
60*4887Schin  *	 filesystems and { libast } has workarounds for win32 locale info.
61*4887Schin  */
62*4887Schin 
63*4887Schin #undef _pathconf
64*4887Schin #undef pathconf
65*4887Schin #undef stat
66*4887Schin 
67*4887Schin extern int		_access(const char*, int);
68*4887Schin extern unsigned int	_alarm(unsigned int);
69*4887Schin extern int		_chmod(const char*, mode_t);
70*4887Schin extern int		_close(int);
71*4887Schin extern pid_t		_execve(const char*, char* const*, char* const*);
72*4887Schin extern int		_link(const char*, const char*);
73*4887Schin extern int		_open(const char*, int, ...);
74*4887Schin extern long		_pathconf(const char*, int);
75*4887Schin extern ssize_t		_read(int, void*, size_t);
76*4887Schin extern int		_rename(const char*, const char*);
77*4887Schin extern pid_t		_spawnve(int, const char*, char* const*, char* const*);
78*4887Schin extern int		_stat(const char*, struct stat*);
79*4887Schin extern int		_unlink(const char*);
80*4887Schin extern int		_utime(const char*, const struct utimbuf*);
81*4887Schin extern int		_utimes(const char*, const struct timeval*);
82*4887Schin extern ssize_t		_write(int, const void*, size_t);
83*4887Schin 
84*4887Schin #if defined(__EXPORT__)
85*4887Schin #define extern	__EXPORT__
86*4887Schin #endif
87*4887Schin 
88*4887Schin static char*
suffix(register const char * path)89*4887Schin suffix(register const char* path)
90*4887Schin {
91*4887Schin 	register const char*	s = path + strlen(path);
92*4887Schin 	register int		c;
93*4887Schin 
94*4887Schin 	while (s > path)
95*4887Schin 		if ((c = *--s) == '.')
96*4887Schin 			return (char*)s + 1;
97*4887Schin 		else if (c == '/' || c == '\\')
98*4887Schin 			break;
99*4887Schin 	return 0;
100*4887Schin }
101*4887Schin 
102*4887Schin static int
execrate(const char * path,char * buf,int size,int physical)103*4887Schin execrate(const char* path, char* buf, int size, int physical)
104*4887Schin {
105*4887Schin 	char*	s;
106*4887Schin 	int	n;
107*4887Schin 	int	oerrno;
108*4887Schin 
109*4887Schin 	if (suffix(path))
110*4887Schin 		return 0;
111*4887Schin 	oerrno = errno;
112*4887Schin 	if (physical || strlen(path) >= size || !(s = pathcanon(strcpy(buf, path), PATH_PHYSICAL|PATH_DOTDOT|PATH_EXISTS)))
113*4887Schin 		snprintf(buf, size, "%s.exe", path);
114*4887Schin 	else if (!suffix(buf) && ((buf + size) - s) >= 4)
115*4887Schin 		strcpy(s, ".exe");
116*4887Schin 	errno = oerrno;
117*4887Schin 	return 1;
118*4887Schin }
119*4887Schin 
120*4887Schin /*
121*4887Schin  * return 0 if path is magic, -1 otherwise
122*4887Schin  * ux!=0 set to 1 if path is unix executable
123*4887Schin  * ux!=0 also retains errno for -1 return
124*4887Schin  */
125*4887Schin 
126*4887Schin static int
magic(const char * path,int * ux)127*4887Schin magic(const char* path, int* ux)
128*4887Schin {
129*4887Schin 	int		fd;
130*4887Schin 	int		r;
131*4887Schin 	int		n;
132*4887Schin 	int		m;
133*4887Schin 	int		oerrno;
134*4887Schin #if CONVERT
135*4887Schin 	unsigned char	buf[512];
136*4887Schin #else
137*4887Schin 	unsigned char	buf[2];
138*4887Schin #endif
139*4887Schin 
140*4887Schin 	oerrno = errno;
141*4887Schin 	if ((fd = _open(path, O_RDONLY, 0)) >= 0)
142*4887Schin 	{
143*4887Schin #if CONVERT
144*4887Schin 		if (ux)
145*4887Schin 			n = sizeof(buf);
146*4887Schin 		else
147*4887Schin #endif
148*4887Schin 			n = 2;
149*4887Schin 		r = (m = _read(fd, buf, n)) >= 2 && (buf[1] == 0x5a && (buf[0] == 0x4c || buf[0] == 0x4d) || ux && buf[0] == '#' && buf[1] == '!' && (*ux = 1) && !(ux = 0)) ? 0 : -1;
150*4887Schin 		close(fd);
151*4887Schin 		if (ux)
152*4887Schin 		{
153*4887Schin 			if (r)
154*4887Schin 				oerrno = ENOEXEC;
155*4887Schin 			else if (m > 61 && (n = buf[60] | (buf[61]<<8) + 92) < (m - 1))
156*4887Schin 				*ux = (buf[n] | (buf[n+1]<<8)) == 3;
157*4887Schin 			else
158*4887Schin 				*ux = 0;
159*4887Schin 		}
160*4887Schin 	}
161*4887Schin 	else if (!ux)
162*4887Schin 		r = -1;
163*4887Schin 	else if (errno == ENOENT)
164*4887Schin 	{
165*4887Schin 		oerrno = errno;
166*4887Schin 		r = -1;
167*4887Schin 	}
168*4887Schin 	else
169*4887Schin 	{
170*4887Schin 		r = 0;
171*4887Schin 		*ux = 0;
172*4887Schin 	}
173*4887Schin 	errno = oerrno;
174*4887Schin 	return r;
175*4887Schin }
176*4887Schin 
177*4887Schin #if _win32_botch_access
178*4887Schin 
179*4887Schin extern int
access(const char * path,int op)180*4887Schin access(const char* path, int op)
181*4887Schin {
182*4887Schin 	int	r;
183*4887Schin 	int	oerrno;
184*4887Schin 	char	buf[PATH_MAX];
185*4887Schin 
186*4887Schin 	oerrno = errno;
187*4887Schin 	if ((r = _access(path, op)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
188*4887Schin 	{
189*4887Schin 		errno = oerrno;
190*4887Schin 		r = _access(buf, op);
191*4887Schin 	}
192*4887Schin 	return r;
193*4887Schin }
194*4887Schin 
195*4887Schin #endif
196*4887Schin 
197*4887Schin #if _win32_botch_alarm
198*4887Schin 
199*4887Schin extern unsigned int
alarm(unsigned int s)200*4887Schin alarm(unsigned int s)
201*4887Schin {
202*4887Schin 	unsigned int		n;
203*4887Schin 	unsigned int		r;
204*4887Schin 
205*4887Schin 	static unsigned int	a;
206*4887Schin 
207*4887Schin 	n = (unsigned int)time(NiL);
208*4887Schin 	if (a <= n)
209*4887Schin 		r = 0;
210*4887Schin 	else
211*4887Schin 		r = a - n;
212*4887Schin 	a = n + s - 1;
213*4887Schin 	(void)_alarm(s);
214*4887Schin 	return r;
215*4887Schin }
216*4887Schin 
217*4887Schin #endif
218*4887Schin 
219*4887Schin #if _win32_botch_chmod
220*4887Schin 
221*4887Schin extern int
chmod(const char * path,mode_t mode)222*4887Schin chmod(const char* path, mode_t mode)
223*4887Schin {
224*4887Schin 	int	r;
225*4887Schin 	int	oerrno;
226*4887Schin 	char	buf[PATH_MAX];
227*4887Schin 
228*4887Schin 	if ((r = _chmod(path, mode)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
229*4887Schin 	{
230*4887Schin 		errno = oerrno;
231*4887Schin 		return _chmod(buf, mode);
232*4887Schin 	}
233*4887Schin 	if (!(r = _chmod(path, mode)) &&
234*4887Schin 	    (mode & (S_IXUSR|S_IXGRP|S_IXOTH)) &&
235*4887Schin 	    !suffix(path) &&
236*4887Schin 	    (strlen(path) + 4) < sizeof(buf))
237*4887Schin 	{
238*4887Schin 		oerrno = errno;
239*4887Schin 		if (!magic(path, NiL))
240*4887Schin 		{
241*4887Schin 			snprintf(buf, sizeof(buf), "%s.exe", path);
242*4887Schin 			_rename(path, buf);
243*4887Schin 		}
244*4887Schin 		errno = oerrno;
245*4887Schin 	}
246*4887Schin 	return r;
247*4887Schin }
248*4887Schin 
249*4887Schin #endif
250*4887Schin 
251*4887Schin #if _win32_botch_execve || _lib_spawn_mode
252*4887Schin 
253*4887Schin #if _lib_spawn_mode
254*4887Schin 
255*4887Schin /*
256*4887Schin  * can anyone get const prototype args straight?
257*4887Schin  */
258*4887Schin 
259*4887Schin #define execve		______execve
260*4887Schin #define spawnve		______spawnve
261*4887Schin 
262*4887Schin #include <process.h>
263*4887Schin 
264*4887Schin #undef	execve
265*4887Schin #undef	spawnve
266*4887Schin 
267*4887Schin #endif
268*4887Schin 
269*4887Schin #if CONVERT
270*4887Schin 
271*4887Schin /*
272*4887Schin  * this intercept converts dos env vars to unix
273*4887Schin  * we'd rather intercept main but can't twist cc to do it
274*4887Schin  * getuid() gets ksh to do the right thing and
275*4887Schin  * that's our main concern
276*4887Schin  *
277*4887Schin  *	DOSPATHVARS='a b c'	convert { a b c }
278*4887Schin  */
279*4887Schin 
280*4887Schin extern uid_t		_getuid(void);
281*4887Schin 
282*4887Schin static int		convertinit;
283*4887Schin 
284*4887Schin /*
285*4887Schin  * convertvars[0] names the list of env var names
286*4887Schin  * convertvars[i] are not converted
287*4887Schin  */
288*4887Schin 
289*4887Schin static const char*	convertvars[] = { "DOSPATHVARS", "PATH" };
290*4887Schin 
291*4887Schin static int
convert(register const char * d,const char * s)292*4887Schin convert(register const char* d, const char* s)
293*4887Schin {
294*4887Schin 	register const char*	t;
295*4887Schin 	register const char*	v;
296*4887Schin 	int			i;
297*4887Schin 
298*4887Schin 	for (i = 0; i < elementsof(convertvars); i++)
299*4887Schin 	{
300*4887Schin 		for (v = convertvars[i], t = s; *t && *t == *v; t++, v++);
301*4887Schin 		if (*t == '=' && *v == 0)
302*4887Schin 			return 0;
303*4887Schin 	}
304*4887Schin 	for (;;)
305*4887Schin 	{
306*4887Schin 		while (*d == ' ' || *d == '\t')
307*4887Schin 			d++;
308*4887Schin 		if (!*d)
309*4887Schin 			break;
310*4887Schin 		for (t = s; *t && *t == *d; d++, t++);
311*4887Schin 		if (*t == '=' && (*d == ' ' || *d == '\t' || *d == 0))
312*4887Schin 			return t - s + 1;
313*4887Schin 		while (*d && *d != ' ' && *d != '\t')
314*4887Schin 			d++;
315*4887Schin 	}
316*4887Schin 	return 0;
317*4887Schin }
318*4887Schin 
319*4887Schin uid_t
getuid(void)320*4887Schin getuid(void)
321*4887Schin {
322*4887Schin 	register char*		d;
323*4887Schin 	register char*		s;
324*4887Schin 	register char*		t;
325*4887Schin 	register char**		e;
326*4887Schin 	int			n;
327*4887Schin 	int			m;
328*4887Schin 
329*4887Schin 	if (!convertinit++ && (d = getenv(convertvars[0])))
330*4887Schin 		for (e = environ; s = *e; e++)
331*4887Schin 			if ((n = convert(d, s)) && (m = cygwin_win32_to_posix_path_list_buf_size(s + n)) > 0)
332*4887Schin 			{
333*4887Schin 				if (!(t = malloc(n + m + 1)))
334*4887Schin 					break;
335*4887Schin 				*e = t;
336*4887Schin 				memcpy(t, s, n);
337*4887Schin 				cygwin_win32_to_posix_path_list(s + n, t + n);
338*4887Schin 			}
339*4887Schin 	return _getuid();
340*4887Schin }
341*4887Schin 
342*4887Schin #endif
343*4887Schin 
344*4887Schin #ifndef _P_OVERLAY
345*4887Schin #define _P_OVERLAY	(-1)
346*4887Schin #endif
347*4887Schin 
348*4887Schin #define DEBUG		1
349*4887Schin 
350*4887Schin static pid_t
runve(int mode,const char * path,char * const * argv,char * const * envv)351*4887Schin runve(int mode, const char* path, char* const* argv, char* const* envv)
352*4887Schin {
353*4887Schin 	register char*	s;
354*4887Schin 	register char**	p;
355*4887Schin 	register char**	v;
356*4887Schin 
357*4887Schin 	void*		m1;
358*4887Schin 	void*		m2;
359*4887Schin 	pid_t		pid;
360*4887Schin 	int		oerrno;
361*4887Schin 	int		ux;
362*4887Schin 	int		n;
363*4887Schin #if defined(_P_DETACH) && defined(_P_NOWAIT)
364*4887Schin 	int		pgrp;
365*4887Schin #endif
366*4887Schin #if CONVERT
367*4887Schin 	char*		d;
368*4887Schin 	char*		t;
369*4887Schin 	int		m;
370*4887Schin #endif
371*4887Schin 	struct stat	st;
372*4887Schin 	char		buf[PATH_MAX];
373*4887Schin 	char		tmp[PATH_MAX];
374*4887Schin 
375*4887Schin #if DEBUG
376*4887Schin 	static int	trace;
377*4887Schin #endif
378*4887Schin 
379*4887Schin #if defined(_P_DETACH) && defined(_P_NOWAIT)
380*4887Schin 	if (mode == _P_DETACH)
381*4887Schin 	{
382*4887Schin 		/*
383*4887Schin 		 * 2004-02-29 cygwin _P_DETACH is useless:
384*4887Schin 		 *	spawn*() returns 0 instead of the spawned pid
385*4887Schin 		 *	spawned { pgid sid } are the same as the parent
386*4887Schin 		 */
387*4887Schin 
388*4887Schin 		mode = _P_NOWAIT;
389*4887Schin 		pgrp = 1;
390*4887Schin 	}
391*4887Schin 	else
392*4887Schin 		pgrp = 0;
393*4887Schin #endif
394*4887Schin 	if (!envv)
395*4887Schin 		envv = (char* const*)environ;
396*4887Schin 	m1 = m2 = 0;
397*4887Schin 	oerrno = errno;
398*4887Schin #if DEBUG
399*4887Schin 	if (!trace)
400*4887Schin 		trace = (s = getenv("_AST_exec_trace")) ? *s : 'n';
401*4887Schin #endif
402*4887Schin 	if (execrate(path, buf, sizeof(buf), 0))
403*4887Schin 	{
404*4887Schin 		if (!_stat(buf, &st))
405*4887Schin 			path = (const char*)buf;
406*4887Schin 		else
407*4887Schin 			errno = oerrno;
408*4887Schin 	}
409*4887Schin 	if (path != (const char*)buf && _stat(path, &st))
410*4887Schin 		return -1;
411*4887Schin 	if (!S_ISREG(st.st_mode) || !(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
412*4887Schin 	{
413*4887Schin 		errno = EACCES;
414*4887Schin 		return -1;
415*4887Schin 	}
416*4887Schin 	if (magic(path, &ux))
417*4887Schin 	{
418*4887Schin #if _CYGWIN_fork_works
419*4887Schin 		errno = ENOEXEC;
420*4887Schin 		return -1;
421*4887Schin #else
422*4887Schin 		ux = 1;
423*4887Schin 		p = (char**)argv;
424*4887Schin 		while (*p++);
425*4887Schin 		if (!(v = (char**)malloc((p - (char**)argv + 2) * sizeof(char*))))
426*4887Schin 		{
427*4887Schin 			errno = EAGAIN;
428*4887Schin 			return -1;
429*4887Schin 		}
430*4887Schin 		m1 = v;
431*4887Schin 		p = v;
432*4887Schin 		*p++ = (char*)path;
433*4887Schin 		*p++ = (char*)path;
434*4887Schin 		path = (const char*)pathshell();
435*4887Schin 		if (*argv)
436*4887Schin 			argv++;
437*4887Schin 		while (*p++ = (char*)*argv++);
438*4887Schin 		argv = (char* const*)v;
439*4887Schin #endif
440*4887Schin 	}
441*4887Schin 
442*4887Schin 	/*
443*4887Schin 	 * the win32 dll search order is
444*4887Schin 	 *	(1) the directory of path
445*4887Schin 	 *	(2) .
446*4887Schin 	 *	(3) /c/(WINNT|WINDOWS)/system32 /c/(WINNT|WINDOWS)
447*4887Schin 	 *	(4) the directories on $PATH
448*4887Schin 	 * there are no cygwin dlls in (3), so if (1) and (2) fail
449*4887Schin 	 * to produce the required dlls its up to (4)
450*4887Schin 	 *
451*4887Schin 	 * the standard allows PATH to be anything once the path
452*4887Schin 	 * to an executable is determined; this code ensures that PATH
453*4887Schin 	 * contains /bin so that at least the cygwin dll, required
454*4887Schin 	 * by all cygwin executables, will be found
455*4887Schin 	 */
456*4887Schin 
457*4887Schin 	if (p = (char**)envv)
458*4887Schin 	{
459*4887Schin 		n = 1;
460*4887Schin 		while (s = *p++)
461*4887Schin 			if (strneq(s, "PATH=", 5))
462*4887Schin 			{
463*4887Schin 				s += 5;
464*4887Schin 				do
465*4887Schin 				{
466*4887Schin 					s = pathcat(tmp, s, ':', NiL, "");
467*4887Schin 					if (streq(tmp, "/usr/bin/") || streq(tmp, "/bin/"))
468*4887Schin 					{
469*4887Schin 						n = 0;
470*4887Schin 						break;
471*4887Schin 					}
472*4887Schin 				} while (s);
473*4887Schin 				if (n)
474*4887Schin 				{
475*4887Schin 					n = 0;
476*4887Schin 					snprintf(tmp, sizeof(tmp), "%s:/bin", *(p - 1));
477*4887Schin 					*(p - 1) = tmp;
478*4887Schin 				}
479*4887Schin 				break;
480*4887Schin 			}
481*4887Schin 		if (n)
482*4887Schin 		{
483*4887Schin 			n = p - (char**)envv + 1;
484*4887Schin 			p = (char**)envv;
485*4887Schin 			if (v = (char**)malloc(n * sizeof(char*)))
486*4887Schin 			{
487*4887Schin 				m2 = v;
488*4887Schin 				envv = (char* const*)v;
489*4887Schin 				*v++ = strcpy(tmp, "PATH=/bin");
490*4887Schin 				while (*v++ = *p++);
491*4887Schin 			}
492*4887Schin 		}
493*4887Schin #if CONVERT
494*4887Schin 		if (!ux && (d = getenv(convertvars[0])))
495*4887Schin 			for (p = (char**)envv; s = *p; p++)
496*4887Schin 				if ((n = convert(d, s)) && (m = cygwin_posix_to_win32_path_list_buf_size(s + n)) > 0)
497*4887Schin 				{
498*4887Schin 					if (!(t = malloc(n + m + 1)))
499*4887Schin 						break;
500*4887Schin 					*p = t;
501*4887Schin 					memcpy(t, s, n);
502*4887Schin 					cygwin_posix_to_win32_path_list(s + n, t + n);
503*4887Schin 				}
504*4887Schin #endif
505*4887Schin 	}
506*4887Schin 
507*4887Schin #if DEBUG
508*4887Schin 	if (trace == 'a' || trace == 'e')
509*4887Schin 	{
510*4887Schin 		sfprintf(sfstderr, "%s %s [", mode == _P_OVERLAY ? "_execve" : "_spawnve", path);
511*4887Schin 		for (n = 0; argv[n]; n++)
512*4887Schin 			sfprintf(sfstderr, " '%s'", argv[n]);
513*4887Schin 		if (trace == 'e')
514*4887Schin 		{
515*4887Schin 			sfprintf(sfstderr, " ] [");
516*4887Schin 			for (n = 0; envv[n]; n++)
517*4887Schin 				sfprintf(sfstderr, " '%s'", envv[n]);
518*4887Schin 		}
519*4887Schin 		sfprintf(sfstderr, " ]\n");
520*4887Schin 		sfsync(sfstderr);
521*4887Schin 	}
522*4887Schin #endif
523*4887Schin #if _lib_spawn_mode
524*4887Schin 	if (mode != _P_OVERLAY)
525*4887Schin 	{
526*4887Schin 		pid = _spawnve(mode, path, argv, envv);
527*4887Schin #if defined(_P_DETACH) && defined(_P_NOWAIT)
528*4887Schin 		if (pid > 0 && pgrp)
529*4887Schin 			setpgid(pid, 0);
530*4887Schin #endif
531*4887Schin 	}
532*4887Schin 	else
533*4887Schin #endif
534*4887Schin 	{
535*4887Schin #if defined(_P_DETACH) && defined(_P_NOWAIT)
536*4887Schin 		if (pgrp)
537*4887Schin 			setpgid(0, 0);
538*4887Schin #endif
539*4887Schin 		pid = _execve(path, argv, envv);
540*4887Schin 	}
541*4887Schin 	if (m1)
542*4887Schin 		free(m1);
543*4887Schin 	if (m2)
544*4887Schin 		free(m2);
545*4887Schin 	return pid;
546*4887Schin }
547*4887Schin 
548*4887Schin #if _win32_botch_execve
549*4887Schin 
550*4887Schin extern pid_t
execve(const char * path,char * const * argv,char * const * envv)551*4887Schin execve(const char* path, char* const* argv, char* const* envv)
552*4887Schin {
553*4887Schin 	return runve(_P_OVERLAY, path, argv, envv);
554*4887Schin }
555*4887Schin 
556*4887Schin #endif
557*4887Schin 
558*4887Schin #if _lib_spawn_mode
559*4887Schin 
560*4887Schin extern pid_t
spawnve(int mode,const char * path,char * const * argv,char * const * envv)561*4887Schin spawnve(int mode, const char* path, char* const* argv, char* const* envv)
562*4887Schin {
563*4887Schin 	return runve(mode, path, argv, envv);
564*4887Schin }
565*4887Schin 
566*4887Schin #endif
567*4887Schin 
568*4887Schin #endif
569*4887Schin 
570*4887Schin #if _win32_botch_getpagesize
571*4887Schin 
572*4887Schin extern size_t
getpagesize(void)573*4887Schin getpagesize(void)
574*4887Schin {
575*4887Schin 	return 64 * 1024;
576*4887Schin }
577*4887Schin 
578*4887Schin #endif
579*4887Schin 
580*4887Schin #if _win32_botch_link
581*4887Schin 
582*4887Schin extern int
link(const char * fp,const char * tp)583*4887Schin link(const char* fp, const char* tp)
584*4887Schin {
585*4887Schin 	int	r;
586*4887Schin 	int	oerrno;
587*4887Schin 	char	fb[PATH_MAX];
588*4887Schin 	char	tb[PATH_MAX];
589*4887Schin 
590*4887Schin 	oerrno = errno;
591*4887Schin 	if ((r = _link(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1))
592*4887Schin 	{
593*4887Schin 		if (execrate(tp, tb, sizeof(tb), 1))
594*4887Schin 			tp = tb;
595*4887Schin 		errno = oerrno;
596*4887Schin 		r = _link(fb, tp);
597*4887Schin 	}
598*4887Schin 	return r;
599*4887Schin }
600*4887Schin 
601*4887Schin #endif
602*4887Schin 
603*4887Schin #if _win32_botch_open || _win32_botch_copy
604*4887Schin 
605*4887Schin #if _win32_botch_copy
606*4887Schin 
607*4887Schin /*
608*4887Schin  * this should intercept the important cases
609*4887Schin  * dup*() and exec*() fd's will not be intercepted
610*4887Schin  */
611*4887Schin 
612*4887Schin typedef struct Exe_test_s
613*4887Schin {
614*4887Schin 	int		test;
615*4887Schin 	ino_t		ino;
616*4887Schin 	char		path[PATH_MAX];
617*4887Schin } Exe_test_t;
618*4887Schin 
619*4887Schin static Exe_test_t*	exe[16];
620*4887Schin 
621*4887Schin extern int
close(int fd)622*4887Schin close(int fd)
623*4887Schin {
624*4887Schin 	int		r;
625*4887Schin 	int		oerrno;
626*4887Schin 	struct stat	st;
627*4887Schin 	char		buf[PATH_MAX];
628*4887Schin 
629*4887Schin 	if (fd >= 0 && fd < elementsof(exe) && exe[fd])
630*4887Schin 	{
631*4887Schin 		r = exe[fd]->test;
632*4887Schin 		exe[fd]->test = 0;
633*4887Schin 		if (r > 0 && !fstat(fd, &st) && st.st_ino == exe[fd]->ino)
634*4887Schin 		{
635*4887Schin 			if (r = _close(fd))
636*4887Schin 				return r;
637*4887Schin 			oerrno = errno;
638*4887Schin 			if (!stat(exe[fd]->path, &st) && st.st_ino == exe[fd]->ino)
639*4887Schin 			{
640*4887Schin 				snprintf(buf, sizeof(buf), "%s.exe", exe[fd]->path);
641*4887Schin 				_rename(exe[fd]->path, buf);
642*4887Schin 			}
643*4887Schin 			errno = oerrno;
644*4887Schin 			return 0;
645*4887Schin 		}
646*4887Schin 	}
647*4887Schin 	return _close(fd);
648*4887Schin }
649*4887Schin 
650*4887Schin extern ssize_t
write(int fd,const void * buf,size_t n)651*4887Schin write(int fd, const void* buf, size_t n)
652*4887Schin {
653*4887Schin 	if (fd >= 0 && fd < elementsof(exe) && exe[fd] && exe[fd]->test < 0)
654*4887Schin 		exe[fd]->test = n >= 2 && ((unsigned char*)buf)[1] == 0x5a && (((unsigned char*)buf)[0] == 0x4c || ((unsigned char*)buf)[0] == 0x4d) && !lseek(fd, (off_t)0, SEEK_CUR);
655*4887Schin 	return _write(fd, buf, n);
656*4887Schin }
657*4887Schin 
658*4887Schin #endif
659*4887Schin 
660*4887Schin extern int
open(const char * path,int flags,...)661*4887Schin open(const char* path, int flags, ...)
662*4887Schin {
663*4887Schin 	int		fd;
664*4887Schin 	int		mode;
665*4887Schin 	int		oerrno;
666*4887Schin 	char		buf[PATH_MAX];
667*4887Schin #if _win32_botch_copy
668*4887Schin 	struct stat	st;
669*4887Schin #endif
670*4887Schin 	va_list		ap;
671*4887Schin 
672*4887Schin 	va_start(ap, flags);
673*4887Schin 	mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
674*4887Schin 	oerrno = errno;
675*4887Schin 	fd = _open(path, flags, mode);
676*4887Schin #if _win32_botch_open
677*4887Schin 	if (fd < 0 && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
678*4887Schin 	{
679*4887Schin 		errno = oerrno;
680*4887Schin 		fd = _open(buf, flags, mode);
681*4887Schin 	}
682*4887Schin #endif
683*4887Schin #if _win32_botch_copy
684*4887Schin 	if (fd >= 0 && fd < elementsof(exe) && strlen(path) < PATH_MAX &&
685*4887Schin 	    (flags & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC) && (mode & 0111))
686*4887Schin 	{
687*4887Schin 		if (!suffix(path) && !fstat(fd, &st) && (exe[fd] || (exe[fd] = (Exe_test_t*)malloc(sizeof(Exe_test_t)))))
688*4887Schin 		{
689*4887Schin 			exe[fd]->test = -1;
690*4887Schin 			exe[fd]->ino = st.st_ino;
691*4887Schin 			strcpy(exe[fd]->path, path);
692*4887Schin 		}
693*4887Schin 		errno = oerrno;
694*4887Schin 	}
695*4887Schin #endif
696*4887Schin 	va_end(ap);
697*4887Schin 	return fd;
698*4887Schin }
699*4887Schin 
700*4887Schin #endif
701*4887Schin 
702*4887Schin #if _win32_botch_pathconf
703*4887Schin 
704*4887Schin extern long
pathconf(const char * path,int op)705*4887Schin pathconf(const char* path, int op)
706*4887Schin {
707*4887Schin 	if (_access(path, F_OK))
708*4887Schin 		return -1;
709*4887Schin 	return _pathconf(path, op);
710*4887Schin }
711*4887Schin 
712*4887Schin #endif
713*4887Schin 
714*4887Schin #if _win32_botch_rename
715*4887Schin 
716*4887Schin extern int
rename(const char * fp,const char * tp)717*4887Schin rename(const char* fp, const char* tp)
718*4887Schin {
719*4887Schin 	int	r;
720*4887Schin 	int	oerrno;
721*4887Schin 	char	fb[PATH_MAX];
722*4887Schin 	char	tb[PATH_MAX];
723*4887Schin 
724*4887Schin 	oerrno = errno;
725*4887Schin 	if ((r = _rename(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1))
726*4887Schin 	{
727*4887Schin 		if (execrate(tp, tb, sizeof(tb), 1))
728*4887Schin 			tp = tb;
729*4887Schin 		errno = oerrno;
730*4887Schin 		r = _rename(fb, tp);
731*4887Schin 	}
732*4887Schin 	return r;
733*4887Schin }
734*4887Schin 
735*4887Schin #endif
736*4887Schin 
737*4887Schin #if _win32_botch_stat
738*4887Schin 
739*4887Schin extern int
stat(const char * path,struct stat * st)740*4887Schin stat(const char* path, struct stat* st)
741*4887Schin {
742*4887Schin 	int	r;
743*4887Schin 	int	oerrno;
744*4887Schin 	char	buf[PATH_MAX];
745*4887Schin 
746*4887Schin 	oerrno = errno;
747*4887Schin 	if ((r = _stat(path, st)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
748*4887Schin 	{
749*4887Schin 		errno = oerrno;
750*4887Schin 		r = _stat(buf, st);
751*4887Schin 	}
752*4887Schin 	return r;
753*4887Schin }
754*4887Schin 
755*4887Schin #endif
756*4887Schin 
757*4887Schin #if _win32_botch_truncate
758*4887Schin 
759*4887Schin extern int
truncate(const char * path,off_t offset)760*4887Schin truncate(const char* path, off_t offset)
761*4887Schin {
762*4887Schin 	int	r;
763*4887Schin 	int	oerrno;
764*4887Schin 	char	buf[PATH_MAX];
765*4887Schin 
766*4887Schin 	oerrno = errno;
767*4887Schin 	if ((r = _truncate(path, offset)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
768*4887Schin 	{
769*4887Schin 		errno = oerrno;
770*4887Schin 		r = _truncate(buf, offset);
771*4887Schin 	}
772*4887Schin 	return r;
773*4887Schin }
774*4887Schin 
775*4887Schin #endif
776*4887Schin 
777*4887Schin #if _win32_botch_unlink
778*4887Schin 
779*4887Schin extern int
unlink(const char * path)780*4887Schin unlink(const char* path)
781*4887Schin {
782*4887Schin 	int		r;
783*4887Schin 	int		drive;
784*4887Schin 	int		mask;
785*4887Schin 	int		suffix;
786*4887Schin 	int		stop;
787*4887Schin 	int		oerrno;
788*4887Schin 	unsigned long	base;
789*4887Schin 	char		buf[PATH_MAX];
790*4887Schin 	char		tmp[MAX_PATH];
791*4887Schin 
792*4887Schin #define DELETED_DIR_1	7
793*4887Schin #define DELETED_DIR_2	16
794*4887Schin 
795*4887Schin 	static char	deleted[] = "%c:\\temp\\.deleted\\%08x.%03x";
796*4887Schin 
797*4887Schin 	static int	count = 0;
798*4887Schin 
799*4887Schin #if __CYGWIN__
800*4887Schin 
801*4887Schin 	DWORD		fattr = FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE;
802*4887Schin 	DWORD		share = FILE_SHARE_DELETE;
803*4887Schin 	HANDLE		hp;
804*4887Schin 	struct stat	st;
805*4887Schin 	char		nat[MAX_PATH];
806*4887Schin 
807*4887Schin 	oerrno = errno;
808*4887Schin 	if (lstat(path, &st) || !S_ISREG(st.st_mode))
809*4887Schin 		goto try_unlink;
810*4887Schin 	cygwin_conv_to_full_win32_path(path, nat);
811*4887Schin 	if (!strncasecmp(nat + 1, ":\\temp\\", 7))
812*4887Schin 		goto try_unlink;
813*4887Schin 	drive = nat[0];
814*4887Schin 	path = (const char*)nat;
815*4887Schin 	for (;;)
816*4887Schin 	{
817*4887Schin 		hp = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL);
818*4887Schin 		if (hp != INVALID_HANDLE_VALUE)
819*4887Schin 		{
820*4887Schin 			CloseHandle(hp);
821*4887Schin 			errno = oerrno;
822*4887Schin 			return 0;
823*4887Schin 		}
824*4887Schin 		if (GetLastError() != ERROR_FILE_NOT_FOUND)
825*4887Schin 			break;
826*4887Schin 		if (path == (const char*)buf || !execrate(path, buf, sizeof(buf), 1))
827*4887Schin 		{
828*4887Schin 			errno = ENOENT;
829*4887Schin 			return -1;
830*4887Schin 		}
831*4887Schin 		path = (const char*)buf;
832*4887Schin 	}
833*4887Schin #else
834*4887Schin 	if (_access(path, 0))
835*4887Schin #if _win32_botch_access
836*4887Schin 	{
837*4887Schin 		if (errno != ENOENT || !execrate(path, buf, sizeof(buf), 1) || _access(buf, 0))
838*4887Schin 			return -1;
839*4887Schin 		path = (const char*)buf;
840*4887Schin 	}
841*4887Schin #else
842*4887Schin 		return -1;
843*4887Schin #endif
844*4887Schin 	drive = 'C':
845*4887Schin #endif
846*4887Schin 
847*4887Schin 	/*
848*4887Schin 	 * rename to a `deleted' path just in case the file is open
849*4887Schin 	 * otherwise directory readers may choke on phantom entries
850*4887Schin 	 */
851*4887Schin 
852*4887Schin 	base = ((getuid() & 0xffff) << 16) | (time(NiL) & 0xffff);
853*4887Schin 	suffix = (getpid() & 0xfff) + count++;
854*4887Schin 	snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix);
855*4887Schin 	if (!_rename(path, tmp))
856*4887Schin 	{
857*4887Schin 		path = (const char*)tmp;
858*4887Schin 		goto try_delete;
859*4887Schin 	}
860*4887Schin 	if (errno != ENOTDIR && errno != ENOENT)
861*4887Schin 		goto try_unlink;
862*4887Schin 	tmp[DELETED_DIR_2] = 0;
863*4887Schin 	if (_access(tmp, 0))
864*4887Schin 	{
865*4887Schin 		mask = umask(0);
866*4887Schin 		tmp[DELETED_DIR_1] = 0;
867*4887Schin 		if (_access(tmp, 0) && _mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO))
868*4887Schin 		{
869*4887Schin 			umask(mask);
870*4887Schin 			goto try_unlink;
871*4887Schin 		}
872*4887Schin 		tmp[DELETED_DIR_1] = '\\';
873*4887Schin 		r = _mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO);
874*4887Schin 		umask(mask);
875*4887Schin 		if (r)
876*4887Schin 			goto try_unlink;
877*4887Schin 		errno = 0;
878*4887Schin 	}
879*4887Schin 	tmp[DELETED_DIR_2] = '\\';
880*4887Schin 	if (!errno && !_rename(path, tmp))
881*4887Schin 	{
882*4887Schin 		path = (const char*)tmp;
883*4887Schin 		goto try_delete;
884*4887Schin 	}
885*4887Schin #if !__CYGWIN__
886*4887Schin 	if (errno == ENOENT)
887*4887Schin 	{
888*4887Schin #if !_win32_botch_access
889*4887Schin 		if (execrate(path, buf, sizeof(buf), 1) && !_rename(buf, tmp))
890*4887Schin 			path = (const char*)tmp;
891*4887Schin #endif
892*4887Schin 		goto try_unlink;
893*4887Schin 	}
894*4887Schin #endif
895*4887Schin 	stop = suffix;
896*4887Schin 	do
897*4887Schin 	{
898*4887Schin 		snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix);
899*4887Schin 		if (!_rename(path, tmp))
900*4887Schin 		{
901*4887Schin 			path = (const char*)tmp;
902*4887Schin 			goto try_delete;
903*4887Schin 		}
904*4887Schin 		if (++suffix > 0xfff)
905*4887Schin 			suffix = 0;
906*4887Schin 	} while (suffix != stop);
907*4887Schin  try_delete:
908*4887Schin #if __CYGWIN__
909*4887Schin 	hp = CreateFile(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL);
910*4887Schin 	if (hp != INVALID_HANDLE_VALUE)
911*4887Schin 	{
912*4887Schin 		CloseHandle(hp);
913*4887Schin 		errno = oerrno;
914*4887Schin 		return 0;
915*4887Schin 	}
916*4887Schin #endif
917*4887Schin  try_unlink:
918*4887Schin 	errno = oerrno;
919*4887Schin 	return _unlink(path);
920*4887Schin }
921*4887Schin 
922*4887Schin #endif
923*4887Schin 
924*4887Schin #if _win32_botch_utime
925*4887Schin 
926*4887Schin #if __CYGWIN__
927*4887Schin 
928*4887Schin /*
929*4887Schin  * cygwin refuses to set st_ctime for some operations
930*4887Schin  * this rejects that refusal
931*4887Schin  */
932*4887Schin 
933*4887Schin static void
ctime_now(const char * path)934*4887Schin ctime_now(const char* path)
935*4887Schin {
936*4887Schin 	HANDLE		hp;
937*4887Schin 	SYSTEMTIME	st;
938*4887Schin 	FILETIME	ct;
939*4887Schin 	WIN32_FIND_DATA	ff;
940*4887Schin 	struct stat	fs;
941*4887Schin 	int		oerrno;
942*4887Schin 	char		tmp[MAX_PATH];
943*4887Schin 
944*4887Schin 	if (_stat(path, &fs) || (fs.st_mode & S_IWUSR) || _chmod(path, (fs.st_mode | S_IWUSR) & S_IPERM))
945*4887Schin 		fs.st_mode = 0;
946*4887Schin 	cygwin_conv_to_win32_path(path, tmp);
947*4887Schin 	hp = CreateFile(tmp, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
948*4887Schin 	if (hp && hp != INVALID_HANDLE_VALUE)
949*4887Schin 	{
950*4887Schin 		GetSystemTime(&st);
951*4887Schin 		SystemTimeToFileTime(&st, &ct);
952*4887Schin 		SetFileTime(hp, &ct, 0, 0);
953*4887Schin 		CloseHandle(hp);
954*4887Schin 	}
955*4887Schin 	if (fs.st_mode)
956*4887Schin 		_chmod(path, fs.st_mode & S_IPERM);
957*4887Schin 	errno = oerrno;
958*4887Schin }
959*4887Schin 
960*4887Schin #else
961*4887Schin 
962*4887Schin #define ctime_now(p)
963*4887Schin 
964*4887Schin #endif
965*4887Schin 
966*4887Schin extern int
utimes(const char * path,const struct timeval * ut)967*4887Schin utimes(const char* path, const struct timeval* ut)
968*4887Schin {
969*4887Schin 	int	r;
970*4887Schin 	int	oerrno;
971*4887Schin 	char	buf[PATH_MAX];
972*4887Schin 
973*4887Schin 	oerrno = errno;
974*4887Schin 	if ((r = _utimes(path, ut)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
975*4887Schin 	{
976*4887Schin 		errno = oerrno;
977*4887Schin 		r = _utimes(path = buf, ut);
978*4887Schin 	}
979*4887Schin 	if (!r)
980*4887Schin 		ctime_now(path);
981*4887Schin 	return r;
982*4887Schin }
983*4887Schin 
984*4887Schin extern int
utime(const char * path,const struct utimbuf * ut)985*4887Schin utime(const char* path, const struct utimbuf* ut)
986*4887Schin {
987*4887Schin 	int	r;
988*4887Schin 	int	oerrno;
989*4887Schin 	char	buf[PATH_MAX];
990*4887Schin 
991*4887Schin 	oerrno = errno;
992*4887Schin 	if ((r = _utime(path, ut)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
993*4887Schin 	{
994*4887Schin 		errno = oerrno;
995*4887Schin 		r = _utime(path = buf, ut);
996*4887Schin 	}
997*4887Schin 	if (!r)
998*4887Schin 		ctime_now(path);
999*4887Schin 	return r;
1000*4887Schin }
1001*4887Schin 
1002*4887Schin #endif
1003*4887Schin 
1004*4887Schin #endif
1005*4887Schin 
1006*4887Schin /*
1007*4887Schin  * some systems (sun) miss a few functions required by their
1008*4887Schin  * own bsd-like macros
1009*4887Schin  */
1010*4887Schin 
1011*4887Schin #if !_lib_bzero || defined(bzero)
1012*4887Schin 
1013*4887Schin #undef	bzero
1014*4887Schin 
1015*4887Schin void
bzero(void * b,size_t n)1016*4887Schin bzero(void* b, size_t n)
1017*4887Schin {
1018*4887Schin 	memset(b, 0, n);
1019*4887Schin }
1020*4887Schin 
1021*4887Schin #endif
1022*4887Schin 
1023*4887Schin #if !_lib_getpagesize || defined(getpagesize)
1024*4887Schin 
1025*4887Schin #ifndef OMITTED
1026*4887Schin #define OMITTED	1
1027*4887Schin #endif
1028*4887Schin 
1029*4887Schin #undef	getpagesize
1030*4887Schin 
1031*4887Schin #ifdef	_SC_PAGESIZE
1032*4887Schin #undef	_AST_PAGESIZE
1033*4887Schin #define _AST_PAGESIZE	(int)sysconf(_SC_PAGESIZE)
1034*4887Schin #else
1035*4887Schin #ifndef _AST_PAGESIZE
1036*4887Schin #define _AST_PAGESIZE	4096
1037*4887Schin #endif
1038*4887Schin #endif
1039*4887Schin 
1040*4887Schin int
getpagesize()1041*4887Schin getpagesize()
1042*4887Schin {
1043*4887Schin 	return _AST_PAGESIZE;
1044*4887Schin }
1045*4887Schin 
1046*4887Schin #endif
1047*4887Schin 
1048*4887Schin #if __CYGWIN__ && defined(__IMPORT__) && defined(__EXPORT__)
1049*4887Schin 
1050*4887Schin #ifndef OMITTED
1051*4887Schin #define OMITTED	1
1052*4887Schin #endif
1053*4887Schin 
1054*4887Schin /*
1055*4887Schin  * a few _imp__FUNCTION symbols are needed to avoid
1056*4887Schin  * static link multiple definitions
1057*4887Schin  */
1058*4887Schin 
1059*4887Schin #ifndef strtod
1060*4887Schin __EXPORT__ double (*_imp__strtod)(const char*, char**) = strtod;
1061*4887Schin #endif
1062*4887Schin 
1063*4887Schin #endif
1064*4887Schin 
1065*4887Schin #ifndef OMITTED
1066*4887Schin 
1067*4887Schin NoN(omitted)
1068*4887Schin 
1069*4887Schin #endif
1070