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