Program.inc revision 218885
1//===- llvm/Support/Unix/Program.cpp -----------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the Unix specific portion of the Program class. 11// 12//===----------------------------------------------------------------------===// 13 14//===----------------------------------------------------------------------===// 15//=== WARNING: Implementation here must contain only generic UNIX code that 16//=== is guaranteed to work on *all* UNIX variants. 17//===----------------------------------------------------------------------===// 18 19#include <llvm/Config/config.h> 20#include "llvm/Support/FileSystem.h" 21#include "Unix.h" 22#if HAVE_SYS_STAT_H 23#include <sys/stat.h> 24#endif 25#if HAVE_SYS_RESOURCE_H 26#include <sys/resource.h> 27#endif 28#if HAVE_SIGNAL_H 29#include <signal.h> 30#endif 31#if HAVE_FCNTL_H 32#include <fcntl.h> 33#endif 34#ifdef HAVE_POSIX_SPAWN 35#include <spawn.h> 36#if !defined(__APPLE__) 37 extern char **environ; 38#else 39#include <crt_externs.h> // _NSGetEnviron 40#endif 41#endif 42 43namespace llvm { 44using namespace sys; 45 46Program::Program() : Data_(0) {} 47 48Program::~Program() {} 49 50unsigned Program::GetPid() const { 51 uint64_t pid = reinterpret_cast<uint64_t>(Data_); 52 return static_cast<unsigned>(pid); 53} 54 55// This function just uses the PATH environment variable to find the program. 56Path 57Program::FindProgramByName(const std::string& progName) { 58 59 // Check some degenerate cases 60 if (progName.length() == 0) // no program 61 return Path(); 62 Path temp; 63 if (!temp.set(progName)) // invalid name 64 return Path(); 65 // Use the given path verbatim if it contains any slashes; this matches 66 // the behavior of sh(1) and friends. 67 if (progName.find('/') != std::string::npos) 68 return temp; 69 70 // At this point, the file name is valid and does not contain slashes. Search 71 // for it through the directories specified in the PATH environment variable. 72 73 // Get the path. If its empty, we can't do anything to find it. 74 const char *PathStr = getenv("PATH"); 75 if (PathStr == 0) 76 return Path(); 77 78 // Now we have a colon separated list of directories to search; try them. 79 size_t PathLen = strlen(PathStr); 80 while (PathLen) { 81 // Find the first colon... 82 const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); 83 84 // Check to see if this first directory contains the executable... 85 Path FilePath; 86 if (FilePath.set(std::string(PathStr,Colon))) { 87 FilePath.appendComponent(progName); 88 if (FilePath.canExecute()) 89 return FilePath; // Found the executable! 90 } 91 92 // Nope it wasn't in this directory, check the next path in the list! 93 PathLen -= Colon-PathStr; 94 PathStr = Colon; 95 96 // Advance past duplicate colons 97 while (*PathStr == ':') { 98 PathStr++; 99 PathLen--; 100 } 101 } 102 return Path(); 103} 104 105static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { 106 if (Path == 0) // Noop 107 return false; 108 const char *File; 109 if (Path->isEmpty()) 110 // Redirect empty paths to /dev/null 111 File = "/dev/null"; 112 else 113 File = Path->c_str(); 114 115 // Open the file 116 int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); 117 if (InFD == -1) { 118 MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for " 119 + (FD == 0 ? "input" : "output")); 120 return true; 121 } 122 123 // Install it as the requested FD 124 if (dup2(InFD, FD) == -1) { 125 MakeErrMsg(ErrMsg, "Cannot dup2"); 126 close(InFD); 127 return true; 128 } 129 close(InFD); // Close the original FD 130 return false; 131} 132 133#ifdef HAVE_POSIX_SPAWN 134static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg, 135 posix_spawn_file_actions_t &FileActions) { 136 if (Path == 0) // Noop 137 return false; 138 const char *File; 139 if (Path->isEmpty()) 140 // Redirect empty paths to /dev/null 141 File = "/dev/null"; 142 else 143 File = Path->c_str(); 144 145 if (int Err = posix_spawn_file_actions_addopen(&FileActions, FD, 146 File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666)) 147 return MakeErrMsg(ErrMsg, "Cannot dup2", Err); 148 return false; 149} 150#endif 151 152static void TimeOutHandler(int Sig) { 153} 154 155static void SetMemoryLimits (unsigned size) 156{ 157#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT 158 struct rlimit r; 159 __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576; 160 161 // Heap size 162 getrlimit (RLIMIT_DATA, &r); 163 r.rlim_cur = limit; 164 setrlimit (RLIMIT_DATA, &r); 165#ifdef RLIMIT_RSS 166 // Resident set size. 167 getrlimit (RLIMIT_RSS, &r); 168 r.rlim_cur = limit; 169 setrlimit (RLIMIT_RSS, &r); 170#endif 171#ifdef RLIMIT_AS // e.g. NetBSD doesn't have it. 172 // Virtual memory. 173 getrlimit (RLIMIT_AS, &r); 174 r.rlim_cur = limit; 175 setrlimit (RLIMIT_AS, &r); 176#endif 177#endif 178} 179 180bool 181Program::Execute(const Path &path, const char **args, const char **envp, 182 const Path **redirects, unsigned memoryLimit, 183 std::string *ErrMsg) { 184 // If this OS has posix_spawn and there is no memory limit being implied, use 185 // posix_spawn. It is more efficient than fork/exec. 186#ifdef HAVE_POSIX_SPAWN 187 if (memoryLimit == 0) { 188 posix_spawn_file_actions_t FileActions; 189 posix_spawn_file_actions_init(&FileActions); 190 191 if (redirects) { 192 // Redirect stdin/stdout. 193 if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) || 194 RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions)) 195 return false; 196 if (redirects[1] == 0 || redirects[2] == 0 || 197 *redirects[1] != *redirects[2]) { 198 // Just redirect stderr 199 if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false; 200 } else { 201 // If stdout and stderr should go to the same place, redirect stderr 202 // to the FD already open for stdout. 203 if (int Err = posix_spawn_file_actions_adddup2(&FileActions, 1, 2)) 204 return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err); 205 } 206 } 207 208 if (!envp) 209#if !defined(__APPLE__) 210 envp = const_cast<const char **>(environ); 211#else 212 // environ is missing in dylibs. 213 envp = const_cast<const char **>(*_NSGetEnviron()); 214#endif 215 216 // Explicitly initialized to prevent what appears to be a valgrind false 217 // positive. 218 pid_t PID = 0; 219 int Err = posix_spawn(&PID, path.c_str(), &FileActions, /*attrp*/0, 220 const_cast<char **>(args), const_cast<char **>(envp)); 221 222 posix_spawn_file_actions_destroy(&FileActions); 223 224 if (Err) 225 return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); 226 227 Data_ = reinterpret_cast<void*>(PID); 228 return true; 229 } 230#endif 231 232 // Create a child process. 233 int child = fork(); 234 switch (child) { 235 // An error occured: Return to the caller. 236 case -1: 237 MakeErrMsg(ErrMsg, "Couldn't fork"); 238 return false; 239 240 // Child process: Execute the program. 241 case 0: { 242 // Redirect file descriptors... 243 if (redirects) { 244 // Redirect stdin 245 if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } 246 // Redirect stdout 247 if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } 248 if (redirects[1] && redirects[2] && 249 *(redirects[1]) == *(redirects[2])) { 250 // If stdout and stderr should go to the same place, redirect stderr 251 // to the FD already open for stdout. 252 if (-1 == dup2(1,2)) { 253 MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); 254 return false; 255 } 256 } else { 257 // Just redirect stderr 258 if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } 259 } 260 } 261 262 // Set memory limits 263 if (memoryLimit!=0) { 264 SetMemoryLimits(memoryLimit); 265 } 266 267 // Execute! 268 if (envp != 0) 269 execve(path.c_str(), 270 const_cast<char **>(args), 271 const_cast<char **>(envp)); 272 else 273 execv(path.c_str(), 274 const_cast<char **>(args)); 275 // If the execve() failed, we should exit. Follow Unix protocol and 276 // return 127 if the executable was not found, and 126 otherwise. 277 // Use _exit rather than exit so that atexit functions and static 278 // object destructors cloned from the parent process aren't 279 // redundantly run, and so that any data buffered in stdio buffers 280 // cloned from the parent aren't redundantly written out. 281 _exit(errno == ENOENT ? 127 : 126); 282 } 283 284 // Parent process: Break out of the switch to do our processing. 285 default: 286 break; 287 } 288 289 Data_ = reinterpret_cast<void*>(child); 290 291 return true; 292} 293 294int 295Program::Wait(const sys::Path &path, 296 unsigned secondsToWait, 297 std::string* ErrMsg) 298{ 299#ifdef HAVE_SYS_WAIT_H 300 struct sigaction Act, Old; 301 302 if (Data_ == 0) { 303 MakeErrMsg(ErrMsg, "Process not started!"); 304 return -1; 305 } 306 307 // Install a timeout handler. The handler itself does nothing, but the simple 308 // fact of having a handler at all causes the wait below to return with EINTR, 309 // unlike if we used SIG_IGN. 310 if (secondsToWait) { 311 memset(&Act, 0, sizeof(Act)); 312 Act.sa_handler = TimeOutHandler; 313 sigemptyset(&Act.sa_mask); 314 sigaction(SIGALRM, &Act, &Old); 315 alarm(secondsToWait); 316 } 317 318 // Parent process: Wait for the child process to terminate. 319 int status; 320 uint64_t pid = reinterpret_cast<uint64_t>(Data_); 321 pid_t child = static_cast<pid_t>(pid); 322 while (waitpid(pid, &status, 0) != child) 323 if (secondsToWait && errno == EINTR) { 324 // Kill the child. 325 kill(child, SIGKILL); 326 327 // Turn off the alarm and restore the signal handler 328 alarm(0); 329 sigaction(SIGALRM, &Old, 0); 330 331 // Wait for child to die 332 if (wait(&status) != child) 333 MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); 334 else 335 MakeErrMsg(ErrMsg, "Child timed out", 0); 336 337 return -1; // Timeout detected 338 } else if (errno != EINTR) { 339 MakeErrMsg(ErrMsg, "Error waiting for child process"); 340 return -1; 341 } 342 343 // We exited normally without timeout, so turn off the timer. 344 if (secondsToWait) { 345 alarm(0); 346 sigaction(SIGALRM, &Old, 0); 347 } 348 349 // Return the proper exit status. Detect error conditions 350 // so we can return -1 for them and set ErrMsg informatively. 351 int result = 0; 352 if (WIFEXITED(status)) { 353 result = WEXITSTATUS(status); 354#ifdef HAVE_POSIX_SPAWN 355 // The posix_spawn child process returns 127 on any kind of error. 356 // Following the POSIX convention for command-line tools (which posix_spawn 357 // itself apparently does not), check to see if the failure was due to some 358 // reason other than the file not existing, and return 126 in this case. 359 bool Exists; 360 if (result == 127 && !llvm::sys::fs::exists(path.str(), Exists) && Exists) 361 result = 126; 362#endif 363 if (result == 127) { 364 if (ErrMsg) 365 *ErrMsg = llvm::sys::StrError(ENOENT); 366 return -1; 367 } 368 if (result == 126) { 369 if (ErrMsg) 370 *ErrMsg = "Program could not be executed"; 371 return -1; 372 } 373 } else if (WIFSIGNALED(status)) { 374 if (ErrMsg) { 375 *ErrMsg = strsignal(WTERMSIG(status)); 376#ifdef WCOREDUMP 377 if (WCOREDUMP(status)) 378 *ErrMsg += " (core dumped)"; 379#endif 380 } 381 return -1; 382 } 383 return result; 384#else 385 if (ErrMsg) 386 *ErrMsg = "Program::Wait is not implemented on this platform yet!"; 387 return -1; 388#endif 389} 390 391bool 392Program::Kill(std::string* ErrMsg) { 393 if (Data_ == 0) { 394 MakeErrMsg(ErrMsg, "Process not started!"); 395 return true; 396 } 397 398 uint64_t pid64 = reinterpret_cast<uint64_t>(Data_); 399 pid_t pid = static_cast<pid_t>(pid64); 400 401 if (kill(pid, SIGKILL) != 0) { 402 MakeErrMsg(ErrMsg, "The process couldn't be killed!"); 403 return true; 404 } 405 406 return false; 407} 408 409bool Program::ChangeStdinToBinary(){ 410 // Do nothing, as Unix doesn't differentiate between text and binary. 411 return false; 412} 413 414bool Program::ChangeStdoutToBinary(){ 415 // Do nothing, as Unix doesn't differentiate between text and binary. 416 return false; 417} 418 419bool Program::ChangeStderrToBinary(){ 420 // Do nothing, as Unix doesn't differentiate between text and binary. 421 return false; 422} 423 424} 425