blob: 72e4e917efb8e27c01e67201780302f26623dc49 [file] [log] [blame]
Misha Brukmanebb0faa2004-06-18 15:38:49 +00001//===- SystemUtils.cpp - Utilities for low-level system tasks -------------===//
John Criswellb576c942003-10-20 19:43:21 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by the LLVM research group and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Chris Lattner4a106452002-12-23 23:50:16 +00009//
10// This file contains functions used to do a variety of low-level, often
11// system-specific, tasks.
12//
13//===----------------------------------------------------------------------===//
14
Reid Spencer551ccae2004-09-01 22:55:40 +000015#include "llvm/Support/SystemUtils.h"
Reid Spencer9665e8a2004-12-13 23:41:37 +000016#include "llvm/System/Program.h"
Reid Spencer44f69662004-12-14 04:18:15 +000017#include "llvm/Config/fcntl.h"
18#include "llvm/Config/sys/wait.h"
Chris Lattner74b1f452004-01-10 19:15:14 +000019#include <algorithm>
Misha Brukmanebb0faa2004-06-18 15:38:49 +000020#include <cerrno>
21#include <cstdlib>
Chris Lattner74b1f452004-01-10 19:15:14 +000022#include <fstream>
23#include <iostream>
Chris Lattnerd67e4392004-07-25 07:34:00 +000024#include <signal.h>
Reid Spencer44f69662004-12-14 04:18:15 +000025
Chris Lattner2cdd21c2003-12-14 21:35:53 +000026using namespace llvm;
Brian Gaeked0fde302003-11-11 22:41:34 +000027
Chris Lattnerb234d462004-04-02 05:04:03 +000028/// isStandardOutAConsole - Return true if we can tell that the standard output
29/// stream goes to a terminal window or console.
30bool llvm::isStandardOutAConsole() {
Brian Gaeke8507ecb2004-04-02 21:26:04 +000031#if HAVE_ISATTY
Chris Lattnerb234d462004-04-02 05:04:03 +000032 return isatty(1);
Brian Gaeke8507ecb2004-04-02 21:26:04 +000033#endif
34 // If we don't have isatty, just return false.
35 return false;
Chris Lattnerb234d462004-04-02 05:04:03 +000036}
37
38
Misha Brukmanf7066c72003-08-07 21:34:25 +000039/// FindExecutable - Find a named executable, giving the argv[0] of program
Misha Brukman44f8a342003-09-29 22:40:07 +000040/// being executed. This allows us to find another LLVM tool if it is built
41/// into the same directory, but that directory is neither the current
42/// directory, nor in the PATH. If the executable cannot be found, return an
43/// empty string.
Misha Brukmanf7066c72003-08-07 21:34:25 +000044///
Chris Lattner49f61c42004-05-28 01:20:58 +000045#undef FindExecutable // needed on windows :(
Reid Spencer9665e8a2004-12-13 23:41:37 +000046sys::Path llvm::FindExecutable(const std::string &ExeName,
Chris Lattner2cdd21c2003-12-14 21:35:53 +000047 const std::string &ProgramPath) {
Reid Spencer9665e8a2004-12-13 23:41:37 +000048 // First check the directory that the calling program is in. We can do this
49 // if ProgramPath contains at least one / character, indicating that it is a
Chris Lattner4a106452002-12-23 23:50:16 +000050 // relative path to bugpoint itself.
51 //
Reid Spencer9665e8a2004-12-13 23:41:37 +000052 sys::Path Result ( ProgramPath );
53 Result.elideFile();
Chris Lattner4a106452002-12-23 23:50:16 +000054
Reid Spencer9665e8a2004-12-13 23:41:37 +000055 if (!Result.isEmpty()) {
56 Result.appendFile(ExeName);
57 if (Result.executable()) return Result;
Chris Lattner4a106452002-12-23 23:50:16 +000058 }
59
Reid Spencer9665e8a2004-12-13 23:41:37 +000060 return sys::Program::FindProgramByName(ExeName);
Chris Lattner4a106452002-12-23 23:50:16 +000061}
62
63static void RedirectFD(const std::string &File, int FD) {
64 if (File.empty()) return; // Noop
65
66 // Open the file
67 int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
68 if (InFD == -1) {
69 std::cerr << "Error opening file '" << File << "' for "
Misha Brukman44f8a342003-09-29 22:40:07 +000070 << (FD == 0 ? "input" : "output") << "!\n";
Chris Lattner4a106452002-12-23 23:50:16 +000071 exit(1);
72 }
73
74 dup2(InFD, FD); // Install it as the requested FD
75 close(InFD); // Close the original FD
76}
77
Chris Lattnerde0213b2004-07-24 07:41:31 +000078static bool Timeout = false;
79static void TimeOutHandler(int Sig) {
80 Timeout = true;
81}
82
Chris Lattner4a106452002-12-23 23:50:16 +000083/// RunProgramWithTimeout - This function executes the specified program, with
84/// the specified null-terminated argument array, with the stdin/out/err fd's
Chris Lattnerde0213b2004-07-24 07:41:31 +000085/// redirected, with a timeout specified by the last argument. This terminates
Chris Lattner4a106452002-12-23 23:50:16 +000086/// the calling program if there is an error executing the specified program.
87/// It returns the return value of the program, or -1 if a timeout is detected.
88///
Chris Lattner2cdd21c2003-12-14 21:35:53 +000089int llvm::RunProgramWithTimeout(const std::string &ProgramPath,
90 const char **Args,
91 const std::string &StdInFile,
92 const std::string &StdOutFile,
Chris Lattnerde0213b2004-07-24 07:41:31 +000093 const std::string &StdErrFile,
94 unsigned NumSeconds) {
Chris Lattnerd895ffe2004-05-27 01:20:55 +000095#ifdef HAVE_SYS_WAIT_H
Chris Lattner4a106452002-12-23 23:50:16 +000096 int Child = fork();
97 switch (Child) {
98 case -1:
99 std::cerr << "ERROR forking!\n";
100 exit(1);
101 case 0: // Child
102 RedirectFD(StdInFile, 0); // Redirect file descriptors...
103 RedirectFD(StdOutFile, 1);
Chris Lattnerbf3d2e22004-04-16 05:35:58 +0000104 if (StdOutFile != StdErrFile)
105 RedirectFD(StdErrFile, 2);
106 else
107 dup2(1, 2);
Chris Lattner4a106452002-12-23 23:50:16 +0000108
109 execv(ProgramPath.c_str(), (char *const *)Args);
Brian Gaeke53e557d2003-10-15 20:46:58 +0000110 std::cerr << "Error executing program: '" << ProgramPath;
Chris Lattner4a106452002-12-23 23:50:16 +0000111 for (; *Args; ++Args)
112 std::cerr << " " << *Args;
Brian Gaeke53e557d2003-10-15 20:46:58 +0000113 std::cerr << "'\n";
Chris Lattner4a106452002-12-23 23:50:16 +0000114 exit(1);
115
116 default: break;
117 }
118
119 // Make sure all output has been written while waiting
120 std::cout << std::flush;
121
Chris Lattnerde0213b2004-07-24 07:41:31 +0000122 // Install a timeout handler.
123 Timeout = false;
124 struct sigaction Act, Old;
125 Act.sa_sigaction = 0;
126 Act.sa_handler = TimeOutHandler;
Chris Lattnerd67e4392004-07-25 07:34:00 +0000127 sigemptyset(&Act.sa_mask);
128 Act.sa_flags = 0;
Chris Lattnerde0213b2004-07-24 07:41:31 +0000129 sigaction(SIGALRM, &Act, &Old);
130
131 // Set the timeout if one is set.
132 if (NumSeconds)
133 alarm(NumSeconds);
134
Chris Lattner4a106452002-12-23 23:50:16 +0000135 int Status;
Chris Lattner21ddf172004-07-24 07:50:48 +0000136 while (wait(&Status) != Child)
Chris Lattner4a106452002-12-23 23:50:16 +0000137 if (errno == EINTR) {
Chris Lattnerde0213b2004-07-24 07:41:31 +0000138 if (Timeout) {
Chris Lattner21ddf172004-07-24 07:50:48 +0000139 // Kill the child.
140 kill(Child, SIGKILL);
141
142 if (wait(&Status) != Child)
143 std::cerr << "Something funny happened waiting for the child!\n";
144
145 alarm(0);
146 sigaction(SIGALRM, &Old, 0);
147 return -1; // Timeout detected
148 } else {
149 std::cerr << "Error waiting for child process!\n";
150 exit(1);
Chris Lattner4a106452002-12-23 23:50:16 +0000151 }
Chris Lattnerde0213b2004-07-24 07:41:31 +0000152 }
Chris Lattnerde0213b2004-07-24 07:41:31 +0000153
154 alarm(0);
155 sigaction(SIGALRM, &Old, 0);
Chris Lattner4a106452002-12-23 23:50:16 +0000156 return Status;
Chris Lattnerd895ffe2004-05-27 01:20:55 +0000157
158#else
159 std::cerr << "RunProgramWithTimeout not implemented on this platform!\n";
160 return -1;
161#endif
Chris Lattner4a106452002-12-23 23:50:16 +0000162}