LLVM API Documentation

Unix/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 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 }