diff options
Diffstat (limited to 'src/user')
| -rw-r--r-- | src/user/init.cc | 237 | ||||
| -rw-r--r-- | src/user/sh.cc | 409 | ||||
| -rw-r--r-- | src/user/usys.S | 13 |
3 files changed, 457 insertions, 202 deletions
diff --git a/src/user/init.cc b/src/user/init.cc index 27c1e2f..827a21e 100644 --- a/src/user/init.cc +++ b/src/user/init.cc @@ -1,221 +1,58 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "ulib/string.h" #include "user/user.h" -#include "common/fcntl.h" -int strlen(const char *s) -{ - int n = 0; - while (s[n]) - n++; - return n; -} - -void print(const char *s) -{ - write(1, s, strlen(s)); -} - -void print_int(int n) -{ - char buf[16]; - int i = 0; - int neg = 0; - if (n == 0) - { - write(1, "0", 1); - return; - } - if (n < 0) - { - neg = 1; - n = -n; - } - while (n > 0) - { - buf[i++] = (n % 10) + '0'; - n /= 10; - } - if (neg) - buf[i++] = '-'; - while (i > 0) - write(1, &buf[--i], 1); -} - -void print_hex(uint64 n) -{ - char buf[16]; - char digits[] = "0123456789ABCDEF"; - write(1, "0x", 2); - if (n == 0) - { - write(1, "0", 1); - return; - } - int i = 0; - while (n > 0) - { - buf[i++] = digits[n % 16]; - n /= 16; - } - while (i > 0) - write(1, &buf[--i], 1); -} - -void test_syscalls() +int main() { - print("\n=== [Test] Starting System Call Check ===\n"); - - print("[1/4] Checking getpid()... "); - int my_pid = getpid(); - if (my_pid > 0) - { - print("PASS (PID="); - print_int(my_pid); - print(")\n"); - } - else - { - print("FAIL (Invalid PID)\n"); - } - - print("[2/4] Checking sbrk() heap allocation... "); - char *p = sbrk(4096); - if (p == (char *)-1) - { - print("FAIL (sbrk returned error)\n"); - } - else - { - p[0] = 'A'; - p[4095] = 'Z'; - if (p[0] == 'A' && p[4095] == 'Z') - { - print("PASS (Allocated at "); - print_hex((uint64)p); - print(")\n"); - } - else - { - print("FAIL (Memory read/write check failed)\n"); - } - } + char *argv[] = {(char *)"sh", 0}; - print("[3/4] Checking fork() and wait()...\n"); - int pid = fork(); + printf("[Init] Starting Lume OS Shell...\n"); - if (pid < 0) - { - print(" FAIL: fork error\n"); - } - else if (pid == 0) + while (1) { - int child_pid = getpid(); - if (child_pid == my_pid) + // printf("fork start\n"); + int pid = fork(); + // printf("fork suceess, pid=%i\n", pid); + + if (pid < 0) { - print(" FAIL: Child has same PID as parent\n"); + printf("[Init] fork failed!\n"); exit(1); } - print(" [Child] I am alive. PID="); - print_int(child_pid); - print("\n"); - print(" [Child] Exiting now.\n"); - exit(0); - } - else - { - print(" [Parent] Forked child PID="); - print_int(pid); - print("\n"); - print(" [Parent] Waiting for child...\n"); - int waited_pid = wait(0); - - if (waited_pid == pid) + if (pid == 0) { - print(" [Parent] Wait returned correct PID.\n"); - print("PASS (Fork/Wait cycle)\n"); - } - else - { - print("FAIL (Wait returned "); - print_int(waited_pid); - print(")\n"); - } - } - - print("[4/4] Checking write()... PASS (Self-evident)\n"); - - print("=== [Test] All Tests Finished ===\n"); -} - - -int main() -{ - print("\n[Lume Shell] Init process started.\n"); - print("[Test] Opening test.txt...\n"); - int fd = open("test.txt", O_RDONLY); - if (fd < 0) - { - print("[Test] Open failed (Is test.txt in fs.img?)\n"); - } - else - { - print("[Test] Open success! fd="); - print_int(fd); - print("\n"); + + char sh_path[] = "/sh"; + exec(sh_path, argv); - char buf[64]; - int n = read(fd, buf, 63); - if (n > 0) - { - buf[n] = 0; - print("[Test] Read content:\n---\n"); - print(buf); - print("\n---\n"); + printf("[Init] exec sh failed\n"); + return 0; + exit(1); } else { - print("[Test] Read returned "); - print_int(n); - print("\n"); - } - close(fd); - print("[Test] File closed.\n"); - } - - - - print("Commands:\n"); - print(" s: Run System Call Tests (fork, wait, mm)\n"); - print(" t: Run Disk Driver Test (VirtIO)\n"); - - while (1) - { - char buf[16]; - write(1, "$ ", 2); - - int n = read(0, buf, sizeof(buf)); - if (n <= 0) - continue; - - if (buf[0] == 's') - { - test_syscalls(); - } - else if (buf[0] == 't') - { - if (fork() == 0) + // break; + int status; + int wpid; + while (1) { - disk_test(); - exit(0); + wpid = wait((uint64)&status); + + if (wpid == pid) + { + printf("Shell Exit"); + break; + } + if (wpid < 0) + { + printf("[Init] wait error or no child\n"); + + break; + } } - wait(0); - } - else if (buf[0] != '\n') - { - print("Unknown command.\n"); } } - - exit(0); return 0; }
\ No newline at end of file diff --git a/src/user/sh.cc b/src/user/sh.cc new file mode 100644 index 0000000..287d2be --- /dev/null +++ b/src/user/sh.cc @@ -0,0 +1,409 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "ulib/string.h" +#include "user/user.h" +#include "common/fcntl.h" + +constexpr int MAX_ARGS = 10; +const char *WHITESPACE = " \t\r\n\v"; +const char *SYMBOLS = "<|>&;()"; + +void panic(const char *s) +{ + printf("shell panic: %s\n", s); + exit(1); +} + +int fork_or_panic() +{ + int pid = fork(); + if (pid == -1) + panic("fork"); + return pid; +} + +struct Command +{ + virtual ~Command() = default; + + virtual void run() = 0; +}; + +struct ExecCommand : public Command +{ + char *argv[MAX_ARGS]; + + ExecCommand() + { + memset(argv, 0, sizeof(argv)); + } + + void run() override + { + if (argv[0] == nullptr) + exit(1); + + exec(argv[0], argv); + + printf("exec %s failed\n", argv[0]); + exit(1); + } +}; + +struct RedirCommand : public Command +{ + Command *sub_cmd; + char *file; + char *efile; // file name end pointer (used by parser) + int mode; + int fd; + + RedirCommand(Command *c, char *f, char *ef, int m, int fd_in) + : sub_cmd(c), file(f), efile(ef), mode(m), fd(fd_in) {} + + ~RedirCommand() { delete sub_cmd; } + + void run() override + { + close(fd); + if (open(file, mode) < 0) + { + printf("open %s failed\n", file); + exit(1); + } + sub_cmd->run(); + } +}; + +struct PipeCommand : public Command +{ + Command *left; + Command *right; + + PipeCommand(Command *l, Command *r) : left(l), right(r) {} + ~PipeCommand() + { + delete left; + delete right; + } + + void run() override + { + int p[2]; + if (pipe(p) < 0) + panic("pipe"); + + if (fork_or_panic() == 0) + { + // Left child: write to pipe + close(1); // close stdout + dup(p[1]); // dup write-end to stdout + close(p[0]); + close(p[1]); + left->run(); + } + + if (fork_or_panic() == 0) + { + // Right child: read from pipe + close(0); // close stdin + dup(p[0]); // dup read-end to stdin + close(p[0]); + close(p[1]); + right->run(); + } + + close(p[0]); + close(p[1]); + wait(0); + wait(0); + exit(0); + } +}; + +struct ListCommand : public Command +{ + Command *left; + Command *right; + + ListCommand(Command *l, Command *r) : left(l), right(r) {} + ~ListCommand() + { + delete left; + delete right; + } + + void run() override + { + if (fork_or_panic() == 0) + { + left->run(); + } + wait(0); + right->run(); + } +}; + +struct BackCommand : public Command +{ + Command *sub_cmd; + + BackCommand(Command *c) : sub_cmd(c) {} + ~BackCommand() { delete sub_cmd; } + + void run() override + { + if (fork_or_panic() == 0) + { + sub_cmd->run(); + } + // Parent doesn't wait + exit(0); + } +}; + +class Parser +{ +public: + static Command *parse(char *s) + { + char *es = s + strlen(s); + Command *cmd = parse_line(&s, es); + peek(&s, es, ""); + if (s != es) + { + printf("leftovers: %s\n", s); + // panic("syntax"); // strict syntax check + } + terminate_strings(cmd); + return cmd; + } + +private: + // Helper: NUL-terminate strings found during parsing + static void terminate_strings(Command *cmd) + { + if (!cmd) + return; + } + + static char get_token(char **ps, char *es, char **q, char **eq) + { + char *s; + int ret; + + s = *ps; + while (s < es && strchr(WHITESPACE, *s)) + s++; + if (q) + *q = s; + ret = *s; + switch (*s) + { + case 0: + break; + case '|': + case '(': + case ')': + case ';': + case '&': + case '<': + s++; + break; + case '>': + s++; + if (*s == '>') + { + ret = '+'; + s++; + } + break; + default: + ret = 'a'; + while (s < es && !strchr(WHITESPACE, *s) && !strchr(SYMBOLS, *s)) + s++; + break; + } + if (eq) + *eq = s; + + while (s < es && strchr(WHITESPACE, *s)) + s++; + *ps = s; + return ret; + } + + static int peek(char **ps, char *es, const char *toks) + { + char *s = *ps; + while (s < es && strchr(WHITESPACE, *s)) + s++; + *ps = s; + return *s && strchr(toks, *s); + } + + // Recursive Descent Parsers + + static Command *parse_line(char **ps, char *es) + { + Command *cmd = parse_pipe(ps, es); + while (peek(ps, es, "&")) + { + get_token(ps, es, 0, 0); + cmd = new BackCommand(cmd); + } + if (peek(ps, es, ";")) + { + get_token(ps, es, 0, 0); + cmd = new ListCommand(cmd, parse_line(ps, es)); + } + return cmd; + } + + static Command *parse_pipe(char **ps, char *es) + { + Command *cmd = parse_exec(ps, es); + if (peek(ps, es, "|")) + { + get_token(ps, es, 0, 0); + cmd = new PipeCommand(cmd, parse_pipe(ps, es)); + } + return cmd; + } + + static Command *parse_exec(char **ps, char *es) + { + char *q, *eq; + int tok, argc; + ExecCommand *cmd = new ExecCommand(); + Command *ret = cmd; + + argc = 0; + ret = parse_redirs(ret, ps, es); + while (!peek(ps, es, "|)&;")) + { + if ((tok = get_token(ps, es, &q, &eq)) == 0) + break; + if (tok != 'a') + panic("syntax"); + + cmd->argv[argc] = q; + *eq = 0; // Temp + + argc++; + if (argc >= MAX_ARGS) + panic("too many args"); + ret = parse_redirs(ret, ps, es); + } + cmd->argv[argc] = 0; + return ret; + } + + static Command *parse_redirs(Command *cmd, char **ps, char *es) + { + int tok; + char *q, *eq; + + while (peek(ps, es, "<>")) + { + tok = get_token(ps, es, 0, 0); + if (get_token(ps, es, &q, &eq) != 'a') + panic("missing file for redirection"); + + *eq = 0; // Null terminate filename immediately + + switch (tok) + { + case '<': + cmd = new RedirCommand(cmd, q, eq, O_RDONLY, 0); + break; + case '>': + cmd = new RedirCommand(cmd, q, eq, O_WRONLY | O_CREATE | O_TRUNC, 1); + break; + case '+': // >> + cmd = new RedirCommand(cmd, q, eq, O_WRONLY | O_CREATE, 1); // Append not fully supported in simple OS yet? + break; + } + } + return cmd; + } +}; + +int getcmd(char *buf, int nbuf) +{ + write(1, "$ ", 2); + memset(buf, 0, nbuf); + + int i = 0; + while (i < nbuf - 1) + { + char c; + int n = read(0, &c, 1); + if (n <= 0) + return -1; + + if (c == '\b' || c == 127) + { + if (i > 0) + { + write(1, "\b \b", 3); + i--; + } + } + else if (c == '\n' || c == '\r') + { + write(1, "\n", 1); + buf[i] = 0; + return 0; + } + else + { + write(1, &c, 1); + buf[i++] = c; + } + } + return -1; +} + +int main() +{ + static char buf[100]; + + // int fd; + // while ((fd = open("console", O_RDWR)) >= 0) + // { + // if (fd >= 3) + // { + // close(fd); + // break; + // } + // } + + printf("\n[Lume Shell] Initialized! \n"); + + while (getcmd(buf, sizeof(buf)) >= 0) + { + if (buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ') + { + buf[strlen(buf) - 1] = 0; // chop \n + if (chdir(buf + 3) < 0) + { + printf("cannot cd %s\n", buf + 3); + } + continue; + } + + if (fork_or_panic() == 0) + { + Command *cmd = Parser::parse(buf); + if (cmd) + { + cmd->run(); + delete cmd; + } + exit(0); + } + wait(0); + } + return 0; +}
\ No newline at end of file diff --git a/src/user/usys.S b/src/user/usys.S index 65937cc..f85917e 100644 --- a/src/user/usys.S +++ b/src/user/usys.S @@ -7,8 +7,16 @@ ecall; \ ret +#define SYSCALL_NAME(name, sysname) \ + .global name; \ + name: \ + li a7, SYS_ ## sysname; \ + ecall; \ + ret + +SYSCALL_NAME(sys_exit, exit) + SYSCALL(fork) -SYSCALL(exit) SYSCALL(wait) SYSCALL(pipe) SYSCALL(read) @@ -29,4 +37,5 @@ SYSCALL(sbrk) SYSCALL(sleep) SYSCALL(uptime) SYSCALL(putc) -SYSCALL(disk_test)
\ No newline at end of file +SYSCALL(disk_test) +SYSCALL(lseek)
\ No newline at end of file |
