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
+266 -66
View File
@@ -33,6 +33,8 @@
#include <resource.h> #include <resource.h>
#include <atomic.h> #include <atomic.h>
#include <kerrors.h> #include <kerrors.h>
#include <syscalls.h>
struct proc_key { struct proc_key {
proc_id id; proc_id id;
@@ -45,7 +47,9 @@ struct thread_key {
struct proc_arg { struct proc_arg {
char *path; char *path;
char **args; char **args;
char **envp;
unsigned int argc; unsigned int argc;
unsigned int envc;
}; };
static struct proc *create_proc_struct(const char *name, bool kernel); 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; else return 1;
} }
// Frees the argument list // Frees an array of strings in kernel space
// Parameters // Parameters
// args argument list. // strings strings array
// args number of arguments // strc number of strings in array
static void kfree_strings_array(char **strings, int strc)
static void free_arg_list(char **args, int argc)
{ {
int cnt = argc; int cnt = strc;
if(args != NULL) { if(strings != NULL) {
for(cnt = 0; cnt < argc; cnt++){ for(cnt = 0; cnt < strc; cnt++){
kfree(args[cnt]); kfree(strings[cnt]);
} }
kfree(strings);
kfree(args);
} }
} }
// Copy argument list from userspace to kernel space // Copy an array of strings from user space to kernel space
// Parameters // Parameters
// args userspace parameters // strings userspace strings array
// argc number of parameters // strc number of strings in array
// kargs usespace parameters // kstrings pointer to the kernel copy
// return < 0 on error and **kargs = NULL // Returns < 0 on error and **kstrings = NULL
static int user_copy_strings_array(char **strings, int strc, char ***kstrings)
static int user_copy_arg_list(char **args, int argc, char ***kargs)
{ {
char **largs; char **lstrings;
int err; int err;
int cnt; int cnt;
char *source; 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; return ERR_VM_BAD_USER_MEMORY;
largs = (char **)kmalloc((argc + 1) * sizeof(char *)); lstrings = (char **)kmalloc((strc + 1) * sizeof(char *));
if(largs == NULL){ if (lstrings == NULL){
return ENOMEM; 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++) { for (cnt = 0; cnt < strc; cnt++) {
err = user_memcpy(&source, &(args[cnt]), sizeof(char *)); err = user_memcpy(&source, &(strings[cnt]), sizeof(char *));
if(err < 0) if(err < 0)
goto error; 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; err = ERR_VM_BAD_USER_MEMORY;
goto error; goto error;
} }
err = user_strncpy(buf,source, SYS_THREAD_ARG_LENGTH_MAX - 1); err = user_strncpy(buf, source, SYS_THREAD_STRING_LENGTH_MAX - 1);
if(err < 0) if (err < 0)
goto error; goto error;
buf[SYS_THREAD_ARG_LENGTH_MAX - 1] = 0; buf[SYS_THREAD_STRING_LENGTH_MAX - 1] = 0;
largs[cnt] = (char *)kstrdup(buf); lstrings[cnt] = (char *)kstrdup(buf);
if(largs[cnt] == NULL){ if (lstrings[cnt] == NULL){
err = ENOMEM; err = ERR_NO_MEMORY;
goto error; goto error;
} }
} }
largs[argc] = NULL; lstrings[strc] = NULL;
*kargs = largs; *kstrings = lstrings;
return B_NO_ERROR; return B_NO_ERROR;
error: error:
free_arg_list(largs,cnt); kfree_strings_array(lstrings, cnt);
dprintf("user_copy_arg_list failed %d \n",err); dprintf("user_copy_strings_array failed %d \n", err);
return err; return err;
} }
@@ -457,7 +458,7 @@ static thread_id _create_thread(const char *name, proc_id pid, addr entry, void
// create user stack // create user stack
// XXX make this better. For now just keep trying to create a stack // XXX make this better. For now just keep trying to create a stack
// until we find a spot. // 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) { while(t->user_stack_base > USER_STACK_REGION) {
sprintf(stack_name, "%s_stack%d", p->name, t->id); sprintf(stack_name, "%s_stack%d", p->name, t->id);
t->user_stack_region_id = vm_create_anonymous_region(p->_aspace_id, stack_name, 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); rc = thread_wait_on_thread(id, &retcode);
rc2 = user_memcpy(uretcode, &retcode, sizeof(retcode)); rc2 = user_memcpy(uretcode, &retcode, sizeof(int));
if(rc2 < 0) if(rc2 < 0)
return rc2; return rc2;
@@ -1340,10 +1341,14 @@ int thread_wait_on_thread(thread_id id, int *retcode)
rc = B_NO_ERROR; rc = B_NO_ERROR;
if (retcode) { if (retcode) {
state = int_disable_interrupts();
GRAB_THREAD_LOCK();
t = thread_get_current_thread(); t = thread_get_current_thread();
dprintf("thread_wait_on_thread: thread %d got return code 0x%x\n", dprintf("thread_wait_on_thread: thread %d got return code 0x%x\n",
t->id, t->sem_deleted_retcode); t->id, t->sem_deleted_retcode);
*retcode = 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) if(rc < 0)
return rc; return rc;
rc2 = user_memcpy(uretcode, &retcode, sizeof(retcode)); rc2 = user_memcpy(uretcode, &retcode, sizeof(int));
if(rc2 < 0) if(rc2 < 0)
return rc2; return rc2;
@@ -1625,6 +1630,7 @@ static struct proc *create_proc_struct(const char *name, bool kernel)
p->main_thread = NULL; p->main_thread = NULL;
p->state = PROC_STATE_BIRTH; p->state = PROC_STATE_BIRTH;
p->pending_signals = SIG_NONE; p->pending_signals = SIG_NONE;
p->user_env_base = NULL;
if(arch_proc_init_proc_struct(p, kernel) < 0) if(arch_proc_init_proc_struct(p, kernel) < 0)
goto error1; goto error1;
@@ -1665,9 +1671,11 @@ static int proc_create_proc2(void *args)
char ustack_name[128]; char ustack_name[128];
int tot_top_size; int tot_top_size;
char **uargs; char **uargs;
char **uenv;
char *udest; char *udest;
struct uspace_prog_args_t *uspa; struct uspace_prog_args_t *uspa;
unsigned int cnt; unsigned int arg_cnt;
unsigned int env_cnt;
t = thread_get_current_thread(); t = thread_get_current_thread();
p = t->proc; p = t->proc;
@@ -1676,8 +1684,8 @@ static int proc_create_proc2(void *args)
// create an initial primary stack region // create an initial primary stack region
tot_top_size = STACK_SIZE + PAGE_ALIGN(get_arguments_data_size(pargs->args,pargs->argc)); 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); t->user_stack_base = ((USER_STACK_REGION - tot_top_size) + USER_STACK_REGION_SIZE);
sprintf(ustack_name, "%s_primary_stack", p->name); 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, 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); 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; 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); uargs = (char **)(uspa + 1);
udest = (char *)(uargs + pargs->argc + 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); // 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++){ for(arg_cnt = 0; arg_cnt < pargs->argc; arg_cnt++) {
uargs[cnt] = udest; uargs[arg_cnt] = udest;
user_strcpy(udest, pargs->args[cnt]); user_strcpy(udest, pargs->args[arg_cnt]);
udest += strlen(pargs->args[cnt]) + 1; 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_name, p->name, sizeof(uspa->prog_name));
user_memcpy(uspa->prog_path, pargs->path, sizeof(uspa->prog_path)); user_memcpy(uspa->prog_path, pargs->path, sizeof(uspa->prog_path));
uspa->argc = cnt; uspa->argc = arg_cnt;
uspa->argv = uargs; uspa->argv = uargs;
uspa->envc = 0; uspa->envc = env_cnt;
uspa->envp = 0; uspa->envp = uenv;
if(pargs->args != NULL) if (pargs->args != NULL)
free_arg_list(pargs->args,pargs->argc); kfree_strings_array(pargs->args, pargs->argc);
if (pargs->envp != NULL)
kfree_strings_array(pargs->envp, pargs->envc);
path = pargs->path; path = pargs->path;
dprintf("proc_create_proc2: loading elf binary '%s'\n", path); dprintf("proc_create_proc2: loading elf binary '%s'\n", path);
@@ -1732,7 +1753,7 @@ static int proc_create_proc2(void *args)
return 0; 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; struct proc *p;
thread_id tid; 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->argc = argc;
pargs->args = args; pargs->args = args;
pargs->envp = envp;
pargs->envc = envc;
// create a new ioctx for this process // create a new ioctx for this process
p->ioctx = vfs_new_io_context(thread_get_current_thread()->proc->ioctx); p->ioctx = vfs_new_io_context(thread_get_current_thread()->proc->ioctx);
@@ -1819,39 +1842,49 @@ err1:
return err; 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 path[SYS_MAX_PATH_LEN];
char name[SYS_MAX_OS_NAME_LEN]; char name[SYS_MAX_OS_NAME_LEN];
char **kargs; char **kargs;
char **kenv;
int rc; int rc;
dprintf("user_proc_create_proc : argc=%d \n",argc); 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; 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; return ERR_VM_BAD_USER_MEMORY;
rc = user_copy_arg_list(args, argc, &kargs); rc = user_copy_strings_array(args, argc, &kargs);
if(rc < 0) 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; goto error;
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
if(rc < 0) if (rc < 0)
goto error; goto error;
path[SYS_MAX_PATH_LEN-1] = 0; path[SYS_MAX_PATH_LEN-1] = 0;
rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1); rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1);
if(rc < 0) if (rc < 0)
goto error; goto error;
name[SYS_MAX_OS_NAME_LEN-1] = 0; 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: error:
free_arg_list(kargs,argc); kfree_strings_array(kargs, argc);
kfree_strings_array(kenv, envc);
return rc; return rc;
} }
@@ -2105,3 +2138,170 @@ int setrlimit(int resource, const struct rlimit * rlp)
return 0; 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;
}
+4
View File
@@ -23,6 +23,8 @@ void _call_ctors(void);
static char empty[1]; static char empty[1];
char *__progname = empty; char *__progname = empty;
char **environ = NULL;
int _start(struct uspace_prog_args_t *uspa) int _start(struct uspace_prog_args_t *uspa)
{ {
int retcode; int retcode;
@@ -38,6 +40,8 @@ int _start(struct uspace_prog_args_t *uspa)
++__progname; ++__progname;
} }
environ = uspa->envp;
retcode = main(uspa->argc, uspa->argv); retcode = main(uspa->argc, uspa->argv);
// __stdio_deinit(); // __stdio_deinit();