diff options
Diffstat (limited to '02_exercise')
-rw-r--r-- | 02_exercise/.gitignore | 2 | ||||
-rw-r--r-- | 02_exercise/shell.c | 146 |
2 files changed, 125 insertions, 23 deletions
diff --git a/02_exercise/.gitignore b/02_exercise/.gitignore new file mode 100644 index 0000000..5aacf99 --- /dev/null +++ b/02_exercise/.gitignore @@ -0,0 +1,2 @@ +prog +shell diff --git a/02_exercise/shell.c b/02_exercise/shell.c index 46b169a..ed53897 100644 --- a/02_exercise/shell.c +++ b/02_exercise/shell.c @@ -1,56 +1,156 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> - -#include <assert.h> -#include <fcntl.h> -#include <signal.h> +#include <unistd.h> #include <stdbool.h> -#include <sys/stat.h> -#include <sys/types.h> #include <sys/wait.h> -#include <unistd.h> #include "array.h" #include "prompt_utils.h" -void print_prompt(char const *const original_wd, char const *current_wd); +int parse_line(char const *line, char ***parts, size_t *part_count); -// Returns the return code of the executed programm -int exec_command(char *command); +// returns the return code of the executed program +int exec_command(const char *path, char *const argv[], unsigned timeout); int main(void) { + chdir("."); + setvbuf(stdout, NULL, _IONBF, 0); char const *const original_wd = get_current_dir_name(); char const *prompt = relative_path(original_wd, original_wd); - printf("%s \n", original_wd); - while (true) { - char *command = NULL; + bool done = false; + while (!done) { + char *line = NULL; size_t cap = 0; __ssize_t length = 0; printf("%s > ", prompt); - if ((length = getline(&command, &cap, stdin)) < 0) { + if ((length = getline(&line, &cap, stdin)) < 0) { fprintf(stderr, "Failed to read from STDIN"); exit(-1); } - if (strstr(command, "cd") != NULL) { - printf("Changing dirs \n"); - chdir("beispiele"); + + line[length - 1] = '\0'; // cut the line feed + + char **arguments = NULL; + size_t argument_count; + parse_line(line, &arguments, &argument_count); + + if (strcmp(arguments[0], "cd") == 0) { + if (arrayLen(arguments) != 3) { + fprintf(stderr, "usage: cd <path>"); + goto clean; + } + + int ret = chdir(arguments[1]); + if (ret) + printf("[%i] ", ret); + free((void *)prompt); char const *current_wd = get_current_dir_name(); prompt = relative_path(original_wd, current_wd); free((void *)current_wd); - } else if (strcmp(command, "exit\n") == 0) { - exit(0); + } else if (strcmp(arguments[0], "exit") == 0) { + done = true; } else { - exec_command(command); + int ret = exec_command(arguments[0], arguments, 0); + if (ret) + printf("[%i] ", ret); } - free((void *)command); + + clean: + free((void *)line); + while (arrayLen(arguments) > 0) { + char *tmp = arrayPop(arguments); + if (tmp) + arrayRelease(tmp); + } + arrayRelease(arguments); } - // Gotta cast to void otherwise we discard qualifiers + free((void *)original_wd); free((void *)prompt); } -int exec_command(char *command) { return 0; } +int parse_line(char const *line, char ***parts, size_t *part_count) { + char *part; + char **local_parts; + + if (arrayInit(part) != 0 || arrayInit(local_parts) != 0) { + fprintf(stderr, "Failed to prepare new part / parts array whilst parsing line"); + return -1; + } + + char c; + int i = 0; + while (true) { + c = line[i++]; + if (c == ' ' || c == '\0') { + arrayPush(part) = '\0'; + arrayPush(local_parts) = part; + if (c == '\0') { + arrayPush(local_parts) = NULL; + break; + } else { + arrayInit(part); + } + } else { + arrayPush(part) = c; + } + } + + *part_count = arrayLen(local_parts); + *parts = local_parts; + + return 0; +} + +void print_prompt() { + size_t length = 1024; + char *buffer = malloc(length * sizeof(char)); + getcwd(buffer, length); + if (buffer == NULL) { + printf(".> "); + } else { + printf("%s > ", buffer); + } +} + +int exec_command(const char *path, char *const argv[], unsigned timeout) { + timeout = timeout ^ timeout; + int pid; + int pipefd[2]; + int status; + char buf[512]; + + pipe(pipefd); + if ((pid = fork()) == 0) { + close(pipefd[0]); + dup2(pipefd[1], 1); // includes close(1); + close(pipefd[1]); + execvp(path, argv); + fprintf(stderr, "could not execute \"%s\"\n", path); + exit(-1); + } + + if (pid < 0) { + fprintf(stderr, "no fork\n"); + exit(-2); + } + + close(pipefd[1]); + + __ssize_t length = 0; + while ((length = read(pipefd[0], buf, 10)) > 0) { + buf[length] = '\0'; + fprintf(stdout, "%s", buf); + fflush(stdout); + } + + waitpid(pid, &status, 0); + + close(pipefd[0]); + + return WEXITSTATUS(status); +} |