adding environmental variables support

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@305 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
lillo 2002-07-18 14:07:56 +00:00
parent 0ba337c0a4
commit 92622c9c58
2 changed files with 270 additions and 66 deletions

View File

@ -33,6 +33,8 @@
#include <resource.h>
#include <atomic.h>
#include <kerrors.h>
#include <syscalls.h>
struct proc_key {
proc_id id;
@ -45,7 +47,9 @@ struct thread_key {
struct proc_arg {
char *path;
char **args;
char **envp;
unsigned int argc;
unsigned int envc;
};
static struct proc *create_proc_struct(const char *name, bool kernel);
@ -211,81 +215,78 @@ static int thread_struct_compare(void *_t, const void *_key)
else return 1;
}
// Frees the argument list
// Frees an array of strings in kernel space
// Parameters
// args argument list.
// args number of arguments
static void free_arg_list(char **args, int argc)
// strings strings array
// strc number of strings in array
static void kfree_strings_array(char **strings, int strc)
{
int cnt = argc;
int cnt = strc;
if(args != NULL) {
for(cnt = 0; cnt < argc; cnt++){
kfree(args[cnt]);
if(strings != NULL) {
for(cnt = 0; cnt < strc; cnt++){
kfree(strings[cnt]);
}
kfree(args);
kfree(strings);
}
}
// Copy argument list from userspace to kernel space
// Copy an array of strings from user space to kernel space
// Parameters
// args userspace parameters
// argc number of parameters
// kargs usespace parameters
// return < 0 on error and **kargs = NULL
static int user_copy_arg_list(char **args, int argc, char ***kargs)
// strings userspace strings array
// strc number of strings in array
// kstrings pointer to the kernel copy
// Returns < 0 on error and **kstrings = NULL
static int user_copy_strings_array(char **strings, int strc, char ***kstrings)
{
char **largs;
char **lstrings;
int err;
int cnt;
char *source;
char buf[SYS_THREAD_ARG_LENGTH_MAX];
char buf[SYS_THREAD_STRING_LENGTH_MAX];
*kargs = NULL;
*kstrings = NULL;
if((addr)args >= KERNEL_BASE && (addr)args <= KERNEL_TOP)
if ((addr)strings >= KERNEL_BASE && (addr)strings <= KERNEL_TOP)
return ERR_VM_BAD_USER_MEMORY;
largs = (char **)kmalloc((argc + 1) * sizeof(char *));
if(largs == NULL){
return ENOMEM;
lstrings = (char **)kmalloc((strc + 1) * sizeof(char *));
if (lstrings == NULL){
return ERR_NO_MEMORY;
}
// scan all parameters and copy to kernel space
// scan all strings and copy to kernel space
for(cnt = 0; cnt < argc; cnt++) {
err = user_memcpy(&source, &(args[cnt]), sizeof(char *));
for (cnt = 0; cnt < strc; cnt++) {
err = user_memcpy(&source, &(strings[cnt]), sizeof(char *));
if(err < 0)
goto error;
if((addr)source >= KERNEL_BASE && (addr)source <= KERNEL_TOP){
if ((addr)source >= KERNEL_BASE && (addr)source <= KERNEL_TOP){
err = ERR_VM_BAD_USER_MEMORY;
goto error;
}
err = user_strncpy(buf,source, SYS_THREAD_ARG_LENGTH_MAX - 1);
if(err < 0)
err = user_strncpy(buf, source, SYS_THREAD_STRING_LENGTH_MAX - 1);
if (err < 0)
goto error;
buf[SYS_THREAD_ARG_LENGTH_MAX - 1] = 0;
buf[SYS_THREAD_STRING_LENGTH_MAX - 1] = 0;
largs[cnt] = (char *)kstrdup(buf);
if(largs[cnt] == NULL){
err = ENOMEM;
lstrings[cnt] = (char *)kstrdup(buf);
if (lstrings[cnt] == NULL){
err = ERR_NO_MEMORY;
goto error;
}
}
largs[argc] = NULL;
lstrings[strc] = NULL;
*kargs = largs;
*kstrings = lstrings;
return B_NO_ERROR;
error:
free_arg_list(largs,cnt);
dprintf("user_copy_arg_list failed %d \n",err);
kfree_strings_array(lstrings, cnt);
dprintf("user_copy_strings_array failed %d \n", err);
return err;
}
@ -457,7 +458,7 @@ static thread_id _create_thread(const char *name, proc_id pid, addr entry, void
// create user stack
// XXX make this better. For now just keep trying to create a stack
// until we find a spot.
t->user_stack_base = (USER_STACK_REGION - STACK_SIZE) + USER_STACK_REGION_SIZE;
t->user_stack_base = (USER_STACK_REGION - STACK_SIZE - ENV_SIZE) + USER_STACK_REGION_SIZE;
while(t->user_stack_base > USER_STACK_REGION) {
sprintf(stack_name, "%s_stack%d", p->name, t->id);
t->user_stack_region_id = vm_create_anonymous_region(p->_aspace_id, stack_name,
@ -1306,7 +1307,7 @@ int user_thread_wait_on_thread(thread_id id, int *uretcode)
rc = thread_wait_on_thread(id, &retcode);
rc2 = user_memcpy(uretcode, &retcode, sizeof(retcode));
rc2 = user_memcpy(uretcode, &retcode, sizeof(int));
if(rc2 < 0)
return rc2;
@ -1340,10 +1341,14 @@ int thread_wait_on_thread(thread_id id, int *retcode)
rc = B_NO_ERROR;
if (retcode) {
state = int_disable_interrupts();
GRAB_THREAD_LOCK();
t = thread_get_current_thread();
dprintf("thread_wait_on_thread: thread %d got return code 0x%x\n",
t->id, t->sem_deleted_retcode);
*retcode = t->sem_deleted_retcode;
RELEASE_THREAD_LOCK();
int_restore_interrupts(state);
}
}
@ -1362,7 +1367,7 @@ int user_proc_wait_on_proc(proc_id id, int *uretcode)
if(rc < 0)
return rc;
rc2 = user_memcpy(uretcode, &retcode, sizeof(retcode));
rc2 = user_memcpy(uretcode, &retcode, sizeof(int));
if(rc2 < 0)
return rc2;
@ -1625,6 +1630,7 @@ static struct proc *create_proc_struct(const char *name, bool kernel)
p->main_thread = NULL;
p->state = PROC_STATE_BIRTH;
p->pending_signals = SIG_NONE;
p->user_env_base = NULL;
if(arch_proc_init_proc_struct(p, kernel) < 0)
goto error1;
@ -1665,9 +1671,11 @@ static int proc_create_proc2(void *args)
char ustack_name[128];
int tot_top_size;
char **uargs;
char **uenv;
char *udest;
struct uspace_prog_args_t *uspa;
unsigned int cnt;
unsigned int arg_cnt;
unsigned int env_cnt;
t = thread_get_current_thread();
p = t->proc;
@ -1676,8 +1684,8 @@ static int proc_create_proc2(void *args)
// create an initial primary stack region
tot_top_size = STACK_SIZE + PAGE_ALIGN(get_arguments_data_size(pargs->args,pargs->argc));
t->user_stack_base = ((USER_STACK_REGION - tot_top_size) + USER_STACK_REGION_SIZE);
tot_top_size = STACK_SIZE + ENV_SIZE + PAGE_ALIGN(get_arguments_data_size(pargs->args, pargs->argc));
t->user_stack_base = ((USER_STACK_REGION - tot_top_size) + USER_STACK_REGION_SIZE);
sprintf(ustack_name, "%s_primary_stack", p->name);
t->user_stack_region_id = vm_create_anonymous_region(p->_aspace_id, ustack_name, (void **)&t->user_stack_base,
REGION_ADDR_EXACT_ADDRESS, tot_top_size, REGION_WIRING_LAZY, LOCK_RW);
@ -1686,27 +1694,40 @@ static int proc_create_proc2(void *args)
return t->user_stack_region_id;
}
uspa = (struct uspace_prog_args_t *)(t->user_stack_base + STACK_SIZE);
uspa = (struct uspace_prog_args_t *)(t->user_stack_base + STACK_SIZE + ENV_SIZE);
uargs = (char **)(uspa + 1);
udest = (char *)(uargs + pargs->argc + 1);
// dprintf("addr: stack base=0x%x uargs = 0x%x udest=0x%x tot_top_size=%d \n\n",t->user_stack_base,uargs,udest,tot_top_size);
for(cnt = 0;cnt < pargs->argc;cnt++){
uargs[cnt] = udest;
user_strcpy(udest, pargs->args[cnt]);
udest += strlen(pargs->args[cnt]) + 1;
for(arg_cnt = 0; arg_cnt < pargs->argc; arg_cnt++) {
uargs[arg_cnt] = udest;
user_strcpy(udest, pargs->args[arg_cnt]);
udest += (strlen(pargs->args[arg_cnt]) + 1);
}
uargs[cnt] = NULL;
uargs[arg_cnt] = NULL;
p->user_env_base = t->user_stack_base + STACK_SIZE;
uenv = (char **)p->user_env_base;
udest = (char *)p->user_env_base + ENV_SIZE - 1;
// dprintf("proc_create_proc2: envc: %d, envp: 0x%p\n", pargs->envc, (void *)pargs->envp);
for (env_cnt=0; env_cnt<pargs->envc; env_cnt++) {
udest -= (strlen(pargs->envp[env_cnt]) + 1);
uenv[env_cnt] = udest;
user_strcpy(udest, pargs->envp[env_cnt]);
}
uenv[env_cnt] = NULL;
user_memcpy(uspa->prog_name, p->name, sizeof(uspa->prog_name));
user_memcpy(uspa->prog_path, pargs->path, sizeof(uspa->prog_path));
uspa->argc = cnt;
uspa->argc = arg_cnt;
uspa->argv = uargs;
uspa->envc = 0;
uspa->envp = 0;
uspa->envc = env_cnt;
uspa->envp = uenv;
if(pargs->args != NULL)
free_arg_list(pargs->args,pargs->argc);
if (pargs->args != NULL)
kfree_strings_array(pargs->args, pargs->argc);
if (pargs->envp != NULL)
kfree_strings_array(pargs->envp, pargs->envc);
path = pargs->path;
dprintf("proc_create_proc2: loading elf binary '%s'\n", path);
@ -1732,7 +1753,7 @@ static int proc_create_proc2(void *args)
return 0;
}
proc_id proc_create_proc(const char *path, const char *name, char **args, int argc, int priority)
proc_id proc_create_proc(const char *path, const char *name, char **args, int argc, char **envp, int envc, int priority)
{
struct proc *p;
thread_id tid;
@ -1769,6 +1790,8 @@ proc_id proc_create_proc(const char *path, const char *name, char **args, int ar
}
pargs->argc = argc;
pargs->args = args;
pargs->envp = envp;
pargs->envc = envc;
// create a new ioctx for this process
p->ioctx = vfs_new_io_context(thread_get_current_thread()->proc->ioctx);
@ -1819,39 +1842,49 @@ err1:
return err;
}
proc_id user_proc_create_proc(const char *upath, const char *uname, char **args, int argc, int priority)
proc_id user_proc_create_proc(const char *upath, const char *uname, char **args, int argc, char **envp, int envc, int priority)
{
char path[SYS_MAX_PATH_LEN];
char name[SYS_MAX_OS_NAME_LEN];
char **kargs;
char **kenv;
int rc;
dprintf("user_proc_create_proc : argc=%d \n",argc);
if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
return ERR_VM_BAD_USER_MEMORY;
if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP)
if ((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP)
return ERR_VM_BAD_USER_MEMORY;
rc = user_copy_arg_list(args, argc, &kargs);
if(rc < 0)
rc = user_copy_strings_array(args, argc, &kargs);
if (rc < 0)
goto error;
if (envp == NULL) {
envp = (char **)thread_get_current_thread()->proc->user_env_base;
for (envc = 0; envp && (envp[envc]); envc++);
}
rc = user_copy_strings_array(envp, envc, &kenv);
if (rc < 0)
goto error;
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
if(rc < 0)
if (rc < 0)
goto error;
path[SYS_MAX_PATH_LEN-1] = 0;
rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1);
if(rc < 0)
if (rc < 0)
goto error;
name[SYS_MAX_OS_NAME_LEN-1] = 0;
return proc_create_proc(path, name, kargs, argc, priority);
return proc_create_proc(path, name, kargs, argc, kenv, envc, priority);
error:
free_arg_list(kargs,argc);
kfree_strings_array(kargs, argc);
kfree_strings_array(kenv, envc);
return rc;
}
@ -2105,3 +2138,170 @@ int setrlimit(int resource, const struct rlimit * rlp)
return 0;
}
int user_setenv(const char *uname, const char *uvalue, int overwrite)
{
char name[SYS_THREAD_STRING_LENGTH_MAX];
char value[SYS_THREAD_STRING_LENGTH_MAX];
int rc;
if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP)
return ERR_VM_BAD_USER_MEMORY;
if((addr)uvalue >= KERNEL_BASE && (addr)uvalue <= KERNEL_TOP)
return ERR_VM_BAD_USER_MEMORY;
rc = user_strncpy(name, uname, SYS_THREAD_STRING_LENGTH_MAX-1);
if(rc < 0)
return rc;
name[SYS_THREAD_STRING_LENGTH_MAX-1] = 0;
rc = user_strncpy(value, uvalue, SYS_THREAD_STRING_LENGTH_MAX-1);
if(rc < 0)
return rc;
value[SYS_THREAD_STRING_LENGTH_MAX-1] = 0;
return sys_setenv(name, value, overwrite);
}
int sys_setenv(const char *name, const char *value, int overwrite)
{
char var[SYS_THREAD_STRING_LENGTH_MAX];
int state;
addr env_space;
char **envp;
int envc;
bool var_exists = false;
int var_pos = 0;
int name_size;
int rc = 0;
int i;
char *p;
dprintf("sys_setenv: entry (name=%s, value=%s)\n", name, value);
if (strlen(name) + strlen(value) + 1 >= SYS_THREAD_STRING_LENGTH_MAX)
return -1;
state = int_disable_interrupts();
GRAB_PROC_LOCK();
strcpy(var, name);
strncat(var, "=", SYS_THREAD_STRING_LENGTH_MAX-1);
name_size = strlen(var);
strncat(var, value, SYS_THREAD_STRING_LENGTH_MAX-1);
env_space = (addr)thread_get_current_thread()->proc->user_env_base;
envp = (char **)env_space;
for (envc=0; envp[envc]; envc++) {
if (!strncmp(envp[envc], var, name_size)) {
var_exists = true;
var_pos = envc;
}
}
if (!var_exists)
var_pos = envc;
dprintf("sys_setenv: variable does%s exist\n", var_exists ? "" : " not");
if ((!var_exists) || (var_exists && overwrite)) {
// XXX- make a better allocator
if (var_exists) {
if (strlen(var) <= strlen(envp[var_pos])) {
strcpy(envp[var_pos], var);
}
else {
for (p=(char *)env_space + ENV_SIZE - 1, i=0; envp[i]; i++)
if (envp[i] < p)
p = envp[i];
p -= (strlen(var) + 1);
if (p < (char *)env_space + (envc * sizeof(char *))) {
rc = -1;
}
else {
envp[var_pos] = p;
strcpy(envp[var_pos], var);
}
}
}
else {
for (p=(char *)env_space + ENV_SIZE - 1, i=0; envp[i]; i++)
if (envp[i] < p)
p = envp[i];
p -= (strlen(var) + 1);
if (p < (char *)env_space + ((envc + 1) * sizeof(char *))) {
rc = -1;
}
else {
envp[envc] = p;
strcpy(envp[envc], var);
envp[envc + 1] = NULL;
}
}
}
dprintf("sys_setenv: variable set.\n");
RELEASE_PROC_LOCK();
int_restore_interrupts(state);
return rc;
}
int user_getenv(const char *uname, char **uvalue)
{
char name[SYS_THREAD_STRING_LENGTH_MAX];
char *value;
int rc;
if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP)
return ERR_VM_BAD_USER_MEMORY;
if((addr)uvalue >= KERNEL_BASE && (addr)uvalue <= KERNEL_TOP)
return ERR_VM_BAD_USER_MEMORY;
rc = user_strncpy(name, uname, SYS_THREAD_STRING_LENGTH_MAX-1);
if (rc < 0)
return rc;
name[SYS_THREAD_STRING_LENGTH_MAX-1] = 0;
rc = sys_getenv(name, &value);
if (rc < 0)
return rc;
rc = user_memcpy(uvalue, &value, sizeof(char *));
if (rc < 0)
return rc;
return 0;
}
int sys_getenv(const char *name, char **value)
{
char **envp;
char *p;
int state;
int i;
int len = strlen(name);
int rc = -1;
state = int_disable_interrupts();
GRAB_PROC_LOCK();
envp = (char **)thread_get_current_thread()->proc->user_env_base;
for (i=0; envp[i]; i++) {
if (!strncmp(envp[i], name, len)) {
p = envp[i] + len;
if (*p == '=') {
*value = (p + 1);
rc = 0;
break;
}
}
}
RELEASE_PROC_LOCK();
int_restore_interrupts(state);
return rc;
}

View File

@ -23,6 +23,8 @@ void _call_ctors(void);
static char empty[1];
char *__progname = empty;
char **environ = NULL;
int _start(struct uspace_prog_args_t *uspa)
{
int retcode;
@ -38,6 +40,8 @@ int _start(struct uspace_prog_args_t *uspa)
++__progname;
}
environ = uspa->envp;
retcode = main(uspa->argc, uspa->argv);
// __stdio_deinit();