void try_shell_ex(char **argv,int exitsuccess, BOOL throw_ok) {/*FIXRESET*/ char *prog; char *cmdstr, *p2, *cmdend; char *originalPtr = NULL; unsigned int cmdsize,cmdlen; char err2[256]; char *ptr; SHELLEXECUTEINFO shinfo; unsigned long mask = SEE_MASK_FLAG_NO_UI; BOOL rc; char *extension; prog=*argv; dprintf("trying shellex for prog %s\n",prog); ptr = prog; if (!is_url(prog)) { while(*ptr) { if (*ptr == '/') *ptr = '\\'; ptr++; } extension = ptr; // search back for "." while(extension != prog) { if (*extension == '.') { extension++; break; } else extension--; } /* check if this matches a member in the no_assoc array. */ if (extension != prog) { if (find_no_assoc(extension)) return; } } originalPtr = cmdstr= heap_alloc(MAX_PATH<<2); cmdsize = MAX_PATH<<2; p2 = cmdstr; cmdlen = 0; cmdend = p2; argv++; // the first arg is the command dprintf("try_shell_ex calling c_a_a_q"); if(!concat_args_and_quote(argv,&originalPtr,&cmdstr,&cmdlen,&cmdend,&cmdsize)) { errno = ENOMEM; heap_free(originalPtr); return; } *cmdend = 0; memset(&shinfo,0,sizeof(shinfo)); shinfo.cbSize = sizeof(shinfo); shinfo.fMask = SEE_MASK_FLAG_DDEWAIT | mask; shinfo.hwnd = NULL; shinfo.lpVerb = NULL; shinfo.lpFile = prog; shinfo.lpParameters = &cmdstr[0]; shinfo.lpDirectory = 0; shinfo.nShow = SW_SHOWDEFAULT; ptr = fix_path_for_child(); rc = pShellExecuteEx(&shinfo); if (rc ) { if (exitsuccess) ExitProcess(0); errno = 0; heap_free(originalPtr); return; } if (throw_ok) { // if we got here, ShellExecuteEx failed, so reset() via stderror() // this may cause the caller to leak, but the assumption is that // only a child process sets exitsuccess, so it will be dead soon // anyway restore_path(ptr); make_err_str(GetLastError(),cmdstr,512);//don't need the full size (void)StringCbPrintf(err2,sizeof(err2),"%s",prog); stderror(ERR_SYSTEM,err2,cmdstr);/*FIXRESET*/ } heap_free(originalPtr); restore_path(ptr); errno = ENOEXEC; }
int nt_texec(char *prog, char**args ) { STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE htemp; DWORD type=0; DWORD dwCreationflags; unsigned int priority; char *argv0 = NULL, *savepath = NULL; char *cmdstr,*cmdend ; char *originalPtr = NULL; unsigned int cmdsize,cmdlen; char *p2; char **savedargs; int retries=0; int hasdot =0; int is_winnt=0; int retval = 1; memset(&si,0,sizeof(si)); savedargs = args; /* MUST FREE !! */ originalPtr = cmdstr= heap_alloc(MAX_PATH<<2); cmdsize = MAX_PATH<<2; is_winnt = (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS); p2 = cmdstr; cmdlen = 0; cmdlen += copy_quote_and_fix_slashes(prog,cmdstr,&hasdot); p2 += cmdlen; if (*cmdstr != '"') { // If not quoted, skip initial character we left for quote *cmdstr = 'A'; cmdstr++; cmdsize--; } *p2 = 0; cmdend = p2; if (!is_winnt) { argv0 = NULL; } else { argv0= heap_alloc(MAX_PATH); (void)StringCbPrintf(argv0,MAX_PATH,"%s",prog); } si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; htemp= (HANDLE)_get_osfhandle(SHIN); DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(), &si.hStdInput,0,TRUE,DUPLICATE_SAME_ACCESS); htemp= (HANDLE)_get_osfhandle(SHOUT); DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(), &si.hStdOutput,0,TRUE,DUPLICATE_SAME_ACCESS); htemp= (HANDLE)_get_osfhandle(SHDIAG); DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(), &si.hStdError,0,TRUE,DUPLICATE_SAME_ACCESS); /* quotespace hack needed since execv() would have separated args, but createproces doesnt -amol 9/14/96 */ args++; // the first arg is the command dprintf("nt_texec calling c_a_a_q"); if(concat_args_and_quote(args,&originalPtr,&cmdstr,&cmdlen,&cmdend,&cmdsize) == NULL) { retval = 1; errno = ENOMEM; heap_free(originalPtr); goto free_mem; } *cmdend = 0; dwCreationflags = GetPriorityClass(GetCurrentProcess()); priority = GetThreadPriority(GetCurrentThread()); if (is_winnt) { retries = 0; // For NT, try ShellExecuteEx first do { if (GetBinaryType(argv0,&type)) break; if (GetLastError() == ERROR_BAD_EXE_FORMAT){ errno = ENOEXEC; if (!__nt_only_start_exes) try_shell_ex(savedargs,0,FALSE); if (errno) { retval = 1; goto free_mem; } else { retval = 0; goto free_mem; } } // only try shellex again after appending ".exe fails else if ( retries > 1 ){ if ( ( (argv0[0] == '\\') ||(argv0[0] == '/') ) && ( (argv0[1] == '\\') ||(argv0[1] == '/') ) && (!args[1]) ) if (!__nt_only_start_exes) try_shell_ex(savedargs,0,FALSE); errno = ENOENT; } if (retries == 0) (void)StringCbPrintf(argv0,MAX_PATH,"%s.exe",prog); else if (retries == 1) { (void)StringCbPrintf(argv0,MAX_PATH,"%s.EXE",prog); } retries++; }while(retries < 3); } savepath = fix_path_for_child(); re_cp: dprintf("nt_texec cmdstr %s\n",cmdstr); if (!CreateProcess(argv0, cmdstr, NULL, NULL, TRUE, // need this for redirecting std handles dwCreationflags, NULL,//envcrap, NULL, &si, &pi) ){ if (GetLastError() == ERROR_BAD_EXE_FORMAT) { errno = ENOEXEC; } else if (GetLastError() == ERROR_INVALID_PARAMETER) { errno = ENAMETOOLONG; }else { errno = ENOENT; } if (!is_winnt && !hasdot) { //append '.' to the end if needed StringCbCat(cmdstr,cmdsize,"."); hasdot=1; goto re_cp; } retval = 1; } else{ int gui_app ; DWORD exitcode; char guivar[50]; if (GetEnvironmentVariable("TCSH_NOASYNCGUI",guivar,50)) gui_app=0; else gui_app= is_gui(argv0); if(!gui_app) { WaitForSingleObject(pi.hProcess,INFINITE); (void)GetExitCodeProcess(pi.hProcess,&exitcode); setv(STRstatus, putn(exitcode), VAR_READWRITE);/*FIXRESET*/ } retval = 0; CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } free_mem: CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); if(savepath) restore_path(savepath); heap_free(originalPtr); if (argv0) heap_free(argv0); return retval; }
void nt_execve_wrapped(char *prog, char**args, char**envir ) { STARTUPINFO si; PROCESS_INFORMATION pi; BOOL bRet; DWORD type=0; char *argv0; char **savedargs = args; unsigned int cmdsize,cmdlen; char *cmdstr ,*cmdend; // int rc=0; // unused variable int retries=0; int is_winnt; int hasdot=0; char myself[512]; memset(&si,0,sizeof(si)); /* * This memory is not freed because we are exec()ed and will * not be alive long. */ /* This version avoids realloc in concat_args_and_quote, so it should be a little bit safer */ /* cmdsize = 65500; * cmdstr= heap_alloc(cmdsize); */ cmdsize = MAX_PATH << 2; cmdstr= heap_alloc(MAX_PATH<<2); is_winnt = (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS); /* replace /bin/sh with myself to be executed */ if( strcmp(prog, "/bin/sh") == 0 ) { if (GetModuleFileName(GetModuleHandle(NULL),myself,512) <= 512) { prog = myself; } } cmdlen = copy_quote_and_fix_slashes(prog,cmdstr,&hasdot); cmdend = cmdstr + cmdlen; *cmdend = 0; if (!is_winnt) { argv0 = NULL; goto win95_directly_here; } else { argv0 = heap_alloc(MAX_PATH); wsprintf(argv0,"%s",prog); } retry: bRet=GetBinaryType(argv0,&type); if (is_winnt && !bRet ) { /* Don't append .EXE if it could be a script file */ if (GetLastError() == ERROR_BAD_EXE_FORMAT) { try_shell_ex(args,1); errno = ENOEXEC; return; } else if (retries) { /* If argv[0] got parsed as \\foo (stupid paths with '/' as one * of the components will do it,) and if argv[1] is not the same, * then this is not a real UNC name. * In other cases, argv[0] and argv[1] here must be the same * anyway. -amol 5/1/6/98 */ if ( ( (*prog == '\\') ||(*prog == '/') ) && ( (prog[1] == '\\') ||(prog[1] == '/') ) && ((*args[0] == *prog) && (args[0][1] == prog[1])) && (!args[1]) ) try_shell_ex(args,1); errno = ENOENT; } if (retries > 2) { return; } if (retries == 0) { wsprintf(argv0,"%s.EXE",prog); retries++; } else if (prog[0] == '\\' && retries == 1) { char ptr[80]; if(GetEnvironmentVariable("ZSHROOT",ptr,80)) { wsprintf(argv0,"%s%s",ptr,prog); } retries++; } else if (prog[0] == '\\' && retries == 2) { char ptr[80]; if(GetEnvironmentVariable("ZSHROOT",ptr,80)) { wsprintf(argv0,"%s%s.EXE",ptr,prog); } retries++; } else retries += 2; goto retry; } else if (bRet && retries > 0) { //re-fix argv0 cmdlen = copy_quote_and_fix_slashes(argv0,cmdstr,&hasdot); cmdend = cmdstr + cmdlen; *cmdend = 0; } win95_directly_here: si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = (HANDLE)_get_osfhandle(0); si.hStdOutput = (HANDLE)_get_osfhandle(1); si.hStdError = (HANDLE)_get_osfhandle(2); *args++; // ignore argv[0]; concat_args_and_quote(args,&cmdstr,&cmdlen,&cmdend,&cmdsize); *cmdend = 0; if (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS) { if (!SetConsoleCtrlHandler(NULL,FALSE)) { errno = ENOENT; } } fix_path_for_child(); if (cmdlen < 1000) dprintf("argv0 %s cmdstr %s\n",argv0,cmdstr); if (!CreateProcess(argv0, cmdstr, NULL, NULL, TRUE, // need this for redirecting std handles 0, NULL,//envcrap, NULL, &si, &pi) ) { if (GetLastError() == ERROR_BAD_EXE_FORMAT) { try_shell_ex(savedargs,1); errno = ENOEXEC; } else if (GetLastError() == ERROR_INVALID_PARAMETER) { /* exceeded command line */ errno = ENAMETOOLONG; } else errno = ENOENT; } else { errno= 0; // { DWORD exitcode=0; int gui_app = 0; if (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS) { SetConsoleCtrlHandler(NULL,TRUE); } if (isset(WINNTWAITFORGUIAPPS)) gui_app = 0; else if (is_winnt) gui_app = is_gui(argv0); else gui_app = is_9x_gui(prog); if (!gui_app) { WaitForSingleObject(pi.hProcess,INFINITE); } (void)GetExitCodeProcess(pi.hProcess,&exitcode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); ExitProcess(exitcode); } } }
void nt_execve(char *prog, char**args, char**envir ) { STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE htemp; BOOL bRet; DWORD type=0; DWORD dwCreationflags; unsigned int priority; char *argv0; char *cmdstr, *cmdend ; char *originalPtr; unsigned int cmdsize,cmdlen; char *p2; char **savedargs; int retries=0; int hasdot =0; int is_winnt ; memset(&si,0,sizeof(si)); savedargs = args; /* * This memory is not freed because we are exec()ed and will * not be alive long. */ originalPtr = cmdstr= heap_alloc(MAX_PATH<<2); is_winnt = (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS); cmdsize = MAX_PATH<<2; p2 = cmdstr; cmdlen = 0; cmdlen += copy_quote_and_fix_slashes(prog,cmdstr,&hasdot); p2 += cmdlen; /* If the command was not quoted , skip initial character we left for quote */ if (*cmdstr != '"') { *cmdstr = 'A'; cmdstr++; cmdsize--; } *p2 = 0; cmdend = p2; if (!is_winnt){ argv0 = NULL; goto win95_directly_here; } else { argv0 = heap_alloc(MAX_PATH); /* not freed */ wsprintf(argv0,"%s",prog); } retry: bRet=GetBinaryType(argv0,&type); dprintf("binary type for %s is %d\n",argv0,bRet); // // For NT, append .EXE and retry // if (is_winnt && !bRet ) { /* Don't append .EXE if it could be a script file */ if (GetLastError() == ERROR_BAD_EXE_FORMAT){ errno = ENOEXEC; if (!__nt_only_start_exes) try_shell_ex(args,1,FALSE); //can't throw on error return; } else if ( retries ){ if ( ( (argv0[0] == '\\') ||(argv0[0] == '/') ) && ( (argv0[1] == '\\') ||(argv0[1] == '/') ) && (!args[1]) ) if (!__nt_only_start_exes) try_shell_ex(args,1,FALSE); errno = ENOENT; } if (retries > 1){ return; } // Try uppercase once and then lower case // if (!retries) wsprintf(argv0,"%s.exe",prog); else wsprintf(argv0,"%s.EXE",prog); /* fix for clearcase */ retries++; goto retry; } win95_directly_here: si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; htemp= (HANDLE)_get_osfhandle(0); DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(), &si.hStdInput,0,TRUE,DUPLICATE_SAME_ACCESS); htemp= (HANDLE)_get_osfhandle(1); DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(), &si.hStdOutput,0,TRUE,DUPLICATE_SAME_ACCESS); htemp= (HANDLE)_get_osfhandle(2); DuplicateHandle(GetCurrentProcess(),htemp,GetCurrentProcess(), &si.hStdError,0,TRUE,DUPLICATE_SAME_ACCESS); *args++; // the first arg is the command dprintf("nt_execve calling c_a_a_q"); if(!concat_args_and_quote(args,&originalPtr,&cmdstr,&cmdlen,&cmdend, &cmdsize)) { dprintf("concat_args_and_quote failed\n"); heap_free(originalPtr); errno = ENOMEM; goto fail_return; } *cmdend = 0; dwCreationflags = GetPriorityClass(GetCurrentProcess()); if (__nt_child_nohupped) { dwCreationflags |= DETACHED_PROCESS; } priority = GetThreadPriority(GetCurrentThread()); (void)fix_path_for_child(); if (is_winnt) dwCreationflags |= CREATE_SUSPENDED; re_cp: dprintf("argv0 %s cmdstr %s\n",argv0,cmdstr); bRet = CreateProcessA(argv0, cmdstr, NULL, NULL, TRUE, // need this for redirecting std handles dwCreationflags, NULL, NULL, &si, &pi); if (!bRet){ if (GetLastError() == ERROR_BAD_EXE_FORMAT) { if (!__nt_only_start_exes) try_shell_ex(savedargs,1,FALSE); errno = ENOEXEC; } else if (GetLastError() == ERROR_INVALID_PARAMETER) { /* can't get invalid parameter, so this must be * the case when we exceed the command length limit. */ errno = ENAMETOOLONG; } else { errno = ENOENT; } if (!is_winnt && !hasdot) { //append '.' to the end if needed lstrcat(cmdstr,"."); hasdot=1; goto re_cp; } } else{ int gui_app ; char guivar[50]; if (GetEnvironmentVariable("TCSH_NOASYNCGUI",guivar,50)) gui_app=0; else { if (is_winnt || hasdot) gui_app= is_gui(argv0); else gui_app = is_9x_gui(prog); } if (is_winnt && !SetThreadPriority(pi.hThread,priority) ) { priority =GetLastError(); } if (is_winnt) ResumeThread(pi.hThread); errno= 0; if (__nt_really_exec||__nt_child_nohupped || gui_app){ ExitProcess(0); } else { DWORD exitcode=0; WaitForSingleObject(pi.hProcess,INFINITE); (void)GetExitCodeProcess(pi.hProcess,&exitcode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); /* * If output was redirected to /dev/clipboard, * we need to close the pipe handles */ if (is_dev_clipboard_active) { CloseHandle((HANDLE)_get_osfhandle(0)); CloseHandle((HANDLE)_get_osfhandle(1)); CloseHandle((HANDLE)_get_osfhandle(2)); CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForSingleObject(ghdevclipthread,60*1000); } ExitProcess(exitcode); } } fail_return: CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); return; }
int nt_execve(const char *prog, const char *const *args, const char *const *envir) { STARTUPINFO si; PROCESS_INFORMATION pi; enum {none, directex, shellex} execmode; DWORD exitcode; DWORD dwCreationflags; int priority; char *argv0; char *cmdstr, *cmdend; unsigned int cmdsize; size_t prognamelen, cmdlen; int hasext; char extension[_MAX_FNAME]; const char *begin, *end, *extptr; static char exts[MAX_PATH]; UNREFERENCED_PARAMETER(envir); /* get default PATHEXT or use empty exts */ if (!*exts) { DWORD rc; /* not initialized */ rc = GetEnvironmentVariable("PATHEXT", exts, sizeof(exts)); if ((rc == 0) || (rc >= sizeof(exts))) /* if error or PATHEXT too big will retry at the next call */ *exts = 0; } /* if prog has an extension initialize begin end to skip PATHEXT search */ prognamelen = strlen(prog); extptr = prog + prognamelen - 1; hasext = 0; while (extptr > prog && !ISPATHSEP(*extptr)) { if (*extptr == '.' && *(extptr - 1) != ':' && !ISPATHSEP(*(extptr - 1))) { hasext++; break; } extptr--; } if (hasext) { begin = "."; end = ""; strcpy(extension, extptr); } else { begin = exts; end = exts; *extension = '\0'; } argv0 = (char *)heap_alloc(MAX_PATH); /* (prognamelen + 1) does not really matter, argv0 is '\0' filled */ memcpy(argv0, prog, prognamelen + 1); errno = 0; execmode = none; /* NOTE: loops over PATHEXT if no extension found */ while (*begin) { size_t extlen; if (GetBinaryType(argv0, &exitcode)) { /* exists and is executable NOTE: an "xxx.exe" without a correct PE header (i.e. a text file) has type "DOS binary", but execution will generate a WOW error */ execmode = directex; break; } if (GetLastError() == ERROR_BAD_EXE_FORMAT) { /* exists but is not "executable" */ execmode = shellex; break; } if (hasext) break; /* get next PATHEXT extension */ while (*begin && (*begin != '.')) begin++; while (*end && (*end != ';')) end++; if (!*begin) break; extlen = end - begin; if (extlen < sizeof(extension)) { memcpy(extension, begin, extlen); extension[extlen] = '\0'; /* prognamelen ignores the last '\r' if present */ memcpy(argv0, prog, prognamelen); /* update argv0 adding the extension to prog */ memcpy(argv0 + prognamelen, extension, extlen + 1); } begin = end; /* skip sequences of ';' */ while (*end && *end == ';') end++; }; cmdstr = (char *)heap_alloc(MAX_PATH << 2); cmdsize = MAX_PATH << 2; cmdlen = 0; cmdend = cmdstr; dbgprintf(PR_VERBOSE, "%s(): execute [%s] extension=[%s] mode=%d hasext=%d\n", __FUNCTION__, argv0, extension, execmode, hasext); /* skip over program name */ args++; /* the file (after PATHEXT search) exists, but it's not "executable" */ if (execmode == shellex) { /* if prog had no extension or has the extension associated to shell scripts */ if ((hasext == 0 && *extension == '\0') || is_shell_script(extension)) { int res = process_shebang(argv0, (const char *const *)&cmdstr, &cmdlen, &cmdend, &cmdsize); if (res < 0) { execmode = none; } else if (res == 0) { char *newargv[2]; cmdlen = copy_quote_and_fix_slashes(gModuleName, cmdstr); cmdend = cmdstr + cmdlen; newargv[0] = path_to_slash(argv0); newargv[1] = NULL; concat_args_and_quote((const char *const *)newargv, &cmdstr, &cmdlen, &cmdend, &cmdsize); *cmdend = 0; argv0 = gModuleName; execmode = directex; } else { cmdend = cmdstr + cmdlen; execmode = directex; } } else { unsigned long shflags = 0L; /* if the file extension is in pathext, use the same console and wait for child. StrStrI() is from shlwapi */ if (StrStrI(exts, extension)) shflags = SEE_MASK_NO_CONSOLE | SEE_MASK_NOCLOSEPROCESS; if (try_shell_ex(argv0, args, shflags, &cmdstr, &cmdsize)) return (0); /* ShellExecute failed, the file has an unknown extension, but it may be a shell script with a shebang */ if (process_shebang(argv0, (const char *const *)&cmdstr, &cmdlen, &cmdend, &cmdsize) > 0) { cmdend = cmdstr + cmdlen; execmode = directex; } else { /* the file extension is NOT known and the file has NO shebang: returns EPERM, see NOTES */ errno = EPERM; return (-1); } } } else if (execmode == directex) { cmdlen = copy_quote_and_fix_slashes(prog, cmdstr); cmdend = cmdstr + cmdlen; } if (execmode == none) { /* error: prog not found even after trying PATHEXT extensions */ errno = ENOENT; return (-1); } concat_args_and_quote(args, &cmdstr, &cmdlen, &cmdend, &cmdsize); if (*cmdstr == ' ') { /* if we left a ' ' for the quote and there is no quote */ cmdstr++; cmdlen--; } *cmdend = 0; init_startupinfo(&si); dwCreationflags = GetPriorityClass(GetCurrentProcess()); priority = GetThreadPriority(GetCurrentThread()); #if defined(W32DEBUG) /* DebugView output is very difficult to read with overlong lines */ if (cmdlen < 128) dbgprintf(PR_EXEC, "%s(): CreateProcess(%s, ..) cmdstr=[%s]\n", __FUNCTION__, argv0, cmdstr); else { char shortbuf[128+4]; memcpy(shortbuf, cmdstr, 128); memcpy(shortbuf + 128, "...", 4); dbgprintf(PR_EXEC, "nt_execve(): CreateProcess(%s, ..) cmdstr=[%s]\n", argv0, shortbuf); } #endif if (!CreateProcess(argv0, cmdstr, NULL, NULL, TRUE, // need this for redirecting std handles dwCreationflags | CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { exitcode = GetLastError(); if (exitcode == ERROR_BAD_EXE_FORMAT) { dbgprintf(PR_ERROR, "!!! CreateProcess(%s, ..) error BAD_EXE_FORMAT in %s\n", argv0, __FUNCTION__); errno = ENOEXEC; } else if (exitcode == ERROR_INVALID_PARAMETER) { dbgprintf(PR_ERROR, "!!! CreateProcess(%s, ..) error INVALID_PARAMETER in %s, cmdstr len=%u\n", argv0, __FUNCTION__, strlen(cmdstr)); /* exceeded command line */ /* return NOT found, ENAMETOOLONG is correct but not understood by the shell that will retry with another path ... */ errno = ENOENT; } else { dbgprintf(PR_ERROR, "!!! CreateProcess(%s, ..) error %ld in %s\n", argv0, exitcode, __FUNCTION__); errno = ENOENT; } goto fail_return; } else { exitcode = 0; if (!SetThreadPriority(pi.hThread, priority)) dbgprintf(PR_ERROR, "!!! SetThreadPriority(0x%p) failed, error %ld\n", pi.hThread, GetLastError()); ResumeThread(pi.hThread); if (!is_gui(argv0)) { if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0) dbgprintf(PR_ERROR, "!!! error %ld waiting for process %ld\n", GetLastError(), pi.dwProcessId); if (!GetExitCodeProcess(pi.hProcess, &exitcode)) dbgprintf(PR_ERROR, "!!! GetExitCodeProcess(0x%p, ..) error %ld in %s\n", pi.hProcess, GetLastError(), __FUNCTION__); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); close_si_handles(); /* @@@@ should wait for the clipboard ? if (is_dev_clipboard_active) { CloseHandle((HANDLE)_get_osfhandle(0)); CloseHandle((HANDLE)_get_osfhandle(1)); CloseHandle((HANDLE)_get_osfhandle(2)); ... WaitForSingleObject(ghdevclipthread,60*1000); } */ dbgprintf(PR_ALL, "--- %s(): Exec'd process %ld terminated with exitcode %ld\n", __FUNCTION__, pi.dwProcessId, exitcode); exec_exit((int)exitcode); } fail_return: heap_free(cmdstr); close_si_handles(); exec_exit(-1); return (-1); }
static int process_shebang(char *argv0, const char *const *cmdstr, size_t *cmdlen, char **cmdend, unsigned int *cmdsize) { HANDLE hfile; char buf[512]; unsigned int nn, t0; char *ptr, *ptr2; char *newargv[4]; char pbuffer[MAX_PATH]; char *filepart; static const char *shellnames[] = {"/bin/sh", "/bin/zsh", "/bin/ksh"}; static const char usrbinenv[] = "/usr/bin/env"; static const char usrbinpython[] = "/usr/bin/python"; static const char usrbinperl[] = "/usr/bin/perl"; static const char usrbintcl[] = "/usr/bin/tcl"; hfile = CreateFile(argv0, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hfile == INVALID_HANDLE_VALUE) return (-1); if (!ReadFile(hfile, buf, (DWORD)sizeof(buf), (DWORD *)&nn, NULL)) { CloseHandle(hfile); return (-1); } CloseHandle(hfile); if (!((nn >= 3) && (buf[0] == '#') && (buf[1] == '!'))) return (0); /* this code is more or less what zexecve() does */ for (t0 = 0; t0 != nn; t0++) if ((buf[t0] == '\n') || (buf[t0] == '\r')) break; while (isspace(buf[t0])) buf[t0--] = '\0'; buf[sizeof(buf)-1] = '\0'; /* @@@@ fails for "/b/s p/pgm" !!! */ for (ptr = buf + 2; *ptr && *ptr == ' '; ptr++) ; for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++) ; /* ptr2 is the program name, ptr points to the args */ dbgprintf(PR_VERBOSE, "%s(): found \"!#\" program=[%s] arg ptr=[%s]\n", __FUNCTION__, ptr2, *ptr ? ptr + 1 : "NULL"); /* append to the cmdstr should have argv0 ('/' or '\' format ?) */ if (*ptr) { *ptr = '\0'; newargv[0] = ptr2; newargv[1] = ptr + 1; newargv[2] = argv0; } else { newargv[0] = ptr2; newargv[1] = argv0; newargv[2] = NULL; } newargv[3] = NULL; concat_args_and_quote((const char *const *)newargv, (char **)cmdstr, cmdlen, cmdend, cmdsize); *cmdend = '\0'; /* if ptr2 is a "well known" shell name set argv0 to our module name */ for (nn = 0; nn < LENGTH_OF(shellnames); nn++) { if (strcmp(ptr2, shellnames[nn]) == 0) { strcpy(argv0, gModuleName); return (1); } } if (strcmp(ptr2, usrbinenv) == 0) { SearchPath(NULL, "env.exe", NULL, sizeof(pbuffer), pbuffer, &filepart); strcpy(argv0, pbuffer); } else if (strcmp(ptr2, usrbinpython) == 0) { SearchPath(NULL, "python.exe", NULL, sizeof(pbuffer), pbuffer, &filepart); strcpy(argv0, pbuffer); } else if (strcmp(ptr2, usrbinperl) == 0) { SearchPath(NULL, "perl.exe", NULL, sizeof(pbuffer), pbuffer, &filepart); strcpy(argv0, pbuffer); } else if (strcmp(ptr2, usrbintcl) == 0) { SearchPath(NULL, "tcl.exe", NULL, sizeof(pbuffer), pbuffer, &filepart); strcpy(argv0, pbuffer); } else { char *exeptr; path_to_backslash(ptr2); strcpy(argv0, ptr2); /* if argv0 does not end with ".exe" add ".exe" */ exeptr = StrStrI(argv0, ".exe"); if ((exeptr == NULL) || (exeptr != strrchr(argv0, '.'))) { strcat(argv0, ".exe"); dbgprintf(PR_VERBOSE, "%s(): argv0 modified to [%s]\n", __FUNCTION__, argv0); } } return (1); }
static int try_shell_ex(char *argv0, const char *const *argv, unsigned long shellexflags, char **cmdstr, unsigned int *cmdsize) { char *cmdend; size_t cmdlen; SHELLEXECUTEINFO shinfo; BOOL nocmd = 0; path_to_backslash(argv0); /* @@@@ is this code really needed ? when ? */ if ((!*argv) && (argv0[0] == '\\') && (argv0[1] == '\\')) { shellexflags |= SEE_MASK_CONNECTNETDRV; nocmd = 1; goto noargs; } cmdend = *cmdstr; cmdlen = 0; concat_args_and_quote(argv, cmdstr, &cmdlen, &cmdend, cmdsize); *cmdend = '\0'; noargs: dbgprintf(PR_EXEC, "ShellExecute(%s, ..) with cmdstr [%s]\n", argv0, *cmdstr); memset(&shinfo, 0, sizeof(shinfo)); shinfo.cbSize = sizeof(shinfo); shinfo.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT | shellexflags; shinfo.hwnd = NULL; shinfo.lpVerb = NULL; shinfo.lpFile = argv0; shinfo.lpParameters = nocmd ? NULL : *cmdstr; shinfo.lpDirectory = 0; shinfo.nShow = SW_SHOWDEFAULT; if (ShellExecuteEx(&shinfo)) { DWORD retval = 255; dbgprintf(PR_EXEC, "ShellExecute() created process handle 0x%p\n", shinfo.hProcess); /* may happen if "executing" a file associated to a running program, i.e. "execute" a .html file with an already opened browser window */ if (shinfo.hProcess != (HANDLE)0) { if (shellexflags & SEE_MASK_NOCLOSEPROCESS) { if ((intptr_t)(shinfo.hInstApp) > 32) { if (WaitForSingleObject(shinfo.hProcess, INFINITE) == WAIT_OBJECT_0) { /* try to get the return value */ GetExitCodeProcess(shinfo.hProcess, &retval); } else { dbgprintf(PR_ERROR, "!!! ShellExecute() [%s] WaitForSingleObject() error %ld\n", argv0, GetLastError()); } } else { dbgprintf(PR_ERROR, "!!! ShellExecute() [%s] error %p\n", argv0, shinfo.hInstApp); } } /* try to close, it may fail but .. what else could we do */ CloseHandle(shinfo.hProcess); } dbgprintf(PR_ALL, "--- %s(): ShellExecute() OK, exiting with code %ld\n", __FUNCTION__, retval); exec_exit((int)retval); } else { dbgprintf(PR_EXEC, "ShellExecute() failed\n"); } return (0); }