Only use -Wl,-R. if HAVE_LINK_R.
[oota-llvm.git] / tools / llee / SysUtils.c
1 //===- SystemUtils.h - Utilities to do low-level system stuff --*- C++ -*--===//
2 //
3 // This file contains functions used to do a variety of low-level, often
4 // system-specific, tasks.
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "SysUtils.h"
9 #include "Config/dlfcn.h"
10 #include "Config/errno.h"
11 #include "Config/fcntl.h"
12 #include "Config/unistd.h"
13 #include "Config/sys/stat.h"
14 #include "Config/sys/types.h"
15 #include "Config/sys/wait.h"
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 /*
21  * isExecutable - This function returns true if given struct stat describes the
22  * file as being executable.
23  */ 
24 unsigned isExecutable(const struct stat *buf) {
25   if (!(buf->st_mode & S_IFREG))
26     return 0;                         // Not a regular file?
27
28   if (buf->st_uid == getuid())        // Owner of file?
29     return buf->st_mode & S_IXUSR;
30   else if (buf->st_gid == getgid())   // In group of file?
31     return buf->st_mode & S_IXGRP;
32   else                                // Unrelated to file?
33     return buf->st_mode & S_IXOTH;
34 }
35
36 /*
37  * isExecutableFile - This function returns true if the filename specified
38  * exists and is executable.
39  */
40 unsigned isExecutableFile(const char *ExeFileName) {
41   struct stat buf;
42   if (stat(ExeFileName, &buf))
43     return 0;                        // Must not be executable!
44
45   return isExecutable(&buf);
46 }
47
48
49 /*
50  * FindExecutable - Find a named executable in the directories listed in $PATH.
51  * If the executable cannot be found, returns NULL.
52  */ 
53 char *FindExecutable(const char *ExeName) {
54   /* Try to find the executable in the path */
55   const char *PathStr = getenv("PATH");
56   if (PathStr == 0) return 0;
57
58   /* Now we have a colon separated list of directories to search, try them. */
59   unsigned PathLen = strlen(PathStr);
60   while (PathLen) {
61     /* Find the next colon */
62     const char *Colon = strchr(PathStr, ':');
63     
64     /* Check to see if this first directory contains the executable... */
65     unsigned DirLen = Colon ? (unsigned)(Colon-PathStr) : strlen(PathStr);
66     char *FilePath = alloca(sizeof(char) * (DirLen+1+strlen(ExeName)+1));
67     unsigned i, e;
68     for (i = 0; i != DirLen; ++i)
69       FilePath[i] = PathStr[i];
70     FilePath[i] = '/';
71     for (i = 0, e = strlen(ExeName); i != e; ++i)
72       FilePath[DirLen + 1 + i] = ExeName[i];
73     FilePath[DirLen + 1 + i] = '\0';
74     if (isExecutableFile(FilePath))
75       return strdup(FilePath); /* Found the executable! */
76
77     /* If Colon is NULL, there are no more colon separators and no more dirs */
78     if (!Colon) break;
79
80     /* Nope, it wasn't in this directory, check the next range! */
81     PathLen -= DirLen;
82     PathStr = Colon;
83     while (*PathStr == ':') {   /* Advance past colons */
84       PathStr++;
85       PathLen--;
86     }
87
88     /* Advance past the colon */
89     ++Colon;
90   }
91
92   /* If we fell out, we ran out of directories to search, return failure. */
93   return NULL;
94 }
95
96 /*
97  * The type of the execve() function is long and boring, but required.
98  */
99 typedef int(*execveTy)(const char*, char *const[], char *const[]);
100
101 /*
102  * This method finds the real `execve' call in the C library and executes the
103  * given program.
104  */
105 int executeProgram(const char *filename, char *const argv[], char *const envp[])
106 {
107   /*
108    * Find a pointer to the *real* execve() function starting the search in the
109    * next library and forward, to avoid finding the one defined in this file.
110    */
111   char *error;
112   execveTy execvePtr = (execveTy) dlsym(RTLD_NEXT, "execve");
113   if ((error = dlerror()) != NULL) {
114     fprintf(stderr, "%s\n", error);
115     return -1;
116   }
117
118   /* Really execute the program */
119   return execvePtr(filename, argv, envp);
120 }