Skip to content

Commit

Permalink
runtime loader: Add support for $ORIGIN in rpath
Browse files Browse the repository at this point in the history
Like in Linux it resolves to the directory of the shared object whose
needed library is to be loaded.
  • Loading branch information
weinhold committed Nov 26, 2013
1 parent 509755e commit 8d23c44
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 37 deletions.
8 changes: 4 additions & 4 deletions src/system/runtime_loader/elf.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;


Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/system/runtime_loader/elf_load_image.cpp
Expand Up @@ -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];
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/system/runtime_loader/elf_load_image.h
Expand Up @@ -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
98 changes: 69 additions & 29 deletions src/system/runtime_loader/runtime_loader.cpp
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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));
} }
} }


Expand All @@ -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));
} }
} }


Expand Down Expand Up @@ -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;


Expand Down
3 changes: 2 additions & 1 deletion src/system/runtime_loader/runtime_loader_private.h
Expand Up @@ -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);
Expand Down

0 comments on commit 8d23c44

Please sign in to comment.