summaryrefslogtreecommitdiff
path: root/410user/progs/shell.c
diff options
context:
space:
mode:
Diffstat (limited to '410user/progs/shell.c')
-rw-r--r--410user/progs/shell.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/410user/progs/shell.c b/410user/progs/shell.c
new file mode 100644
index 0000000..5546d7f
--- /dev/null
+++ b/410user/progs/shell.c
@@ -0,0 +1,276 @@
+/** @file 410user/progs/shell.c
+ * @author ?
+ * @brief The shell.
+ * @public yes
+ * @for p2 p3
+ * @covers fork exec wait set_status vanish print ls
+ * @status done
+ */
+
+/* --- Since we're not calling thr_init() --- */
+/* (this is sleazy violence, *not* good form) */
+#define malloc _malloc
+#define calloc _calloc
+#define realloc _realloc
+#define free _free
+
+/* --- Includes --- */
+#include <string.h>
+#include <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <simics.h>
+
+/* --- Defines --- */
+#define MAX_LENGTH 1024
+
+
+/* --- Initialized Global Strings --- */
+char prompt[] = "[410-shell]$ ";
+char startmsg[] = "Starting shell...\n";
+char exitmsg[] = "Exiting shell...\n";
+char forkerrmsg[] = "Shell: Cannot fork process.\n";
+char waitfailed[] = "wait() failed\n";
+char finished[] = "Process finished\n";
+char too_long[] = "That string is too long.\n";
+char null_check[] = "I've lost null termination!\n";
+char nothing[] = "Readline returned nothing!\n";
+
+/* --- These are global only to avoid stack growth --- */
+/* (unclean, but lets the shell run before swexn() and new_pages()) */
+char buf[MAX_LENGTH];
+char *cmd_argv[MAX_LENGTH];
+char separators[4] = { ' ', '\t', '\n' };
+
+static void print_ls(void);
+static void sort_names(char **names, int num_entries);
+static int mystical_readline(int len, char *buf);
+static int console_height(void);
+
+/* Not all kernels support getchar().
+ *
+ * Try to use it, but if it doesn't work fall back to readline().
+ */
+static int fallback_getchar(void)
+{
+ char buf[2];
+
+ mystical_readline(2, buf);
+
+ return (unsigned char)buf[0]; // cast prevents sign extension
+}
+
+static int try_getchar(void)
+{
+ static int missing_getchar = 0;
+ int c;
+
+ if (missing_getchar || (c = getchar()) < 0) {
+ missing_getchar = 1;
+ return fallback_getchar();
+ }
+ return c;
+}
+#define getchar try_getchar
+
+/* --- Main --- */
+int
+main(int argc, char *argv[])
+{
+ int n;
+ int pid;
+ int res;
+ int j;
+ int ret;
+
+ print(strlen(startmsg), startmsg);
+
+ while(1) {
+
+ bzero(buf, MAX_LENGTH);
+ print(strlen(prompt), prompt);
+ n = mystical_readline(MAX_LENGTH - 1, buf);
+ if (n == 0) {
+ /* Empty result; this shouldn't happen. */
+ print(strlen(nothing), nothing);
+ continue;
+ } else if(n >= MAX_LENGTH) {
+ /* line too big -- kernel declared that it clobbered memory */
+ print(strlen(too_long), too_long);
+ exit(-1);
+ } else if(buf[MAX_LENGTH - 1] != '\0') {
+ /* Overflow -- kernel tapdanced on random memory! */
+ print(strlen(null_check), null_check);
+ exit(-1);
+ }
+
+ buf[n] = '\0';
+ j = 0;
+ if(!(cmd_argv[j++] = strtok(buf, separators))) {
+ continue;
+ }
+ if((strcmp(cmd_argv[0], "exit") == 0)) {
+ print(strlen(exitmsg), exitmsg);
+ exit(0);
+ }
+ if((strcmp(cmd_argv[0], "ls") == 0)) {
+ print_ls();
+ continue;
+ }
+
+ while((cmd_argv[j++] = strtok(NULL, separators)));
+
+ pid = fork();
+ if(pid < 0) {
+ print(sizeof(forkerrmsg), forkerrmsg);
+ continue;
+ }
+ if(pid == 0) {
+ exec(cmd_argv[0], cmd_argv);
+ exit(-1);
+ }
+ else {
+ if((ret = wait(&res)) < 0) {
+ printf("\nshell: wait on process %d failed!\n", pid);
+ }
+ else {
+ printf("\nshell: process %d finished with exit status %d\n", ret, res);
+ }
+ }
+ } /* while loop */
+}
+
+/* emulate the old ls() system call using readfile() */
+int ls(int size, char *buf)
+{
+ int i;
+ int num_files = 0;
+ int amt_read;
+
+ amt_read = readfile(".", buf, size, 0);
+ if (amt_read < 0) return amt_read;
+ /* ls() returned failure if the buffer wasn't big enough for the
+ * entire listing. So if readfile() didn't return short (that is,
+ * there might be more), fail. */
+ if (amt_read == size) return -1;
+
+ /* Now scan through the buffer counting null terminators.
+ * Skip the one at the end. */
+ for (i = 0; i < amt_read - 1; i++) {
+ if (buf[i] == '\0') {
+ num_files++;
+ }
+ }
+
+ return num_files;
+}
+
+static void print_ls()
+{
+ char *buf = NULL;
+ static int size = 16;
+ int num_entries;
+ char ** names = NULL;
+ char *bufptr;
+ int index;
+ int len;
+
+ /* get the array of entries */
+ buf = (char *)malloc(sizeof(char) * size);
+ if (buf == NULL) {
+ printf("Can't malloc(%d)!\n", sizeof(char) * size);
+ goto cleanup;
+ }
+ while ((num_entries = ls(size, buf)) < 0) {
+ size *= 2;
+ char *nbuf = (char *)realloc(buf, sizeof(char) * size);
+ if (nbuf == NULL) {
+ printf("Can't realloc(%d)!\n", sizeof(char) * size);
+ goto cleanup;
+ } else {
+ buf = nbuf;
+ }
+ }
+
+ names = (char **)calloc(num_entries, sizeof(char *));
+ if (names == NULL) {
+ printf("Can't calloc(%d)!\n", num_entries * sizeof(char *));
+ goto cleanup;
+ }
+
+ /* get pointers to each string in the array */
+ bufptr = buf;
+ index = 0;
+ while ((len = strlen(bufptr)) > 0) {
+ names[index++] = bufptr;
+ bufptr += len + 1;
+ }
+
+ sort_names(names, num_entries);
+
+ printf("Listing the user tests\n");
+ for (index = 0; index < num_entries; index++) {
+ if (index != 0 && index % (console_height() - 2) == 0) {
+ printf("Hit a key to continue\n");
+ getchar();
+ }
+ printf("%s\n", names[index]);
+ }
+
+cleanup:
+ if (buf) {
+ free(buf);
+ buf = NULL;
+ }
+ if (names) {
+ free(names);
+ names = NULL;
+ }
+}
+
+static void sort_names(char **names, int num_entries) {
+ /* I invented this cool new sorting algorithm! It's really fast! */
+ int swapped;
+ int i;
+ do {
+ swapped = 0;
+ for (i = 0; i < num_entries - 1; i++) {
+ if (strcmp(names[i], names[i+1]) > 0) {
+ char *tmp = names[i];
+ names[i] = names[i+1];
+ names[i+1] = tmp;
+ swapped = 1;
+ }
+ }
+ } while (swapped);
+}
+
+static int mystical_readline(int len, char *buf) {
+ if (len <= 0) { return 0; }
+
+ buf[0] = '\0';
+ /* If we're in the test harness, this does something very special! */
+ sim_call(0x04108005, buf, len);
+
+ return (buf[0] ? strlen(buf) : readline(len, buf));
+}
+
+static int console_height() {
+ static int console_height = -1;
+
+ if (console_height == -1) {
+ /* determine the height of the console */
+ int curstartrow, curstartcol;
+ get_cursor_pos(&curstartrow, &curstartcol);
+ console_height = 0;
+ while (set_cursor_pos(console_height, 0) == 0) {
+ console_height++;
+ }
+ set_cursor_pos(curstartrow, curstartcol);
+
+ }
+
+ return console_height;
+}