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 FileActionsStore; 189 posix_spawn_file_actions_t *FileActions = 0; 190 191 if (redirects) { 192 FileActions = &FileActionsStore; 193 posix_spawn_file_actions_init(FileActions); 194 195 // Redirect stdin/stdout. 196 if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) || 197 RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions)) 198 return false; 199 if (redirects[1] == 0 || redirects[2] == 0 || 200 *redirects[1] != *redirects[2]) { 201 // Just redirect stderr 202 if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false; 203 } else { 204 // If stdout and stderr should go to the same place, redirect stderr 205 // to the FD already open for stdout. 206 if (int Err = posix_spawn_file_actions_adddup2(FileActions, 1, 2)) 207 return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err); 208 } 209 } 210 211 if (!envp) 212#if !defined(__APPLE__) 213 envp = const_cast<const char **>(environ); 214#else 215 // environ is missing in dylibs. 216 envp = const_cast<const char **>(*_NSGetEnviron()); 217#endif 218 219 // Explicitly initialized to prevent what appears to be a valgrind false 220 // positive. 221 pid_t PID = 0; 222 int Err = posix_spawn(&PID, path.c_str(), FileActions, /*attrp*/0, 223 const_cast<char **>(args), const_cast<char **>(envp)); 224 225 if (FileActions) 226 posix_spawn_file_actions_destroy(FileActions); 227 228 if (Err) 229 return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); 230 231 Data_ = reinterpret_cast<void*>(PID); 232 return true; 233 } 234#endif 235 236 // Create a child process. 237 int child = fork(); 238 switch (child) { 239 // An error occurred: Return to the caller. 240 case -1: 241 MakeErrMsg(ErrMsg, "Couldn't fork"); 242 return false; 243 244 // Child process: Execute the program. 245 case 0: { 246 // Redirect file descriptors... 247 if (redirects) { 248 // Redirect stdin 249 if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } 250 // Redirect stdout 251 if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } 252 if (redirects[1] && redirects[2] && 253 *(redirects[1]) == *(redirects[2])) { 254 // If stdout and stderr should go to the same place, redirect stderr 255 // to the FD already open for stdout. 256 if (-1 == dup2(1,2)) { 257 MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); 258 return false; 259 } 260 } else { 261 // Just redirect stderr 262 if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } 263 } 264 } 265 266 // Set memory limits 267 if (memoryLimit!=0) { 268 SetMemoryLimits(memoryLimit); 269 } 270 271 // Execute! 272 if (envp != 0) 273 execve(path.c_str(), 274 const_cast<char **>(args), 275 const_cast<char **>(envp)); 276 else 277 execv(path.c_str(), 278 const_cast<char **>(args)); 279 // If the execve() failed, we should exit. Follow Unix protocol and 280 // return 127 if the executable was not found, and 126 otherwise. 281 // Use _exit rather than exit so that atexit functions and static 282 // object destructors cloned from the parent process aren't 283 // redundantly run, and so that any data buffered in stdio buffers 284 // cloned from the parent aren't redundantly written out. 285 _exit(errno == ENOENT ? 127 : 126); 286 } 287 288 // Parent process: Break out of the switch to do our processing. 289 default: 290 break; 291 } 292 293 Data_ = reinterpret_cast<void*>(child); 294 295 return true; 296} 297 298int 299Program::Wait(const sys::Path &path, 300 unsigned secondsToWait, 301 std::string* ErrMsg) 302{ 303#ifdef HAVE_SYS_WAIT_H 304 struct sigaction Act, Old; 305 306 if (Data_ == 0) { 307 MakeErrMsg(ErrMsg, "Process not started!"); 308 return -1; 309 } 310 311#ifdef ENABLE_SIGNAL_OVERRIDES 312 // Install a timeout handler. The handler itself does nothing, but the simple 313 // fact of having a handler at all causes the wait below to return with EINTR, 314 // unlike if we used SIG_IGN. 315 if (secondsToWait) { 316 memset(&Act, 0, sizeof(Act)); 317 Act.sa_handler = TimeOutHandler; 318 sigemptyset(&Act.sa_mask); 319 sigaction(SIGALRM, &Act, &Old); 320 alarm(secondsToWait); 321 } 322#endif 323 324 // Parent process: Wait for the child process to terminate. 325 int status; 326 uint64_t pid = reinterpret_cast<uint64_t>(Data_); 327 pid_t child = static_cast<pid_t>(pid); 328 while (waitpid(pid, &status, 0) != child) { 329#ifdef ENABLE_SIGNAL_OVERRIDES 330 if (secondsToWait && errno == EINTR) { 331 // Kill the child. 332 kill(child, SIGKILL); 333 334 // Turn off the alarm and restore the signal handler 335 alarm(0); 336 sigaction(SIGALRM, &Old, 0); 337 338 // Wait for child to die 339 if (wait(&status) != child) 340 MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); 341 else 342 MakeErrMsg(ErrMsg, "Child timed out", 0); 343 344 return -2; // Timeout detected 345 } else 346#endif 347 if (errno != EINTR) { 348 MakeErrMsg(ErrMsg, "Error waiting for child process"); 349 return -1; 350 } 351 } 352 353#ifdef ENABLE_SIGNAL_OVERRIDES 354 // We exited normally without timeout, so turn off the timer. 355 if (secondsToWait) { 356 alarm(0); 357 sigaction(SIGALRM, &Old, 0); 358 } 359#endif 360 361 // Return the proper exit status. Detect error conditions 362 // so we can return -1 for them and set ErrMsg informatively. 363 int result = 0; 364 if (WIFEXITED(status)) { 365 result = WEXITSTATUS(status); 366#ifdef HAVE_POSIX_SPAWN 367 // The posix_spawn child process returns 127 on any kind of error. 368 // Following the POSIX convention for command-line tools (which posix_spawn 369 // itself apparently does not), check to see if the failure was due to some 370 // reason other than the file not existing, and return 126 in this case. 371 bool Exists; 372 if (result == 127 && !llvm::sys::fs::exists(path.str(), Exists) && Exists) 373 result = 126; 374#endif 375 if (result == 127) { 376 if (ErrMsg) 377 *ErrMsg = llvm::sys::StrError(ENOENT); 378 return -1; 379 } 380 if (result == 126) { 381 if (ErrMsg) 382 *ErrMsg = "Program could not be executed"; 383 return -1; 384 } 385 } else if (WIFSIGNALED(status)) { 386 if (ErrMsg) { 387 *ErrMsg = strsignal(WTERMSIG(status)); 388#ifdef WCOREDUMP 389 if (WCOREDUMP(status)) 390 *ErrMsg += " (core dumped)"; 391#endif 392 } 393 // Return a special value to indicate that the process received an unhandled 394 // signal during execution as opposed to failing to execute. 395 return -2; 396 } 397 return result; 398#else 399 if (ErrMsg) 400 *ErrMsg = "Program::Wait is not implemented on this platform yet!"; 401 return -1; 402#endif 403} 404 405bool 406Program::Kill(std::string* ErrMsg) { 407 if (Data_ == 0) { 408 MakeErrMsg(ErrMsg, "Process not started!"); 409 return true; 410 } 411 412 uint64_t pid64 = reinterpret_cast<uint64_t>(Data_); 413 pid_t pid = static_cast<pid_t>(pid64); 414 415 if (kill(pid, SIGKILL) != 0) { 416 MakeErrMsg(ErrMsg, "The process couldn't be killed!"); 417 return true; 418 } 419 420 return false; 421} 422 423bool Program::ChangeStdinToBinary(){ 424 // Do nothing, as Unix doesn't differentiate between text and binary. 425 return false; 426} 427 428bool Program::ChangeStdoutToBinary(){ 429 // Do nothing, as Unix doesn't differentiate between text and binary. 430 return false; 431} 432 433bool Program::ChangeStderrToBinary(){ 434 // Do nothing, as Unix doesn't differentiate between text and binary. 435 return false; 436} 437 438} 439