Add write_file () syscall, CE implement redirections, libarena arena_realloc ()
All checks were successful
Build documentation / build-and-deploy (push) Successful in 2m14s
All checks were successful
Build documentation / build-and-deploy (push) Successful in 2m14s
This commit is contained in:
187
ce/ce.c
187
ce/ce.c
@@ -16,6 +16,46 @@
|
||||
|
||||
static struct arena arena;
|
||||
|
||||
struct strbuf {
|
||||
char* items;
|
||||
size_t count, capacity;
|
||||
};
|
||||
|
||||
void strbuf_append (struct strbuf* strbuf, char c) {
|
||||
if (strbuf->items == NULL) {
|
||||
strbuf->capacity = 256;
|
||||
strbuf->count = 0;
|
||||
strbuf->items = arena_malloc (&arena, strbuf->capacity);
|
||||
} else {
|
||||
if (strbuf->count == strbuf->capacity) {
|
||||
size_t prev_capacity = strbuf->capacity;
|
||||
strbuf->capacity *= 2;
|
||||
strbuf->items = arena_realloc (&arena, strbuf->items, prev_capacity, strbuf->capacity);
|
||||
}
|
||||
}
|
||||
strbuf->items[strbuf->count++] = c;
|
||||
}
|
||||
|
||||
void strbuf_append_str (struct strbuf* strbuf, const char* s) {
|
||||
while (*s)
|
||||
strbuf_append (strbuf, *s++);
|
||||
}
|
||||
|
||||
struct context {
|
||||
struct strbuf strbuf;
|
||||
};
|
||||
|
||||
#define CPRINTF_BUF_MAX 4096
|
||||
|
||||
#define cprintf(context, fmt, ...) \
|
||||
do { \
|
||||
char* __cprintf_buf = malloc (CPRINTF_BUF_MAX); \
|
||||
memset (__cprintf_buf, 0, CPRINTF_BUF_MAX); \
|
||||
snprintf (__cprintf_buf, CPRINTF_BUF_MAX, (fmt), ##__VA_ARGS__); \
|
||||
strbuf_append_str (&(context)->strbuf, __cprintf_buf); \
|
||||
free (__cprintf_buf); \
|
||||
} while (0)
|
||||
|
||||
#define LINE_BUFFER_MAX 1024
|
||||
#define TOKEN_MAX 64
|
||||
#define CMD_ARGS_MAX 64
|
||||
@@ -25,6 +65,7 @@ static struct arena arena;
|
||||
#define TOKEN_CLASS_CPAREN 1
|
||||
#define TOKEN_CLASS_WORD 2
|
||||
#define TOKEN_CLASS_SEMICOLON 3
|
||||
#define TOKEN_CLASS_REDIR 4
|
||||
|
||||
struct token {
|
||||
struct list_node_link tokens_link;
|
||||
@@ -33,12 +74,14 @@ struct token {
|
||||
};
|
||||
|
||||
#define PREC_NONE 0
|
||||
#define PREC_SEQ 1
|
||||
#define PREC_LOWEST 2
|
||||
#define PREC_LOWEST 1
|
||||
#define PREC_SEQ 2
|
||||
#define PREC_REDIR 3
|
||||
|
||||
#define AST_NODE_CLASS_CMD 0
|
||||
#define AST_NODE_CLASS_SUBSHELL 1
|
||||
#define AST_NODE_CLASS_SEQ 2
|
||||
#define AST_NODE_CLASS_REDIR 3
|
||||
|
||||
struct ast_node;
|
||||
|
||||
@@ -57,12 +100,18 @@ struct ast_seq {
|
||||
struct ast_node* right;
|
||||
};
|
||||
|
||||
struct ast_redir {
|
||||
struct ast_node* source;
|
||||
char* file_path;
|
||||
};
|
||||
|
||||
struct ast_node {
|
||||
int class;
|
||||
union {
|
||||
struct ast_cmd cmd;
|
||||
struct ast_subshell subshell;
|
||||
struct ast_seq seq;
|
||||
struct ast_redir redir;
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -90,11 +139,15 @@ static struct ast_node* oparen_nud (struct parser* parser, struct token* token);
|
||||
static struct ast_node* semicolon_led (struct parser* parser, struct token* token,
|
||||
struct ast_node* left);
|
||||
|
||||
static struct ast_node* redir_led (struct parser* parser, struct token* token,
|
||||
struct ast_node* left);
|
||||
|
||||
static struct parse_rule parse_rules[] = {
|
||||
[TOKEN_CLASS_WORD] = {&word_nud, NULL, PREC_NONE},
|
||||
[TOKEN_CLASS_OPAREN] = {&oparen_nud, NULL, PREC_NONE},
|
||||
[TOKEN_CLASS_CPAREN] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_CLASS_SEMICOLON] = {NULL, &semicolon_led, PREC_SEQ},
|
||||
[TOKEN_CLASS_REDIR] = {NULL, &redir_led, PREC_REDIR},
|
||||
};
|
||||
|
||||
static struct token* get_token (struct list_node_link* link) {
|
||||
@@ -179,6 +232,19 @@ static struct ast_node* semicolon_led (struct parser* parser, struct token* toke
|
||||
return node;
|
||||
}
|
||||
|
||||
static struct ast_node* redir_led (struct parser* parser, struct token* token,
|
||||
struct ast_node* left) {
|
||||
struct ast_node* node = arena_malloc (&arena, sizeof (*node));
|
||||
node->class = AST_NODE_CLASS_REDIR;
|
||||
node->u.redir.source = left;
|
||||
|
||||
struct token* next_token = advance (parser);
|
||||
if (next_token != NULL && next_token->class == TOKEN_CLASS_WORD)
|
||||
node->u.redir.file_path = next_token->buffer;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static int e_pid;
|
||||
static int e_pgid;
|
||||
|
||||
@@ -211,13 +277,15 @@ static void classify_tokens (struct list_node_link* tokens) {
|
||||
token->class = TOKEN_CLASS_CPAREN;
|
||||
} else if (strcmp (token->buffer, ";") == 0) {
|
||||
token->class = TOKEN_CLASS_SEMICOLON;
|
||||
} else if (strcmp (token->buffer, ">") == 0) {
|
||||
token->class = TOKEN_CLASS_REDIR;
|
||||
} else {
|
||||
token->class = TOKEN_CLASS_WORD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void execute (struct ast_node* root);
|
||||
static void execute (struct ast_node* root, struct context* context);
|
||||
|
||||
static void parse_tokens (struct list_node_link* tokens) {
|
||||
struct parser parser;
|
||||
@@ -225,20 +293,24 @@ static void parse_tokens (struct list_node_link* tokens) {
|
||||
parser.next = get_token (tokens);
|
||||
|
||||
while (parser.next != NULL) {
|
||||
struct ast_node* root = parse_precedence (&parser, PREC_LOWEST);
|
||||
struct ast_node* root = parse_precedence (&parser, PREC_NONE);
|
||||
|
||||
if (root != NULL) {
|
||||
execute (root);
|
||||
struct context context = {0};
|
||||
execute (root, &context);
|
||||
|
||||
if (context.strbuf.items != NULL)
|
||||
printf ("%.*s", (int)context.strbuf.count, context.strbuf.items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void echo (char** strings, size_t strings_count) {
|
||||
static void echo (struct context* context, char** strings, size_t strings_count) {
|
||||
for (size_t i = 0; i < strings_count; i++)
|
||||
printf ("%s ", strings[i]);
|
||||
cprintf (context, "%s ", strings[i]);
|
||||
}
|
||||
|
||||
static void mkfile (char** file_paths, size_t files_count) {
|
||||
static void mkfile (struct context* context, char** file_paths, size_t files_count) {
|
||||
char volume[VOLUME_MAX];
|
||||
const char* path;
|
||||
int ret;
|
||||
@@ -247,12 +319,12 @@ static void mkfile (char** file_paths, size_t files_count) {
|
||||
const char* file_path = file_paths[i];
|
||||
|
||||
if (!path_parse (file_path, volume, &path)) {
|
||||
printf ("ERROR bad path '%s'\n", file_path);
|
||||
cprintf (context, "ERROR bad path '%s'\n", file_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((ret = volume_open (volume)) < 0) {
|
||||
printf ("ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
|
||||
cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -262,7 +334,7 @@ static void mkfile (char** file_paths, size_t files_count) {
|
||||
}
|
||||
}
|
||||
|
||||
static void cat (char** file_paths, size_t files_count) {
|
||||
static void cat (struct context* context, char** file_paths, size_t files_count) {
|
||||
struct desc desc;
|
||||
char volume[VOLUME_MAX];
|
||||
const char* path;
|
||||
@@ -272,12 +344,12 @@ static void cat (char** file_paths, size_t files_count) {
|
||||
const char* file_path = file_paths[i];
|
||||
|
||||
if (!path_parse (file_path, volume, &path)) {
|
||||
printf ("ERROR bad path '%s'\n", file_path);
|
||||
cprintf (context, "ERROR bad path '%s'\n", file_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((ret = volume_open (volume)) < 0) {
|
||||
printf ("ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
|
||||
cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -293,7 +365,7 @@ static void cat (char** file_paths, size_t files_count) {
|
||||
|
||||
memset (buffer, 0, desc.size + 1);
|
||||
read_file (path, 0, (uint8_t*)buffer, desc.size);
|
||||
printf ("%s\n", buffer);
|
||||
cprintf (context, "%s\n", buffer);
|
||||
|
||||
close:
|
||||
if (buffer != NULL)
|
||||
@@ -302,7 +374,7 @@ static void cat (char** file_paths, size_t files_count) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ls (const char* path_string) {
|
||||
static void ls (struct context* context, const char* path_string) {
|
||||
struct desc desc;
|
||||
char volume[VOLUME_MAX];
|
||||
const char* path;
|
||||
@@ -310,81 +382,108 @@ static void ls (const char* path_string) {
|
||||
struct dir_entry entry;
|
||||
|
||||
if (!path_parse (path_string, volume, &path)) {
|
||||
printf ("ERROR bad path '%s'\n", path_string);
|
||||
cprintf (context, "ERROR bad path '%s'\n", path_string);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ret = volume_open (volume)) < 0) {
|
||||
printf ("ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
|
||||
cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
|
||||
return;
|
||||
}
|
||||
|
||||
describe (path, &desc);
|
||||
|
||||
if (desc.type != FS_DIR) {
|
||||
printf ("ERROR '%s' is not a directory\n", path_string);
|
||||
cprintf (context, "ERROR '%s' is not a directory\n", path_string);
|
||||
volume_close ();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t entries = desc.size;
|
||||
printf ("total entries: %zu\n", entries);
|
||||
printf ("\n");
|
||||
cprintf (context, "total entries: %zu\n", entries);
|
||||
cprintf (context, "\n");
|
||||
|
||||
for (size_t entry_num = 0; entry_num < entries; entry_num++) {
|
||||
read_dir_entry (path, &entry, entry_num);
|
||||
describe (entry.path, &desc);
|
||||
|
||||
printf ("%-40s%c %-40zu\n", entry.path, (desc.type == FS_DIR ? '*' : ' '), desc.size);
|
||||
cprintf (context, "%-40s%c %-40zu\n", entry.path, (desc.type == FS_DIR ? '*' : ' '), desc.size);
|
||||
}
|
||||
|
||||
volume_close ();
|
||||
}
|
||||
|
||||
static void quit1 (void) {
|
||||
static void quit1 (struct context* context) {
|
||||
run = false;
|
||||
printf ("Goodbye!\n");
|
||||
cprintf (context, "Goodbye!\n");
|
||||
}
|
||||
|
||||
static void help (void) {
|
||||
printf ("Available commands:\n");
|
||||
printf ("echo <word1> <word2> <word3> ...\n");
|
||||
printf ("help\n");
|
||||
printf ("cat <file path>\n");
|
||||
printf ("ls <directory path>\n");
|
||||
printf ("mkfile <file path>\n");
|
||||
printf ("quit\n");
|
||||
static void help (struct context* context) {
|
||||
cprintf (context, "Available commands:\n");
|
||||
cprintf (context, "echo <word1> <word2> <word3> ...\n");
|
||||
cprintf (context, "help\n");
|
||||
cprintf (context, "cat <file path>\n");
|
||||
cprintf (context, "ls <directory path>\n");
|
||||
cprintf (context, "mkfile <file path>\n");
|
||||
cprintf (context, "quit\n");
|
||||
}
|
||||
|
||||
static void execute_cmd (struct ast_cmd* cmd) {
|
||||
static void execute_cmd (struct ast_cmd* cmd, struct context* context) {
|
||||
if (strcmp (cmd->name, "echo") == 0) {
|
||||
echo (cmd->args, cmd->arg_count);
|
||||
echo (context, cmd->args, cmd->arg_count);
|
||||
} else if (strcmp (cmd->name, "help") == 0) {
|
||||
help ();
|
||||
help (context);
|
||||
} else if (strcmp (cmd->name, "cat") == 0) {
|
||||
cat (cmd->args, cmd->arg_count);
|
||||
cat (context, cmd->args, cmd->arg_count);
|
||||
} else if (strcmp (cmd->name, "ls") == 0) {
|
||||
ls (cmd->args[0]);
|
||||
ls (context, cmd->args[0]);
|
||||
} else if (strcmp (cmd->name, "quit") == 0) {
|
||||
quit1 ();
|
||||
quit1 (context);
|
||||
} else if (strcmp (cmd->name, "mkfile") == 0) {
|
||||
mkfile (cmd->args, cmd->arg_count);
|
||||
mkfile (context, cmd->args, cmd->arg_count);
|
||||
} else {
|
||||
printf ("ERROR unknown command '%s'\n", cmd->name);
|
||||
cprintf (context, "ERROR unknown command '%s'\n", cmd->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void execute (struct ast_node* root) {
|
||||
static void execute_redir (struct ast_redir* redir, struct context* context) {
|
||||
char volume[VOLUME_MAX];
|
||||
const char* path;
|
||||
int ret;
|
||||
|
||||
if (!(path_parse (redir->file_path, volume, &path))) {
|
||||
cprintf (context, "ERROR bad path '%s'\n", redir->file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ret = volume_open (volume)) < 0) {
|
||||
cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
|
||||
return;
|
||||
}
|
||||
|
||||
create_file (path);
|
||||
write_file (path, 0, (uint8_t*)context->strbuf.items, context->strbuf.count);
|
||||
|
||||
volume_close ();
|
||||
}
|
||||
|
||||
static void execute (struct ast_node* root, struct context* context) {
|
||||
struct context subcontext = {0};
|
||||
|
||||
switch (root->class) {
|
||||
case AST_NODE_CLASS_CMD:
|
||||
execute_cmd (&root->u.cmd);
|
||||
execute_cmd (&root->u.cmd, context);
|
||||
break;
|
||||
case AST_NODE_CLASS_SUBSHELL:
|
||||
execute (root->u.subshell.inner);
|
||||
execute (root->u.subshell.inner, &subcontext);
|
||||
break;
|
||||
case AST_NODE_CLASS_SEQ:
|
||||
execute (root->u.seq.left);
|
||||
execute (root->u.seq.right);
|
||||
execute (root->u.seq.left, context);
|
||||
execute (root->u.seq.right, context);
|
||||
break;
|
||||
case AST_NODE_CLASS_REDIR:
|
||||
execute (root->u.redir.source, &subcontext);
|
||||
execute_redir (&root->u.redir, &subcontext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,6 @@
|
||||
#define SYS_GET_EXEC_PID 21
|
||||
#define SYS_READ_DIR_ENTRY 22
|
||||
#define SYS_CREATE_FILE 23
|
||||
#define SYS_WRITE_FILE 24
|
||||
|
||||
#endif // _M_SYSCALL_DEFS_H
|
||||
|
||||
@@ -205,6 +205,25 @@ int vfs_read_file (struct proc* proc, const char* volume_name, const char* path,
|
||||
return volume->driver_ops.read_file (volume, path, buffer, off, size);
|
||||
}
|
||||
|
||||
int vfs_write_file (struct proc* proc, const char* volume_name, const char* path, uint8_t* buffer,
|
||||
size_t off, size_t size) {
|
||||
struct vfs_volume* volume = vfs_find_volume (volume_name);
|
||||
|
||||
if (volume == NULL)
|
||||
return -ST_NOT_FOUND;
|
||||
|
||||
spin_lock (&volume->lock);
|
||||
|
||||
if (volume->locked && volume->owner != proc) {
|
||||
spin_unlock (&volume->lock);
|
||||
return -ST_PERMISSION_ERROR;
|
||||
}
|
||||
|
||||
spin_unlock (&volume->lock);
|
||||
|
||||
return volume->driver_ops.write_file (volume, path, buffer, off, size);
|
||||
}
|
||||
|
||||
int vfs_create_file (struct proc* proc, const char* volume_name, const char* path) {
|
||||
struct vfs_volume* volume = vfs_find_volume (volume_name);
|
||||
|
||||
|
||||
@@ -69,6 +69,9 @@ int vfs_format (struct proc* proc, const char* volume_name);
|
||||
int vfs_read_file (struct proc* proc, const char* volume, const char* path, uint8_t* buffer,
|
||||
size_t off, size_t size);
|
||||
|
||||
int vfs_write_file (struct proc* proc, const char* volume, const char* path, uint8_t* buffer,
|
||||
size_t off, size_t size);
|
||||
|
||||
int vfs_describe (struct proc* proc, const char* volume, const char* path, struct desc* desc);
|
||||
|
||||
int vfs_read_dir_entry (struct proc* proc, const char* volume, const char* path,
|
||||
|
||||
@@ -483,6 +483,38 @@ DEFINE_SYSCALL (sys_create_file) {
|
||||
return SYSRESULT (ret);
|
||||
}
|
||||
|
||||
/* int write_file (char* path, size_t off, uint8_t* buffer, size_t size) */
|
||||
DEFINE_SYSCALL (sys_write_file) {
|
||||
uintptr_t uvaddr_path = a1;
|
||||
size_t off = (size_t)a2;
|
||||
uintptr_t uvaddr_buffer = a3;
|
||||
size_t size = (size_t)a4;
|
||||
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
uintptr_t out_paddr;
|
||||
|
||||
spin_lock (&proc->procgroup->lock);
|
||||
out_paddr = mm_v2p (&proc->procgroup->pd, uvaddr_path);
|
||||
spin_unlock (&proc->procgroup->lock);
|
||||
|
||||
if (out_paddr == 0)
|
||||
return SYSRESULT (-ST_BAD_ADDRESS_SPACE);
|
||||
|
||||
const char* path = (const char*)((uintptr_t)hhdm->offset + out_paddr);
|
||||
|
||||
uint8_t* buffer = sys_get_user_buffer (proc, uvaddr_buffer, size);
|
||||
|
||||
if (buffer == NULL)
|
||||
return SYSRESULT (-ST_BAD_ADDRESS_SPACE);
|
||||
|
||||
spin_lock (&proc->lock);
|
||||
int ret = vfs_write_file (proc, proc->cwv, path, buffer, off, size);
|
||||
spin_unlock (&proc->lock);
|
||||
|
||||
return SYSRESULT (ret);
|
||||
}
|
||||
|
||||
/* int get_exec_pid (void) */
|
||||
DEFINE_SYSCALL (sys_get_exec_pid) { return SYSRESULT (proc->exec_pid); }
|
||||
|
||||
@@ -510,6 +542,7 @@ static syscall_handler_func_t handler_table[] = {
|
||||
[SYS_GET_EXEC_PID] = &sys_get_exec_pid,
|
||||
[SYS_READ_DIR_ENTRY] = &sys_read_dir_entry,
|
||||
[SYS_CREATE_FILE] = &sys_create_file,
|
||||
[SYS_WRITE_FILE] = &sys_write_file,
|
||||
};
|
||||
|
||||
syscall_handler_func_t syscall_find_handler (int syscall_num) {
|
||||
|
||||
@@ -76,3 +76,15 @@ void* arena_malloc (struct arena* arena, size_t size) {
|
||||
arena->end->size += size1;
|
||||
return result;
|
||||
}
|
||||
|
||||
void* arena_realloc (struct arena* arena, void* memory, size_t prev_size, size_t new_size) {
|
||||
if (new_size <= prev_size)
|
||||
return memory;
|
||||
|
||||
void* new_memory = arena_malloc (arena, new_size);
|
||||
|
||||
for (size_t i = 0; i < prev_size; i++)
|
||||
((uint8_t*)new_memory)[i] = ((uint8_t*)memory)[i];
|
||||
|
||||
return new_memory;
|
||||
}
|
||||
|
||||
@@ -23,4 +23,6 @@ void arena_destroy (struct arena* arena);
|
||||
|
||||
void* arena_malloc (struct arena* arena, size_t size);
|
||||
|
||||
void* arena_realloc (struct arena* arena, void* memory, size_t prev_size, size_t new_size);
|
||||
|
||||
#endif // _LIBARENA_ARENA_H
|
||||
|
||||
@@ -70,3 +70,7 @@ int read_dir_entry (const char* path, struct dir_entry* entry, size_t entry_num)
|
||||
}
|
||||
|
||||
int create_file (const char* path) { return (int)do_syscall (SYS_CREATE_FILE, path); }
|
||||
|
||||
int write_file (const char* path, size_t off, uint8_t* buffer, size_t size) {
|
||||
return (int)do_syscall (SYS_WRITE_FILE, path, off, buffer, size);
|
||||
}
|
||||
|
||||
@@ -84,4 +84,7 @@ int read_dir_entry (const char* path, struct dir_entry* entry, size_t entry_num)
|
||||
/* create a file */
|
||||
int create_file (const char* path);
|
||||
|
||||
/* write to a file */
|
||||
int write_file (const char* path, size_t off, uint8_t* buffer, size_t size);
|
||||
|
||||
#endif // _LIBMSL_M_SYSTEM_H
|
||||
|
||||
Reference in New Issue
Block a user