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