From fe7f3a2f1d5df2fe66703388a07076bec704b713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 27 Jun 2006 00:07:42 +0000 Subject: [PATCH] Now supports symbolic links correctly, and no longer loads the same shared library twice. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17929 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../private/runtime_loader/runtime_loader.h | 4 +- src/system/runtime_loader/elf.c | 42 +++++++------ src/system/runtime_loader/runtime_loader.c | 60 +++++++++++++------ 3 files changed, 70 insertions(+), 36 deletions(-) diff --git a/headers/private/runtime_loader/runtime_loader.h b/headers/private/runtime_loader/runtime_loader.h index 77ce191cc9..331d0bd960 100644 --- a/headers/private/runtime_loader/runtime_loader.h +++ b/headers/private/runtime_loader/runtime_loader.h @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2002, Manuel J. Petit. All rights reserved. @@ -29,7 +29,7 @@ typedef struct elf_region_t { typedef struct image_t { // image identification - char path[B_OS_NAME_LENGTH]; + char path[B_PATH_NAME_LENGTH]; char name[B_OS_NAME_LENGTH]; image_id id; image_type type; diff --git a/src/system/runtime_loader/elf.c b/src/system/runtime_loader/elf.c index 55581198fe..59fddd4979 100644 --- a/src/system/runtime_loader/elf.c +++ b/src/system/runtime_loader/elf.c @@ -178,21 +178,15 @@ static image_t * find_image_in_queue(image_queue_t *queue, const char *name, bool isPath, uint32 typeMask) { - image_t *iter; + image_t *image; - if (isPath) { - for (iter = queue->head; iter; iter = iter->next) { - if (strncmp(iter->path, name, sizeof(iter->path)) == 0 - && typeMask & IMAGE_TYPE_TO_MASK(iter->type)) { - return iter; - } - } - } else { - for (iter = queue->head; iter; iter = iter->next) { - if (strncmp(iter->name, name, sizeof(iter->path)) == 0 - && typeMask & IMAGE_TYPE_TO_MASK(iter->type)) { - return iter; - } + for (image = queue->head; image; image = image->next) { + const char *imageName = isPath ? image->path : image->name; + int length = isPath ? sizeof(image->path) : sizeof(image->name); + + if (!strncmp(imageName, name, length) + && (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) { + return image; } } @@ -207,8 +201,7 @@ find_image(char const *name, uint32 typeMask) image_t *image; image = find_image_in_queue(&sLoadedImages, name, isPath, typeMask); - - if (!image) + if (image == NULL) image = find_image_in_queue(&sLoadingImages, name, isPath, typeMask); return image; @@ -891,7 +884,10 @@ load_container(char const *name, image_type type, const char *rpath, image_t **_ // If the path is not absolute, we prepend the CWD to make it one. if (path[0] != '/') { char relativePath[PATH_MAX]; - strcpy(relativePath, path); + if (!strncmp(path, "./", 2)) + strcpy(relativePath, path + 2); + else + strcpy(relativePath, path); // get the CWD status = _kern_getcwd(path, sizeof(path)); @@ -909,6 +905,18 @@ load_container(char const *name, image_type type, const char *rpath, image_t **_ } } + // Test again if this image has been registered already - this time, + // we can check the full path, not just its name as noted. + // You could end up loading an image twice with symbolic links, else. + if (type != B_ADD_ON_IMAGE) { + found = find_image(path, APP_OR_LIBRARY_TYPE); + if (found) { + atomic_add(&found->ref_count, 1); + *_image = found; + return B_OK; + } + } + length = _kern_read(fd, 0, &eheader, sizeof(eheader)); if (length != sizeof(eheader)) { status = B_NOT_AN_EXECUTABLE; diff --git a/src/system/runtime_loader/runtime_loader.c b/src/system/runtime_loader/runtime_loader.c index e52bed5c07..7fc6448b07 100644 --- a/src/system/runtime_loader/runtime_loader.c +++ b/src/system/runtime_loader/runtime_loader.c @@ -78,16 +78,18 @@ search_path_for_type(image_type type) static int -try_open_executable(const char *dir, int dirLen, const char *name, char *path, - int pathLen) +try_open_executable(const char *dir, int dirLength, const char *name, char *path, + size_t pathLength) { - int nameLen = strlen(name); + size_t nameLength = strlen(name); + struct stat stat; + status_t status; // construct the path - if (dirLen > 0) { + if (dirLength > 0) { char *buffer = path; - if (dirLen >= 2 && strncmp(dir, "%A", 2) == 0) { + 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) // ToDo: Maybe using first image info is better suited than @@ -98,39 +100,63 @@ try_open_executable(const char *dir, int dirLen, const char *name, char *path, // copy what's left (when the application name is removed) if (lastSlash != NULL) { strlcpy(buffer, gProgramArgs->program_path, - min(pathLen, lastSlash + 1 - gProgramArgs->program_path)); + min((int)pathLength, lastSlash + 1 - gProgramArgs->program_path)); } else - strlcpy(buffer, ".", pathLen); + strlcpy(buffer, ".", pathLength); bytesCopied = strlen(buffer); buffer += bytesCopied; - pathLen -= bytesCopied; + pathLength -= bytesCopied; dir += 2; - dirLen -= 2; + dirLength -= 2; } - if (dirLen + 1 + nameLen >= pathLen) + if (dirLength + 1 + nameLength >= pathLength) return B_NAME_TOO_LONG; - memcpy(buffer, dir, dirLen); - buffer[dirLen] = '/'; - strcpy(buffer + dirLen + 1, name); + memcpy(buffer, dir, dirLength); + buffer[dirLength] = '/'; + strcpy(buffer + dirLength + 1, name); } else { - if (nameLen >= pathLen) + if (nameLength >= pathLength) return B_NAME_TOO_LONG; - strcpy(path + dirLen + 1, name); + strcpy(path + dirLength + 1, name); } TRACE(("runtime_loader: try_open_container(): %s\n", path)); + // Test if the target is a symbolic link, and correct the path in this case + + status = _kern_read_stat(-1, path, false, &stat, sizeof(struct stat)); + if (status < B_OK) + return status; + + if (S_ISLNK(stat.st_mode)) { + char buffer[PATH_MAX]; + size_t length = PATH_MAX; + char *lastSlash; + + // it's a link, indeed + status = _kern_read_link(-1, path, buffer, &length); + if (status < B_OK) + return status; + + lastSlash = strrchr(path, '/'); + if (buffer[0] != '/' && lastSlash != NULL) { + // relative path + strlcpy(lastSlash + 1, buffer, lastSlash + 1 - path + pathLength); + } else + strlcpy(path, buffer, pathLength); + } + return _kern_open(-1, path, O_RDONLY, 0); } static int search_executable_in_path_list(const char *name, const char *pathList, - int pathListLen, char *pathBuffer, int pathBufferLen) + int pathListLen, char *pathBuffer, size_t pathBufferLength) { const char *pathListEnd = pathList + pathListLen; status_t status = B_ENTRY_NOT_FOUND; @@ -147,7 +173,7 @@ search_executable_in_path_list(const char *name, const char *pathList, pathEnd++; fd = try_open_executable(pathList, pathEnd - pathList, name, pathBuffer, - pathBufferLen); + pathBufferLength); if (fd >= 0) { // see if it's a dir struct stat stat;