From 83c2cae69d8032deea6430dd689123509ba1d615 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 24 Mar 2008 20:32:20 +0000 Subject: [PATCH] Implemented execvp() for real. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24560 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/libroot/posix/unistd/Jamfile | 2 +- .../libroot/posix/unistd/{exec.c => exec.cpp} | 132 +++++++++++++----- 2 files changed, 97 insertions(+), 37 deletions(-) rename src/system/libroot/posix/unistd/{exec.c => exec.cpp} (53%) diff --git a/src/system/libroot/posix/unistd/Jamfile b/src/system/libroot/posix/unistd/Jamfile index a208288feb..a65e690162 100644 --- a/src/system/libroot/posix/unistd/Jamfile +++ b/src/system/libroot/posix/unistd/Jamfile @@ -10,7 +10,7 @@ MergeObject posix_unistd.o : conf.c directory.c dup.c - exec.c + exec.cpp _exit.c fcntl.c fork.c diff --git a/src/system/libroot/posix/unistd/exec.c b/src/system/libroot/posix/unistd/exec.cpp similarity index 53% rename from src/system/libroot/posix/unistd/exec.c rename to src/system/libroot/posix/unistd/exec.cpp index e58dc8fe44..c0bfaa8481 100644 --- a/src/system/libroot/posix/unistd/exec.c +++ b/src/system/libroot/posix/unistd/exec.cpp @@ -4,15 +4,16 @@ */ -#include #include +#include -#include -#include #include -#include +#include #include +#include #include +#include +#include static int @@ -47,16 +48,19 @@ copy_arguments(va_list list, const char **args, const char *arg) } -// #pragma mark - - - -int -execve(const char *path, char * const args[], char * const environment[]) +static int +do_exec(const char *path, char * const args[], char * const environment[], + bool useDefaultInterpreter) { int32 argCount = 0, envCount = 0; char invoker[B_FILE_NAME_LENGTH]; char **newArgs = NULL; + if (path == NULL) { + errno = B_BAD_VALUE; + return -1; + } + // count argument/environment list entries here, we don't want // to do this in the kernel while (args[argCount] != NULL) @@ -71,30 +75,29 @@ execve(const char *path, char * const args[], char * const environment[]) } // test validity of executable + support for scripts - { - status_t status = __test_executable(path, invoker); + status_t status = __test_executable(path, invoker); + if (status < B_OK) { + if (status == B_NOT_AN_EXECUTABLE && useDefaultInterpreter) { + strcpy(invoker, "/bin/sh"); + status = B_OK; + } else { + errno = status; + return -1; + } + } + + if (invoker[0] != '\0') { + status = __parse_invoke_line(invoker, &newArgs, &args, &argCount, path); if (status < B_OK) { errno = status; return -1; } - if (invoker[0]) { - status = __parse_invoke_line(invoker, &newArgs, &args, &argCount, path); - if (status < B_OK) { - errno = status; - return -1; - } - - path = newArgs[0]; - } + path = newArgs[0]; } - // "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, argCount, newArgs ? newArgs : args, envCount, environment); + errno = _kern_exec(path, argCount, newArgs ? newArgs : args, envCount, + environment); // if this call returns, something definitely went wrong free(newArgs); @@ -102,18 +105,75 @@ execve(const char *path, char * const args[], char * const environment[]) } +// #pragma mark - + + int -execv(const char *path, char * const *argv) +execve(const char *path, char* const args[], char* const environment[]) { - return execve(path, argv, environ); + return do_exec(path, args, environment, false); } int -execvp(const char *file, char * const *argv) +execv(const char *path, char * const *argv) { - // ToDo: do the "p" thing - return execve(file, argv, environ); + return do_exec(path, argv, environ, false); +} + + +int +execvp(const char *file, char* const* argv) +{ + // let do_exec() handle cases where file is a path (or invalid) + if (file == NULL || strchr(file, '/') != NULL) + return do_exec(file, argv, environ, true); + + // file is just a leaf name, so we have to look it up in the path + + // get the PATH + const char* paths = getenv("PATH"); + if (paths == NULL) { + errno = B_ENTRY_NOT_FOUND; + return -1; + } + + int fileNameLen = strlen(file); + + // iterate through the paths + while (true) { + const char* pathEnd = strchr(paths, ':'); + int pathLen = (pathEnd ? pathEnd - paths : strlen(paths)); + + // We skip empty paths and those that would become too long. + // The latter is not really correct, but practically irrelevant. + if (pathLen == 0 + || pathLen + 1 + fileNameLen >= B_PATH_NAME_LENGTH) { + continue; + } + + // concatinate the program path + char path[B_PATH_NAME_LENGTH]; + memcpy(path, paths, pathLen); + path[pathLen] = '\0'; + + if (path[pathLen - 1] != '/') + strcat(path, "/"); + strcat(path, file); + + // if executable, execute it + if (access(path, X_OK) == 0) + return do_exec(path, argv, environ, true); + + // not found yet -- get the next path, if any + if (pathEnd == NULL) + break; + + paths = pathEnd + 1; + } + + errno = B_ENTRY_NOT_FOUND; + return -1; } @@ -132,12 +192,12 @@ execl(const char *path, const char *arg, ...) // copy arguments - args = alloca((count + 1) * sizeof(char *)); + args = (const char**)alloca((count + 1) * sizeof(char *)); va_start(list, arg); copy_arguments(list, args, arg); va_end(list); - return execve(path, (char * const *)args, environ); + return do_exec(path, (char * const *)args, environ, false); } @@ -156,7 +216,7 @@ execlp(const char *file, const char *arg, ...) // copy arguments - args = alloca((count + 1) * sizeof(char *)); + args = (const char**)alloca((count + 1) * sizeof(char *)); va_start(list, arg); copy_arguments(list, args, arg); va_end(list); @@ -181,12 +241,12 @@ execle(const char *path, const char *arg, ... /*, char **env */) // copy arguments - args = alloca((count + 1) * sizeof(char *)); + args = (const char**)alloca((count + 1) * sizeof(char *)); va_start(list, arg); copy_arguments(list, args, arg); va_end(list); - return execve(path, (char * const *)args, env); + return do_exec(path, (char * const *)args, env, false); }