268 lines
5.5 KiB
C
268 lines
5.5 KiB
C
#include "macro.h"
|
|
#include "config.h"
|
|
|
|
#include "cli.h"
|
|
#include "print.h"
|
|
|
|
#include "fs.h"
|
|
#include "ctrl.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
static const struct CliCommandEntry cmd[] = {
|
|
// mandatory commands
|
|
{"mkfs", 1, (enum CliArgType[]) {INT}, fs_mkfs},
|
|
{"create", 1, (enum CliArgType[]) {STR}, fs_create},
|
|
{"stat", 1, (enum CliArgType[]) {STR}, fs_stat},
|
|
{"ls", 0, NULL, fs_ls},
|
|
{"ln", 2, (enum CliArgType[]) {STR, STR}, fs_ln},
|
|
{"rm", 1, (enum CliArgType[]) {STR}, fs_rm},
|
|
{"truncate", 2, (enum CliArgType[]) {STR, INT}, fs_truncate},
|
|
{"open", 1, (enum CliArgType[]) {STR}, fs_open},
|
|
{"seek", 2, (enum CliArgType[]) {INT, INT}, fs_seek},
|
|
{"read", 2, (enum CliArgType[]) {INT, INT}, fs_read},
|
|
{"write", 2, (enum CliArgType[]) {INT, STR}, fs_write},
|
|
{"close", 1, (enum CliArgType[]) {INT}, fs_close},
|
|
|
|
// custom commands
|
|
{"use", 1, (enum CliArgType[]) {STR}, fs_use},
|
|
{"la", 0, NULL, fs_la},
|
|
{"prohibit-write", 0, NULL, fs_prohibit_write},
|
|
{"allow-write", 0, NULL, fs_allow_write},
|
|
{"exit", 0, NULL, ctrl_exit}
|
|
};
|
|
|
|
|
|
static void destroy_tokenized_line(char **tokenized_line)
|
|
{
|
|
for (int j = 0; j < CLI_MAX_ACCEPTED_ARGS; j++)
|
|
if (tokenized_line[j])
|
|
free(tokenized_line[j]);
|
|
|
|
free(tokenized_line);
|
|
}
|
|
|
|
static int tokenized_line_len(char **t)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < CLI_MAX_ACCEPTED_ARGS; i++)
|
|
if (!t[i])
|
|
break;
|
|
|
|
return i;
|
|
}
|
|
|
|
static char **tokenize_line(char *line, ssize_t result)
|
|
{
|
|
if (result > CLI_MAX_LINE_LENGTH) {
|
|
pr_err("command too long (%d > %d)\n", result+1, CLI_MAX_LINE_LENGTH);
|
|
return NULL;
|
|
}
|
|
|
|
char **tokenized_line = malloc(sizeof(char *) * CLI_MAX_ACCEPTED_ARGS);
|
|
memset(tokenized_line, 0, sizeof(char *) * CLI_MAX_ACCEPTED_ARGS);
|
|
|
|
unsigned int i, t, l;
|
|
for (
|
|
i = 0, t = 0, l = 0;
|
|
i < CLI_MAX_LINE_LENGTH,
|
|
t <= CLI_MAX_ACCEPTED_ARGS,
|
|
l < CLI_MAX_TOKEN_LENGTH;
|
|
i++
|
|
) {
|
|
if (line[i] == '\n') {
|
|
if (l) {
|
|
if (t == CLI_MAX_ACCEPTED_ARGS) {
|
|
t++;
|
|
break;
|
|
}
|
|
|
|
tokenized_line[t] = malloc(sizeof(char) * (l+1));
|
|
memcpy(tokenized_line[t], &(line[i-l]), l);
|
|
tokenized_line[t][l] = '\0';
|
|
|
|
t++;
|
|
}
|
|
|
|
break;
|
|
} else if (line[i] == ' ') {
|
|
if (l) {
|
|
if (t == CLI_MAX_ACCEPTED_ARGS) {
|
|
t++;
|
|
break;
|
|
}
|
|
|
|
tokenized_line[t] = malloc(sizeof(char) * (l+1));
|
|
memcpy(tokenized_line[t], &(line[i-l]), l);
|
|
tokenized_line[t][l] = '\0';
|
|
|
|
l = 0;
|
|
t++;
|
|
}
|
|
} else {
|
|
l++;
|
|
}
|
|
}
|
|
|
|
if (
|
|
i >= CLI_MAX_LINE_LENGTH ||
|
|
t > CLI_MAX_ACCEPTED_ARGS ||
|
|
l >= CLI_MAX_TOKEN_LENGTH ||
|
|
t == 0
|
|
) goto cli_process_error;
|
|
|
|
return tokenized_line;
|
|
|
|
|
|
cli_process_error:
|
|
// print error
|
|
if (i >= CLI_MAX_LINE_LENGTH)
|
|
pr_err("command too long (> %d)\n", CLI_MAX_LINE_LENGTH);
|
|
|
|
if (t > CLI_MAX_ACCEPTED_ARGS)
|
|
pr_err("too many arguments (> %d)\n", CLI_MAX_ACCEPTED_ARGS);
|
|
|
|
if (l >= CLI_MAX_TOKEN_LENGTH)
|
|
pr_err("argument %d too long (> %d)\n", t, CLI_MAX_TOKEN_LENGTH);
|
|
|
|
// clean up
|
|
destroy_tokenized_line(tokenized_line);
|
|
|
|
// return
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void *format_args(char **tokenized_line, unsigned int arg_count, enum CliArgType *arg_types)
|
|
{
|
|
char *new_struct;
|
|
|
|
{
|
|
// prepare struct space
|
|
unsigned int struct_size = 0;
|
|
|
|
for (unsigned int i = 0; i < arg_count; i++)
|
|
switch (arg_types[i]) {
|
|
case INT:
|
|
struct_size += sizeof(int);
|
|
break;
|
|
case STR:
|
|
struct_size += sizeof(char *);
|
|
break;
|
|
}
|
|
|
|
new_struct = malloc(struct_size);
|
|
memset(new_struct, 0, struct_size);
|
|
}
|
|
|
|
unsigned int struct_offset = 0;
|
|
|
|
for (unsigned int i = 0; i < arg_count; i++)
|
|
{
|
|
if (arg_types[i] == INT) {
|
|
if (!tokenized_line[i+1]) {
|
|
pr_err("missing argument %d of type 'integer'\n", i+1);
|
|
goto abandon_struct;
|
|
}
|
|
|
|
int value;
|
|
int result = sscanf(tokenized_line[i+1], "%d", &value);
|
|
|
|
if (result != 1) {
|
|
pr_err("argument %d must be of type 'integer'\n", i+1);
|
|
goto abandon_struct;
|
|
}
|
|
|
|
*((int*) &(new_struct[struct_offset])) = value;
|
|
struct_offset += sizeof(int);
|
|
}
|
|
else if (arg_types[i] == STR) {
|
|
if (!tokenized_line[i+1]) {
|
|
pr_err("missing argument %d of type 'string'\n", i+1);
|
|
goto abandon_struct;
|
|
}
|
|
|
|
*((char**) &(new_struct[struct_offset])) = tokenized_line[i+1];
|
|
struct_offset += sizeof(char *);
|
|
}
|
|
}
|
|
|
|
return new_struct;
|
|
|
|
abandon_struct:
|
|
free(new_struct);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
unsigned int cli_poll_process_next(void)
|
|
{
|
|
for ( ;; ) {
|
|
fputs(fs_get_cwd(), stdout);
|
|
|
|
if (fs_get_cwd()[0]) {
|
|
fputs(" $ ", stdout);
|
|
} else {
|
|
fputs("$ ", stdout);
|
|
}
|
|
|
|
size_t buf_size = 0;
|
|
char *line = NULL;
|
|
|
|
ssize_t result = getline(&line, &buf_size, stdin);
|
|
if (result == -1)
|
|
return 0x1;
|
|
|
|
char **tokenized_line = tokenize_line(line, result);
|
|
free(line);
|
|
|
|
if (tokenized_line == NULL)
|
|
continue;
|
|
|
|
unsigned int i;
|
|
for (i = 0; (i < LEN(cmd)) && strcmp(tokenized_line[0], cmd[i].cmd); i++);
|
|
if (i == LEN(cmd)) {
|
|
pr_err("command '%s' not found\n", tokenized_line[0]);
|
|
destroy_tokenized_line(tokenized_line);
|
|
continue;
|
|
}
|
|
|
|
{
|
|
int tll = tokenized_line_len(tokenized_line);
|
|
|
|
if ((cmd[i].arg_count + 1) != tll) {
|
|
pr_err("wrong amount of arguments for '%s' (%d required, %d got)\n", tokenized_line[0], cmd[i].arg_count, tll-1);
|
|
destroy_tokenized_line(tokenized_line);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
int (*executor)(void *) = cmd[i].process;
|
|
void *data;
|
|
|
|
if (cmd[i].arg_count) {
|
|
data = format_args(tokenized_line, cmd[i].arg_count, cmd[i].args);
|
|
|
|
if (data == NULL) {
|
|
destroy_tokenized_line(tokenized_line);
|
|
continue;
|
|
}
|
|
} else {
|
|
data = NULL;
|
|
}
|
|
|
|
int execution_result_code = executor(data);
|
|
|
|
if (data)
|
|
free(data);
|
|
|
|
destroy_tokenized_line(tokenized_line);
|
|
|
|
if (0x1 == execution_result_code)
|
|
return 0x1;
|
|
}
|
|
}
|