Add PATH variable.

This commit is contained in:
Jonas 'Sortie' Termansen 2013-01-05 15:08:44 +01:00
parent f29abd73ec
commit 15c48f4efc
2 changed files with 76 additions and 19 deletions

View File

@ -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 <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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;
}

View File

@ -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);