summaryrefslogtreecommitdiff
path: root/userland/sh
diff options
context:
space:
mode:
Diffstat (limited to 'userland/sh')
-rw-r--r--userland/sh/Makefile13
-rwxr-xr-xuserland/sh/shbin0 -> 44776 bytes
-rw-r--r--userland/sh/sh.c224
-rwxr-xr-xuserland/sh/sh_abin0 -> 9200 bytes
-rwxr-xr-xuserland/sh/sh_badbin0 -> 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
new file mode 100755
index 0000000..7791495
--- /dev/null
+++ b/userland/sh/sh
Binary files differ
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
new file mode 100755
index 0000000..7b435ab
--- /dev/null
+++ b/userland/sh/sh_a
Binary files differ
diff --git a/userland/sh/sh_bad b/userland/sh/sh_bad
new file mode 100755
index 0000000..7f93418
--- /dev/null
+++ b/userland/sh/sh_bad
Binary files differ