Rough support for environment variables
- libc functions not implemented yet - see `env` for an example of reading variables - see `esh` for an example of how to set and maintain variables for sending to other applications Both of the above will be the basis for the libc implementation.
This commit is contained in:
parent
272a2a3809
commit
deaa6ad513
@ -123,6 +123,11 @@ typedef struct {
|
||||
Elf32_Word sh_entsize;
|
||||
} Elf32_Shdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
uintptr_t ptr;
|
||||
} Elf32_auxv;
|
||||
|
||||
/* sh_type values */
|
||||
#define SHT_NONE 0
|
||||
#define SHT_PROGBITS 1
|
||||
|
@ -323,7 +323,7 @@ void set_fpu_cw(const uint16_t);
|
||||
void enable_fpu();
|
||||
|
||||
/* ELF */
|
||||
int exec( char *, int, char **);
|
||||
int exec( char *, int, char **, char **);
|
||||
int system( char *, int, char **);
|
||||
|
||||
/* Sytem Calls */
|
||||
|
@ -35,7 +35,8 @@ int
|
||||
exec(
|
||||
char * path, /* Path to the executable to run */
|
||||
int argc, /* Argument count (ie, /bin/echo hello world = 3) */
|
||||
char ** argv /* Argument strings (including executable path) */
|
||||
char ** argv, /* Argument strings (including executable path) */
|
||||
char ** env /* Environmen variables */
|
||||
) {
|
||||
|
||||
/* Open the file */
|
||||
@ -110,10 +111,27 @@ exec(
|
||||
alloc_frame(get_page(stack_pointer, 1, current_directory), 0, 1);
|
||||
}
|
||||
|
||||
/* Collect arguments */
|
||||
int envc = 0;
|
||||
for (envc = 0; env[envc] != NULL; ++envc);
|
||||
|
||||
/* Format auxv */
|
||||
Elf32_auxv auxv[] = {
|
||||
{256, 0xDEADBEEF},
|
||||
{0, 0}
|
||||
};
|
||||
int auxvc = 0;
|
||||
for (auxvc = 0; auxv[auxvc].id != 0; ++auxvc);
|
||||
|
||||
uintptr_t heap = current_process->image.entry + current_process->image.size;
|
||||
alloc_frame(get_page(heap, 1, current_directory), 0, 1);
|
||||
char ** argv_ = (char **)heap;
|
||||
heap += sizeof(char *) * (argc + 1);
|
||||
char ** env_ = (char **)heap;
|
||||
heap += sizeof(char *) * (envc + 1);
|
||||
void * auxv_ptr = (void *)heap;
|
||||
heap += sizeof(Elf32_auxv) * (auxvc);
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
alloc_frame(get_page(heap, 1, current_directory), 0, 1);
|
||||
argv_[i] = (char *)heap;
|
||||
@ -123,6 +141,16 @@ exec(
|
||||
/* Don't forget the NULL at the end of that... */
|
||||
argv_[argc] = 0;
|
||||
|
||||
for (int i = 0; i < envc; ++i) {
|
||||
alloc_frame(get_page(heap, 1, current_directory), 0, 1);
|
||||
env_[i] = (char *)heap;
|
||||
memcpy((void *)heap, env[i], strlen(env[i]) * sizeof(char) + 1);
|
||||
heap += strlen(env[i]) + 1;
|
||||
}
|
||||
env_[envc] = 0;
|
||||
|
||||
memcpy(auxv_ptr, auxv, sizeof(Elf32_auxv) * (auxvc));
|
||||
|
||||
current_process->image.heap = heap; /* heap end */
|
||||
current_process->image.heap_actual = heap + (0x1000 - heap % 0x1000);
|
||||
current_process->image.user_stack = USER_STACK_TOP;
|
||||
@ -135,7 +163,7 @@ exec(
|
||||
/* Go go go */
|
||||
enter_user_jmp(entry, argc, argv_, USER_STACK_TOP);
|
||||
|
||||
/* We should never reach this code */
|
||||
/* We should never reach this code */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -147,7 +175,8 @@ system(
|
||||
) {
|
||||
int child = fork();
|
||||
if (child == 0) {
|
||||
exec(path,argc,argv);
|
||||
char * env[] = {NULL};
|
||||
exec(path,argc,argv,env);
|
||||
debug_print(ERROR, "Failed to execute process!");
|
||||
kexit(-1);
|
||||
return -1;
|
||||
|
@ -182,22 +182,35 @@ static int execve(const char * filename, char *const argv[], char *const envp[])
|
||||
validate((void *)argv);
|
||||
validate((void *)filename);
|
||||
validate((void *)envp);
|
||||
int i = 0;
|
||||
while (argv[i]) {
|
||||
++i;
|
||||
int argc = 0, envc = 0;
|
||||
while (argv[argc]) { ++argc; }
|
||||
if (envp) {
|
||||
while (envp[envc]) { ++envc; }
|
||||
}
|
||||
debug_print(INFO, "Allocating space for arguments...");
|
||||
char ** argv_ = malloc(sizeof(char *) * i);
|
||||
for (int j = 0; j < i; ++j) {
|
||||
char ** argv_ = malloc(sizeof(char *) * argc);
|
||||
for (int j = 0; j < argc; ++j) {
|
||||
argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char));
|
||||
memcpy(argv_[j], argv[j], strlen(argv[j]) + 1);
|
||||
}
|
||||
char ** envp_;
|
||||
if (envp && envc) {
|
||||
envp_ = malloc(sizeof(char *) * (envc + 1));
|
||||
for (int j = 0; j < envc; ++j) {
|
||||
envp_[j] = malloc((strlen(envp[j]) + 1) * sizeof(char));
|
||||
memcpy(envp_[j], envp[j], strlen(envp[j]) + 1);
|
||||
}
|
||||
envp_[envc] = 0;
|
||||
} else {
|
||||
envp_ = malloc(sizeof(char *));
|
||||
envp_[0] = NULL;
|
||||
}
|
||||
debug_print(INFO,"Releasing all shmem regions...");
|
||||
shm_release_all((process_t *)current_process);
|
||||
|
||||
debug_print(INFO,"Executing...");
|
||||
/* Discard envp */
|
||||
exec((char *)filename, i, (char **)argv_);
|
||||
exec((char *)filename, argc, (char **)argv_, (char **)envp_);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
18
userspace/env.c
Normal file
18
userspace/env.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
unsigned int x = 0;
|
||||
unsigned int nulls = 0;
|
||||
for (x = 0; 1; ++x) {
|
||||
if (!argv[x]) {
|
||||
++nulls;
|
||||
if (nulls == 2) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (nulls == 1) {
|
||||
printf("%s\n", argv[x]);
|
||||
}
|
||||
}
|
||||
}
|
135
userspace/esh.c
135
userspace/esh.c
@ -19,21 +19,57 @@
|
||||
|
||||
#include "lib/list.h"
|
||||
|
||||
#define SHELL_COMMANDS 512
|
||||
/* Environment Variables */
|
||||
#define ENV_SIZE 1024
|
||||
char * envp[ENV_SIZE];
|
||||
size_t envc;
|
||||
|
||||
int env_find(char * variable) {
|
||||
char key[512];
|
||||
sprintf(key, "%s=", variable);
|
||||
for (int i = 0; i < envc; ++i) {
|
||||
if (strstr(envp[i], key) == envp[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void _setenv(char * val) {
|
||||
char * newval = malloc(strlen(val) + 1);
|
||||
memcpy(newval, val, strlen(val) + 1);
|
||||
char * k = val;
|
||||
if (!strstr(k, "=")) return;
|
||||
char * v = strtok(k, "=");
|
||||
int index = env_find(k);
|
||||
if (index < 0) {
|
||||
envp[envc] = newval;
|
||||
envc++;
|
||||
} else {
|
||||
envp[index] = realloc(envp[index], strlen(newval) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* A shell command is like a C program */
|
||||
typedef uint32_t(*shell_command_t) (int argc, char ** argv);
|
||||
char * shell_commands[SHELL_COMMANDS];
|
||||
shell_command_t shell_pointers[SHELL_COMMANDS];
|
||||
|
||||
/* We have a static array that fits a certain number of them. */
|
||||
#define SHELL_COMMANDS 512
|
||||
char * shell_commands[SHELL_COMMANDS]; /* Command names */
|
||||
shell_command_t shell_pointers[SHELL_COMMANDS]; /* Command functions */
|
||||
|
||||
/* This is the number of actual commands installed */
|
||||
uint32_t shell_commands_len = 0;
|
||||
|
||||
/* We also support history through a circular buffer. */
|
||||
#define SHELL_HISTORY_ENTRIES 128
|
||||
char * shell_history[SHELL_HISTORY_ENTRIES];
|
||||
size_t shell_history_count = 0;
|
||||
size_t shell_history_offset = 0;
|
||||
|
||||
size_t shell_scroll = 0;
|
||||
char shell_temp[1024];
|
||||
|
||||
int pid;
|
||||
int pid; /* Process ID of the shell */
|
||||
|
||||
char * shell_history_prev(size_t item);
|
||||
|
||||
@ -624,7 +660,6 @@ try_rev_search_again:
|
||||
start_at = match_index + 1;
|
||||
break;
|
||||
case '\n':
|
||||
/* XXX execute */
|
||||
memcpy(context->buffer, match, strlen(match) + 1);
|
||||
context->collected = strlen(match);
|
||||
context->offset = context->collected;
|
||||
@ -714,6 +749,14 @@ size_t read_entry_continued(char * buffer) {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
inline int variable_char(uint8_t c) {
|
||||
if (c >= 65 && c <= 90) return 1;
|
||||
if (c >= 97 && c <= 122) return 1;
|
||||
if (c >= 48 && c <= 57) return 1;
|
||||
if (c == 95) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shell_exec(char * buffer, size_t buffer_size) {
|
||||
|
||||
/* Read previous history entries */
|
||||
@ -754,6 +797,44 @@ int shell_exec(char * buffer, size_t buffer_size) {
|
||||
|
||||
while (*p) {
|
||||
switch (*p) {
|
||||
case '$':
|
||||
if (quoted != '\'') {
|
||||
p++;
|
||||
char var[100];
|
||||
int coll = 0;
|
||||
if (*p == '{') {
|
||||
p++;
|
||||
while (*p != '}' && *p != '\0' && (coll < 100)) {
|
||||
var[coll] = *p;
|
||||
coll++;
|
||||
var[coll] = '\0';
|
||||
p++;
|
||||
}
|
||||
if (*p == '}') {
|
||||
p++;
|
||||
}
|
||||
} else {
|
||||
while (*p != '\0' && variable_char(*p) && (coll < 100)) {
|
||||
var[coll] = *p;
|
||||
coll++;
|
||||
var[coll] = '\0';
|
||||
p++;
|
||||
}
|
||||
}
|
||||
int i = env_find(var);
|
||||
if (i >= 0) {
|
||||
char * c = strstr(envp[i], "=");
|
||||
c++;
|
||||
backtick = 0;
|
||||
for (int i = 0; i < strlen(c); ++i) {
|
||||
buffer_[collected] = c[i];
|
||||
collected++;
|
||||
}
|
||||
buffer_[collected] = '\0';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
goto _next;
|
||||
case '\"':
|
||||
if (quoted == '\"') {
|
||||
if (backtick) {
|
||||
@ -893,7 +974,7 @@ _done:
|
||||
|
||||
uint32_t f = fork();
|
||||
if (getpid() != pid) {
|
||||
int i = execve(cmd, argv, NULL);
|
||||
int i = execve(cmd, argv, envp);
|
||||
return i;
|
||||
} else {
|
||||
int ret_code = 0;
|
||||
@ -947,6 +1028,27 @@ void sort_commands() {
|
||||
}
|
||||
}
|
||||
|
||||
void collect_environment(int argc, char ** argv) {
|
||||
unsigned int x = 0;
|
||||
unsigned int nulls = 0;
|
||||
memset(envp, 0x00, sizeof(char *) * ENV_SIZE);
|
||||
#if 0
|
||||
while (1) {
|
||||
if (!argv[x]) {
|
||||
++nulls;
|
||||
if (nulls == 2) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (nulls == 1) {
|
||||
_setenv(argv[x]);
|
||||
}
|
||||
++x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int nowait = 0;
|
||||
int free_cmd = 0;
|
||||
@ -954,6 +1056,8 @@ int main(int argc, char ** argv) {
|
||||
|
||||
pid = getpid();
|
||||
|
||||
collect_environment(argc, argv);
|
||||
|
||||
syscall_signal(2, sig_int);
|
||||
|
||||
getusername();
|
||||
@ -1022,7 +1126,24 @@ uint32_t shell_cmd_history(int argc, char * argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t shell_cmd_test(int argc, char * argv[]) {
|
||||
printf("%d arguments.\n", argc);
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
printf("%d -> %s\n", i, argv[i]);
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
||||
uint32_t shell_cmd_export(int argc, char * argv[]) {
|
||||
if (argc > 1) {
|
||||
_setenv(argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void install_commands() {
|
||||
shell_install_command("cd", shell_cmd_cd);
|
||||
shell_install_command("history", shell_cmd_history);
|
||||
shell_install_command("export", shell_cmd_export);
|
||||
shell_install_command("test", shell_cmd_test);
|
||||
}
|
||||
|
19
userspace/stack-reaper.c
Normal file
19
userspace/stack-reaper.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
printf("Exploring the stack...\n");
|
||||
unsigned int x = 0;
|
||||
unsigned int nulls = 0;
|
||||
while (1) {
|
||||
if (!argv[x]) { ++nulls; }
|
||||
printf("argv[%.2d] = [%p] %s\n", x, argv[x], argv[x]);
|
||||
++x;
|
||||
if (nulls == 2) { break; }
|
||||
}
|
||||
printf("[ELF AuxV]\n");
|
||||
while (1) {
|
||||
printf("auxv[%.2d] = %.2d -> 0x%x\n", x, (unsigned int)argv[x], (unsigned int)argv[x+1]);
|
||||
if (argv[x] == 0) { break; } /* AT_NULL, technically, but that's 0 */
|
||||
x += 2;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user