hrev46449 adds 1 changeset to branch 'master' old head: 509755e136168e2930dd7e1301d979f6e9244778 new head: 8d23c440f7b0433f0daccf7e4018f99b8d3c3459 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=8d23c44+%5E509755e ---------------------------------------------------------------------------- 8d23c44: 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. [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev46449 Commit: 8d23c440f7b0433f0daccf7e4018f99b8d3c3459 URL: http://cgit.haiku-os.org/haiku/commit/?id=8d23c44 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Tue Nov 26 15:39:50 2013 UTC ---------------------------------------------------------------------------- 5 files changed, 78 insertions(+), 37 deletions(-) src/system/runtime_loader/elf.cpp | 8 +- src/system/runtime_loader/elf_load_image.cpp | 4 +- src/system/runtime_loader/elf_load_image.h | 2 +- src/system/runtime_loader/runtime_loader.cpp | 98 ++++++++++++++------ .../runtime_loader/runtime_loader_private.h | 3 +- ---------------------------------------------------------------------------- diff --git a/src/system/runtime_loader/elf.cpp b/src/system/runtime_loader/elf.cpp index 430ee9f..e7d7514 100644 --- a/src/system/runtime_loader/elf.cpp +++ b/src/system/runtime_loader/elf.cpp @@ -119,7 +119,7 @@ load_immediate_dependencies(image_t *image) const char *name = STRING(image, neededOffset); status_t loadStatus = load_image(name, B_LIBRARY_IMAGE, - rpath, &image->needed[j]); + rpath, image->path, &image->needed[j]); if (loadStatus < B_OK) { status = loadStatus; // 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); 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) { KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, strerror(status)); @@ -410,7 +410,7 @@ load_program(char const *path, void **_entry) 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) 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) { rld_unlock(); KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, diff --git a/src/system/runtime_loader/elf_load_image.cpp b/src/system/runtime_loader/elf_load_image.cpp index 2b12538..f1c17b4 100644 --- a/src/system/runtime_loader/elf_load_image.cpp +++ b/src/system/runtime_loader/elf_load_image.cpp @@ -377,7 +377,7 @@ parse_elf_header(elf_ehdr* eheader, int32* _pheaderSize, status_t load_image(char const* name, image_type type, const char* rpath, - image_t** _image) + const char* requestingObjectPath, image_t** _image) { int32 pheaderSize, sheaderSize; char path[PATH_MAX]; @@ -421,7 +421,7 @@ load_image(char const* name, image_type type, const char* rpath, // find and open the file fd = open_executable(path, type, rpath, get_program_path(), - sSearchPathSubDir); + requestingObjectPath, sSearchPathSubDir); if (fd < 0) { FATAL("Cannot open file %s: %s\n", name, strerror(fd)); KTRACE("rld: load_container(\"%s\"): failed to open file", name); diff --git a/src/system/runtime_loader/elf_load_image.h b/src/system/runtime_loader/elf_load_image.h index e7c4e23..77ead88 100644 --- a/src/system/runtime_loader/elf_load_image.h +++ b/src/system/runtime_loader/elf_load_image.h @@ -11,7 +11,7 @@ status_t parse_elf_header(elf_ehdr* eheader, int32* _pheaderSize, int32* _sheaderSize); 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 diff --git a/src/system/runtime_loader/runtime_loader.cpp b/src/system/runtime_loader/runtime_loader.cpp index 664cf72..8864ef3 100644 --- a/src/system/runtime_loader/runtime_loader.cpp +++ b/src/system/runtime_loader/runtime_loader.cpp @@ -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 try_open_executable(const char *dir, int dirLength, const char *name, - const char *programPath, const char *abiSpecificSubDir, char *path, - size_t pathLength) + const char *programPath, const char *requestingObjectPath, + const char *abiSpecificSubDir, char *path, size_t pathLength) { size_t nameLength = strlen(name); struct stat stat; @@ -111,24 +160,12 @@ try_open_executable(const char *dir, int dirLength, const char *name, if (programPath == NULL) programPath = gProgramArgs->program_path; - if (dirLength >= 2 && strncmp(dir, "%A", 2) == 0) { - // Replace %A with current app folder path (of course, - // this must be the first part of the path) - char *lastSlash = strrchr(programPath, '/'); - int bytesCopied; - - // 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; + if (replace_executable_path_placeholder(dir, dirLength, "%A", 2, + programPath, buffer, pathLength, status) + || replace_executable_path_placeholder(dir, dirLength, "$ORIGIN", 7, + requestingObjectPath, buffer, pathLength, status)) { + if (status != B_OK) + return status; } else if (abiSpecificSubDir != NULL) { // 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 @@ -187,8 +224,8 @@ try_open_executable(const char *dir, int dirLength, const char *name, static int search_executable_in_path_list(const char *name, const char *pathList, - int pathListLen, const char *programPath, const char *abiSpecificSubDir, - char *pathBuffer, size_t pathBufferLength) + int pathListLen, const char *programPath, const char *requestingObjectPath, + const char *abiSpecificSubDir, char *pathBuffer, size_t pathBufferLength) { const char *pathListEnd = pathList + pathListLen; status_t status = B_ENTRY_NOT_FOUND; @@ -205,7 +242,8 @@ search_executable_in_path_list(const char *name, const char *pathList, pathEnd++; fd = try_open_executable(pathList, pathEnd - pathList, name, - programPath, abiSpecificSubDir, pathBuffer, pathBufferLength); + programPath, requestingObjectPath, abiSpecificSubDir, pathBuffer, + pathBufferLength); if (fd >= 0) { // see if it's a dir struct stat stat; @@ -228,7 +266,8 @@ search_executable_in_path_list(const char *name, const char *pathList, 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) { char buffer[PATH_MAX]; 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 (firstList) { fd = search_executable_in_path_list(name, firstList, - semicolon - firstList, programPath, NULL, buffer, - sizeof(buffer)); + semicolon - firstList, programPath, requestingObjectPath, NULL, + buffer, sizeof(buffer)); } if (fd < 0) { 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 (const char *paths = search_path_for_type(type)) { 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)); - 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) return fd; diff --git a/src/system/runtime_loader/runtime_loader_private.h b/src/system/runtime_loader/runtime_loader_private.h index 81dabfe..036a465 100644 --- a/src/system/runtime_loader/runtime_loader_private.h +++ b/src/system/runtime_loader/runtime_loader_private.h @@ -56,7 +56,8 @@ extern "C" { int runtime_loader(void* arg, void* commpage); 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 get_executable_architecture(const char* path, const char** _architecture);