1/*$Header: /p/tcsh/cvsroot/tcsh/win32/ntfunc.c,v 1.19 2006/08/27 01:13:28 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 * ntfunc.c builtins specific to NT
33 * -amol
34 *
35 */
36#pragma warning(push,3)
37#define WIN32_LEAN_AND_MEAN
38#include <windows.h>
39#include <shellapi.h>
40#pragma warning(pop)
41#include <errno.h>
42#include <sh.h>
43#include "ed.h"
44
45#include "nt.const.h"
46
47
48extern DWORD gdwPlatform;
49
50extern	 int StrQcmp(Char *, Char *);
51extern int hashval_extern(Char*);
52extern int bit_extern(int,int);
53extern void bis_extern(int,int);
54extern int hashname(Char*);
55
56extern void NT_ClearScreen_WholeBuffer(void);
57
58BOOL is_url(const char *cmd);
59
60void error(char * ) ;
61void make_err_str(unsigned int ,char *,int) ;
62
63#define	INF INT_MAX
64struct	biltins nt_bfunc[] = {
65	{ "cls",		docls,		0,	0	},
66#ifdef NTDBG
67	{ "debugbreak",	dodebugbreak,	0,	0	},
68#endif /* NTDBG */
69	{ "ps",	dops,	0,	1	},
70	{ "shutdown",	doshutdown,	0,	2	},
71	{ "start",		dostart,	1,	INF	},
72	{ "title",		dotitle,	1,	INF	},
73};
74int nt_nbfunc = sizeof nt_bfunc / sizeof *nt_bfunc;
75
76char start_usage[] = { ":\n \
77	Similar to cmd.exe's start  \n \
78		start [-Ttitle] [-Dpath] [-min] [-max] [-separate] [-shared] \n \
79		[-low|normal|realtime|high] program args \n \
80		Batch/Cmd files must be started with CMD /K \n"
81};
82
83struct biltins * nt_check_additional_builtins(Char *cp) {
84
85	register struct biltins  *bp1, *bp2;
86	int i;
87
88	for (bp1 = nt_bfunc, bp2 = nt_bfunc + nt_nbfunc; bp1 < bp2;bp1++) {
89
90		if ((i = ((char) *cp) - *bp1->bname) == 0 &&
91				(i = StrQcmp(cp, str2short(bp1->bname))) == 0)
92			return bp1;
93	}
94	return (0);
95}
96void nt_print_builtins(size_t maxwidth) {
97
98	/* would use print_by_column() in tw.parse.c but that assumes
99	 * we have an array of Char * to pass.. (sg)
100	 */
101	extern int Tty_raw_mode;
102	extern int TermH;		/* from the editor routines */
103	extern int lbuffed;		/* from sh.print.c */
104
105	register struct biltins *b;
106	register size_t row, col, columns, rows;
107	size_t w ,oldmax;
108
109
110	/* find widest string */
111
112	oldmax = maxwidth;
113
114	for ( b = nt_bfunc; b < &nt_bfunc[nt_nbfunc]; ++b)
115		maxwidth = max(maxwidth, (int)lstrlen(b->bname));
116
117	if (oldmax != maxwidth)
118		++maxwidth;					/* for space */
119
120	columns = (TermH + 1) / maxwidth;	/* PWP: terminal size change */
121	if (!columns)
122		columns = 1;
123	rows = (nt_nbfunc + (columns - 1)) / columns;
124
125	for (b = nt_bfunc, row = 0; row < rows; row++) {
126		for (col = 0; col < columns; col++) {
127			if (b < &nt_bfunc[nt_nbfunc]) {
128				w = (int)lstrlen(b->bname);
129				xprintf("%s", b->bname);
130				if (col < (columns - 1))	/* Not last column? */
131					for (; w < maxwidth; w++)
132						xputchar(' ');
133				++b;
134			}
135		}
136		if (Tty_raw_mode)
137			xputchar('\r');
138		xputchar('\n');
139	}
140
141}
142/* patch from TAGA Nayuta for start . */
143BOOL is_directory(const char *the_cmd) {
144	DWORD attr = GetFileAttributes(the_cmd);
145	return (attr != 0xFFFFFFFF &&
146			(attr & FILE_ATTRIBUTE_DIRECTORY));
147}
148void dostart(Char ** vc, struct command *c) {
149
150	char *cmdstr,*cmdend,*ptr;
151	char argv0[256];/*FIXBUF*/
152	DWORD cmdsize;
153	char *currdir=NULL;
154	char *savepath;
155	char **v = NULL;
156	STARTUPINFO si;
157	PROCESS_INFORMATION pi;
158	DWORD dwCreationFlags=CREATE_NEW_CONSOLE;
159	DWORD k,cmdlen,j,jj,ret;
160
161
162	UNREFERENCED_PARAMETER(c);
163	vc++;
164
165	cmdsize = 512;
166	cmdstr = heap_alloc(cmdsize);
167	cmdend = cmdstr;
168	cmdlen = 0;
169
170	memset(&si,0,sizeof(si));
171	si.cb = sizeof(si);
172
173	vc = glob_all_or_error(vc);
174	v = short2blk(vc);
175	if(v == NULL) {
176		stderror(ERR_NOMEM);
177		return;
178	}
179	blkfree(vc);
180	for (k = 0; v[k] != NULL ; k++){
181
182		if ( v[k][0] == '-' ) {
183			/* various options */
184			if( (v[k][1] == 'T') || (v[k][1] == 't'))
185				si.lpTitle =&( v[k][2]);
186			else if ( (v[k][1] == 'D') || (v[k][1] == 'd'))
187				currdir =&( v[k][2]);
188			else if (!_stricmp(&v[k][1],"MIN") )
189				si.wShowWindow = SW_SHOWMINIMIZED;
190			else if (!_stricmp(&v[k][1],"MAX") )
191				si.wShowWindow = SW_SHOWMAXIMIZED;
192			else if (!_stricmp(&v[k][1],"SEPARATE") )
193				dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
194			else if (!_stricmp(&v[k][1],"SHARED") )
195				dwCreationFlags |= CREATE_SHARED_WOW_VDM;
196			else if (!_stricmp(&v[k][1],"LOW") )
197				dwCreationFlags |= IDLE_PRIORITY_CLASS;
198			else if (!_stricmp(&v[k][1],"NORMAL") )
199				dwCreationFlags |= NORMAL_PRIORITY_CLASS;
200			else if (!_stricmp(&v[k][1],"HIGH") )
201				dwCreationFlags |= HIGH_PRIORITY_CLASS;
202			else if (!_stricmp(&v[k][1],"REALTIME") )
203				dwCreationFlags |= REALTIME_PRIORITY_CLASS;
204			else{
205				blkfree((Char **)v);
206				stderror(ERR_SYSTEM,start_usage,"See CMD.EXE for more info");/*FIXRESET*/
207			}
208		}
209		else{ // non-option arg
210			break;
211		}
212	}
213	/*
214	 * Stop the insanity of requiring start "tcsh -l"
215	 * Option processing now stops at first non-option arg
216	 * -amol 5/30/96
217	 */
218	for (jj=k;v[jj] != NULL; jj++) {
219		j=(lstrlen(v[jj]) + 2);
220		if (j + cmdlen > cmdsize) {
221			ptr = cmdstr;
222			cmdstr = heap_realloc(cmdstr, max(cmdsize << 1, j+cmdlen) );
223			if(!cmdstr)
224			{
225				heap_free(ptr);
226				stderror(ERR_NOMEM,"start");/*FIXRESET*/
227			}
228			cmdend =  cmdstr + (cmdend - ptr);
229			cmdsize <<= 1;
230		}
231		ptr = v[jj];
232		while (*ptr) {
233			*cmdend++ = *ptr++;
234			cmdlen++;
235		}
236		*cmdend++ = ' ';
237		cmdlen++;
238	}
239	if (jj == k) {
240		blkfree((Char **)v);
241		stderror(ERR_SYSTEM,start_usage,"See CMD.EXE for more info");/*FIXRESET*/
242		return;
243	}
244	*cmdend = 0;
245	StringCbCopy(argv0,sizeof(argv0),v[k]);
246
247
248	/*
249	 * strictly speaking, it should do no harm to set the path
250	 * back to '\'-delimited even in the parent, but in the
251	 * interest of consistency, we save the old value and restore it
252	 * later
253	 */
254
255	savepath = fix_path_for_child();
256
257	if (! CreateProcess(NULL,
258				cmdstr,
259				NULL,
260				NULL,
261				FALSE,
262				dwCreationFlags,
263				NULL,
264				currdir,
265				&si,
266				&pi) ) {
267
268		restore_path(savepath);
269
270		ret = GetLastError();
271		if (ret == ERROR_BAD_EXE_FORMAT || ret == ERROR_ACCESS_DENIED ||
272				(ret == ERROR_FILE_NOT_FOUND &&
273				 (is_url(v[k]) || is_directory(v[k]))
274				)
275		   ) {
276
277			char erbuf[MAX_PATH];
278
279			errno = ENOEXEC;
280
281			try_shell_ex(&v[k],0,FALSE);
282
283			heap_free(cmdstr); /* free !! */
284
285			if (errno) {
286				strerror_s(erbuf,sizeof(erbuf),errno);
287				stderror(ERR_ARCH,argv0,erbuf);/*FIXRESET*/
288			}
289		}
290		else if (ret == ERROR_INVALID_PARAMETER) {
291
292			errno = ENAMETOOLONG;
293
294			heap_free(cmdstr); /* free !! */
295
296			stderror(ERR_TOOLARGE,argv0);/*FIXRESET*/
297
298		}
299		else {
300			errno = ENOENT;
301			if (
302					( (v[k][0] == '\\') ||(v[k][0] == '/') ) &&
303					( (v[k][1] == '\\') ||(v[k][1] == '/') ) &&
304					(!v[k+1])
305			   )
306				try_shell_ex(&v[k],0,FALSE);
307
308			heap_free(cmdstr); /* free !! */
309			if (errno) {
310				stderror(ERR_NOTFOUND,argv0);/*FIXRESET*/
311			}
312		}
313	}
314	else {
315		CloseHandle(pi.hProcess);
316		CloseHandle(pi.hThread);
317
318		heap_free(cmdstr);
319		restore_path(savepath);
320	}
321	blkfree((Char **)v);
322	return;
323}
324void error(char * ebuf) {
325
326	write(2,(unsigned char*)ebuf,lstrlen(ebuf));
327}
328void make_err_str(unsigned int error,char *buf,int size) {
329
330	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
331			NULL,
332			error,
333			MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
334			buf,
335			size,
336			NULL);
337	return;
338
339}
340
341// We should really use the environ array, but NT likes it to be sorted.
342// So we just let the win32 apis  take care of inheritance of the environment.
343// -amol 4/7/97
344//
345//char nameBuf[BUFSIZ], valBuf[BUFSIZ];
346char dummy;
347char *nameBuf=&dummy, *valBuf=&dummy;
348
349void nt_set_env(const Char *name, const Char *val) {
350	char *cname, *cval;
351	int len;
352
353	cname = name?short2str(name):NULL;
354	if(cname) {
355		len = lstrlen(cname);
356		nameBuf = heap_alloc(len+1);
357		if (!nameBuf) {
358			stderror(ERR_TOOLARGE);
359		}
360		StringCbCopy(nameBuf,len+1,cname);
361	}
362	cval = val?short2str(val):NULL;
363	if(cval) {
364		len = lstrlen(cval);
365		valBuf = heap_alloc(len+1);
366		StringCbCopy(valBuf,len+1,cval);
367	}
368
369	SetEnvironmentVariable(nameBuf,cval?valBuf:NULL);
370
371	if (!lstrcmp(nameBuf,"TCSHONLYSTARTEXES"))
372		init_shell_dll();
373
374	heap_free(nameBuf);
375	if (cval)
376		heap_free(valBuf);
377
378
379}
380void dotitle(Char **vc, struct command * c) {
381
382	int k;
383	char titlebuf[512];
384	char errbuf[128],err2[128];
385	char **v;
386
387	UNREFERENCED_PARAMETER(c);
388	vc++;
389	vc = glob_all_or_error(vc);
390	cleanup_push(vc, blk_cleanup);
391
392	if ((k=GetConsoleTitle(titlebuf,512) ) != 0) {
393		titlebuf[k]=0;
394		setcopy(STRoldtitle,str2short(titlebuf),VAR_READWRITE);
395	}
396
397	memset(titlebuf,0,512);
398	v = short2blk(vc);
399	cleanup_until(vc);
400	cleanup_push((Char **)v, blk_cleanup);
401	for (k = 0; v[k] != NULL ; k++){
402		__try {
403			StringCbCat(titlebuf,sizeof(titlebuf),v[k]);
404			StringCbCat(titlebuf,sizeof(titlebuf)," ");
405		}
406		__except(GetExceptionCode()) {
407			stderror(ERR_TOOMANY);
408		}
409	}
410
411	if (!SetConsoleTitle(titlebuf) ) {
412		make_err_str(GetLastError(),errbuf,128);
413		(void)StringCbPrintf(err2,sizeof(err2),"%s",v[k]);
414		stderror(ERR_SYSTEM,err2,errbuf);
415	}
416	cleanup_until((Char **)v);
417	return;
418}
419void docls(Char **vc, struct command *c) {
420	UNREFERENCED_PARAMETER(vc);
421	UNREFERENCED_PARAMETER(c);
422	NT_ClearScreen_WholeBuffer();
423}
424int nt_feed_to_cmd(char *file,char **argv) {
425
426	char *ptr, *orig;
427	char cmdbuf[128];
428	HANDLE htemp;
429	STARTUPINFO si;
430	PROCESS_INFORMATION pi;
431
432	if (!file)
433		return 1;
434
435	ptr = strrchr(file,'.');
436
437	if(!ptr)
438		return 1;
439
440	if (lstrlen(ptr) <4)
441		return 1;
442
443	if ( _stricmp(ptr,".bat") &&  _stricmp(ptr,".cmd") )
444		return 1;
445
446
447	memset(&si,0,sizeof(si));
448	memset(&pi,0,sizeof(pi));
449
450	si.cb = sizeof(si);
451	si.dwFlags = STARTF_USESTDHANDLES;
452	htemp= (HANDLE)_get_osfhandle(0);
453	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
454			&si.hStdInput,0,TRUE,DUPLICATE_SAME_ACCESS);
455	htemp= (HANDLE)_get_osfhandle(1);
456	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
457			&si.hStdOutput,0,TRUE,DUPLICATE_SAME_ACCESS);
458	htemp= (HANDLE)_get_osfhandle(2);
459	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
460			&si.hStdError,0,TRUE,DUPLICATE_SAME_ACCESS);
461
462
463	ptr =file;
464	while(*ptr) {
465		if (*ptr == '/')
466			*ptr = '\\';
467		ptr++;
468	}
469	if (gdwPlatform == VER_PLATFORM_WIN32_WINDOWS){
470		(void)StringCbPrintf(cmdbuf,sizeof(cmdbuf),
471							 "command.com /c %s",file);
472	}
473	else
474		(void)StringCbPrintf(cmdbuf,sizeof(cmdbuf),
475							 "cmd /c %s",file);
476
477	argv++;
478	ptr = &cmdbuf[0] ;
479	orig = ptr;
480	while(*argv) {
481		StringCbCat(ptr,sizeof(cmdbuf) - (orig - ptr), " ");
482		StringCbCat(ptr,sizeof(cmdbuf) - (orig - ptr),*argv);
483		argv++;
484	}
485
486	ptr = fix_path_for_child();
487
488	if (!CreateProcess(NULL,
489				cmdbuf,
490				NULL,
491				NULL,
492				TRUE,
493				0,//CREATE_NEW_CONSOLE |CREATE_NEW_PROCESS_GROUP,
494				NULL,
495				NULL,
496				&si,
497				&pi) ){
498		restore_path(ptr);
499	}
500	else {
501
502		restore_path(ptr);
503		CloseHandle(pi.hThread);
504		WaitForSingleObject(pi.hProcess,INFINITE);
505		CloseHandle(pi.hProcess);
506		ExitProcess(0);
507	}
508
509	return 1; /*NOTREACHED*/
510}
511static char *hb_subst_array[20] ;
512void init_hb_subst(void) {
513	int i= 0;
514	size_t len;
515	char envbuf[1024];
516	char *ptr;
517	char *p2;
518
519	envbuf[0]=0;
520
521	GetEnvironmentVariable("TCSHSUBSTHB",envbuf,1024);
522
523	ptr = &envbuf[0];
524
525	if (!*ptr)
526		return;
527
528	p2 = ptr;
529
530	while (*ptr) {
531		if (*ptr == ';') {
532			len = ptr - p2;
533			if (!len){
534				ptr++;
535				continue;
536			}
537			hb_subst_array[i] = heap_alloc(len+1);
538			StringCbCopy(hb_subst_array[i],len + 1, p2);
539
540			i++;
541			p2 = ptr+1;
542		}
543		ptr++;
544	}
545}
546char *hb_subst(char *orig) {
547	int i, match;
548	char *p1;
549
550	for(i =0 ;i <20; i++) {
551		p1 = hb_subst_array[i];
552		if (!p1)
553			continue;
554		while(*p1 != ' ')
555			p1++;
556
557		*p1 = 0;
558		match = !_stricmp(orig,hb_subst_array[i]);
559		*p1 = ' ';
560		if (match){
561			return (p1+1);
562		}
563	}
564	return NULL;
565
566}
567typedef BOOL (__stdcall *shell_ex_func)(LPSHELLEXECUTEINFO);
568
569/* DO NOT initialize these here -amol */
570static HMODULE hShellDll;
571static shell_ex_func pShellExecuteEx;
572int __nt_only_start_exes;
573
574static char no_assoc[256]; //the environment string/*FIXBUF*/
575static char *no_assoc_array[20]; // the list of extensions to NOT try /*FIXBUF*/
576// explorer associations for
577
578void init_shell_dll(void) {
579
580	int rc,i;
581	size_t len;
582	char *p2, *ptr;
583
584	if (!hShellDll) {
585		hShellDll = LoadLibrary("Shell32.dll");
586		if (hShellDll) {
587			pShellExecuteEx = (shell_ex_func)GetProcAddress(
588					hShellDll,
589					"ShellExecuteEx");
590		}
591	}
592	rc=GetEnvironmentVariable("TCSHONLYSTARTEXES",no_assoc,256) ;
593	if (!rc || (rc > 255))
594		return;
595
596	if (rc == 1) {
597		__nt_only_start_exes = 1;
598		return;
599	}
600
601	ptr = &no_assoc[0];
602	i = 0;
603
604	if (!ptr)
605		return;
606
607	p2 = ptr;
608
609	while (i < 20) {
610		if (*ptr == ';' || (!*ptr)) {
611			len = ptr - p2;
612			if (!len){
613				ptr++;
614				continue;
615			}
616			no_assoc_array[i] = heap_alloc(len+1);
617			StringCbCopy(no_assoc_array[i],len+1, p2);
618			dprintf("no_assoc array %d inited to %s\n",i,no_assoc_array[i]);
619
620			i++;
621			p2 = ptr+1;
622		}
623		if (!*ptr)
624			break;
625		ptr++;
626	}
627#if NTDBG
628	for(i=0;i<20,no_assoc_array[i] != NULL;i++)
629		dprintf("no_assoc array %d inited remains %s\n",i,no_assoc_array[i]);
630#endif NTDBG
631
632}
633// return non-zero if str is found in no_assoc_array
634int find_no_assoc(char *my_str) {
635	int i, match;
636	char *p1;
637
638	for(i =0 ;i <20; i++) {
639		p1 = no_assoc_array[i];
640		dprintf("no_assoc array %d is %s\n",i,no_assoc_array[i]);
641		if (!p1)
642			continue;
643		match = !_stricmp(my_str,no_assoc_array[i]);
644		if (match)
645			return 1;
646	}
647	return 0;
648}
649void try_shell_ex(char **argv,int exitsuccess, BOOL throw_ok) {/*FIXRESET*/
650
651	char *prog;
652	char *cmdstr, *p2, *cmdend;
653	char *originalPtr = NULL;
654	unsigned int cmdsize,cmdlen;
655	char err2[256];
656	char *ptr;
657	SHELLEXECUTEINFO shinfo;
658	unsigned long  mask = SEE_MASK_FLAG_NO_UI;
659	BOOL rc;
660	char *extension;
661
662	prog=*argv;
663
664	dprintf("trying shellex for prog %s\n",prog);
665	ptr = prog;
666	if (!is_url(prog)) {
667
668		while(*ptr) {
669			if (*ptr == '/')
670				*ptr = '\\';
671			ptr++;
672		}
673
674		extension = ptr;
675
676		// search back for "."
677		while(extension != prog) {
678			if (*extension == '.') {
679				extension++;
680				break;
681			}
682			else
683				extension--;
684		}
685		/* check if this matches a member in the no_assoc array.
686		 */
687		if (extension != prog)  {
688			if (find_no_assoc(extension))
689				return;
690		}
691
692	}
693	originalPtr = cmdstr= heap_alloc(MAX_PATH<<2);
694
695	cmdsize = MAX_PATH<<2;
696
697	p2 = cmdstr;
698
699	cmdlen = 0;
700	cmdend = p2;
701
702	argv++; // the first arg is the command
703
704
705	dprintf("try_shell_ex calling c_a_a_q");
706	if(!concat_args_and_quote(argv,&originalPtr,&cmdstr,&cmdlen,&cmdend,&cmdsize))
707	{
708		errno = ENOMEM;
709		heap_free(originalPtr);
710		return;
711	}
712
713	*cmdend = 0;
714
715
716	memset(&shinfo,0,sizeof(shinfo));
717	shinfo.cbSize = sizeof(shinfo);
718	shinfo.fMask = SEE_MASK_FLAG_DDEWAIT | mask;
719	shinfo.hwnd = NULL;
720	shinfo.lpVerb = NULL;
721	shinfo.lpFile = prog;
722	shinfo.lpParameters = &cmdstr[0];
723	shinfo.lpDirectory = 0;
724	shinfo.nShow = SW_SHOWDEFAULT;
725
726
727	ptr = fix_path_for_child();
728
729	rc = pShellExecuteEx(&shinfo);
730	if (rc ) {
731		if (exitsuccess)
732			ExitProcess(0);
733		errno = 0;
734
735		heap_free(originalPtr);
736		return;
737	}
738	if (throw_ok) {
739		// if we got here, ShellExecuteEx failed, so reset() via stderror()
740		// this may cause the caller to leak, but the assumption is that
741		// only a child process sets exitsuccess, so it will be dead soon
742		// anyway
743
744		restore_path(ptr);
745
746		make_err_str(GetLastError(),cmdstr,512);//don't need the full size
747		(void)StringCbPrintf(err2,sizeof(err2),"%s",prog);
748		stderror(ERR_SYSTEM,err2,cmdstr);/*FIXRESET*/
749	}
750
751	heap_free(originalPtr);
752	restore_path(ptr);
753
754	errno = ENOEXEC;
755
756}
757#ifdef NTDBG
758void dodebugbreak(Char **vc, struct command *c) {
759	UNREFERENCED_PARAMETER(vc);
760	UNREFERENCED_PARAMETER(c);
761	DebugBreak();
762}
763#endif NTDBG
764int nt_texec(char *, char**) ;
765static Char *epath;
766static Char *abspath[] = {STRNULL,0};
767int nt_try_fast_exec(struct command *t) {
768	register Char  **pv, **av;
769	register Char *dp,*sav;
770	register char **tt;
771	register char *f;
772	register struct varent *v;
773	register int hashval,i;
774	register int slash;
775	int rc = 0, gflag;
776	Char *vp;
777	Char   *blk[2];
778
779	vp = varval(STRNTslowexec);
780	if (vp != STRNULL)
781		return 1;
782
783	blk[0] = t->t_dcom[0];
784	blk[1] = 0;
785
786	// don't do backtick
787	if(Strchr(t->t_dcom[0],'`') )
788		return 1;
789
790
791	gflag = tglob(blk);
792	if (gflag) {
793		pv = globall(blk, gflag);
794		if (pv == 0) {
795			return 1;
796		}
797	}
798	else
799		pv = saveblk(blk);
800
801	trim(pv);
802
803	epath = Strsave(pv[0]);
804	v = adrof(STRpath);
805	if (v == 0 && epath[0] != '/' && epath[0] != '.') {
806		blkfree(pv);
807		return 1;
808	}
809	slash = any(short2str(epath),'/');
810	/*
811	 * Glob the argument list, if necessary. Otherwise trim off the quote bits.
812	 */
813	av = &t->t_dcom[1];
814	gflag = tglob(av);
815	if (gflag) {
816		av = globall(av, gflag);/*FIXRESET*/
817		if (av == 0) {
818			blkfree(pv);
819			return 1;
820		}
821	}
822	else
823		av = saveblk(av);
824
825	blkfree(t->t_dcom);
826	t->t_dcom = blkspl(pv, av);
827	xfree((ptr_t) pv);
828	xfree((ptr_t) av);
829	av = t->t_dcom;
830	//trim(av);
831
832	if (*av == NULL || **av == '\0')
833		return 1;
834
835	xechoit(av);/*FIXRESET*/		/* Echo command if -x */
836	if (v == 0 || v->vec[0] == 0 || slash)
837		pv = abspath;
838	else
839		pv = v->vec;
840
841	sav = Strspl(STRslash,*av);
842	hashval = hashval_extern(*av);
843
844	i = 0;
845	do {
846#pragma warning(disable:4310)
847		if (!slash && ABSOLUTEP(pv[0]) && havhash) {
848#pragma warning(default:4310)
849			if (!bit_extern(hashval,i)){
850				pv++;i++;
851				continue;
852			}
853		}
854		if (pv[0][0] == 0 || eq(pv[0],STRdot)) {
855
856			tt = short2blk(av);
857			f = short2str(*av);
858
859			rc = nt_texec(f, tt);
860
861			blkfree((Char**)tt);
862			if (!rc)
863				break;
864		}
865		else {
866			dp = Strspl(*pv,sav);
867			tt = short2blk(av);
868			f = short2str(dp);
869
870			rc = nt_texec(f, tt);
871
872			blkfree((Char**)tt);
873			xfree((ptr_t)dp);
874			if (!rc)
875				break;
876		}
877		pv++;
878		i++;
879	}while(*pv);
880	return rc;
881}
882int nt_texec(char *prog, char**args ) {
883
884	STARTUPINFO si;
885	PROCESS_INFORMATION pi;
886	HANDLE htemp;
887	DWORD type=0;
888	DWORD dwCreationflags;
889	unsigned int priority;
890	char *argv0 = NULL, *savepath = NULL;
891	char *cmdstr,*cmdend ;
892	char *originalPtr = NULL;
893	unsigned int cmdsize,cmdlen;
894	char *p2;
895	char **savedargs;
896	int retries=0;
897	int hasdot =0;
898	int is_winnt=0;
899	int retval = 1;
900
901	memset(&si,0,sizeof(si));
902	savedargs = args;
903
904	/* MUST FREE !! */
905	originalPtr = cmdstr= heap_alloc(MAX_PATH<<2);
906	cmdsize = MAX_PATH<<2;
907
908	is_winnt = (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS);
909
910
911	p2 = cmdstr;
912
913	cmdlen = 0;
914	cmdlen += copy_quote_and_fix_slashes(prog,cmdstr,&hasdot);
915	p2 += cmdlen;
916
917	if (*cmdstr != '"') {
918		// If not quoted, skip initial character we left for quote
919		*cmdstr = 'A';
920		cmdstr++;
921		cmdsize--;
922	}
923	*p2 = 0;
924	cmdend = p2;
925
926	if (!is_winnt) {
927		argv0 = NULL;
928	}
929	else {
930		argv0= heap_alloc(MAX_PATH);
931		(void)StringCbPrintf(argv0,MAX_PATH,"%s",prog);
932	}
933
934	si.cb = sizeof(STARTUPINFO);
935	si.dwFlags = STARTF_USESTDHANDLES;
936	htemp= (HANDLE)_get_osfhandle(SHIN);
937	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
938			&si.hStdInput,0,TRUE,DUPLICATE_SAME_ACCESS);
939	htemp= (HANDLE)_get_osfhandle(SHOUT);
940	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
941			&si.hStdOutput,0,TRUE,DUPLICATE_SAME_ACCESS);
942	htemp= (HANDLE)_get_osfhandle(SHDIAG);
943	DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(),
944			&si.hStdError,0,TRUE,DUPLICATE_SAME_ACCESS);
945
946
947	/*
948	   quotespace hack needed since execv() would have separated args, but
949	   createproces doesnt
950	   -amol 9/14/96
951	 */
952
953	args++; // the first arg is the command
954
955	dprintf("nt_texec calling c_a_a_q");
956	if(concat_args_and_quote(args,&originalPtr,&cmdstr,&cmdlen,&cmdend,&cmdsize) == NULL)
957	{
958		retval = 1;
959		errno  = ENOMEM;
960		heap_free(originalPtr);
961		goto free_mem;
962	}
963
964	*cmdend = 0;
965
966	dwCreationflags = GetPriorityClass(GetCurrentProcess());
967	priority = GetThreadPriority(GetCurrentThread());
968
969	if (is_winnt) {
970		retries = 0;
971		// For NT, try ShellExecuteEx first
972		do {
973			if (GetBinaryType(argv0,&type))
974				break;
975			if (GetLastError() == ERROR_BAD_EXE_FORMAT){
976				errno = ENOEXEC;
977				if (!__nt_only_start_exes)
978					try_shell_ex(savedargs,0,FALSE);
979				if (errno) {
980					retval = 1;
981					goto free_mem;
982				}
983				else {
984					retval = 0;
985					goto free_mem;
986				}
987			}
988			// only try shellex again after appending ".exe fails
989			else if ( retries > 1 ){
990				if (
991						( (argv0[0] == '\\') ||(argv0[0] == '/') ) &&
992						( (argv0[1] == '\\') ||(argv0[1] == '/') ) &&
993						(!args[1])
994				   )
995					if (!__nt_only_start_exes)
996						try_shell_ex(savedargs,0,FALSE);
997				errno  = ENOENT;
998			}
999			if (retries == 0)
1000				(void)StringCbPrintf(argv0,MAX_PATH,"%s.exe",prog);
1001			else if (retries == 1) {
1002				(void)StringCbPrintf(argv0,MAX_PATH,"%s.EXE",prog);
1003			}
1004			retries++;
1005		}while(retries < 3);
1006	}
1007	savepath = fix_path_for_child();
1008re_cp:
1009	dprintf("nt_texec cmdstr %s\n",cmdstr);
1010
1011
1012	if (!CreateProcess(argv0,
1013				cmdstr,
1014				NULL,
1015				NULL,
1016				TRUE, // need this for redirecting std handles
1017				dwCreationflags,
1018				NULL,//envcrap,
1019				NULL,
1020				&si,
1021				&pi) ){
1022
1023		if (GetLastError() == ERROR_BAD_EXE_FORMAT) {
1024			errno  = ENOEXEC;
1025		}
1026		else if (GetLastError() == ERROR_INVALID_PARAMETER) {
1027			errno = ENAMETOOLONG;
1028		}else {
1029			errno  = ENOENT;
1030		}
1031		if (!is_winnt && !hasdot) { //append '.' to the end if needed
1032			StringCbCat(cmdstr,cmdsize,".");
1033			hasdot=1;
1034			goto re_cp;
1035		}
1036		retval = 1;
1037	}
1038	else{
1039		int gui_app ;
1040		DWORD exitcode;
1041		char guivar[50];
1042
1043
1044		if (GetEnvironmentVariable("TCSH_NOASYNCGUI",guivar,50))
1045			gui_app=0;
1046		else
1047			gui_app= is_gui(argv0);
1048
1049		if(!gui_app) {
1050			WaitForSingleObject(pi.hProcess,INFINITE);
1051			(void)GetExitCodeProcess(pi.hProcess,&exitcode);
1052			setv(STRstatus, putn(exitcode), VAR_READWRITE);/*FIXRESET*/
1053		}
1054		retval = 0;
1055		CloseHandle(pi.hProcess);
1056		CloseHandle(pi.hThread);
1057	}
1058free_mem:
1059	CloseHandle(si.hStdInput);
1060	CloseHandle(si.hStdOutput);
1061	CloseHandle(si.hStdError);
1062
1063	if(savepath)
1064		restore_path(savepath);
1065
1066	heap_free(originalPtr);
1067	if (argv0)
1068		heap_free(argv0);
1069	return retval;
1070}
1071BOOL is_url(const char *thecmd) {
1072	char *protocol;
1073	const char *c;
1074	HKEY hkey;
1075	char buf[2];
1076	DWORD type;
1077	DWORD size;
1078
1079	c = strchr(thecmd, ':');
1080	size = (DWORD)(c - thecmd);
1081	if (!c || size <= 1)
1082		return FALSE;
1083
1084	protocol = (char *)heap_alloc(size + 2);
1085	StringCbCopy(protocol,size+2, thecmd);
1086	protocol[size] = '\0';
1087
1088	if (RegOpenKeyEx(HKEY_CLASSES_ROOT, protocol, 0, KEY_READ, &hkey)
1089			!= ERROR_SUCCESS ) {
1090		heap_free(protocol);
1091		return FALSE;
1092	}
1093
1094	heap_free(protocol);
1095
1096	type = REG_SZ;
1097	size = sizeof(buf);
1098	if ( RegQueryValueEx(hkey, "URL Protocol", NULL, &type, (BYTE*)buf, &size)
1099			!= ERROR_SUCCESS) {
1100		RegCloseKey(hkey);
1101		return FALSE;
1102	}
1103	RegCloseKey(hkey);
1104	return TRUE;
1105}
1106/*
1107 * patch based on work by Chun-Pong Yu (bol.pacific.net.sg)
1108 */
1109BOOL is_nt_executable(char *path,char *extension) {
1110	DWORD exetype;
1111
1112	if (GetBinaryType(path,&exetype))
1113		return TRUE;
1114	if (*extension && find_no_assoc(extension))
1115		return TRUE;
1116
1117	return FALSE;
1118}
1119int executable(const Char *dir, const Char *name, int dir_ok)
1120{
1121	struct stat stbuf;
1122	Char    path[MAXPATHLEN + 1];
1123	char   *strname;
1124	char extension[MAXPATHLEN];
1125	char *ptr, *p2 ;
1126	int has_ext = 0;
1127	extern void copyn(Char *, const Char *, size_t);
1128	extern void catn(Char *, const Char *, int);
1129
1130	(void) memset(path, 0, sizeof(path));
1131
1132	if (dir && *dir) {
1133		copyn(path, dir, MAXPATHLEN);
1134		catn(path, name, MAXPATHLEN);
1135
1136		p2 = ptr = short2str(path);
1137
1138		while (*ptr++)
1139			continue;
1140		--ptr;
1141
1142		while(ptr > p2) {
1143			if (*ptr == '/')
1144				break;
1145			if (*ptr == '.') {
1146				has_ext = 1;
1147				StringCbCopy(extension,MAXPATHLEN,ptr+1);
1148				break;
1149			}
1150			ptr--;
1151		}
1152		if (!has_ext && (nt_stat(p2, &stbuf) == -1))
1153			catn(path, STRdotEXE, MAXPATHLEN);
1154		strname = short2str(path);
1155	}
1156	else
1157		strname = short2str(name);
1158
1159	return (stat(strname, &stbuf) != -1 &&
1160			((dir_ok && S_ISDIR(stbuf.st_mode)) ||
1161			 (S_ISREG(stbuf.st_mode) &&
1162			  (is_nt_executable(strname,extension) ||
1163			   (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)))
1164			 )));
1165}
1166	int
1167nt_check_if_windir(char *path)
1168{
1169	char windir[MAX_PATH];
1170
1171	(void)GetWindowsDirectory(windir, sizeof(windir));
1172	windir[2] = '/';
1173
1174	return (strstr(path, windir) != NULL);
1175}
1176
1177	void
1178nt_check_name_and_hash(int is_windir, char *file, int i)
1179{
1180	char name_only[MAX_PATH];
1181	char *tmp = (char *)strrchr(file, '.');
1182	char uptmp[5], *nameptr, *np2;
1183	int icount, hashval;
1184
1185	if(!tmp || tmp[4])
1186		goto nodot;
1187
1188	for (icount = 0; icount < 4; icount++)
1189		uptmp[icount] = (char)toupper(tmp[icount]);
1190	uptmp[4]=0;
1191
1192	if (is_windir)
1193		if((uptmp[1] != 'E') || (uptmp[2] != 'X') || (uptmp[3] != 'E'))
1194			return;
1195	(void) memset(name_only, 0, MAX_PATH);
1196	nameptr = file;
1197	np2 = name_only;
1198	while(nameptr != tmp) {
1199		*np2++= (char)tolower(*nameptr);
1200		nameptr++;
1201	}
1202	hashval = hashname(str2short(name_only));
1203	bis_extern(hashval, i);
1204nodot:
1205	hashval = hashname(str2short(file));
1206	bis_extern(hashval, i);
1207}
1208