#include "macro.h" #include "config.h" #include "cli.h" #include "print.h" #include "fs.h" #include "ctrl.h" #include #include static const struct CliCommandEntry cmd[] = { // mandatory commands {"mkfs", 1, (enum CliArgType[]) {INT}, fs_mkfs}, {"create", 1, (enum CliArgType[]) {STR}, fs_create}, // custom commands {"use", 1, (enum CliArgType[]) {STR}, fs_use}, {"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("$ ", 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; } }