LLVM API Documentation
00001 //===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by Reid Spencer and is distributed under the 00006 // University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the Unix specific portion of the Program class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 //===----------------------------------------------------------------------===// 00015 //=== WARNING: Implementation here must contain only generic UNIX code that 00016 //=== is guaranteed to work on *all* UNIX variants. 00017 //===----------------------------------------------------------------------===// 00018 00019 #include <llvm/Config/config.h> 00020 #include "Unix.h" 00021 #include <iostream> 00022 #if HAVE_SYS_STAT_H 00023 #include <sys/stat.h> 00024 #endif 00025 #if HAVE_SIGNAL_H 00026 #include <signal.h> 00027 #endif 00028 #if HAVE_FCNTL_H 00029 #include <fcntl.h> 00030 #endif 00031 00032 extern char** environ; 00033 00034 namespace llvm { 00035 using namespace sys; 00036 00037 // This function just uses the PATH environment variable to find the program. 00038 Path 00039 Program::FindProgramByName(const std::string& progName) { 00040 00041 // Check some degenerate cases 00042 if (progName.length() == 0) // no program 00043 return Path(); 00044 Path temp; 00045 if (!temp.set(progName)) // invalid name 00046 return Path(); 00047 // FIXME: have to check for absolute filename - we cannot assume anything 00048 // about "." being in $PATH 00049 if (temp.canExecute()) // already executable as is 00050 return temp; 00051 00052 // At this point, the file name is valid and its not executable 00053 00054 // Get the path. If its empty, we can't do anything to find it. 00055 const char *PathStr = getenv("PATH"); 00056 if (PathStr == 0) 00057 return Path(); 00058 00059 // Now we have a colon separated list of directories to search; try them. 00060 unsigned PathLen = strlen(PathStr); 00061 while (PathLen) { 00062 // Find the first colon... 00063 const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); 00064 00065 // Check to see if this first directory contains the executable... 00066 Path FilePath; 00067 if (FilePath.set(std::string(PathStr,Colon))) { 00068 FilePath.appendComponent(progName); 00069 if (FilePath.canExecute()) 00070 return FilePath; // Found the executable! 00071 } 00072 00073 // Nope it wasn't in this directory, check the next path in the list! 00074 PathLen -= Colon-PathStr; 00075 PathStr = Colon; 00076 00077 // Advance past duplicate colons 00078 while (*PathStr == ':') { 00079 PathStr++; 00080 PathLen--; 00081 } 00082 } 00083 return Path(); 00084 } 00085 00086 static void RedirectFD(const std::string &File, int FD) { 00087 if (File.empty()) return; // Noop 00088 00089 // Open the file 00090 int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); 00091 if (InFD == -1) { 00092 ThrowErrno("Cannot open file '" + File + "' for " 00093 + (FD == 0 ? "input" : "output") + "!\n"); 00094 } 00095 00096 dup2(InFD, FD); // Install it as the requested FD 00097 close(InFD); // Close the original FD 00098 } 00099 00100 static bool Timeout = false; 00101 static void TimeOutHandler(int Sig) { 00102 Timeout = true; 00103 } 00104 00105 int 00106 Program::ExecuteAndWait(const Path& path, 00107 const char** args, 00108 const char** envp, 00109 const Path** redirects, 00110 unsigned secondsToWait 00111 ) { 00112 if (!path.canExecute()) 00113 throw path.toString() + " is not executable"; 00114 00115 #ifdef HAVE_SYS_WAIT_H 00116 // Create a child process. 00117 int child = fork(); 00118 switch (child) { 00119 // An error occured: Return to the caller. 00120 case -1: 00121 ThrowErrno(std::string("Couldn't execute program '") + path.toString() + 00122 "'"); 00123 break; 00124 00125 // Child process: Execute the program. 00126 case 0: { 00127 // Redirect file descriptors... 00128 if (redirects) { 00129 if (redirects[0]) 00130 if (redirects[0]->isEmpty()) 00131 RedirectFD("/dev/null",0); 00132 else 00133 RedirectFD(redirects[0]->toString(), 0); 00134 if (redirects[1]) 00135 if (redirects[1]->isEmpty()) 00136 RedirectFD("/dev/null",1); 00137 else 00138 RedirectFD(redirects[1]->toString(), 1); 00139 if (redirects[1] && redirects[2] && 00140 *(redirects[1]) != *(redirects[2])) { 00141 if (redirects[2]->isEmpty()) 00142 RedirectFD("/dev/null",2); 00143 else 00144 RedirectFD(redirects[2]->toString(), 2); 00145 } else { 00146 dup2(1, 2); 00147 } 00148 } 00149 00150 // Set up the environment 00151 char** env = environ; 00152 if (envp != 0) 00153 env = (char**) envp; 00154 00155 // Execute! 00156 execve (path.c_str(), (char** const)args, env); 00157 // If the execve() failed, we should exit and let the parent pick up 00158 // our non-zero exit status. 00159 exit (errno); 00160 } 00161 00162 // Parent process: Break out of the switch to do our processing. 00163 default: 00164 break; 00165 } 00166 00167 // Make sure stderr and stdout have been flushed 00168 std::cerr << std::flush; 00169 std::cout << std::flush; 00170 fsync(1); 00171 fsync(2); 00172 00173 struct sigaction Act, Old; 00174 00175 // Install a timeout handler. 00176 if (secondsToWait) { 00177 Timeout = false; 00178 Act.sa_sigaction = 0; 00179 Act.sa_handler = TimeOutHandler; 00180 sigemptyset(&Act.sa_mask); 00181 Act.sa_flags = 0; 00182 sigaction(SIGALRM, &Act, &Old); 00183 alarm(secondsToWait); 00184 } 00185 00186 // Parent process: Wait for the child process to terminate. 00187 int status; 00188 while (wait(&status) != child) 00189 if (secondsToWait && errno == EINTR) { 00190 // Kill the child. 00191 kill(child, SIGKILL); 00192 00193 // Turn off the alarm and restore the signal handler 00194 alarm(0); 00195 sigaction(SIGALRM, &Old, 0); 00196 00197 // Wait for child to die 00198 if (wait(&status) != child) 00199 ThrowErrno("Child timedout but wouldn't die"); 00200 00201 return -1; // Timeout detected 00202 } else { 00203 ThrowErrno("Error waiting for child process"); 00204 } 00205 00206 // We exited normally without timeout, so turn off the timer. 00207 if (secondsToWait) { 00208 alarm(0); 00209 sigaction(SIGALRM, &Old, 0); 00210 } 00211 00212 // Return the proper exit status. 0=success, >0 is programs' exit status, 00213 // <0 means a signal was returned, -9999999 means the program dumped core. 00214 int result = 0; 00215 if (WIFEXITED (status)) 00216 result = WEXITSTATUS(status); 00217 else if (WIFSIGNALED(status)) 00218 result = 0 - WTERMSIG(status); 00219 #ifdef WCOREDUMP 00220 if (WCOREDUMP(status)) 00221 result |= 0x01000000; 00222 #endif 00223 return result; 00224 #else 00225 return -99; 00226 #endif 00227 00228 } 00229 00230 }