diff options
author | Reid Spencer <rspencer@reidspencer.com> | 2004-08-29 19:20:41 +0000 |
---|---|---|
committer | Reid Spencer <rspencer@reidspencer.com> | 2004-08-29 19:20:41 +0000 |
commit | 52a7efafba1045a8c7a3fe545487d11d53e6f93a (patch) | |
tree | 82fe005bfccae757d989b9ccc6dfd6a130140b3f /lib/System/Unix | |
parent | fd5c345a0e5b18206adc65a9a9f5ab3b5e4d7bd3 (diff) | |
download | external_llvm-52a7efafba1045a8c7a3fe545487d11d53e6f93a.zip external_llvm-52a7efafba1045a8c7a3fe545487d11d53e6f93a.tar.gz external_llvm-52a7efafba1045a8c7a3fe545487d11d53e6f93a.tar.bz2 |
Initial commit of an platform-indepdendent implementation for the
"Program" operating system concept (find and execute programs).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16084 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/System/Unix')
-rw-r--r-- | lib/System/Unix/Program.cpp | 133 | ||||
-rw-r--r-- | lib/System/Unix/Program.inc | 133 |
2 files changed, 266 insertions, 0 deletions
diff --git a/lib/System/Unix/Program.cpp b/lib/System/Unix/Program.cpp new file mode 100644 index 0000000..6943d52 --- /dev/null +++ b/lib/System/Unix/Program.cpp @@ -0,0 +1,133 @@ +//===- 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 "Unix.h" +#include <sys/stat.h> +#include <fcntl.h> +#include <Config/config.h> +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +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<std::string>& 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 diff --git a/lib/System/Unix/Program.inc b/lib/System/Unix/Program.inc new file mode 100644 index 0000000..6943d52 --- /dev/null +++ b/lib/System/Unix/Program.inc @@ -0,0 +1,133 @@ +//===- 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 "Unix.h" +#include <sys/stat.h> +#include <fcntl.h> +#include <Config/config.h> +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +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<std::string>& 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 |