blob: 60912b246d92d1ad860d811d49f91283071efd27 [file] [log] [blame]
Misha Brukman3b87f212004-08-04 21:19:49 +00001/*===- SystemUtils.h - Utilities to do low-level system stuff -------------===*\
2 *
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 *===----------------------------------------------------------------------===
9 *
10 * This file contains functions used to do a variety of low-level, often
11 * system-specific, tasks.
12 *
13\*===----------------------------------------------------------------------===*/
Misha Brukman0abaaf42003-08-11 22:29:36 +000014
15#include "SysUtils.h"
Reid Spencer551ccae2004-09-01 22:55:40 +000016#include "llvm/Config/dlfcn.h"
17#include "llvm/Config/fcntl.h"
18#include "llvm/Config/unistd.h"
19#include "llvm/Config/sys/stat.h"
20#include "llvm/Config/sys/types.h"
21#include "llvm/Config/sys/wait.h"
Chris Lattnere275fe82004-01-10 19:15:38 +000022#include <errno.h>
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000023#include <stdio.h>
Misha Brukman0abaaf42003-08-11 22:29:36 +000024#include <stdlib.h>
25#include <string.h>
26
Misha Brukman593ece02003-08-15 23:31:16 +000027/*
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000028 * isExecutable - This function returns true if given struct stat describes the
29 * file as being executable.
30 */
31unsigned isExecutable(const struct stat *buf) {
32 if (!(buf->st_mode & S_IFREG))
33 return 0; // Not a regular file?
34
35 if (buf->st_uid == getuid()) // Owner of file?
36 return buf->st_mode & S_IXUSR;
37 else if (buf->st_gid == getgid()) // In group of file?
38 return buf->st_mode & S_IXGRP;
39 else // Unrelated to file?
40 return buf->st_mode & S_IXOTH;
41}
42
43/*
Misha Brukman593ece02003-08-15 23:31:16 +000044 * isExecutableFile - This function returns true if the filename specified
45 * exists and is executable.
46 */
47unsigned isExecutableFile(const char *ExeFileName) {
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000048 struct stat buf;
49 if (stat(ExeFileName, &buf))
Misha Brukman593ece02003-08-15 23:31:16 +000050 return 0; // Must not be executable!
Misha Brukman0abaaf42003-08-11 22:29:36 +000051
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000052 return isExecutable(&buf);
Misha Brukman0abaaf42003-08-11 22:29:36 +000053}
54
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000055
Misha Brukman593ece02003-08-15 23:31:16 +000056/*
57 * FindExecutable - Find a named executable in the directories listed in $PATH.
58 * If the executable cannot be found, returns NULL.
59 */
Misha Brukman0abaaf42003-08-11 22:29:36 +000060char *FindExecutable(const char *ExeName) {
61 /* Try to find the executable in the path */
62 const char *PathStr = getenv("PATH");
Misha Brukman00ce8402003-09-27 22:26:37 +000063 if (PathStr == 0) return 0;
Misha Brukman0abaaf42003-08-11 22:29:36 +000064
Misha Brukman593ece02003-08-15 23:31:16 +000065 /* Now we have a colon separated list of directories to search, try them. */
Misha Brukman0abaaf42003-08-11 22:29:36 +000066 unsigned PathLen = strlen(PathStr);
67 while (PathLen) {
68 /* Find the next colon */
69 const char *Colon = strchr(PathStr, ':');
70
71 /* Check to see if this first directory contains the executable... */
Misha Brukman00ce8402003-09-27 22:26:37 +000072 unsigned DirLen = Colon ? (unsigned)(Colon-PathStr) : strlen(PathStr);
Misha Brukman0abaaf42003-08-11 22:29:36 +000073 char *FilePath = alloca(sizeof(char) * (DirLen+1+strlen(ExeName)+1));
74 unsigned i, e;
75 for (i = 0; i != DirLen; ++i)
76 FilePath[i] = PathStr[i];
77 FilePath[i] = '/';
78 for (i = 0, e = strlen(ExeName); i != e; ++i)
79 FilePath[DirLen + 1 + i] = ExeName[i];
80 FilePath[DirLen + 1 + i] = '\0';
81 if (isExecutableFile(FilePath))
82 return strdup(FilePath); /* Found the executable! */
83
84 /* If Colon is NULL, there are no more colon separators and no more dirs */
85 if (!Colon) break;
86
87 /* Nope, it wasn't in this directory, check the next range! */
88 PathLen -= DirLen;
89 PathStr = Colon;
90 while (*PathStr == ':') { /* Advance past colons */
91 PathStr++;
92 PathLen--;
93 }
94
95 /* Advance past the colon */
96 ++Colon;
97 }
98
Misha Brukman593ece02003-08-15 23:31:16 +000099 /* If we fell out, we ran out of directories to search, return failure. */
Misha Brukman0abaaf42003-08-11 22:29:36 +0000100 return NULL;
101}
Misha Brukman2e1fbdd2003-09-29 22:37:00 +0000102
103/*
104 * The type of the execve() function is long and boring, but required.
105 */
106typedef int(*execveTy)(const char*, char *const[], char *const[]);
107
108/*
109 * This method finds the real `execve' call in the C library and executes the
110 * given program.
111 */
112int executeProgram(const char *filename, char *const argv[], char *const envp[])
113{
114 /*
115 * Find a pointer to the *real* execve() function starting the search in the
116 * next library and forward, to avoid finding the one defined in this file.
117 */
Reid Spencere6bd6382004-09-14 15:46:13 +0000118 const char *error;
Misha Brukman2e1fbdd2003-09-29 22:37:00 +0000119 execveTy execvePtr = (execveTy) dlsym(RTLD_NEXT, "execve");
120 if ((error = dlerror()) != NULL) {
121 fprintf(stderr, "%s\n", error);
122 return -1;
123 }
124
125 /* Really execute the program */
126 return execvePtr(filename, argv, envp);
127}