LLVM API Documentation

Program.inc

Go to the documentation of this file.
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 }