diff --git a/libc/execvpe.cpp b/libc/execvpe.cpp index 01c5709a..52ad7e79 100644 --- a/libc/execvpe.cpp +++ b/libc/execvpe.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of the Sortix C Library. @@ -22,31 +22,79 @@ *******************************************************************************/ +#include #include #include #include -#if defined(PLATFORM_X86) - #define CPUTYPE_STR "i486-sortix" -#elif defined(PLATFORM_X64) - #define CPUTYPE_STR "x86_64-sortix" -#else - #error No cputype environmental variable provided here. -#endif +// TODO: Move this to some generic environment interface! +static const char* LookupEnvironment(const char* name, char* const* envp) +{ + size_t equalpos = strcspn(name, "="); + if ( name[equalpos] == '=' ) + return NULL; + size_t namelen = equalpos; + for ( size_t i = 0; envp[i]; i++ ) + { + if ( strncmp(name, envp[i], namelen) ) + continue; + if ( envp[i][namelen] != '=' ) + continue; + return envp[i] + namelen + 1; + } + return NULL; +} -// Note that the only PATH variable in Sortix is the one used here. +// TODO: Provide an interface that allows user-space to find out which command +// would have been executed (according to PATH) had execvpe been called now. +// This is of value to programs such as which(1), instead of repeating much of +// this logic there. extern "C" int execvpe(const char* filename, char* const* argv, char* const* envp) { - if ( strchr(filename, '/') ) + const char* path = LookupEnvironment("PATH", envp); + // TODO: Should there be a default PATH value? + if ( strchr(filename, '/') || !path ) return execve(filename, argv, envp); - size_t filenamelen = strlen(filename); - const char* PATH = "/" CPUTYPE_STR "/bin"; - size_t pathlen = strlen(PATH); - char* pathname = (char*) malloc(filenamelen + 1 + pathlen + 1); - if ( !pathname ) { return -1; } - stpcpy(stpcpy(stpcpy(pathname, PATH), "/"), filename); - int result = execve(pathname, argv, envp); - free(pathname); - return result; + + // Search each directory in the PATH variable for a suitable file. + size_t filename_len = strlen(filename); + while ( *path ) + { + size_t len = strcspn(path, ":"); + if ( !len ) + { + // Sortix doesn't support that the empty string means current + // directory. While it does inductively make sense, the common + // kernel interfaces such as openat doesn't accept it and software + // often just prefix their directories and a colon to PATH without + // regard to whether it's already empty. S + path++; + continue; + } + + // Determine the full path to the file if it is in the directory. + size_t fullpath_len = len + 1 + filename_len + 1; + char* fullpath = (char*) malloc(fullpath_len * sizeof(char)); + if ( !fullpath ) + return -1; + stpcpy(stpcpy(stpncpy(fullpath, path, len), "/"), filename); + if ( (path += len + 1)[0] == ':' ) + path++; + + execve(fullpath, argv, envp); + free(fullpath); + + // TODO: There may be some security concerns here as to whether to + // continue or abort execution. For instance, if a directory in the + // start of the PATH has permissions set up too restrictively, then + // it would never look in the later directories (and you can't execute + // anything without absolute paths). And other situations. + if ( errno == EACCES ) + return -1; + if ( errno == ENOENT ) + continue; + + } + return -1; } diff --git a/utils/init.cpp b/utils/init.cpp index f893d82a..9a1f5556 100644 --- a/utils/init.cpp +++ b/utils/init.cpp @@ -79,6 +79,15 @@ int main(int /*argc*/, char* /*argv*/[]) // we are running. setenv("objtype", getenv("cputype"), 0); + // Set up the PATH variable. + const char* prefix = "/"; + const char* cputype = getenv("cputype"); + const char* suffix = "/bin"; + char* path = new char[strlen(prefix) + strlen(cputype) + strlen(suffix) + 1]; + stpcpy(stpcpy(stpcpy(path, prefix), cputype), suffix); + setenv("PATH", path, 0); + delete[] path; + // Make sure that we have a /tmp directory. mkdir("/tmp", 01777);