Implemented execvp() for real.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24560 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -10,7 +10,7 @@ MergeObject posix_unistd.o :
|
|||||||
conf.c
|
conf.c
|
||||||
directory.c
|
directory.c
|
||||||
dup.c
|
dup.c
|
||||||
exec.c
|
exec.cpp
|
||||||
_exit.c
|
_exit.c
|
||||||
fcntl.c
|
fcntl.c
|
||||||
fork.c
|
fork.c
|
||||||
|
|||||||
@@ -4,15 +4,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <syscalls.h>
|
|
||||||
#include <libroot_private.h>
|
#include <libroot_private.h>
|
||||||
|
#include <syscalls.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
#include <stdio.h>
|
#include <errno.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -47,16 +48,19 @@ copy_arguments(va_list list, const char **args, const char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
static int
|
||||||
|
do_exec(const char *path, char * const args[], char * const environment[],
|
||||||
|
bool useDefaultInterpreter)
|
||||||
int
|
|
||||||
execve(const char *path, char * const args[], char * const environment[])
|
|
||||||
{
|
{
|
||||||
int32 argCount = 0, envCount = 0;
|
int32 argCount = 0, envCount = 0;
|
||||||
char invoker[B_FILE_NAME_LENGTH];
|
char invoker[B_FILE_NAME_LENGTH];
|
||||||
char **newArgs = NULL;
|
char **newArgs = NULL;
|
||||||
|
|
||||||
|
if (path == NULL) {
|
||||||
|
errno = B_BAD_VALUE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// count argument/environment list entries here, we don't want
|
// count argument/environment list entries here, we don't want
|
||||||
// to do this in the kernel
|
// to do this in the kernel
|
||||||
while (args[argCount] != NULL)
|
while (args[argCount] != NULL)
|
||||||
@@ -71,14 +75,18 @@ execve(const char *path, char * const args[], char * const environment[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test validity of executable + support for scripts
|
// 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_OK) {
|
||||||
|
if (status == B_NOT_AN_EXECUTABLE && useDefaultInterpreter) {
|
||||||
|
strcpy(invoker, "/bin/sh");
|
||||||
|
status = B_OK;
|
||||||
|
} else {
|
||||||
errno = status;
|
errno = status;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (invoker[0]) {
|
if (invoker[0] != '\0') {
|
||||||
status = __parse_invoke_line(invoker, &newArgs, &args, &argCount, path);
|
status = __parse_invoke_line(invoker, &newArgs, &args, &argCount, path);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
errno = status;
|
errno = status;
|
||||||
@@ -87,14 +95,9 @@ execve(const char *path, char * const args[], char * const environment[])
|
|||||||
|
|
||||||
path = newArgs[0];
|
path = newArgs[0];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// "argv[0]" and "path" should be identical here, but they don't have
|
errno = _kern_exec(path, argCount, newArgs ? newArgs : args, envCount,
|
||||||
// to. Instead of worrying and needing to copy the array, we just
|
environment);
|
||||||
// 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);
|
|
||||||
// if this call returns, something definitely went wrong
|
// if this call returns, something definitely went wrong
|
||||||
|
|
||||||
free(newArgs);
|
free(newArgs);
|
||||||
@@ -102,18 +105,75 @@ execve(const char *path, char * const args[], char * const environment[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
int
|
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
|
int
|
||||||
execvp(const char *file, char * const *argv)
|
execv(const char *path, char * const *argv)
|
||||||
{
|
{
|
||||||
// ToDo: do the "p" thing
|
return do_exec(path, argv, environ, false);
|
||||||
return execve(file, argv, environ);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
// copy arguments
|
||||||
|
|
||||||
args = alloca((count + 1) * sizeof(char *));
|
args = (const char**)alloca((count + 1) * sizeof(char *));
|
||||||
va_start(list, arg);
|
va_start(list, arg);
|
||||||
copy_arguments(list, args, arg);
|
copy_arguments(list, args, arg);
|
||||||
va_end(list);
|
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
|
// copy arguments
|
||||||
|
|
||||||
args = alloca((count + 1) * sizeof(char *));
|
args = (const char**)alloca((count + 1) * sizeof(char *));
|
||||||
va_start(list, arg);
|
va_start(list, arg);
|
||||||
copy_arguments(list, args, arg);
|
copy_arguments(list, args, arg);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
@@ -181,12 +241,12 @@ execle(const char *path, const char *arg, ... /*, char **env */)
|
|||||||
|
|
||||||
// copy arguments
|
// copy arguments
|
||||||
|
|
||||||
args = alloca((count + 1) * sizeof(char *));
|
args = (const char**)alloca((count + 1) * sizeof(char *));
|
||||||
va_start(list, arg);
|
va_start(list, arg);
|
||||||
copy_arguments(list, args, arg);
|
copy_arguments(list, args, arg);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return execve(path, (char * const *)args, env);
|
return do_exec(path, (char * const *)args, env, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user