Switched from the old team_create_team() to a load_image() compatible mechanism.

The path name is now always taken from the provided argument list (except for
_user_exec() which now replaces args[0] with the path argument).
The team_arg structure know nows if it must delete its arguments or not - this
also fixes a memory leak in case team_create_team() failed when invoked from
userland.
load_image() is now also exported for the kernel.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9360 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-10-14 18:07:04 +00:00
parent 4496669366
commit bd4b903e57
+81 -78
View File
@@ -40,11 +40,11 @@ struct team_key {
};
struct team_arg {
char *path;
uint32 arg_count;
char **args;
uint32 env_count;
char **env;
bool owns_arrays;
};
struct fork_arg {
@@ -717,11 +717,11 @@ team_delete_team(struct team *team)
}
static int
get_arguments_data_size(char **args, int argc)
static uint32
get_arguments_data_size(char **args, int32 argc)
{
uint32 size = 0;
int count;
int32 count;
for (count = 0; count < argc; count++)
size += strlen(args[count]) + 1;
@@ -733,28 +733,27 @@ get_arguments_data_size(char **args, int argc)
static void
free_team_arg(struct team_arg *teamArg)
{
free(teamArg->path);
if (teamArg->owns_arrays) {
free_strings_array(teamArg->args, teamArg->arg_count);
free_strings_array(teamArg->env, teamArg->env_count);
}
free(teamArg);
}
static struct team_arg *
create_team_arg(const char *path, int32 argc, char **args, int32 envCount, char **env)
create_team_arg(int32 argc, char **args, int32 envCount, char **env, bool deleteArrays)
{
struct team_arg *teamArg = (struct team_arg *)malloc(sizeof(struct team_arg));
if (teamArg == NULL)
return NULL;
teamArg->path = strdup(path);
if (teamArg->path == NULL) {
free(teamArg);
return NULL;
}
teamArg->arg_count = argc;
teamArg->args = args;
teamArg->env_count = envCount;
teamArg->env = env;
teamArg->owns_arrays = deleteArrays;
return teamArg;
}
@@ -767,7 +766,7 @@ team_create_thread_start(void *args)
struct thread *t;
struct team *team;
struct team_arg *teamArgs = args;
char *path;
const char *path;
addr entry;
char ustack_name[128];
uint32 sizeLeft;
@@ -780,7 +779,7 @@ team_create_thread_start(void *args)
t = thread_get_current_thread();
team = t->team;
TRACE(("team_create_team2: entry thread %ld\n", t->id));
TRACE(("team_create_thread_start: entry thread %ld\n", t->id));
// create an initial primary stack region
@@ -797,7 +796,7 @@ team_create_thread_start(void *args)
t->user_stack_region_id = create_area_etc(team, ustack_name, (void **)&t->user_stack_base,
B_EXACT_ADDRESS, sizeLeft, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (t->user_stack_region_id < 0) {
dprintf("team_create_team2: could not create default user stack region\n");
dprintf("team_create_thread_start: could not create default user stack region\n");
return t->user_stack_region_id;
}
@@ -826,8 +825,9 @@ team_create_thread_start(void *args)
team->user_env_base = t->user_stack_base + t->user_stack_size + TLS_SIZE;
uenv = (char **)team->user_env_base;
udest = (char *)team->user_env_base + ENV_SIZE - 1;
path = teamArgs->args[0];
TRACE(("team_create_team2: envc: %d, envp: 0x%p\n", teamArgs->env_count, (void *)teamArgs->env));
TRACE(("team_create_thread_start: envc: %d, envp: 0x%p\n", teamArgs->env_count, (void *)teamArgs->env));
for (i = 0; i < envCount; i++) {
ssize_t length = user_strlcpy(udest, teamArgs->env[i], sizeLeft) + 1;
@@ -838,32 +838,25 @@ team_create_thread_start(void *args)
}
uenv[envCount] = NULL;
user_memcpy(uspa->program_name, team->name, sizeof(uspa->program_name));
user_memcpy(uspa->program_path, teamArgs->path, sizeof(uspa->program_path));
user_memcpy(uspa->program_path, path, sizeof(uspa->program_path));
uspa->argc = argCount;
uspa->argv = uargs;
uspa->envc = envCount;
uspa->envp = uenv;
free_strings_array(teamArgs->args, teamArgs->arg_count);
free_strings_array(teamArgs->env, teamArgs->env_count);
TRACE(("team_create_thread_start: loading elf binary '%s'\n", path));
path = teamArgs->path;
TRACE(("team_create_team2: loading elf binary '%s'\n", path));
free_team_arg(teamArgs);
// ToDo: don't use fixed paths!
err = elf_load_user_image("/boot/beos/system/lib/rld.so", team, 0, &entry);
// free the args
free_team_arg(teamArgs);
if (err < 0) {
// Luckily, we don't have to clean up the mess we created - that's
// done for us by the normal team deletion process
return err;
}
TRACE(("team_create_team2: loaded elf. entry = 0x%lx\n", entry));
TRACE(("team_create_thread_start: loaded elf. entry = 0x%lx\n", entry));
team->state = TEAM_STATE_NORMAL;
@@ -875,26 +868,32 @@ team_create_thread_start(void *args)
}
team_id
team_create_team(const char *path, const char *name, char **args, int argc, char **env, int envCount, int priority)
/** The BeOS kernel exports a function with this name, but most probably with
* different parameters; we should not make it public.
*/
static thread_id
load_image_etc(int32 argCount, const char **args, int32 envCount, const char **env,
bool deleteStrings, int32 priority)
{
struct process_group *group;
struct team *team, *parent;
const char *threadName;
thread_id tid;
team_id pid;
thread_id thread;
int err;
cpu_status state;
struct team_arg *teamArgs;
TRACE(("team_create_team: entry '%s', name '%s' args = %p argc = %d\n",
path, name, args, argc));
if (args == NULL || argCount == 0)
return B_BAD_VALUE;
team = create_team_struct(name, false);
TRACE(("load_image_etc: name '%s', args = %p, argCount = %ld\n",
args[0], args, argCount));
team = create_team_struct(args[0], false);
if (team == NULL)
return B_NO_MEMORY;
pid = team->id;
parent = thread_get_current_thread()->team;
state = disable_interrupts();
@@ -908,7 +907,7 @@ team_create_team(const char *path, const char *name, char **args, int argc, char
restore_interrupts(state);
// copy the args over
teamArgs = create_team_arg(path, argc, args, envCount, env);
teamArgs = create_team_arg(argCount, (char **)args, envCount, (char **)env, deleteStrings);
if (teamArgs == NULL) {
err = B_NO_MEMORY;
goto err1;
@@ -927,22 +926,20 @@ team_create_team(const char *path, const char *name, char **args, int argc, char
goto err3;
// cut the path from the main thread name
threadName = strrchr(name, '/');
threadName = strrchr(args[0], '/');
if (threadName != NULL)
threadName++;
else
threadName = name;
threadName = args[0];
// create a kernel thread, but under the context of the new team
tid = spawn_kernel_thread_etc(team_create_thread_start, threadName, B_NORMAL_PRIORITY, teamArgs, team->id);
if (tid < 0) {
err = tid;
thread = spawn_kernel_thread_etc(team_create_thread_start, threadName, B_NORMAL_PRIORITY, teamArgs, team->id);
if (thread < 0) {
err = thread;
goto err4;
}
resume_thread(tid);
return pid;
return thread;
err4:
vm_put_aspace(team->aspace);
@@ -969,14 +966,19 @@ err1:
}
/** Almost shuts down the current team and loads a new image into it.
* If successful, this function does not return and will takeover ownership of
* the arguments provided.
*/
static status_t
exec_team(const char *path, int32 argCount, char **args, int32 envCount, char **env)
exec_team(int32 argCount, char **args, int32 envCount, char **env)
{
struct team *team = thread_get_current_thread()->team;
struct team_arg *teamArgs;
status_t status;
TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld)\n", path, argCount, envCount));
TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld)\n", args[0], argCount, envCount));
// switching the kernel at run time is probably not a good idea :)
if (team == team_get_kernel_team())
@@ -992,7 +994,7 @@ exec_team(const char *path, int32 argCount, char **args, int32 envCount, char **
// ToDo: maybe we should make sure upfront that the target path is an app?
teamArgs = create_team_arg(path, argCount, args, envCount, env);
teamArgs = create_team_arg(argCount, args, envCount, env, true);
if (teamArgs == NULL)
return B_NO_MEMORY;
@@ -1367,6 +1369,18 @@ wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnC
// public team API
thread_id
load_image(int32 argCount, const char **args, const char **env)
{
// count env variables
int32 envCount = 0;
while (env && env[envCount] != NULL)
envCount++;
return load_image_etc(argCount, args, envCount, env, false, B_NORMAL_PRIORITY);
}
status_t
wait_for_team(team_id id, status_t *_returnCode)
{
@@ -1723,6 +1737,9 @@ _user_exec(const char *userPath, int32 argCount, char * const *userArgs,
char **args;
char **env;
if (argCount < 1)
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userArgs) || !IS_USER_ADDRESS(userEnvironment)
|| user_strlcpy(path, userPath, sizeof(path)) < B_OK)
return B_BAD_ADDRESS;
@@ -1737,12 +1754,15 @@ _user_exec(const char *userPath, int32 argCount, char * const *userArgs,
return status;
}
status = exec_team(path, argCount, args, envCount, env);
// replace args[0] with the path argument, just to be on the safe side
free(args[0]);
args[0] = strdup(path);
status = exec_team(argCount, args, envCount, env);
// this one only returns in case of error
free_strings_array(args, argCount);
free_strings_array(env, envCount);
return status;
}
@@ -1974,44 +1994,27 @@ _user_wait_for_team(team_id id, status_t *_userReturnCode)
team_id
_user_create_team(const char *userPath, const char *userName, char **userArgs,
int argCount, char **userEnv, int envCount, int priority)
_user_load_image(int32 argCount, const char **userArgs, int32 envCount,
const char **userEnv, int32 priority)
{
char path[SYS_MAX_PATH_LEN];
char name[B_OS_NAME_LENGTH];
char **args = NULL;
char **env = NULL;
int rc;
TRACE(("user_team_create_team: argc = %d\n", argCount));
TRACE(("_user_load_image_etc: argc = %d\n", argCount));
if (!IS_USER_ADDRESS(userPath)
|| !IS_USER_ADDRESS(userName))
if (argCount < 1 || userArgs == NULL || userEnv == NULL)
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(userArgs) || !IS_USER_ADDRESS(userEnv)
|| user_copy_strings_array((char * const *)userArgs, argCount, &args) < B_OK)
return B_BAD_ADDRESS;
rc = user_copy_strings_array(userArgs, argCount, &args);
if (rc < 0)
goto error;
if (userEnv == NULL) {
// ToDo: this doesn't look particularly safe to me - where
// is user_env_base?
userEnv = (char **)thread_get_current_thread()->team->user_env_base;
for (envCount = 0; userEnv && (userEnv[envCount]); envCount++);
}
if (user_copy_strings_array(userEnv, envCount, &env) < B_OK
|| user_strlcpy(path, userPath, SYS_MAX_PATH_LEN) < B_OK
|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) {
rc = B_BAD_ADDRESS;
goto error;
if (user_copy_strings_array((char * const *)userEnv, envCount, &env) < B_OK) {
free_strings_array(args, argCount);
return B_BAD_ADDRESS;
}
return team_create_team(path, name, args, argCount, env, envCount, priority);
error:
free_strings_array(args, argCount);
free_strings_array(env, envCount);
return rc;
return load_image_etc(argCount, (const char **)args, envCount, (const char **)env, true, priority);
}