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