#include "src/lib/memory.h" #include "src/lib/string.h" #include "src/lib/util.h" #include "src/user/syscall.h" static exit_code_t help(uint8_t argc, char **argv, uint64_t stdin, uint64_t stdout); static exit_code_t cd(uint8_t argc, char **argv, uint64_t stdin, uint64_t stdout); #define PATH "/bin/" #define WRITE_S(o, s) write(o, s, sizeof(s) - 1); #define WRITE_D(o, s) write(o, s, string_length(s)); typedef exit_code_t (*app_t)(uint8_t argc, char **argv, uint64_t stdin, uint64_t stdout); typedef struct { const char *name; app_t app; } app_entry_t; static app_entry_t builtins[] = { {"help", help}, {"cd", cd}, }; static exit_code_t help(uint8_t argc, __attribute__((unused)) char **argv, __attribute__((unused)) uint64_t stdin, uint64_t stdout) { if (argc > 1) { ERR_S("help: expects no arguments\n"); return EXIT_CODE_GENERAL_FAILURE; } WRITE_S(stdout, "Available commands:\n"); for (uint64_t i = 0; i < sizeof(builtins) / sizeof(app_entry_t); i++) { WRITE_D(stdout, builtins[i].name); WRITE_S(stdout, "\n"); } return EXIT_CODE_OK; } static exit_code_t cd(uint8_t argc, char **argv, __attribute__((unused)) uint64_t stdin, __attribute__((unused)) uint64_t stdout) { if (argc != 2) { ERR_S("cd: requires a single path\n"); return EXIT_CODE_GENERAL_FAILURE; } if (chdir(argv[1]) == (uint64_t)-1) { ERR_S("cd: path does not exist\n"); return EXIT_CODE_GENERAL_FAILURE; } return EXIT_CODE_OK; } static void print_prompt() { char path[256]; uint8_t pl = getcwd(256, path); char *components[16]; uint8_t cl = string_split(path, '/', 16, components); OUT_S("[") OUT_D(pl == 1 ? "/" : components[cl - 1]); OUT_S("]$ "); } static void free_fds(uint64_t *fds, uint8_t fds_count) { for (uint8_t i = 0; i < fds_count; i++) { close(fds[i]); } } static void kill_pids(__attribute__((unused)) uint64_t *pids, __attribute__((unused)) uint8_t pid_count) { // TODO. } static void execute(char *command) { OUT_S("\n"); if (string_equal(command, "^C")) { print_prompt(); return; } if (string_equal(command, "^D")) { exit(EXIT_CODE_OK); return; } char *subcommands[16]; uint8_t subcommands_count = (uint8_t)string_split(command, '|', 16, subcommands); uint64_t fds[32]; uint8_t fds_count = 0; uint64_t pids[16]; uint8_t pids_count = 0; for (uint8_t i = 0; i < subcommands_count; i++) { if (!string_trim(subcommands[i], ' ', &subcommands[i])) { if (subcommands_count > 1) { ERR_S("Syntax error.\n"); } break; } char *argv[16]; uint8_t argc = (uint8_t)string_split(subcommands[i], ' ', 16, argv); uint64_t stdin = 0; uint64_t stdout = 1; if (i > 0) { stdin = fds[fds_count - 1]; } if (i < subcommands_count - 1) { if (pipe(&fds[fds_count], &fds[fds_count + 1]) == (uint64_t)-1) { kill_pids(pids, pids_count); free_fds(fds, fds_count); print_prompt(); return; } fds_count += 2; stdout = fds[fds_count - 2]; } uint8_t j; for (j = 0; j < sizeof(builtins) / sizeof(app_entry_t); j++) { if (string_equal(argv[0], builtins[j].name)) { builtins[j].app(argc, argv, stdin, stdout); pids[pids_count++] = 0; break; } } if (j == sizeof(builtins) / sizeof(app_entry_t)) { uint64_t size = sizeof(PATH) + string_length(argv[0]) + 1; char *path = memory_allocate(size); memory_copy(PATH, sizeof(PATH), path); memory_copy(argv[0], size - sizeof(PATH), path + sizeof(PATH) - 1); uint64_t pid = spawn(path, argc, (const char **)argv, stdin, stdout); memory_free(path); if (pid == (uint64_t)-1) { kill_pids(pids, pids_count); free_fds(fds, fds_count); print_prompt(); return; } else { pids[pids_count++] = pid; } } } for (uint8_t i = 0; i < pids_count; i++) { if (pids[i]) { waitpid(pids[i]); } if (i > 0) { close(fds[(i - 1) * 2 + 1]); } if (i < pids_count - 1) { close(fds[i * 2]); } } print_prompt(); } exit_code_t main() { ERR_S("Welcome to FreywarOS v" VERSION "!\n\n"); print_prompt(); char line[256]; uint64_t offset = 0; char chunk[64]; uint64_t received; while ((received = read(0, sizeof(chunk), chunk))) { for (uint64_t i = 0; i < received; i++) { if (chunk[i] == '\n') { line[offset] = '\0'; execute(line); offset = 0; } else if (offset < 255) { line[offset++] = chunk[i]; } } } return EXIT_CODE_OK; }