LLVM API Documentation
00001 //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by Jeff Cohen and is distributed under the 00006 // University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file provides the Win32 specific implementation of the Program class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "Win32.h" 00015 #include <cstdio> 00016 #include <malloc.h> 00017 #include <io.h> 00018 #include <fcntl.h> 00019 00020 //===----------------------------------------------------------------------===// 00021 //=== WARNING: Implementation here must contain only Win32 specific code 00022 //=== and must not be UNIX code 00023 //===----------------------------------------------------------------------===// 00024 00025 namespace llvm { 00026 using namespace sys; 00027 00028 // This function just uses the PATH environment variable to find the program. 00029 Path 00030 Program::FindProgramByName(const std::string& progName) { 00031 00032 // Check some degenerate cases 00033 if (progName.length() == 0) // no program 00034 return Path(); 00035 Path temp; 00036 if (!temp.set(progName)) // invalid name 00037 return Path(); 00038 if (temp.canExecute()) // already executable as is 00039 return temp; 00040 00041 // At this point, the file name is valid and its not executable. 00042 // Let Windows search for it. 00043 char buffer[MAX_PATH]; 00044 char *dummy = NULL; 00045 DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, 00046 buffer, &dummy); 00047 00048 // See if it wasn't found. 00049 if (len == 0) 00050 return Path(); 00051 00052 // See if we got the entire path. 00053 if (len < MAX_PATH) 00054 return Path(buffer); 00055 00056 // Buffer was too small; grow and retry. 00057 while (true) { 00058 char *b = reinterpret_cast<char *>(_alloca(len+1)); 00059 DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); 00060 00061 // It is unlikely the search failed, but it's always possible some file 00062 // was added or removed since the last search, so be paranoid... 00063 if (len2 == 0) 00064 return Path(); 00065 else if (len2 <= len) 00066 return Path(b); 00067 00068 len = len2; 00069 } 00070 } 00071 00072 static HANDLE RedirectIO(const Path *path, int fd) { 00073 HANDLE h; 00074 if (path == 0) { 00075 DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), 00076 GetCurrentProcess(), &h, 00077 0, TRUE, DUPLICATE_SAME_ACCESS); 00078 return h; 00079 } 00080 00081 const char *fname = path->toString().c_str(); 00082 if (*fname == 0) 00083 fname = "NUL"; 00084 00085 SECURITY_ATTRIBUTES sa; 00086 sa.nLength = sizeof(sa); 00087 sa.lpSecurityDescriptor = 0; 00088 sa.bInheritHandle = TRUE; 00089 00090 h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, 00091 &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, 00092 FILE_ATTRIBUTE_NORMAL, NULL); 00093 if (h == INVALID_HANDLE_VALUE) { 00094 ThrowError(std::string(fname) + ": Can't open file for " + 00095 (fd ? "input: " : "output: ")); 00096 } 00097 return h; 00098 } 00099 00100 int 00101 Program::ExecuteAndWait(const Path& path, 00102 const char** args, 00103 const char** envp, 00104 const Path** redirects, 00105 unsigned secondsToWait) { 00106 if (!path.canExecute()) 00107 throw path.toString() + " is not executable"; 00108 00109 // Windows wants a command line, not an array of args, to pass to the new 00110 // process. We have to concatenate them all, while quoting the args that 00111 // have embedded spaces. 00112 00113 // First, determine the length of the command line. 00114 unsigned len = 0; 00115 for (unsigned i = 0; args[i]; i++) { 00116 len += strlen(args[i]) + 1; 00117 if (strchr(args[i], ' ')) 00118 len += 2; 00119 } 00120 00121 // Now build the command line. 00122 char *command = reinterpret_cast<char *>(_alloca(len)); 00123 char *p = command; 00124 00125 for (unsigned i = 0; args[i]; i++) { 00126 const char *arg = args[i]; 00127 size_t len = strlen(arg); 00128 bool needsQuoting = strchr(arg, ' ') != 0; 00129 if (needsQuoting) 00130 *p++ = '"'; 00131 memcpy(p, arg, len); 00132 p += len; 00133 if (needsQuoting) 00134 *p++ = '"'; 00135 *p++ = ' '; 00136 } 00137 00138 *p = 0; 00139 00140 // Create a child process. 00141 STARTUPINFO si; 00142 memset(&si, 0, sizeof(si)); 00143 si.cb = sizeof(si); 00144 si.hStdInput = INVALID_HANDLE_VALUE; 00145 si.hStdOutput = INVALID_HANDLE_VALUE; 00146 si.hStdError = INVALID_HANDLE_VALUE; 00147 00148 if (redirects) { 00149 si.dwFlags = STARTF_USESTDHANDLES; 00150 00151 try { 00152 si.hStdInput = RedirectIO(redirects[0], 0); 00153 si.hStdOutput = RedirectIO(redirects[1], 1); 00154 if (redirects[1] && redirects[2] && *(redirects[1]) != *(redirects[2])) { 00155 si.hStdError = RedirectIO(redirects[2], 2); 00156 } else { 00157 DuplicateHandle(GetCurrentProcess(), si.hStdOutput, 00158 GetCurrentProcess(), &si.hStdError, 00159 0, TRUE, DUPLICATE_SAME_ACCESS); 00160 } 00161 } catch (...) { 00162 CloseHandle(si.hStdInput); 00163 CloseHandle(si.hStdOutput); 00164 CloseHandle(si.hStdError); 00165 throw; 00166 } 00167 } 00168 00169 PROCESS_INFORMATION pi; 00170 memset(&pi, 0, sizeof(pi)); 00171 00172 fflush(stdout); 00173 fflush(stderr); 00174 BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, FALSE, 0, 00175 envp, NULL, &si, &pi); 00176 DWORD err = GetLastError(); 00177 00178 // Regardless of whether the process got created or not, we are done with 00179 // the handles we created for it to inherit. 00180 CloseHandle(si.hStdInput); 00181 CloseHandle(si.hStdOutput); 00182 CloseHandle(si.hStdError); 00183 00184 // Now throw an error if the process didn't get created. 00185 if (!rc) 00186 { 00187 SetLastError(err); 00188 ThrowError(std::string("Couldn't execute program '") + 00189 path.toString() + "'"); 00190 } 00191 00192 // Wait for it to terminate. 00193 DWORD millisecondsToWait = INFINITE; 00194 if (secondsToWait > 0) 00195 millisecondsToWait = secondsToWait * 1000; 00196 00197 if (WaitForSingleObject(pi.hProcess, millisecondsToWait) == WAIT_TIMEOUT) { 00198 if (!TerminateProcess(pi.hProcess, 1)) { 00199 ThrowError(std::string("Failed to terminate timed-out program '") + 00200 path.toString() + "'"); 00201 } 00202 WaitForSingleObject(pi.hProcess, INFINITE); 00203 } 00204 00205 // Get its exit status. 00206 DWORD status; 00207 rc = GetExitCodeProcess(pi.hProcess, &status); 00208 err = GetLastError(); 00209 00210 // Done with the handles; go close them. 00211 CloseHandle(pi.hProcess); 00212 CloseHandle(pi.hThread); 00213 00214 if (!rc) { 00215 SetLastError(err); 00216 ThrowError(std::string("Failed getting status for program '") + 00217 path.toString() + "'"); 00218 } 00219 00220 return status; 00221 } 00222 00223 void Program::ChangeStdinToBinary(){ 00224 int result = _setmode( _fileno(stdin), _O_BINARY ); 00225 if( result == -1 ) 00226 throw std::string("Cannot set input mode on stdin to binary."); 00227 } 00228 00229 void Program::ChangeStdoutToBinary(){ 00230 int result = _setmode( _fileno(stdout), _O_BINARY ); 00231 if( result == -1 ) 00232 throw std::string("Cannot set output mode on stdout to binary."); 00233 } 00234 00235 }