The "shebang" handler is supposed to parse arguments, too - we now do that.

Also, when the line is too long, E2BIG is returned.
Thanks to Korli who pointed me to this: http://homepages.cwi.nl/~aeb/std/shebang/


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13114 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-06-14 12:39:06 +00:00
parent be22452f3b
commit 43ed6aa0db
4 changed files with 111 additions and 52 deletions

View File

@ -12,7 +12,9 @@
struct uspace_program_args;
struct real_time_data;
status_t __test_executable(const char *path, char *starter);
status_t __parse_invoke_line(char *invoker, char ***_newArgs,
char * const **_oldArgs, int32 *_argCount);
status_t __test_executable(const char *path, char *invoker);
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);

View File

@ -20,8 +20,8 @@ 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;
char invoker[B_FILE_NAME_LENGTH];
char **newArgs = NULL;
int32 envCount = 0;
thread_id thread;
@ -30,26 +30,15 @@ load_image(int32 argCount, const char **args, const char **environ)
// test validity of executable + support for scripts
{
status_t status = __test_executable(args[0], starter);
status_t status = __test_executable(args[0], invoker);
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++;
if (invoker[0]) {
status = __parse_invoke_line(invoker, &newArgs,
(char * const **)&args, &argCount);
if (status < B_OK)
return status;
}
}
@ -118,10 +107,84 @@ clear_caches(void *address, size_t length, uint32 flags)
// #pragma mark -
status_t
__test_executable(const char *path, char *starter)
static char *
next_argument(char **_start, bool separate)
{
return sRuntimeLinker->test_executable(path, geteuid(), getegid(), starter);
char *line = *_start;
char quote = 0;
int32 i;
// eliminate leading spaces
while (line[0] == ' ')
line++;
if (line[0] == '"' || line[0] == '\'') {
quote = line[0];
line++;
}
if (!line[0])
return NULL;
for (i = 0;; i++) {
if (line[i] == '\\' && line[i + 1] != '\0')
continue;
if ((!quote && line[i] == ' ') || line[i] == quote || line[i] == '\0') {
// argument separator!
if (separate)
line[i] = '\0';
*_start = &line[i + 1];
return line;
}
}
return NULL;
}
status_t
__parse_invoke_line(char *invoker, char ***_newArgs,
char * const **_oldArgs, int32 *_argCount)
{
int32 i, count = 0;
char *arg = invoker;
char **newArgs;
// count arguments in the line
while (next_argument(&arg, false)) {
count++;
}
// this is a shell script and requires special treatment
newArgs = malloc((*_argCount + count + 1) * sizeof(void *));
if (newArgs == NULL)
return B_NO_MEMORY;
// copy invoker and old arguments and to newArgs
for (i = 0; (arg = next_argument(&invoker, true)) != NULL; i++) {
newArgs[i] = arg;
}
for (i = 0; i < *_argCount; i++) {
newArgs[i + count] = (char *)(*_oldArgs)[i];
}
newArgs[i + count] = NULL;
*_newArgs = newArgs;
*_oldArgs = (char * const *)newArgs;
*_argCount += count;
return B_OK;
}
status_t
__test_executable(const char *path, char *invoker)
{
return sRuntimeLinker->test_executable(path, geteuid(), getegid(), invoker);
}

View File

@ -54,7 +54,7 @@ int
execve(const char *path, char * const args[], char * const environment[])
{
int32 argCount = 0, envCount = 0;
char starter[B_FILE_NAME_LENGTH];
char invoker[B_FILE_NAME_LENGTH];
char **newArgs = NULL;
// count argument/environment list entries here, we don't want
@ -72,31 +72,20 @@ execve(const char *path, char * const args[], char * const environment[])
// test validity of executable + support for scripts
{
status_t status = __test_executable(args[0], starter);
status_t status = __test_executable(args[0], invoker);
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;
if (invoker[0]) {
status = __parse_invoke_line(invoker, &newArgs, &args, &argCount);
if (status < B_OK) {
errno = status;
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++;
path = newArgs[0];
}
}

View File

@ -206,7 +206,7 @@ open_executable(char *name, image_type type, const char *rpath)
*/
status_t
test_executable(const char *name, uid_t user, gid_t group, char *starter)
test_executable(const char *name, uid_t user, gid_t group, char *invoker)
{
char path[B_PATH_NAME_LENGTH];
char buffer[B_FILE_NAME_LENGTH];
@ -251,18 +251,23 @@ test_executable(const char *name, uid_t user, gid_t group, char *starter)
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';
char *end;
buffer[length - 1] = '\0';
if ((end = strchr(buffer, '\n')) != NULL)
end[0] = '\0';
strcpy(starter, buffer + 2);
}
end = strchr(buffer, '\n');
if (end == NULL) {
status = E2BIG;
goto out;
} else
end[0] = '\0';
if (invoker)
strcpy(invoker, buffer + 2);
status = B_OK;
}
} else if (status == B_OK && starter)
starter[0] = '\0';
} else if (status == B_OK && invoker)
invoker[0] = '\0';
out:
_kern_close(fd);