runtime loader: Add support for $ORIGIN in rpath
Like in Linux it resolves to the directory of the shared object whose needed library is to be loaded.
This commit is contained in:
@@ -119,7 +119,7 @@ load_immediate_dependencies(image_t *image)
|
|||||||
const char *name = STRING(image, neededOffset);
|
const char *name = STRING(image, neededOffset);
|
||||||
|
|
||||||
status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
|
status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
|
||||||
rpath, &image->needed[j]);
|
rpath, image->path, &image->needed[j]);
|
||||||
if (loadStatus < B_OK) {
|
if (loadStatus < B_OK) {
|
||||||
status = loadStatus;
|
status = loadStatus;
|
||||||
// correct error code in case the file could not been found
|
// correct error code in case the file could not been found
|
||||||
@@ -308,7 +308,7 @@ preload_image(char const* path)
|
|||||||
KTRACE("rld: preload_image(\"%s\")", path);
|
KTRACE("rld: preload_image(\"%s\")", path);
|
||||||
|
|
||||||
image_t *image = NULL;
|
image_t *image = NULL;
|
||||||
status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, &image);
|
status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, &image);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
|
KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
|
||||||
strerror(status));
|
strerror(status));
|
||||||
@@ -410,7 +410,7 @@ load_program(char const *path, void **_entry)
|
|||||||
|
|
||||||
TRACE(("rld: load %s\n", path));
|
TRACE(("rld: load %s\n", path));
|
||||||
|
|
||||||
status = load_image(path, B_APP_IMAGE, NULL, &gProgramImage);
|
status = load_image(path, B_APP_IMAGE, NULL, NULL, &gProgramImage);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@@ -516,7 +516,7 @@ load_library(char const *path, uint32 flags, bool addOn, void** _handle)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = load_image(path, type, NULL, &image);
|
status = load_image(path, type, NULL, NULL, &image);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
rld_unlock();
|
rld_unlock();
|
||||||
KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
|
KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ parse_elf_header(elf_ehdr* eheader, int32* _pheaderSize,
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
load_image(char const* name, image_type type, const char* rpath,
|
load_image(char const* name, image_type type, const char* rpath,
|
||||||
image_t** _image)
|
const char* requestingObjectPath, image_t** _image)
|
||||||
{
|
{
|
||||||
int32 pheaderSize, sheaderSize;
|
int32 pheaderSize, sheaderSize;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
@@ -421,7 +421,7 @@ load_image(char const* name, image_type type, const char* rpath,
|
|||||||
|
|
||||||
// find and open the file
|
// find and open the file
|
||||||
fd = open_executable(path, type, rpath, get_program_path(),
|
fd = open_executable(path, type, rpath, get_program_path(),
|
||||||
sSearchPathSubDir);
|
requestingObjectPath, sSearchPathSubDir);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
FATAL("Cannot open file %s: %s\n", name, strerror(fd));
|
FATAL("Cannot open file %s: %s\n", name, strerror(fd));
|
||||||
KTRACE("rld: load_container(\"%s\"): failed to open file", name);
|
KTRACE("rld: load_container(\"%s\"): failed to open file", name);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
status_t parse_elf_header(elf_ehdr* eheader, int32* _pheaderSize,
|
status_t parse_elf_header(elf_ehdr* eheader, int32* _pheaderSize,
|
||||||
int32* _sheaderSize);
|
int32* _sheaderSize);
|
||||||
status_t load_image(char const* name, image_type type, const char* rpath,
|
status_t load_image(char const* name, image_type type, const char* rpath,
|
||||||
image_t** _image);
|
const char* requestingObjectPath, image_t** _image);
|
||||||
|
|
||||||
|
|
||||||
#endif // ELF_LOAD_IMAGE_H
|
#endif // ELF_LOAD_IMAGE_H
|
||||||
|
|||||||
@@ -94,10 +94,59 @@ search_path_for_type(image_type type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
replace_executable_path_placeholder(const char*& dir, int& dirLength,
|
||||||
|
const char* placeholder, size_t placeholderLength,
|
||||||
|
const char* replacementSubPath, char*& buffer, size_t& bufferSize,
|
||||||
|
status_t& _error)
|
||||||
|
{
|
||||||
|
if (dirLength < (int)placeholderLength
|
||||||
|
|| strncmp(dir, placeholder, placeholderLength) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replacementSubPath == NULL) {
|
||||||
|
_error = B_ENTRY_NOT_FOUND;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* lastSlash = strrchr(replacementSubPath, '/');
|
||||||
|
|
||||||
|
// Copy replacementSubPath without the last component (the application file
|
||||||
|
// name, respectively the requesting executable file name).
|
||||||
|
size_t toCopy;
|
||||||
|
if (lastSlash != NULL) {
|
||||||
|
toCopy = lastSlash - replacementSubPath;
|
||||||
|
strlcpy(buffer, replacementSubPath,
|
||||||
|
std::min((ssize_t)bufferSize, lastSlash + 1 - replacementSubPath));
|
||||||
|
} else {
|
||||||
|
replacementSubPath = ".";
|
||||||
|
toCopy = 1;
|
||||||
|
strlcpy(buffer, ".", bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toCopy >= bufferSize) {
|
||||||
|
_error = B_NAME_TOO_LONG;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer, replacementSubPath, toCopy);
|
||||||
|
buffer[toCopy] = '\0';
|
||||||
|
|
||||||
|
buffer += toCopy;
|
||||||
|
bufferSize -= toCopy;
|
||||||
|
dir += placeholderLength;
|
||||||
|
dirLength -= placeholderLength;
|
||||||
|
|
||||||
|
_error = B_OK;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
try_open_executable(const char *dir, int dirLength, const char *name,
|
try_open_executable(const char *dir, int dirLength, const char *name,
|
||||||
const char *programPath, const char *abiSpecificSubDir, char *path,
|
const char *programPath, const char *requestingObjectPath,
|
||||||
size_t pathLength)
|
const char *abiSpecificSubDir, char *path, size_t pathLength)
|
||||||
{
|
{
|
||||||
size_t nameLength = strlen(name);
|
size_t nameLength = strlen(name);
|
||||||
struct stat stat;
|
struct stat stat;
|
||||||
@@ -111,24 +160,12 @@ try_open_executable(const char *dir, int dirLength, const char *name,
|
|||||||
if (programPath == NULL)
|
if (programPath == NULL)
|
||||||
programPath = gProgramArgs->program_path;
|
programPath = gProgramArgs->program_path;
|
||||||
|
|
||||||
if (dirLength >= 2 && strncmp(dir, "%A", 2) == 0) {
|
if (replace_executable_path_placeholder(dir, dirLength, "%A", 2,
|
||||||
// Replace %A with current app folder path (of course,
|
programPath, buffer, pathLength, status)
|
||||||
// this must be the first part of the path)
|
|| replace_executable_path_placeholder(dir, dirLength, "$ORIGIN", 7,
|
||||||
char *lastSlash = strrchr(programPath, '/');
|
requestingObjectPath, buffer, pathLength, status)) {
|
||||||
int bytesCopied;
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
// copy what's left (when the application name is removed)
|
|
||||||
if (lastSlash != NULL) {
|
|
||||||
strlcpy(buffer, programPath,
|
|
||||||
std::min((long)pathLength, lastSlash + 1 - programPath));
|
|
||||||
} else
|
|
||||||
strlcpy(buffer, ".", pathLength);
|
|
||||||
|
|
||||||
bytesCopied = strlen(buffer);
|
|
||||||
buffer += bytesCopied;
|
|
||||||
pathLength -= bytesCopied;
|
|
||||||
dir += 2;
|
|
||||||
dirLength -= 2;
|
|
||||||
} else if (abiSpecificSubDir != NULL) {
|
} else if (abiSpecificSubDir != NULL) {
|
||||||
// We're looking for a library or an add-on and the executable has
|
// We're looking for a library or an add-on and the executable has
|
||||||
// not been compiled with a compiler using the same ABI as the one
|
// not been compiled with a compiler using the same ABI as the one
|
||||||
@@ -187,8 +224,8 @@ try_open_executable(const char *dir, int dirLength, const char *name,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
search_executable_in_path_list(const char *name, const char *pathList,
|
search_executable_in_path_list(const char *name, const char *pathList,
|
||||||
int pathListLen, const char *programPath, const char *abiSpecificSubDir,
|
int pathListLen, const char *programPath, const char *requestingObjectPath,
|
||||||
char *pathBuffer, size_t pathBufferLength)
|
const char *abiSpecificSubDir, char *pathBuffer, size_t pathBufferLength)
|
||||||
{
|
{
|
||||||
const char *pathListEnd = pathList + pathListLen;
|
const char *pathListEnd = pathList + pathListLen;
|
||||||
status_t status = B_ENTRY_NOT_FOUND;
|
status_t status = B_ENTRY_NOT_FOUND;
|
||||||
@@ -205,7 +242,8 @@ search_executable_in_path_list(const char *name, const char *pathList,
|
|||||||
pathEnd++;
|
pathEnd++;
|
||||||
|
|
||||||
fd = try_open_executable(pathList, pathEnd - pathList, name,
|
fd = try_open_executable(pathList, pathEnd - pathList, name,
|
||||||
programPath, abiSpecificSubDir, pathBuffer, pathBufferLength);
|
programPath, requestingObjectPath, abiSpecificSubDir, pathBuffer,
|
||||||
|
pathBufferLength);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
// see if it's a dir
|
// see if it's a dir
|
||||||
struct stat stat;
|
struct stat stat;
|
||||||
@@ -228,7 +266,8 @@ search_executable_in_path_list(const char *name, const char *pathList,
|
|||||||
|
|
||||||
int
|
int
|
||||||
open_executable(char *name, image_type type, const char *rpath,
|
open_executable(char *name, image_type type, const char *rpath,
|
||||||
const char *programPath, const char *abiSpecificSubDir)
|
const char *programPath, const char *requestingObjectPath,
|
||||||
|
const char *abiSpecificSubDir)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
int fd = B_ENTRY_NOT_FOUND;
|
int fd = B_ENTRY_NOT_FOUND;
|
||||||
@@ -266,12 +305,13 @@ open_executable(char *name, image_type type, const char *rpath,
|
|||||||
// If there is no ';', we set only secondList to simplify things.
|
// If there is no ';', we set only secondList to simplify things.
|
||||||
if (firstList) {
|
if (firstList) {
|
||||||
fd = search_executable_in_path_list(name, firstList,
|
fd = search_executable_in_path_list(name, firstList,
|
||||||
semicolon - firstList, programPath, NULL, buffer,
|
semicolon - firstList, programPath, requestingObjectPath, NULL,
|
||||||
sizeof(buffer));
|
buffer, sizeof(buffer));
|
||||||
}
|
}
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fd = search_executable_in_path_list(name, secondList,
|
fd = search_executable_in_path_list(name, secondList,
|
||||||
strlen(secondList), programPath, NULL, buffer, sizeof(buffer));
|
strlen(secondList), programPath, requestingObjectPath, NULL,
|
||||||
|
buffer, sizeof(buffer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +320,7 @@ open_executable(char *name, image_type type, const char *rpath,
|
|||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
if (const char *paths = search_path_for_type(type)) {
|
if (const char *paths = search_path_for_type(type)) {
|
||||||
fd = search_executable_in_path_list(name, paths, strlen(paths),
|
fd = search_executable_in_path_list(name, paths, strlen(paths),
|
||||||
programPath, abiSpecificSubDir, buffer, sizeof(buffer));
|
programPath, NULL, abiSpecificSubDir, buffer, sizeof(buffer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +377,7 @@ test_executable(const char *name, char *invoker)
|
|||||||
|
|
||||||
strlcpy(path, name, sizeof(path));
|
strlcpy(path, name, sizeof(path));
|
||||||
|
|
||||||
fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL);
|
fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL, NULL);
|
||||||
if (fd < B_OK)
|
if (fd < B_OK)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ extern "C" {
|
|||||||
|
|
||||||
int runtime_loader(void* arg, void* commpage);
|
int runtime_loader(void* arg, void* commpage);
|
||||||
int open_executable(char* name, image_type type, const char* rpath,
|
int open_executable(char* name, image_type type, const char* rpath,
|
||||||
const char* programPath, const char* abiSpecificSubDir);
|
const char* programPath, const char* requestingObjectPath,
|
||||||
|
const char* abiSpecificSubDir);
|
||||||
status_t test_executable(const char* path, char* interpreter);
|
status_t test_executable(const char* path, char* interpreter);
|
||||||
status_t get_executable_architecture(const char* path,
|
status_t get_executable_architecture(const char* path,
|
||||||
const char** _architecture);
|
const char** _architecture);
|
||||||
|
|||||||
Reference in New Issue
Block a user