diff options
author | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
commit | 4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch) | |
tree | 80f156b7940d9d19971395f335530170c69516c7 /userland/sh |
Move everything into a new repo.
Diffstat (limited to 'userland/sh')
-rw-r--r-- | userland/sh/Makefile | 13 | ||||
-rwxr-xr-x | userland/sh/sh | bin | 0 -> 44776 bytes | |||
-rw-r--r-- | userland/sh/sh.c | 224 | ||||
-rwxr-xr-x | userland/sh/sh_a | bin | 0 -> 9200 bytes | |||
-rwxr-xr-x | userland/sh/sh_bad | bin | 0 -> 9188 bytes |
5 files changed, 237 insertions, 0 deletions
diff --git a/userland/sh/Makefile b/userland/sh/Makefile new file mode 100644 index 0000000..adccfb3 --- /dev/null +++ b/userland/sh/Makefile @@ -0,0 +1,13 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough -fsanitize=shift,signed-integer-overflow,bounds +BINS=sh +all: $(BINS) + +sh.o: sh.c + $(CC) $(CFLAGS) -L../libc/ -lc -c sh.c -I../libc/ +# $(CC) $(CFLAGS) ../libc/libc.o ../libc/crt0.o sh.c -I../libc/ + +clean: + rm sh sh.o +sh: sh.o + $(CC) -shared -o sh -ffreestanding -nostdlib $(CFLAGS) sh.o -L../libc/ -lc -lgcc #-L../libc/c.a diff --git a/userland/sh/sh b/userland/sh/sh Binary files differnew file mode 100755 index 0000000..7791495 --- /dev/null +++ b/userland/sh/sh diff --git a/userland/sh/sh.c b/userland/sh/sh.c new file mode 100644 index 0000000..5fe7f63 --- /dev/null +++ b/userland/sh/sh.c @@ -0,0 +1,224 @@ +#include <assert.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#define MAX_ARGS 20 + +#define IS_SPECIAL(_c) (';' == _c || '\n' == _c || '&' == _c || '|' == _c) + +char *PATH = "/:/bin"; + +int can_open(char *f) { + int rc; + if (-1 == (rc = open(f, O_RDONLY, 0))) + return 0; + close(rc); + return 1; +} + +int find_path(char *file, char *buf) { + if ('/' == *file || '.' == *file) { // Real path + if (!can_open(file)) { + return 0; + } + strcpy(buf, file); + return 1; + } + + char *p = PATH; + for (;;) { + char *b = p; + for (; *p && ':' != *p; p++) + ; + size_t l = p - b; + strlcpy(buf, b, l); + strcat(buf, "/"); + strcat(buf, file); + if (can_open(buf)) { + return 1; + } + if (!*p) + break; + p++; + } + return 0; +} + +int internal_exec(char *file, char **argv) { + char r_path[PATH_MAX]; + if (!find_path(file, r_path)) + return 0; + if (-1 == execv(r_path, argv)) { + perror("exec"); + return 0; + } + return 1; +} + +int execute_program(char *s, size_t l, int ignore_rc, int f_stdout, + int *new_out) { + if (!l) + return -1; + + char c[l + 1]; + memcpy(c, s, l); + c[l] = 0; + + char *argv[MAX_ARGS]; + int args = 0; + char *p = c; + for (size_t i = 0; i <= l; i++) { + if (' ' == c[i]) { + if (p == c + i) { + for (; ' ' == *p; p++, i++) + ; + i--; + continue; + } + c[i] = '\0'; + + if (strlen(p) == 0) + break; + + argv[args] = p; + args++; + p = c + i + 1; + } else if (i == l) { + if (strlen(p) == 0) + break; + argv[args] = p; + args++; + } + } + argv[args] = NULL; + + int fd[2]; + pipe(fd); + + int pid = fork(); + if (0 == pid) { + if (new_out) + dup2(fd[1], 1); + if (-1 != f_stdout) + dup2(f_stdout, 0); + close(fd[0]); + if (!internal_exec(argv[0], argv)) { + printf("exec failed\n"); + exit(1); + } + } + + close(fd[1]); + if (new_out) + *new_out = fd[0]; + + if (ignore_rc) + return 0; + + int rc; + wait(&rc); + return rc; +} + +int compute_expression(char *exp) { + char *n = exp; + int ignore_next = 0; + int rc; + int f_stdout = -1; + int new_out = f_stdout; + for (; *exp; exp++) { + if (!IS_SPECIAL(*exp)) { + continue; + } + if ('\n' == *exp) + break; + if (';' == *exp) { + if (!ignore_next) { + execute_program(n, exp - n, 0, f_stdout, NULL); + } + n = exp + 1; + continue; + } + if ('&' == *exp && '&' == *(exp + 1)) { + if (!ignore_next) { + rc = execute_program(n, exp - n, 0, f_stdout, NULL); + if (0 != rc) + ignore_next = 1; + } + n = exp + 2; + exp++; + continue; + } else if ('&' == *exp) { + if (!ignore_next) { + execute_program(n, exp - n, 1, f_stdout, NULL); + } + n = exp + 1; + continue; + } + if ('|' == *exp && '|' == *(exp + 1)) { + if (!ignore_next) { + rc = execute_program(n, exp - n, 0, f_stdout, NULL); + if (0 == rc) + ignore_next = 1; + } + n = exp + 2; + exp++; + continue; + } else if ('|' == *exp) { + if (!ignore_next) { + execute_program(n, exp - n, 1, f_stdout, &new_out); + f_stdout = new_out; + } + n = exp + 1; + continue; + } + } + if (!ignore_next) + rc = execute_program(n, exp - n, 0, f_stdout, NULL); + return rc; +} + +char *get_line(void) { + char *str = malloc(1024); + char *p = str; + int rc; + for (;;) { + if (0 == (rc = read(0, p, 1))) { + continue; + } + if (0 > rc) { + perror("read"); + continue; + } + if (8 == *p) { + if (p == str) + continue; + putchar(*p); + p--; + continue; + } + putchar(*p); + if ('\n' == *p) { + break; + } + p++; + } + p++; + *p = '\0'; + return str; +} + +int main(void) { + for (;;) { + printf("/ : "); + char *l = get_line(); + compute_expression(l); + free(l); + } + return 0; +} diff --git a/userland/sh/sh_a b/userland/sh/sh_a Binary files differnew file mode 100755 index 0000000..7b435ab --- /dev/null +++ b/userland/sh/sh_a diff --git a/userland/sh/sh_bad b/userland/sh/sh_bad Binary files differnew file mode 100755 index 0000000..7f93418 --- /dev/null +++ b/userland/sh/sh_bad |