blob: 2ec6148a6601a9131446358a3a12ff8db9d2f5c9 [file] [log] [blame]
Misha Brukman0abaaf42003-08-11 22:29:36 +00001//===- 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"
Misha Brukman2e1fbdd2003-09-29 22:37:00 +00009#include "Config/dlfcn.h"
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000010#include "Config/fcntl.h"
11#include "Config/unistd.h"
12#include "Config/sys/stat.h"
13#include "Config/sys/types.h"
14#include "Config/sys/wait.h"
Chris Lattnere275fe82004-01-10 19:15:38 +000015#include <errno.h>
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000016#include <stdio.h>
Misha Brukman0abaaf42003-08-11 22:29:36 +000017#include <stdlib.h>
18#include <string.h>
19
Misha Brukman593ece02003-08-15 23:31:16 +000020/*
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000021 * isExecutable - This function returns true if given struct stat describes the
22 * file as being executable.
23 */
24unsigned 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/*
Misha Brukman593ece02003-08-15 23:31:16 +000037 * isExecutableFile - This function returns true if the filename specified
38 * exists and is executable.
39 */
40unsigned isExecutableFile(const char *ExeFileName) {
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000041 struct stat buf;
42 if (stat(ExeFileName, &buf))
Misha Brukman593ece02003-08-15 23:31:16 +000043 return 0; // Must not be executable!
Misha Brukman0abaaf42003-08-11 22:29:36 +000044
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000045 return isExecutable(&buf);
Misha Brukman0abaaf42003-08-11 22:29:36 +000046}
47
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000048
Misha Brukman593ece02003-08-15 23:31:16 +000049/*
50 * FindExecutable - Find a named executable in the directories listed in $PATH.
51 * If the executable cannot be found, returns NULL.
52 */
Misha Brukman0abaaf42003-08-11 22:29:36 +000053char *FindExecutable(const char *ExeName) {
54 /* Try to find the executable in the path */
55 const char *PathStr = getenv("PATH");
Misha Brukman00ce8402003-09-27 22:26:37 +000056 if (PathStr == 0) return 0;
Misha Brukman0abaaf42003-08-11 22:29:36 +000057
Misha Brukman593ece02003-08-15 23:31:16 +000058 /* Now we have a colon separated list of directories to search, try them. */
Misha Brukman0abaaf42003-08-11 22:29:36 +000059 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... */
Misha Brukman00ce8402003-09-27 22:26:37 +000065 unsigned DirLen = Colon ? (unsigned)(Colon-PathStr) : strlen(PathStr);
Misha Brukman0abaaf42003-08-11 22:29:36 +000066 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
Misha Brukman593ece02003-08-15 23:31:16 +000092 /* If we fell out, we ran out of directories to search, return failure. */
Misha Brukman0abaaf42003-08-11 22:29:36 +000093 return NULL;
94}
Misha Brukman2e1fbdd2003-09-29 22:37:00 +000095
96/*
97 * The type of the execve() function is long and boring, but required.
98 */
99typedef 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 */
105int 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}