1/*$Header: /p/tcsh/cvsroot/tcsh/win32/support.c,v 1.14 2008/08/31 14:09:01 amold Exp $*/
2/*-
3 * Copyright (c) 1980, 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/*
32 * support.c
33 * various routines to do exec, etc.
34 *
35 */
36
37#define WIN32_LEAN_AND_MEAN
38#include <windows.h>
39#include <wincon.h>
40#include <fcntl.h>
41#include <errno.h>
42#include <stdio.h>
43#include <locale.h>
44#include "ntport.h"
45#include "sh.err.h"
46#include "sh.h"
47#include "nt.const.h"
48
49
50DWORD gdwPlatform,gdwVersion;
51unsigned short __nt_really_exec = 0,__nt_child_nohupped =0;
52DWORD gdwStackSize = 524288;//0.5 MB
53
54void path_slashify(char *pstr) {
55	while(*pstr) {
56#ifdef DSPMBYTE
57		if (Ismbyte1(*pstr) && *(pstr + 1))
58			pstr ++;
59		else
60#endif /* DSPMBYTE */
61			if (*pstr == '\\')
62				*pstr = '/';
63		pstr++;
64	}
65}
66
67void do_nothing(const wchar_t *p1, const wchar_t *p2, const wchar_t*p3,
68		unsigned int p4, uintptr_t p5) {
69        UNREFERENCED_PARAMETER(p1);
70        UNREFERENCED_PARAMETER(p2);
71        UNREFERENCED_PARAMETER(p3);
72        UNREFERENCED_PARAMETER(p4);
73        UNREFERENCED_PARAMETER(p5);
74}
75void nt_init(void) {
76
77
78#ifdef SECURE_CD
79	{
80		char temp[512];/*FIXBUF*/
81		extern char gcurr_drive;
82		if(!GetCurrentDirectory(512,temp))
83			ExitProcess((DWORD)-1);
84		gcurr_drive=temp[0];
85	}
86#endif SECURE_CD
87
88	_set_invalid_parameter_handler(do_nothing);
89	init_stdio();
90	nt_init_signals();
91	nt_term_init();
92	init_hb_subst();
93	setlocale(LC_ALL,"");
94	init_shell_dll();
95	init_plister();
96	fork_init();
97	init_clipboard();
98	return;
99}
100void nt_cleanup(void){
101	nt_term_cleanup();
102	nt_cleanup_signals();
103	cleanup_netbios();
104}
105void caseify_pwd(char *curwd) {
106	char *sp, *dp, p,*s;
107	WIN32_FIND_DATA fdata;
108	HANDLE hFind;
109
110	if (gdwPlatform !=VER_PLATFORM_WIN32_NT)
111		return;
112
113	if (*curwd == '\\' && (!curwd[1] || curwd[1] == '\\'))
114		return;
115	sp = curwd +3;
116	dp = curwd +3;
117	do {
118		p= *sp;
119		if (p && p != '\\'){
120			sp++;
121			continue;
122		}
123		else {
124			*sp = 0;
125			hFind = FindFirstFile(curwd,&fdata);
126			*sp = p;
127			if (hFind != INVALID_HANDLE_VALUE) {
128				FindClose(hFind);
129				s = fdata.cFileName;
130				while(*s) {
131					*dp++ = *s++;
132				}
133				dp++;
134				sp = dp;
135			}
136			else {
137				sp++;
138				dp = sp;
139			}
140		}
141		sp++;
142	}while(p != 0);
143
144}
145static char defcwd[MAX_PATH];
146char * forward_slash_get_cwd(char * path, size_t maxlen) {
147
148	char *ptemp;
149	Char *vp;
150	int rc ;
151
152	if ((path == NULL) || (maxlen == 0)) {
153		path = &defcwd[0];
154		maxlen = MAX_PATH;
155	}
156
157	rc = GetCurrentDirectory((DWORD)maxlen,path);
158	if (rc > maxlen) {
159		errno = ERANGE;
160		return NULL;
161	}
162	vp = varval(STRNTcaseifypwd);
163	if (vp != STRNULL) {
164		caseify_pwd(path);
165	}
166	ptemp=path;
167
168	path_slashify(ptemp);
169
170	return path;
171}
172void getmachine (void) {
173
174	char temp[256];
175	char *vendor, *ostype;
176	OSVERSIONINFO osver;
177	SYSTEM_INFO sysinfo;
178
179
180	memset(&osver,0,sizeof(osver));
181	memset(&sysinfo,0,sizeof(sysinfo));
182	vendor = "Microsoft";
183
184	tsetenv(STRVENDOR,str2short(vendor));
185
186	osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
187
188	if (!GetVersionEx(&osver)) {
189		MessageBox(NULL,"GetVersionEx failed in getmachine",
190				"tcsh",MB_ICONHAND);
191		ExitProcess(0xFF);
192	}
193	GetSystemInfo(&sysinfo);
194
195	if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
196		char *ostr;
197		ostype = "WindowsNT";
198		ostr = "Windows NT";
199
200		(void)StringCbPrintf(temp,sizeof(temp),"%s %d.%d Build %d (%s)",
201							 ostr,
202							 osver.dwMajorVersion,osver.dwMinorVersion,
203							 osver.dwBuildNumber,
204							 osver.szCSDVersion[0]?osver.szCSDVersion:"");
205		tsetenv(STRHOSTTYPE,str2short(temp));
206	}
207	else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
208		ostype = "Windows9x";
209		(void)StringCbPrintf(temp,sizeof(temp),
210							 "Win9x %d.%d:%d",osver.dwMajorVersion,osver.dwMinorVersion,
211							 LOWORD(osver.dwBuildNumber));
212		tsetenv(STRHOSTTYPE,str2short(temp));
213	}
214	else {
215		ostype = "WindowsWhoKnows";
216		MessageBox(NULL,"Unknown platform","tcsh",MB_ICONHAND);
217	}
218	tsetenv(STROSTYPE,str2short(ostype));
219	switch (sysinfo.wProcessorArchitecture) {
220		case PROCESSOR_ARCHITECTURE_INTEL:
221			if ( ( sysinfo.wProcessorLevel < 3) ||
222					( sysinfo.wProcessorLevel > 9)  )
223				sysinfo.wProcessorLevel = 3;
224
225			(void)StringCbPrintf(temp,sizeof(temp),
226								 "i%d86",sysinfo.wProcessorLevel);
227			break;
228		case PROCESSOR_ARCHITECTURE_ALPHA:
229			(void)StringCbPrintf(temp,sizeof(temp),"Alpha");
230			break;
231		case PROCESSOR_ARCHITECTURE_MIPS:
232			(void)StringCbPrintf(temp,sizeof(temp),"Mips");
233			break;
234		case PROCESSOR_ARCHITECTURE_PPC:
235			(void)StringCbPrintf(temp,sizeof(temp),"PPC");
236			break;
237		case PROCESSOR_ARCHITECTURE_AMD64:
238			(void)StringCbPrintf(temp,sizeof(temp),"AMD64");
239			break;
240		default:
241			(void)StringCbPrintf(temp,sizeof(temp),"Unknown");
242			break;
243	}
244	tsetenv(STRMACHTYPE,str2short(temp));
245
246}
247void nt_exec(char *prog, char**args) {
248	nt_execve(prog,args,NULL);
249}
250void nt_execve(char *prog, char**args, char**envir ) {
251
252	STARTUPINFO si;
253	PROCESS_INFORMATION pi;
254	HANDLE htemp;
255	BOOL bRet;
256	DWORD type=0;
257	DWORD dwCreationflags;
258	unsigned int priority;
259	char *argv0= NULL;
260	char *cmdstr, *cmdend ;
261	char *originalPtr;
262	unsigned int cmdsize,cmdlen;
263	char *p2;
264	char **savedargs;
265	int retries=0;
266	int hasdot =0;
267	int is_winnt ;
268
269	UNREFERENCED_PARAMETER(envir);
270
271	memset(&si,0,sizeof(si));
272	savedargs = args;
273
274	/*
275	 * This memory is not freed because we are exec()ed and will
276	 * not be alive long.
277	 */
278	originalPtr = cmdstr= heap_alloc(MAX_PATH<<2);
279
280	is_winnt = (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS);
281
282
283	cmdsize = MAX_PATH<<2;
284
285	p2 = cmdstr;
286
287	cmdlen = 0;
288	cmdlen += copy_quote_and_fix_slashes(prog,cmdstr,&hasdot);
289
290	p2 += cmdlen;
291
292	/* If the command was not quoted ,
293	   skip initial character we left for quote */
294	if (*cmdstr != '"') {
295		*cmdstr = 'A';
296		cmdstr++;
297		cmdsize--;
298	}
299	*p2 = 0;
300	cmdend = p2;
301
302
303	if (!is_winnt){
304		argv0 = NULL;
305		goto win95_directly_here;
306	}
307	else {
308		argv0 = heap_alloc(MAX_PATH); /* not freed */
309		(void)StringCbPrintf(argv0,MAX_PATH,"%s",prog);
310	}
311
312retry:
313
314	bRet=GetBinaryType(argv0,&type);
315	dprintf("binary type for %s is %d\n",argv0,bRet);
316	//
317	// For NT, append .EXE and retry
318	//
319	if (is_winnt && !bRet ) {
320		/* Don't append .EXE if it could be a script file */
321		if (GetLastError() == ERROR_BAD_EXE_FORMAT){
322			errno = ENOEXEC;
323			if (!__nt_only_start_exes)
324				try_shell_ex(args,1,FALSE); //can't throw on error
325			return;
326		}
327		else if ( retries ){
328			if (
329					( (argv0[0] == '\\') ||(argv0[0] == '/') ) &&
330					( (argv0[1] == '\\') ||(argv0[1] == '/') ) &&
331					(!args[1])
332			   )
333				if (!__nt_only_start_exes)
334					try_shell_ex(args,1,FALSE);
335			errno  = ENOENT;
336		}
337		if (retries > 1){
338			return;
339		}
340		// Try uppercase once and then lower case
341		//
342		if (!retries) {
343			(void)StringCbPrintf(argv0,MAX_PATH,"%s.exe",prog);
344		}
345		else  {
346			(void)StringCbPrintf(argv0,MAX_PATH,"%s.EXE",prog);
347			/* fix for clearcase */
348		}
349		retries++;
350		goto retry;
351	}
352
353win95_directly_here:
354
355	si.cb = sizeof(STARTUPINFO);
356	si.dwFlags = STARTF_USESTDHANDLES;
357	htemp= (HANDLE)_get_osfhandle(0);
358	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
359			&si.hStdInput,0,TRUE,DUPLICATE_SAME_ACCESS);
360	htemp= (HANDLE)_get_osfhandle(1);
361	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
362			&si.hStdOutput,0,TRUE,DUPLICATE_SAME_ACCESS);
363	htemp= (HANDLE)_get_osfhandle(2);
364	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
365			&si.hStdError,0,TRUE,DUPLICATE_SAME_ACCESS);
366
367
368
369	args++; // the first arg is the command
370
371
372	dprintf("nt_execve calling c_a_a_q");
373	if(!concat_args_and_quote(args,&originalPtr,&cmdstr,&cmdlen,&cmdend,
374				&cmdsize))
375	{
376		dprintf("concat_args_and_quote failed\n");
377		heap_free(originalPtr);
378		errno = ENOMEM;
379		goto fail_return;
380	}
381
382	*cmdend = 0;
383
384	dwCreationflags = GetPriorityClass(GetCurrentProcess());
385	if (__nt_child_nohupped) {
386		dwCreationflags |= DETACHED_PROCESS;
387	}
388	priority = GetThreadPriority(GetCurrentThread());
389
390	(void)fix_path_for_child();
391
392	if (is_winnt)
393		dwCreationflags |= CREATE_SUSPENDED;
394
395
396re_cp:
397	dprintf("argv0 %s cmdstr %s\n",argv0,cmdstr);
398	bRet = CreateProcessA(argv0, cmdstr,
399			NULL, NULL,
400			TRUE, // need this for redirecting std handles
401			dwCreationflags,
402			NULL, NULL,
403			&si,
404			&pi);
405	if (!bRet){
406		if (GetLastError() == ERROR_BAD_EXE_FORMAT) {
407			if (!__nt_only_start_exes)
408				try_shell_ex(savedargs,1,FALSE);
409			errno  = ENOEXEC;
410		}
411		else if (GetLastError() == ERROR_INVALID_PARAMETER) {
412			/* can't get invalid parameter, so this must be
413			 *  the case when we exceed the command length limit.
414			 */
415			errno = ENAMETOOLONG;
416		}
417		else {
418			errno  = ENOENT;
419		}
420		if (!is_winnt && !hasdot) { //append '.' to the end if needed
421			(void)StringCbCat(cmdstr,cmdsize,".");
422			hasdot=1;
423			goto re_cp;
424		}
425	}
426	else{
427		int gui_app ;
428		char guivar[50];
429
430		if (GetEnvironmentVariable("TCSH_NOASYNCGUI",guivar,50))
431			gui_app=0;
432		else {
433			if (is_winnt || hasdot)
434				gui_app= is_gui(argv0);
435			else
436				gui_app = is_9x_gui(prog);
437		}
438
439		if (is_winnt && !SetThreadPriority(pi.hThread,priority) ) {
440			priority =GetLastError();
441		}
442		if (is_winnt)
443			ResumeThread(pi.hThread);
444		errno= 0;
445
446		if (__nt_really_exec||__nt_child_nohupped || gui_app){
447			ExitProcess(0);
448		}
449		else {
450			DWORD exitcode=0;
451			WaitForSingleObject(pi.hProcess,INFINITE);
452			(void)GetExitCodeProcess(pi.hProcess,&exitcode);
453			CloseHandle(pi.hProcess);
454			CloseHandle(pi.hThread);
455			/*
456			 * If output was redirected to /dev/clipboard,
457			 * we need to close the pipe handles
458			 */
459			if (is_dev_clipboard_active) {
460				CloseHandle((HANDLE)_get_osfhandle(0));
461				CloseHandle((HANDLE)_get_osfhandle(1));
462				CloseHandle((HANDLE)_get_osfhandle(2));
463				CloseHandle(si.hStdInput);
464				CloseHandle(si.hStdOutput);
465				CloseHandle(si.hStdError);
466				WaitForSingleObject(ghdevclipthread,60*1000);
467			}
468			ExitProcess(exitcode);
469		}
470	}
471fail_return:
472	CloseHandle(si.hStdInput);
473	CloseHandle(si.hStdOutput);
474	CloseHandle(si.hStdError);
475	return;
476}
477/* This function from  Mark Tucker (mtucker@fiji.sidefx.com) */
478int quoteProtect(char *dest, char *src,unsigned long destsize) {
479	char	*prev, *curr;
480	for (curr = src; *curr; curr++) {
481
482		// Protect " from MS-DOS expansion
483		if (*curr == '"') {
484			// Now, protect each preceeding backslash
485			for (prev = curr-1; prev >= src && *prev == '\\'; prev--) {
486				*dest++ = '\\';
487				destsize--;
488				if(destsize == 0)
489					return ERROR_BUFFER_OVERFLOW;
490			}
491
492			*dest++ = '\\';
493			destsize--;
494			if(destsize == 0)
495				return ERROR_BUFFER_OVERFLOW;
496		}
497		*dest++ = *curr;
498		destsize--;
499		if(destsize == 0)
500			return ERROR_BUFFER_OVERFLOW;
501
502	}
503	*dest = 0;
504
505	return NO_ERROR;
506}
507
508
509int gethostname(char *buf, int len) {
510	GetComputerName(buf,(DWORD*)&len);
511	return 0;
512}
513int nt_chdir (char *path) {
514	char *tmp = path;
515	if (gdwPlatform !=VER_PLATFORM_WIN32_NT) {
516		while(*tmp) {
517			if (*tmp == '/') *tmp = '\\';
518			tmp++;
519		}
520	}
521	return _chdir(path);
522}
523void WINAPI uhef( EXCEPTION_POINTERS *lpep) {
524	ExitProcess(lpep->ExceptionRecord->ExceptionCode);
525}
526extern BOOL CreateWow64Events(DWORD,HANDLE*,HANDLE*,BOOL);
527// load kernel32 and look for iswow64. if not found, assume FALSE
528BOOL bIsWow64Process = FALSE;
529void init_wow64(void) {
530	HMODULE hlib;
531	//BOOL (WINAPI *pfnIsWow64)(HANDLE,BOOL*);
532	FARPROC pfnIsWow64;
533
534	bIsWow64Process = FALSE;
535
536	hlib = LoadLibrary("kernel32.dll");
537	if (!hlib) {
538		return;
539	}
540	pfnIsWow64 = GetProcAddress(hlib,"IsWow64Process");
541	if (!pfnIsWow64) {
542		FreeLibrary(hlib);
543		return;
544	}
545	if (!pfnIsWow64(GetCurrentProcess(),&bIsWow64Process) )
546		bIsWow64Process = FALSE;
547
548	FreeLibrary(hlib);
549	return;
550
551}
552
553extern void mainCRTStartup(void *);
554
555/*
556 * heap_init() MUST NOT be moved outside the entry point. Sometimes child
557 * processes may load random DLLs not loaded by the parent and
558 * use the heap address reserved for fmalloc() in the parent. This
559 * causes havoc as no dynamic memory can then be inherited.
560 *
561 */
562extern void heap_init(void);
563
564#include <forkdata.h>
565void silly_entry(void *peb) {
566	char * path1=NULL;
567	int rc;
568	char temp[MAX_PATH+5];
569	char buf[MAX_PATH];
570	char ptr1[MAX_PATH];
571	char ptr2[MAX_PATH];
572	char ptr3[MAX_PATH];
573	OSVERSIONINFO osver;
574
575	osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
576
577	if (!GetVersionEx(&osver)) {
578		MessageBox(NULL,"GetVersionEx failed","tcsh",MB_ICONHAND);
579		ExitProcess(0xFF);
580	}
581	gdwVersion = osver.dwMajorVersion;
582
583	if(gdwVersion < 6) // no wow64 hackery for vista.
584	{
585		init_wow64();
586	}
587
588#ifdef _M_IX86
589	// look at the explanation in fork.c for why we do these steps.
590	if (bIsWow64Process) {
591		HANDLE h64Parent,h64Child;
592		char *stk, *end;
593		DWORD mb = (1<<20);
594
595		// if we found the events, then we're the product of a fork()
596		if (CreateWow64Events(GetCurrentProcessId(),
597					&h64Parent,&h64Child,TRUE)) {
598
599			if (!h64Parent || !h64Child)
600				return;
601
602			// tell parent we're rolling
603			SetEvent(h64Child);
604
605			if(WaitForSingleObject(h64Parent,FORK_TIMEOUT) != WAIT_OBJECT_0) {
606				return;
607			}
608
609			// if __forked is 0, we shouldn't have found the events
610			if (!__forked)
611				return;
612		}
613
614		// now create the stack
615
616		if (!__forked) {
617			stk = VirtualAlloc(NULL,mb+65536,MEM_COMMIT,PAGE_READWRITE);
618			if (!stk) {
619				dprintf("virtual alloc in parent failed %d\n",GetLastError());
620				return;
621			}
622			end = stk + mb + 65536;
623			end -= sizeof(char*);
624
625			__fork_stack_begin = end;
626
627			__asm {mov esp,end };
628
629			set_stackbase(end);
630			heap_init();
631		}
632		else { // child process
633			stk = (char*)__fork_stack_begin + sizeof(char*)- mb - 65536;
634
635			dprintf("begin is 0x%08x\n",stk);
636			end = VirtualAlloc(stk, mb+65536 , MEM_RESERVE , PAGE_READWRITE);
637			if (!end) {
638				rc = GetLastError();
639				dprintf("virtual alloc 1 in child failed %d\n",rc);
640				return;
641			}
642			stk = VirtualAlloc(end, mb+65536 , MEM_COMMIT , PAGE_READWRITE);
643			if (!stk) {
644				rc = GetLastError();
645				dprintf("virtual alloc 2 in child failed %d\n",rc);
646				return;
647			}
648			end = stk + mb + 65536;
649			__asm {mov esp, end};
650			set_stackbase(end);
651
652			SetEvent(h64Child);
653
654			CloseHandle(h64Parent);
655			CloseHandle(h64Child);
656		}
657	}
658#endif _M_IX86
659
660
661	SetFileApisToOEM();
662
663	if (!bIsWow64Process)
664		heap_init();
665
666
667
668
669	/* If home is set, we only need to change '\' to '/' */
670	rc = GetEnvironmentVariable("HOME",buf,MAX_PATH);
671	if (rc && (rc < MAX_PATH)){
672		path_slashify(buf);
673		(void)SetEnvironmentVariable("HOME",buf);
674		goto skippy;
675	}
676
677	memset(ptr1,0,MAX_PATH);
678	memset(ptr2,0,MAX_PATH);
679	memset(ptr3,0,MAX_PATH);
680
681	if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
682		GetEnvironmentVariable("USERPROFILE",ptr1,MAX_PATH);
683		GetEnvironmentVariable("HOMEDRIVE",ptr2,MAX_PATH);
684		GetEnvironmentVariable("HOMEPATH",ptr3,MAX_PATH);
685
686		ptr1[MAX_PATH -1] = ptr2[MAX_PATH-1] = ptr3[MAX_PATH-1]= 0;
687
688#pragma warning(disable:4995)
689		if (!ptr1[0] || osver.dwMajorVersion <4) {
690			wsprintfA(temp, "%s%s",ptr2[0]?ptr2:"C:",ptr3[0]?ptr3:"\\");
691		}
692		else if (osver.dwMajorVersion >= 4) {
693			wsprintfA(temp, "%s",ptr1);
694		}
695#pragma warning(default:4995)
696	}
697	else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
698
699		rc = GetWindowsDirectory(ptr1,MAX_PATH);
700		if (rc > MAX_PATH) {
701			MessageBox(NULL,"This should never happen","tcsh",MB_ICONHAND);
702			ExitProcess(0xFF);
703		}
704		(void)StringCbPrintf(temp,sizeof(temp),"%s",ptr1);
705	}
706	else {
707		MessageBox(NULL,"Unknown platform","tcsh",MB_ICONHAND);
708	}
709	path_slashify(temp);
710	SetEnvironmentVariable("HOME",temp);
711
712skippy:
713	gdwPlatform = osver.dwPlatformId;
714
715
716	rc = GetEnvironmentVariable("Path",path1,0);
717	if ( rc !=0) {
718
719		path1 =heap_alloc(rc);
720
721		GetEnvironmentVariable("Path",path1,rc);
722		SetEnvironmentVariable("Path",NULL);
723		/*SetEnvironmentVariable("PATH",NULL);*/
724		SetEnvironmentVariable("PATH",path1);
725
726		heap_free(path1);
727	}
728	mainCRTStartup(peb);
729}
730
731/*
732 * Copy source into target, quote if it has space, also converting '/' to '\'.
733 *
734 * hasdot is set to 1 if source ends in a file extension
735 * return value is the  length of the string copied.
736 */
737int copy_quote_and_fix_slashes(char *source,char *target, int *hasdot ) {
738
739	int len ;
740	int hasspace;
741	char *save;
742	char *ptr;
743
744	save = target; /* leave space for quote */
745	len = 1;
746
747	target++;
748
749	hasspace = 0;
750	while(*source) {
751		if (*source == '/')
752			*source = '\\';
753		else if (*source == ' ')
754			hasspace = 1;
755
756		*target++ = *source;
757
758		source++;
759		len++;
760	}
761	ptr  = target;//source;
762	while( (ptr > save ) && (*ptr != '\\')) {
763		if (*ptr == '.')
764			*hasdot = 1;
765		ptr--;
766	}
767
768	if (hasspace) {
769		*save = '"';
770		*target = '"';
771		len++;
772	}
773	return len;
774}
775/*
776 * This routine is a replacement for the old, horrible strcat() loop
777 * that was used to turn the argv[] array into a string for CreateProcess().
778 * It's about a zillion times faster.
779 * -amol 2/4/99
780 */
781char *concat_args_and_quote(char **args, char **poriginalPtr,char **cstr,
782		unsigned int *clen, char **cend, unsigned int *cmdsize) {
783
784	unsigned int argcount, arglen, cmdlen;
785	char *tempptr, *cmdend ,*cmdstr;
786	short quotespace = 0;
787	short quotequote = 0;
788	short noquoteprotect = 0;
789	char *tempquotedbuf;
790	unsigned long tqlen = 256;
791	int rc;
792
793	dprintf("entering concat_args_and_quote\n");
794	tempquotedbuf = heap_alloc(tqlen);
795
796	noquoteprotect = (short)(varval(STRNTnoquoteprotect) != STRNULL);
797	/*
798	   quotespace hack needed since execv() would have separated args, but
799	   createproces doesnt
800	   -amol 9/14/96
801	 */
802	cmdend= *cend;
803	cmdstr = *cstr;
804	cmdlen = *clen;
805
806	argcount = 0;
807	while (*args) {
808
809		*cmdend++ = ' ';
810		cmdlen++;
811
812		tempptr = *args;
813
814		arglen = 0;
815		argcount++;
816
817		//dprintf("args is %s\n",*args);
818		if (!*tempptr) {
819			*cmdend++ = '"';
820			*cmdend++ = '"';
821		}
822		while(*tempptr) {
823			if (*tempptr == ' ' || *tempptr == '\t')
824				quotespace = 1;
825			else if (*tempptr == '"')
826				quotequote = 1;
827			tempptr++;
828			arglen++;
829		}
830		if (arglen + cmdlen +4 > *cmdsize) { // +4 is if we have to quote
831
832
833			tempptr = heap_realloc(*poriginalPtr,*cmdsize<<1);
834
835			if(!tempptr)
836				return NULL;
837
838			// If it's not the same heap block, re-adjust the pointers.
839			if (tempptr != *poriginalPtr) {
840				cmdstr = tempptr + (cmdstr - *poriginalPtr);
841				cmdend = tempptr + (cmdend- *poriginalPtr);
842				*poriginalPtr = tempptr;
843			}
844
845			*cmdsize <<=1;
846		}
847		if (quotespace)
848			*cmdend++ = '"';
849
850		if ((noquoteprotect == 0) && quotequote){
851			tempquotedbuf[0]=0;
852
853			tempptr = &tempquotedbuf[0];
854
855			rc = quoteProtect(tempquotedbuf,*args,tqlen);
856
857			while(rc == ERROR_BUFFER_OVERFLOW) {
858				char *tmp = tempquotedbuf;
859				tempquotedbuf = heap_realloc(tempquotedbuf,tqlen <<1);
860				if(!tempquotedbuf) {
861					heap_free(tmp);
862					return NULL;
863				}
864				tqlen <<= 1;
865				tempptr = &tempquotedbuf[0];
866				rc = quoteProtect(tempquotedbuf,*args,tqlen);
867			}
868			while (*tempptr) {
869				*cmdend = *tempptr;
870				cmdend++;
871				tempptr++;
872			}
873			cmdlen +=2;
874		}
875		else {
876			tempptr = *args;
877			while(*tempptr) {
878				*cmdend = *tempptr;
879				cmdend++;
880				tempptr++;
881			}
882		}
883
884		if (quotespace) {
885			*cmdend++ = '"';
886			cmdlen +=2;
887		}
888		cmdlen += arglen;
889
890		args++;
891	}
892	*clen = cmdlen;
893	*cend = cmdend;
894	*cstr = cmdstr;
895
896	heap_free(tempquotedbuf);
897
898
899	return cmdstr;
900}
901char *fix_path_for_child(void) {
902
903	char *ptr;
904	Char *vp;
905	char *pathstr;
906	char *oldpath;
907	long len;
908
909	vp = varval(STRNTlamepathfix);
910
911	if (vp != STRNULL) {
912
913		len = GetEnvironmentVariable("PATH",NULL,0);
914
915		oldpath = heap_alloc(len+1);
916		pathstr = heap_alloc(len+1);
917
918		len = GetEnvironmentVariable("PATH",oldpath,len+1);
919		memcpy(pathstr,oldpath,len);
920
921		ptr = pathstr;
922		while(*ptr) {
923			if (*ptr == '/')
924				*ptr = '\\';
925			ptr++;
926		}
927		SetEnvironmentVariable("PATH",pathstr);
928		heap_free(pathstr);
929
930		return oldpath; //freed in restore_path;
931	}
932	else
933		return NULL;
934
935}
936void restore_path(char *oldpath) {
937	if (oldpath) {
938		SetEnvironmentVariable("PATH",oldpath);
939		heap_free(oldpath);
940	}
941}
942