diff --git a/headers/private/kernel/user_runtime.h b/headers/private/kernel/user_runtime.h index 3c182386a6..7fa913ab36 100644 --- a/headers/private/kernel/user_runtime.h +++ b/headers/private/kernel/user_runtime.h @@ -1,13 +1,18 @@ /* -** Copyright 2002, Manuel J. Petit. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ + * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2002, Manuel J. Petit. All rights reserved. + * Distributed under the terms of the NewOS License. + */ #ifndef KERNEL_USER_RUNTIME_H_ #define KERNEL_USER_RUNTIME_H_ + #include #include + #define MAGIC_APP_NAME "_APP_" struct rld_export { @@ -18,6 +23,8 @@ struct rld_export { int32 symbolType, void **_location); status_t (*get_nth_image_symbol)(image_id imageID, int32 num, char *symbolName, int32 *nameLength, int32 *symbolType, void **_location); + status_t (*test_executable)(const char *path, uid_t user, gid_t group, + char *starter); }; struct uspace_program_args { @@ -34,6 +41,4 @@ struct uspace_program_args { struct rld_export *rld_export; }; -typedef void (libinit_f)(unsigned, struct uspace_program_args const *); - #endif /* KERNEL_USER_RUNTIME_H_ */ diff --git a/headers/private/libroot/libroot_private.h b/headers/private/libroot/libroot_private.h index 25412e476b..b510d1ea94 100644 --- a/headers/private/libroot/libroot_private.h +++ b/headers/private/libroot/libroot_private.h @@ -6,9 +6,13 @@ #define LIBROOT_PRIVATE_H +#include + + struct uspace_program_args; struct real_time_data; +status_t __test_executable(const char *path, char *starter); void __init_image(const struct uspace_program_args *args); void __init_dlfcn(const struct uspace_program_args *args); void __init_env(const struct uspace_program_args *args); diff --git a/src/system/libroot/os/image.c b/src/system/libroot/os/image.c index a420128126..47c9efdd0f 100644 --- a/src/system/libroot/os/image.c +++ b/src/system/libroot/os/image.c @@ -11,6 +11,8 @@ #include #include +#include + static struct rld_export const *sRuntimeLinker; @@ -18,17 +20,48 @@ static struct rld_export const *sRuntimeLinker; thread_id load_image(int32 argCount, const char **args, const char **environ) { + char starter[B_FILE_NAME_LENGTH]; + const char **newArgs = NULL; int32 envCount = 0; + thread_id thread; if (argCount < 1 || environ == NULL) return B_BAD_VALUE; + // test validity of executable + support for scripts + { + status_t status = __test_executable(args[0], starter); + if (status < B_OK) + return status; + + if (starter[0]) { + int32 i; + + // this is a shell script and requires special treatment + newArgs = malloc((argCount + 2) * sizeof(void *)); + if (newArgs == NULL) + return B_NO_MEMORY; + + // copy args and have "starter" as new app + newArgs[0] = starter; + for (i = 0; i < argCount; i++) + newArgs[i + 1] = args[i]; + newArgs[i + 1] = NULL; + + args = newArgs; + argCount++; + } + } + // count environment variables while (environ[envCount] != NULL) envCount++; - return _kern_load_image(argCount, args, envCount, environ, + thread = _kern_load_image(argCount, args, envCount, environ, B_NORMAL_PRIORITY, B_WAIT_TILL_LOADED); + + free(newArgs); + return thread; } @@ -85,6 +118,13 @@ clear_caches(void *address, size_t length, uint32 flags) // #pragma mark - +status_t +__test_executable(const char *path, char *starter) +{ + return sRuntimeLinker->test_executable(path, geteuid(), getegid(), starter); +} + + void __init_image(const struct uspace_program_args *args) { diff --git a/src/system/libroot/posix/unistd/exec.c b/src/system/libroot/posix/unistd/exec.c index ed4bb19fb3..ec1a70bfa9 100644 --- a/src/system/libroot/posix/unistd/exec.c +++ b/src/system/libroot/posix/unistd/exec.c @@ -1,16 +1,18 @@ -/* -** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. -** Distributed under the terms of the Haiku License. -*/ +/* + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ #include +#include #include #include #include #include #include +#include static int @@ -49,31 +51,64 @@ copy_arguments(va_list list, const char **args, const char *arg) int -execve(const char *path, char * const argv[], char * const environment[]) +execve(const char *path, char * const args[], char * const environment[]) { - int32 argc = 0, envCount = 0; + int32 argCount = 0, envCount = 0; + char starter[B_FILE_NAME_LENGTH]; + char **newArgs = NULL; // count argument/environment list entries here, we don't want // to do this in the kernel - while (argv[argc] != NULL) - argc++; + while (args[argCount] != NULL) + argCount++; while (environment[envCount] != NULL) envCount++; - if (argc == 0) { + if (argCount == 0) { // we need some more info on what to do... errno = B_BAD_VALUE; return -1; } + // test validity of executable + support for scripts + { + status_t status = __test_executable(args[0], starter); + if (status < B_OK) { + errno = status; + return -1; + } + + if (starter[0]) { + int32 i; + + // this is a shell script and requires special treatment + newArgs = malloc((argCount + 2) * sizeof(void *)); + if (newArgs == NULL) { + errno = B_NO_MEMORY; + return -1; + } + + // copy args and have "starter" as new app + newArgs[0] = starter; + for (i = 0; i < argCount; i++) + newArgs[i + 1] = args[i]; + newArgs[i + 1] = NULL; + + path = starter; + args = newArgs; + argCount++; + } + } + // "argv[0]" and "path" should be identical here, but they don't have // to. Instead of worrying and needing to copy the array, we just // don't care and pass everything to the kernel - it will have to // do the right thing :) - errno = _kern_exec(path, argc, argv, envCount, environment); + errno = _kern_exec(path, argCount, args, envCount, environment); // if this call returns, something definitely went wrong + free(newArgs); return -1; } diff --git a/src/system/runtime_loader/rld.c b/src/system/runtime_loader/rld.c index 8f1a50e297..edc5351048 100644 --- a/src/system/runtime_loader/rld.c +++ b/src/system/runtime_loader/rld.c @@ -7,11 +7,268 @@ */ -#include #include #include #include "rld_priv.h" +#include +#include +#include + + +struct uspace_program_args *gProgramArgs; + + +static const char * +search_path_for_type(image_type type) +{ + const char *path = NULL; + + switch (type) { + case B_APP_IMAGE: + path = getenv("PATH"); + break; + case B_LIBRARY_IMAGE: + path = getenv("LIBRARY_PATH"); + break; + case B_ADD_ON_IMAGE: + path = getenv("ADDON_PATH"); + break; + + default: + return NULL; + } + + // ToDo: for now, if the variable was not set, return default paths + if (path != NULL) + return path; + + switch (type) { + case B_APP_IMAGE: + return "/boot/home/config/bin:" + "/bin:" + "/boot/apps:" + "/boot/preferences:" + "/boot/beos/apps:" + "/boot/beos/preferences:" + "/boot/develop/tools/gnupro/bin"; + + case B_LIBRARY_IMAGE: + return "%A/lib:/boot/home/config/lib:/boot/beos/system/lib"; + + case B_ADD_ON_IMAGE: + return "%A/add-ons" + ":/boot/home/config/add-ons" + ":/boot/beos/system/add-ons"; + + default: + return NULL; + } +} + + +static int +try_open_executable(const char *dir, int dirLen, const char *name, char *path, + int pathLen) +{ + int nameLen = strlen(name); + + // construct the path + if (dirLen > 0) { + char *buffer = path; + + if (dirLen >= 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 + // gProgamArgs->program_path here? + char *lastSlash = strrchr(gProgramArgs->program_path, '/'); + int bytesCopied; + + // 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)); + } else + strlcpy(buffer, ".", pathLen); + + bytesCopied = strlen(buffer); + buffer += bytesCopied; + pathLen -= bytesCopied; + dir += 2; + dirLen -= 2; + } + + if (dirLen + 1 + nameLen >= pathLen) + return B_NAME_TOO_LONG; + + memcpy(buffer, dir, dirLen); + buffer[dirLen] = '/'; + strcpy(buffer + dirLen + 1, name); + } else { + if (nameLen >= pathLen) + return B_NAME_TOO_LONG; + + strcpy(path + dirLen + 1, name); + } + + //TRACE(("rld.so: try_open_container(): %s\n", path)); + + 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) +{ + const char *pathListEnd = pathList + pathListLen; + + //TRACE(("rld.so: search_container_in_path_list() %s in %.*s\n", name, + // pathListLen, pathList)); + + while (pathListLen > 0) { + const char *pathEnd = pathList; + int fd; + + // find the next ':' or run till the end of the string + while (pathEnd < pathListEnd && *pathEnd != ':') + pathEnd++; + + fd = try_open_executable(pathList, pathEnd - pathList, name, pathBuffer, + pathBufferLen); + if (fd >= 0) + return fd; + + pathListLen = pathListEnd - pathEnd - 1; + pathList = pathEnd + 1; + } + + return B_ENTRY_NOT_FOUND; +} + + +int +open_executable(char *name, image_type type, const char *rpath) +{ + const char *paths; + char buffer[PATH_MAX]; + int fd = -1; + + if (strchr(name, '/')) { + // the name already contains a path, we don't have to search for it + return _kern_open(-1, name, O_RDONLY, 0); + } + + // first try rpath (DT_RPATH) + if (rpath) { + // It consists of a colon-separated search path list. Optionally it + // follows a second search path list, separated from the first by a + // semicolon. + const char *semicolon = strchr(rpath, ';'); + const char *firstList = (semicolon ? rpath : NULL); + const char *secondList = (semicolon ? semicolon + 1 : rpath); + // If there is no ';', we set only secondList to simplify things. + if (firstList) { + fd = search_executable_in_path_list(name, firstList, + semicolon - firstList, buffer, sizeof(buffer)); + } + if (fd < 0) { + fd = search_executable_in_path_list(name, secondList, + strlen(secondList), buffer, sizeof(buffer)); + } + } + + // let's evaluate the system path variables to find the container + if (fd < 0) { + paths = search_path_for_type(type); + if (paths) { + fd = search_executable_in_path_list(name, paths, strlen(paths), + buffer, sizeof(buffer)); + } + } + + if (fd >= 0) { + // we found it, copy path! + //TRACE(("rld.so: open_container(%s): found at %s\n", name, buffer)); + strlcpy(name, buffer, PATH_MAX); + return fd; + } + + return B_ENTRY_NOT_FOUND; +} + + +/** Tests if there is an executable file at the provided path. It will + * also test if the file has a valid ELF header or is a shell script. + * Even if the runtime loader does not need to be able to deal with + * both types, the caller will give scripts a proper treatment. + */ + +status_t +test_executable(const char *name, uid_t user, gid_t group, char *starter) +{ + char path[B_PATH_NAME_LENGTH]; + char buffer[B_FILE_NAME_LENGTH]; + // must be large enough to hold the ELF header + struct stat stat; + status_t status; + ssize_t length; + int fd; + + strlcpy(path, name, sizeof(path)); + + fd = open_executable(path, B_APP_IMAGE, NULL); + if (fd < B_OK) + return fd; + + // see if it's executable at all + + status = _kern_read_stat(fd, NULL, true, &stat, sizeof(struct stat)); + if (status != B_OK) + goto out; + + // shift mode bits, to check directly against accessMode + if (user == stat.st_uid) + stat.st_mode >>= 6; + else if (group == stat.st_gid) + stat.st_mode >>= 3; + + if (~(stat.st_mode & S_IRWXO) & X_OK) { + status = B_NOT_ALLOWED; + goto out; + } + + // read and verify the ELF header + + length = _kern_read(fd, 0, buffer, sizeof(buffer)); + if (length < 0) { + status = length; + goto out; + } + + status = elf_verify_header(buffer, length); + if (status == B_NOT_AN_EXECUTABLE) { + // test for shell scripts + if (!strncmp(buffer, "#!", 2)) { + status = B_OK; + if (starter) { + char *end; + buffer[length - 1] = '\0'; + + if ((end = strchr(buffer, '\n')) != NULL) + end[0] = '\0'; + strcpy(starter, buffer + 2); + } + } + } else if (status == B_OK && starter) + starter[0] = '\0'; + +out: + _kern_close(fd); + return status; +} + /** This is the main entry point of the runtime loader as * specified by its ld-script. @@ -20,8 +277,9 @@ int runtime_loader(void *_args) { - struct uspace_program_args *args = (struct uspace_program_args *)_args; - void *entry = 0; + void *entry = NULL; + + gProgramArgs = (struct uspace_program_args *)_args; #if DEBUG_RLD close(0); open("/dev/console", 0); /* stdin */ @@ -30,14 +288,15 @@ runtime_loader(void *_args) #endif rldheap_init(); - rldexport_init(args); - rldelf_init(args); + rldexport_init(); + rldelf_init(); - load_program(args->program_path, &entry); + load_program(gProgramArgs->program_path, &entry); if (entry == NULL) return -1; // call the program entry point (usually _start()) - return ((int (*)(int, void *, void *, void *))entry)(args->argc, args->argv, args->envp, args); + return ((int (*)(int, void *, void *, const void *))entry)(gProgramArgs->argc, + gProgramArgs->argv, gProgramArgs->envp, gProgramArgs); } diff --git a/src/system/runtime_loader/rld_priv.h b/src/system/runtime_loader/rld_priv.h index a002a13c65..b3e8c8f504 100644 --- a/src/system/runtime_loader/rld_priv.h +++ b/src/system/runtime_loader/rld_priv.h @@ -13,6 +13,8 @@ int runtime_loader(void *arg); +int open_executable(char *name, image_type type, const char *rpath); +status_t test_executable(const char *path, uid_t user, gid_t group, char *starter); status_t unload_program(image_id imageID); image_id load_program(char const *path, void **entry); @@ -23,12 +25,15 @@ status_t get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, int32 *_n status_t get_symbol(image_id imageID, char const *symbolName, int32 symbolType, void **_location); -void rldelf_init(struct uspace_program_args const *uspa); -void rldexport_init(struct uspace_program_args *uspa); +status_t elf_verify_header(void *header, int32 length); +void rldelf_init(void); +void rldexport_init(void); // RLD heap void rldheap_init(void); void *rldalloc(size_t); void rldfree(void *p); +extern struct uspace_program_args *gProgramArgs; + #endif /* RUN_TIME_LINKER_H */ diff --git a/src/system/runtime_loader/rldaux.c b/src/system/runtime_loader/rldaux.c index 84b628a299..c055b0027a 100644 --- a/src/system/runtime_loader/rldaux.c +++ b/src/system/runtime_loader/rldaux.c @@ -1,13 +1,37 @@ -/* -** Copyright 2001, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ #include #include +#include #include +#include "rld_priv.h" + + +char * +getenv(const char *name) +{ + // ToDo: this should use the real environ pointer once available! + // (or else, any updates to the search paths while the app is running are ignored) + char **environ = gProgramArgs->envp; + int32 length = strlen(name); + int32 i; + + for (i = 0; environ[i] != NULL; i++) { + if (!strncmp(name, environ[i], length) && environ[i][length] == '=') + return environ[i] + length + 1; + } + + return NULL; +} + int printf(const char *fmt, ...) diff --git a/src/system/runtime_loader/rldelf.c b/src/system/runtime_loader/rldelf.c index 8580830c6c..4c207c1f18 100644 --- a/src/system/runtime_loader/rldelf.c +++ b/src/system/runtime_loader/rldelf.c @@ -71,9 +71,7 @@ enum { #define APP_OR_LIBRARY_TYPE (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE)) - -typedef -struct elf_region_t { +typedef struct elf_region_t { area_id id; addr_t start; addr_t size; @@ -85,7 +83,6 @@ struct elf_region_t { uint32 flags; } elf_region_t; - typedef struct image_t { // image identification char path[B_OS_NAME_LENGTH]; @@ -122,13 +119,12 @@ typedef struct image_t { elf_region_t regions[1]; } image_t; - -typedef -struct image_queue_t { +typedef struct image_queue_t { image_t *head; image_t *tail; } image_queue_t; +typedef void (libinit_f)(unsigned, struct uspace_program_args const *); static image_queue_t gLoadedImages = {0, 0}; static image_queue_t gLoadingImages = {0, 0}; @@ -140,8 +136,6 @@ static sem_id rld_sem; static thread_id rld_sem_owner; static int32 rld_sem_count; -static struct uspace_program_args const *gProgramArgs; - #define STRING(image, offset) ((char *)(&(image)->strtab[(offset)])) #define SYMNAME(image, sym) STRING(image, (sym)->st_name) @@ -205,24 +199,6 @@ rld_lock() } -char * -getenv(const char *name) -{ - // ToDo: this should use the real environ pointer once available! - // (or else, any updates to the search paths while the app is running are ignored) - char **environ = gProgramArgs->envp; - int32 length = strlen(name); - int32 i; - - for (i = 0; environ[i] != NULL; i++) { - if (!strncmp(name, environ[i], length) && environ[i][length] == '=') - return environ[i] + length + 1; - } - - return NULL; -} - - static void enqueue_image(image_queue_t *queue, image_t *image) { @@ -928,194 +904,6 @@ relocate_image(image_t *image) } -static const char * -search_path_for_type(image_type type) -{ - const char *path = NULL; - - switch (type) { - case B_APP_IMAGE: - path = getenv("PATH"); - break; - case B_LIBRARY_IMAGE: - path = getenv("LIBRARY_PATH"); - break; - case B_ADD_ON_IMAGE: - path = getenv("ADDON_PATH"); - break; - - default: - return NULL; -#if 0 - case B_APP_IMAGE: - return getenv("PATH"); - case B_LIBRARY_IMAGE: - return getenv("LIBRARY_PATH"); - case B_ADD_ON_IMAGE: - return getenv("ADDON_PATH"); -#endif - } - - // ToDo: for now, if the variable was not set, return default paths - if (path != NULL) - return path; - - switch (type) { - case B_APP_IMAGE: - return "/boot/home/config/bin:" - "/bin:" - "/boot/apps:" - "/boot/preferences:" - "/boot/beos/apps:" - "/boot/beos/preferences:" - "/boot/develop/tools/gnupro/bin"; - - case B_LIBRARY_IMAGE: - return "%A/lib:/boot/home/config/lib:/boot/beos/system/lib"; - - case B_ADD_ON_IMAGE: - return "%A/add-ons" - ":/boot/home/config/add-ons" - ":/boot/beos/system/add-ons"; - - default: - return NULL; - } -} - - -static int -try_open_container(const char *dir, int dirLen, const char *name, char *path, - int pathLen) -{ - int nameLen = strlen(name); - - // construct the path - if (dirLen > 0) { - char *buffer = path; - - if (dirLen >= 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 - // gProgamArgs->program_path here? - char *lastSlash = strrchr(gProgramArgs->program_path, '/'); - int bytesCopied; - - // 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)); - } else - strlcpy(buffer, ".", pathLen); - - bytesCopied = strlen(buffer); - buffer += bytesCopied; - pathLen -= bytesCopied; - dir += 2; - dirLen -= 2; - } - - if (dirLen + 1 + nameLen >= pathLen) - return B_NAME_TOO_LONG; - - memcpy(buffer, dir, dirLen); - buffer[dirLen] = '/'; - strcpy(buffer + dirLen + 1, name); - } else { - if (nameLen >= pathLen) - return B_NAME_TOO_LONG; - - strcpy(path + dirLen + 1, name); - } - - TRACE(("rld.so: try_open_container(): %s\n", path)); - - return _kern_open(-1, path, O_RDONLY, 0); -} - - -static int -search_container_in_path_list(const char *name, const char *pathList, - int pathListLen, char *pathBuffer, int pathBufferLen) -{ - const char *pathListEnd = pathList + pathListLen; - - TRACE(("rld.so: search_container_in_path_list() %s in %.*s\n", name, - pathListLen, pathList)); - - while (pathListLen > 0) { - const char *pathEnd = pathList; - int fd; - - // find the next ':' or run till the end of the string - while (pathEnd < pathListEnd && *pathEnd != ':') - pathEnd++; - - fd = try_open_container(pathList, pathEnd - pathList, name, pathBuffer, - pathBufferLen); - if (fd >= 0) - return fd; - - pathListLen = pathListEnd - pathEnd - 1; - pathList = pathEnd + 1; - } - - return B_ENTRY_NOT_FOUND; -} - - -static int -open_container(char *name, image_type type, const char *rpath) -{ - const char *paths; - char buffer[PATH_MAX]; - int fd = -1; - - if (strchr(name, '/')) { - // the name already contains a path, we don't have to search for it - return _kern_open(-1, name, O_RDONLY, 0); - } - - // first try rpath (DT_RPATH) - if (rpath) { - // It consists of a colon-separated search path list. Optionally it - // follows a second search path list, separated from the first by a - // semicolon. - const char *semicolon = strchr(rpath, ';'); - const char *firstList = (semicolon ? rpath : NULL); - const char *secondList = (semicolon ? semicolon + 1 : rpath); - // If there is no ';', we set only secondList to simplify things. - if (firstList) { - fd = search_container_in_path_list(name, firstList, - semicolon - firstList, buffer, sizeof(buffer)); - } - if (fd < 0) { - fd = search_container_in_path_list(name, secondList, - strlen(secondList), buffer, sizeof(buffer)); - } - } - - // let's evaluate the system path variables to find the container - if (fd < 0) { - paths = search_path_for_type(type); - if (paths) { - fd = search_container_in_path_list(name, paths, strlen(paths), - buffer, sizeof(buffer)); - } - } - - if (fd >= 0) { - // we found it, copy path! - TRACE(("rld.so: open_container(%s): found at %s\n", name, buffer)); - strlcpy(name, buffer, PATH_MAX); - return fd; - } - - return B_ENTRY_NOT_FOUND; -} - - static image_t * load_container(char const *name, image_type type, const char *rpath) { @@ -1146,7 +934,7 @@ load_container(char const *name, image_type type, const char *rpath) strlcpy(path, name, sizeof(path)); // Try to load explicit image path first - fd = open_container(path, type, rpath); + fd = open_executable(path, type, rpath); FATAL((fd < 0), fd, "cannot open file %s\n", path); len = _kern_read(fd, 0, &eheader, sizeof(eheader)); @@ -1546,15 +1334,24 @@ get_symbol(image_id imageID, char const *symbolName, int32 symbolType, void **_l // #pragma mark - -/* - * init routine, just get hold of the user-space program args - */ + +/** Read and verify the ELF header */ + +status_t +elf_verify_header(void *header, int32 length) +{ + int32 programSize, sectionSize; + + if (length < (int32)sizeof(struct Elf32_Ehdr)) + return B_BAD_VALUE; + + return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, §ionSize); +} + void -rldelf_init(struct uspace_program_args const *_args) +rldelf_init(void) { - gProgramArgs = _args; - rld_sem = create_sem(1, "rld_lock"); rld_sem_owner = -1; rld_sem_count = 0; diff --git a/src/system/runtime_loader/rldexport.c b/src/system/runtime_loader/rldexport.c index e015a86e89..cda693607c 100644 --- a/src/system/runtime_loader/rldexport.c +++ b/src/system/runtime_loader/rldexport.c @@ -42,16 +42,24 @@ export_get_nth_image_symbol(image_id id, int32 num, char *nameBuffer, int32 *_na } +static status_t +export_test_executable(const char *path, uid_t user, gid_t group, char *starter) +{ + return test_executable(path, user, group, starter); +} + + void -rldexport_init(struct uspace_program_args *args) +rldexport_init(void) { static struct rld_export exports = { // dynamic loading support API export_load_add_on, export_unload_add_on, export_get_image_symbol, - export_get_nth_image_symbol + export_get_nth_image_symbol, + export_test_executable }; - args->rld_export = &exports; + gProgramArgs->rld_export = &exports; }