blob: 2538c0e3cdcfa612848109bc076851f7a9ed3188 [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"
17#include <unistd.h>
18#include <wait.h>
19#include <sys/fcntl.h>
Chris Lattner74b1f452004-01-10 19:15:14 +000020#include <algorithm>
Misha Brukmanebb0faa2004-06-18 15:38:49 +000021#include <cerrno>
22#include <cstdlib>
Chris Lattner74b1f452004-01-10 19:15:14 +000023#include <fstream>
24#include <iostream>
Chris Lattnerd67e4392004-07-25 07:34:00 +000025#include <signal.h>
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}
John Criswell5afb5f62003-09-17 15:13:59 +0000163
164
Misha Brukmand6af6862004-06-02 00:09:46 +0000165// ExecWait - executes a program with the specified arguments and environment.
166// It then waits for the progarm to termiante and then returns to the caller.
John Criswell5afb5f62003-09-17 15:13:59 +0000167//
168// Inputs:
169// argv - The arguments to the program as an array of C strings. The first
170// argument should be the name of the program to execute, and the
171// last argument should be a pointer to NULL.
172//
173// envp - The environment passes to the program as an array of C strings in
174// the form of "name=value" pairs. The last element should be a
175// pointer to NULL.
176//
177// Outputs:
178// None.
179//
180// Return value:
181// 0 - No errors.
182// 1 - The program could not be executed.
183// 1 - The program returned a non-zero exit status.
184// 1 - The program terminated abnormally.
185//
186// Notes:
187// The program will inherit the stdin, stdout, and stderr file descriptors
188// as well as other various configuration settings (umask).
189//
190// This function should not print anything to stdout/stderr on its own. It is
191// a generic library function. The caller or executed program should report
192// errors in the way it sees fit.
193//
John Criswelle5b3e152003-09-17 19:02:49 +0000194// This function does not use $PATH to find programs.
195//
Chris Lattner2cdd21c2003-12-14 21:35:53 +0000196int llvm::ExecWait(const char * const old_argv[],
197 const char * const old_envp[]) {
Chris Lattnerd895ffe2004-05-27 01:20:55 +0000198#ifdef HAVE_SYS_WAIT_H
John Criswelle5b3e152003-09-17 19:02:49 +0000199 // Create local versions of the parameters that can be passed into execve()
200 // without creating const problems.
John Criswelle5b3e152003-09-17 19:02:49 +0000201 char ** const argv = (char ** const) old_argv;
202 char ** const envp = (char ** const) old_envp;
John Criswell5afb5f62003-09-17 15:13:59 +0000203
John Criswell5afb5f62003-09-17 15:13:59 +0000204 // Create a child process.
Chris Lattnerd895ffe2004-05-27 01:20:55 +0000205 switch (fork()) {
John Criswelle5b3e152003-09-17 19:02:49 +0000206 // An error occured: Return to the caller.
John Criswell5afb5f62003-09-17 15:13:59 +0000207 case -1:
208 return 1;
209 break;
210
John Criswelle5b3e152003-09-17 19:02:49 +0000211 // Child process: Execute the program.
John Criswell5afb5f62003-09-17 15:13:59 +0000212 case 0:
John Criswelle5b3e152003-09-17 19:02:49 +0000213 execve (argv[0], argv, envp);
John Criswelle5b3e152003-09-17 19:02:49 +0000214 // If the execve() failed, we should exit and let the parent pick up
215 // our non-zero exit status.
John Criswelle5b3e152003-09-17 19:02:49 +0000216 exit (1);
John Criswell5afb5f62003-09-17 15:13:59 +0000217
John Criswelle5b3e152003-09-17 19:02:49 +0000218 // Parent process: Break out of the switch to do our processing.
John Criswell5afb5f62003-09-17 15:13:59 +0000219 default:
220 break;
221 }
222
Misha Brukmand6af6862004-06-02 00:09:46 +0000223 // Parent process: Wait for the child process to terminate.
Chris Lattnerd895ffe2004-05-27 01:20:55 +0000224 int status;
John Criswell5afb5f62003-09-17 15:13:59 +0000225 if ((wait (&status)) == -1)
John Criswell5afb5f62003-09-17 15:13:59 +0000226 return 1;
John Criswell5afb5f62003-09-17 15:13:59 +0000227
John Criswell5afb5f62003-09-17 15:13:59 +0000228 // If the program exited normally with a zero exit status, return success!
John Criswell5afb5f62003-09-17 15:13:59 +0000229 if (WIFEXITED (status) && (WEXITSTATUS(status) == 0))
John Criswell5afb5f62003-09-17 15:13:59 +0000230 return 0;
Chris Lattnerd895ffe2004-05-27 01:20:55 +0000231#else
232 std::cerr << "llvm::ExecWait not implemented on this platform!\n";
233#endif
John Criswell5afb5f62003-09-17 15:13:59 +0000234
John Criswell5afb5f62003-09-17 15:13:59 +0000235 // Otherwise, return failure.
John Criswell5afb5f62003-09-17 15:13:59 +0000236 return 1;
237}