//===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file was developed by Reid Spencer and is distributed under the // University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Unix specific portion of the Program class. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only generic UNIX code that //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// #include #include "Unix.h" #include #include #ifdef HAVE_SYS_WAIT_H #include #endif extern char** environ; namespace llvm { using namespace sys; // This function just uses the PATH environment variable to find the program. Program Program::FindProgramByName(const std::string& progName) { // Check some degenerate cases if (progName.length() == 0) // no program return Program(); Program temp; if (!temp.set_file(progName)) // invalid name return Program(); if (temp.executable()) // already executable as is return temp; // At this point, the file name is valid and its not executable // Get the path. If its empty, we can't do anything to find it. const char *PathStr = getenv("PATH"); if (PathStr == 0) return Program(); // Now we have a colon separated list of directories to search; try them. unsigned PathLen = strlen(PathStr); while (PathLen) { // Find the first colon... const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); // Check to see if this first directory contains the executable... Program FilePath; if (FilePath.set_directory(std::string(PathStr,Colon))) { FilePath.append_file(progName); if (FilePath.executable()) return FilePath; // Found the executable! } // Nope it wasn't in this directory, check the next path in the list! PathLen -= Colon-PathStr; PathStr = Colon; // Advance past duplicate colons while (*PathStr == ':') { PathStr++; PathLen--; } } return Program(); } // int Program::ExecuteAndWait(const std::vector& args) const { if (!executable()) throw get() + " is not executable"; #ifdef HAVE_SYS_WAIT_H // Create local versions of the parameters that can be passed into execve() // without creating const problems. const char* argv[ args.size() + 2 ]; unsigned index = 0; std::string progname(this->getLast()); argv[index++] = progname.c_str(); for (unsigned i = 0; i < args.size(); i++) argv[index++] = args[i].c_str(); argv[index] = 0; // Create a child process. switch (fork()) { // An error occured: Return to the caller. case -1: ThrowErrno(std::string("Couldn't execute program '") + get() + "'"); break; // Child process: Execute the program. case 0: execve (get().c_str(), (char** const)argv, environ); // If the execve() failed, we should exit and let the parent pick up // our non-zero exit status. exit (errno); // Parent process: Break out of the switch to do our processing. default: break; } // Parent process: Wait for the child process to terminate. int status; if ((::wait (&status)) == -1) ThrowErrno(std::string("Failed waiting for program '") + get() + "'"); // If the program exited normally with a zero exit status, return success! if (WIFEXITED (status)) return WEXITSTATUS(status); else if (WIFSIGNALED(status)) throw std::string("Program '") + get() + "' received terminating signal."; else return 0; #else throw std::string("Program::ExecuteAndWait not implemented on this platform!\n"); #endif } } // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab