From fd4fd05f2ca784030625f1f4ea5afc156b46a283 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Tue, 6 Jul 2021 23:35:13 -0400 Subject: [PATCH 01/27] fix leak in child process --- src/launch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/launch.c b/src/launch.c index 478e97b..e0fc300 100644 --- a/src/launch.c +++ b/src/launch.c @@ -39,6 +39,7 @@ void launch_program(StringArray *args) { execvp(args->array[0], argv); fprintf(stderr, "%s: command not found\n", args->array[0]); + free_string_array(args); exit(EXIT_FAILURE); } else if (child < 0) { From cc153bd481c0c0e89a44c5cff33772d8fb609390 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Tue, 6 Jul 2021 23:47:19 -0400 Subject: [PATCH 02/27] add memory cleanup at exit --- src/include/array.h | 5 +++++ src/loop.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/include/array.h b/src/include/array.h index cdf048a..23a70d3 100644 --- a/src/include/array.h +++ b/src/include/array.h @@ -22,6 +22,11 @@ typedef struct { size_t size; } StringArray; +typedef struct { + void **array; + size_t size; +} CleanArray; + void create_string_array(StringArray *string_array); void insert_string_array(StringArray *string_array, char *string); diff --git a/src/loop.c b/src/loop.c index 67b8105..15cdf18 100644 --- a/src/loop.c +++ b/src/loop.c @@ -22,10 +22,39 @@ #include "console_line.h" #include "launch.h" +static CleanArray clean; + +/** + * Add memory address to array to be cleaned up later. + * @param data The data to be cleaned up on exit. + */ +void add_to_cleanup(void *data) { + clean.array = realloc(clean.array, (clean.size + 1) * sizeof(void *)); + clean.array[clean.size++] = data; +} + +/** + * Cleanup memory when exiting. + */ +void exit_cleanup() { + for (size_t i = 0; i < clean.size; i++) { + if (clean.array[i] != NULL) { + free(clean.array[i]); + clean.array[i] = NULL; + } + } + if (clean.array != NULL) { + free(clean.array); + clean.array = NULL; + } +} + /** * This is the loop that checks for user input and acts on it. */ void loop() { + clean.size = 0; + atexit(exit_cleanup); while (1) { print_input_line(); From b9b6d60aff632bf42b8dae43af62b0109f87d354 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Tue, 6 Jul 2021 23:54:18 -0400 Subject: [PATCH 03/27] change variable type to size_t --- src/array.c | 4 ++-- src/launch.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array.c b/src/array.c index 5e41e1c..55bcff4 100644 --- a/src/array.c +++ b/src/array.c @@ -62,7 +62,7 @@ void insert_string_array(StringArray *string_array, char *string) { */ void delete_string_array(StringArray *string_array, int index) { if (string_array->array != NULL && string_array->size > 0 && string_array->size > index) { - for (int i = index; i < string_array->size - 1; i++) { + for (size_t i = index; i < string_array->size - 1; i++) { free(string_array->array[i]); string_array->array[i] = NULL; string_array->array[i] = malloc(sizeof(string_array->array[i + 1])); @@ -99,7 +99,7 @@ void free_string_array(StringArray *string_array) { exit(EXIT_FAILURE); } else { - for (int i = 0; i < string_array->size; i++) { + for (size_t i = 0; i < string_array->size; i++) { if (string_array->array[i] != NULL) { free(string_array->array[i]); string_array->array[i] = NULL; diff --git a/src/launch.c b/src/launch.c index e0fc300..128c07b 100644 --- a/src/launch.c +++ b/src/launch.c @@ -32,7 +32,7 @@ void launch_program(StringArray *args) { if (child == 0) { // Copy the array and add a NULL to the end of it char *argv[args->size + 1]; - for (int i = 0; i < args->size; i++) { + for (size_t i = 0; i < args->size; i++) { argv[i] = args->array[i]; } argv[args->size] = NULL; From 2d6303e311cc583720242308497d7f33028e0d7b Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 7 Jul 2021 00:00:31 -0400 Subject: [PATCH 04/27] check for failure on realloc --- src/loop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/loop.c b/src/loop.c index 15cdf18..443b5e0 100644 --- a/src/loop.c +++ b/src/loop.c @@ -30,6 +30,10 @@ static CleanArray clean; */ void add_to_cleanup(void *data) { clean.array = realloc(clean.array, (clean.size + 1) * sizeof(void *)); + if (clean.array == NULL) { + perror("realloc"); + exit(EXIT_FAILURE); + } clean.array[clean.size++] = data; } From 1b68196f1627755620e67a5a4e5b8a53c2373c0a Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 7 Jul 2021 00:21:55 -0400 Subject: [PATCH 05/27] add missing definitions to loop header --- src/include/loop.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/include/loop.h b/src/include/loop.h index 0586ad7..5b02bf2 100644 --- a/src/include/loop.h +++ b/src/include/loop.h @@ -15,5 +15,9 @@ #ifndef _MYSHELLIN_LOOP #define _MYSHELLIN_LOOP +void add_to_cleanup(void *data); + +void exit_cleanup(); + void loop(); #endif From e548acdb8a7ce3cb7766b5ea505ddf0d41c87320 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Fri, 16 Jul 2021 13:35:29 -0400 Subject: [PATCH 06/27] change the way string arrays are initialized --- src/array.c | 35 +++++++++++++++++------------------ src/include/array.h | 2 +- src/loop.c | 15 +++++++-------- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/array.c b/src/array.c index 55bcff4..cf60ace 100644 --- a/src/array.c +++ b/src/array.c @@ -19,11 +19,13 @@ /** * Create a String Array by initializing its structure. - * @param string_array The String Array to create. + * @return Returns a new String Array. */ -void create_string_array(StringArray *string_array) { +StringArray *create_string_array() { + StringArray *string_array = malloc(sizeof(StringArray)); string_array->array = NULL; string_array->size = 0; + return string_array; } /** @@ -93,22 +95,19 @@ void delete_string_array(StringArray *string_array, int index) { * @param string_array The String Array to free. */ void free_string_array(StringArray *string_array) { - if (string_array->array == NULL) { - fprintf(stderr, "StringArray is not freeable!\n"); - free_string_array(string_array); - exit(EXIT_FAILURE); + for (size_t i = 0; i < string_array->size; i++) { + if (string_array->array[i] != NULL) { + free(string_array->array[i]); + string_array->array[i] = NULL; + } } - else { - for (size_t i = 0; i < string_array->size; i++) { - if (string_array->array[i] != NULL) { - free(string_array->array[i]); - string_array->array[i] = NULL; - } - } - if (string_array->array != NULL) { - free(string_array->array); - string_array->array = NULL; - } - string_array->size = 0; + if (string_array->array != NULL) { + free(string_array->array); + string_array->array = NULL; + } + string_array->size = 0; + if (string_array != NULL) { + free(string_array); + string_array = NULL; } } diff --git a/src/include/array.h b/src/include/array.h index 23a70d3..a30e90d 100644 --- a/src/include/array.h +++ b/src/include/array.h @@ -27,7 +27,7 @@ typedef struct { size_t size; } CleanArray; -void create_string_array(StringArray *string_array); +StringArray *create_string_array(); void insert_string_array(StringArray *string_array, char *string); diff --git a/src/loop.c b/src/loop.c index 443b5e0..e7d2aad 100644 --- a/src/loop.c +++ b/src/loop.c @@ -64,13 +64,12 @@ void loop() { char *line = get_console_input(); - StringArray args; - create_string_array(&args); + StringArray *args = create_string_array(); char *saveptr = NULL; char *token = strtok_r(line, " ", &saveptr); while (token) { - insert_string_array(&args, token); + insert_string_array(args, token); token = strtok_r(NULL, " ", &saveptr); } if (line != NULL) { @@ -79,17 +78,17 @@ void loop() { } // The user didn't type anything so restart the loop - if (args.size == 0) { + if (args->size == 0) { continue; } - if (is_builtin(args.array[0])) { - run_builtin(&args); + if (is_builtin(args->array[0])) { + run_builtin(args); } else { - launch_program(&args); + launch_program(args); } - free_string_array(&args); + free_string_array(args); } } From 1cbe850a108177621ad584de919629c51f4361b9 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Fri, 16 Jul 2021 13:36:25 -0400 Subject: [PATCH 07/27] fix memory leak when user doesn't enter anything --- src/loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/loop.c b/src/loop.c index e7d2aad..5aaf20e 100644 --- a/src/loop.c +++ b/src/loop.c @@ -79,6 +79,7 @@ void loop() { // The user didn't type anything so restart the loop if (args->size == 0) { + free_string_array(args); continue; } From 6c3f8259e9dd5d30e27e214d363a5eef0760a479 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Fri, 16 Jul 2021 14:16:53 -0400 Subject: [PATCH 08/27] make StringArrays NULL terminated --- src/array.c | 16 +++++++++++++--- src/launch.c | 14 ++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/array.c b/src/array.c index cf60ace..0c2bbed 100644 --- a/src/array.c +++ b/src/array.c @@ -23,6 +23,10 @@ */ StringArray *create_string_array() { StringArray *string_array = malloc(sizeof(StringArray)); + if (string_array == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } string_array->array = NULL; string_array->size = 0; return string_array; @@ -35,25 +39,30 @@ StringArray *create_string_array() { */ void insert_string_array(StringArray *string_array, char *string) { if (string_array->size == 0) { - string_array->array = malloc(sizeof(char *)); + string_array->array = malloc(2 * sizeof(char *)); if (string_array->array == NULL) { perror("malloc"); + free_string_array(string_array); exit(EXIT_FAILURE); } } else { - string_array->array = realloc(string_array->array, (string_array->size + 1) * sizeof(char *)); + string_array->array = realloc(string_array->array, (string_array->size + 2) * sizeof(char *)); if (string_array->array == NULL) { perror("realloc"); + free_string_array(string_array); exit(EXIT_FAILURE); } } string_array->array[string_array->size] = malloc(sizeof(string)); if (string_array->array == NULL) { perror("malloc"); + free_string_array(string_array); exit(EXIT_FAILURE); } strcpy(string_array->array[string_array->size], string); + // A NULL terminated array + string_array->array[string_array->size + 1] = NULL; string_array->size++; } @@ -76,9 +85,10 @@ void delete_string_array(StringArray *string_array, int index) { } free(string_array->array[string_array->size - 1]); string_array->array[string_array->size - 1] = NULL; - string_array->array = realloc(string_array->array, (string_array->size - 1) * sizeof(char *)); + string_array->array = realloc(string_array->array, (string_array->size) * sizeof(char *)); if (string_array->array == NULL) { perror("realloc"); + free_string_array(string_array); exit(EXIT_FAILURE); } string_array->size--; diff --git a/src/launch.c b/src/launch.c index 128c07b..00b8938 100644 --- a/src/launch.c +++ b/src/launch.c @@ -30,17 +30,11 @@ void launch_program(StringArray *args) { child = fork(); if (child == 0) { - // Copy the array and add a NULL to the end of it - char *argv[args->size + 1]; - for (size_t i = 0; i < args->size; i++) { - argv[i] = args->array[i]; + if (execvp(args->array[0], args->array) == -1) { + fprintf(stderr, "%s: command not found\n", args->array[0]); + free_string_array(args); + exit(EXIT_FAILURE); } - argv[args->size] = NULL; - - execvp(args->array[0], argv); - fprintf(stderr, "%s: command not found\n", args->array[0]); - free_string_array(args); - exit(EXIT_FAILURE); } else if (child < 0) { perror("fork"); From 9c5752e9a9210056424b9ee4592183d5c438342b Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Fri, 16 Jul 2021 22:52:26 -0400 Subject: [PATCH 09/27] add environment variables --- src/array.c | 97 +++++++++++++++++++++++++++++++++++++++++++-- src/builtins.c | 3 ++ src/console_line.c | 7 ++-- src/include/array.h | 19 +++++++++ src/loop.c | 6 ++- 5 files changed, 124 insertions(+), 8 deletions(-) diff --git a/src/array.c b/src/array.c index 0c2bbed..30d2a92 100644 --- a/src/array.c +++ b/src/array.c @@ -38,7 +38,7 @@ StringArray *create_string_array() { * @param string The string to insert into the String Array. */ void insert_string_array(StringArray *string_array, char *string) { - if (string_array->size == 0) { + if (string_array->array == NULL) { string_array->array = malloc(2 * sizeof(char *)); if (string_array->array == NULL) { perror("malloc"); @@ -54,7 +54,7 @@ void insert_string_array(StringArray *string_array, char *string) { exit(EXIT_FAILURE); } } - string_array->array[string_array->size] = malloc(sizeof(string)); + string_array->array[string_array->size] = malloc(strlen(string) * sizeof(char *)); if (string_array->array == NULL) { perror("malloc"); free_string_array(string_array); @@ -76,7 +76,7 @@ void delete_string_array(StringArray *string_array, int index) { for (size_t i = index; i < string_array->size - 1; i++) { free(string_array->array[i]); string_array->array[i] = NULL; - string_array->array[i] = malloc(sizeof(string_array->array[i + 1])); + string_array->array[i] = malloc(strlen(string_array->array[i + 1]) * sizeof(char *)); if (string_array->array[i] == NULL) { perror("malloc"); exit(EXIT_FAILURE); @@ -121,3 +121,94 @@ void free_string_array(StringArray *string_array) { string_array = NULL; } } + +/** + * Create a new Array List. + * @return Returns the newly created Array List. + */ +ArrayList *create_array_list() { + ArrayList *array_list = malloc(sizeof(ArrayList)); + if (array_list == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + array_list->keys = NULL; + array_list->values = NULL; + array_list->size = 0; + return array_list; +} + +/** + * Set a key inside the Array List. + * @param array_list The Array List to work on. + * @param key The key to insert/update. + * @param value The value to insert/update. + */ +void set_array_list(ArrayList *array_list, char *key, char *value) { + if (array_list->keys == NULL) { + array_list->keys = create_string_array(); + array_list->values = create_string_array(); + } + for (size_t i = 0; i < array_list->size; i++) { + if (strcmp(array_list->keys->array[i], key) == 0) { + array_list->values->array[i] = realloc(array_list->values->array[i], strlen(value) * sizeof(char *)); + strcpy(array_list->values->array[i], value); + if (array_list->values->array[i] == NULL) { + perror("realloc"); + exit(EXIT_FAILURE); + } + return; + } + } + insert_string_array(array_list->keys, key); + insert_string_array(array_list->values, value); + array_list->size++; +} + +/** + * Get a value based on a key from an Array List. + * @param array_list The Array List to work on. + * @param key The key to search for. + * @return Returns the value if the key is found in the Array List otherwise it returns NULL. + */ +char *get_array_list(ArrayList *array_list, char *key) { + if (array_list->keys != NULL) { + for (size_t i = 0; i < array_list->size; i++) { + if (strcmp(array_list->keys->array[i], key) == 0) { + return array_list->values->array[i]; + } + } + } + return NULL; +} + +/** + * Remove a key from the Array List. + * @param array_list The Array List to work on. + * @param key The key to remove. + */ +void unset_array_list(ArrayList *array_list, char *key) { + if (array_list->keys != NULL) { + for (size_t i = 0; i < array_list->size; i++) { + if (strcmp(array_list->keys->array[i], key) == 0) { + delete_string_array(array_list->keys, i); + delete_string_array(array_list->values, i); + array_list->size--; + return; + } + } + } +} + +/** + * Free all the memory used in the Array List. + * @param array_list The Array List to free. + */ +void free_array_list(ArrayList *array_list) { + if (array_list != NULL) { + free_string_array(array_list->keys); + free_string_array(array_list->values); + free(array_list); + array_list = NULL; + } +} diff --git a/src/builtins.c b/src/builtins.c index 1f33298..586f82c 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -84,5 +84,8 @@ void change_directory(StringArray *args) { if (chdir(args->array[1]) != 0) { perror("cd"); } + else { + set_array_list(variables, "PWD", get_working_directory()); + } } } diff --git a/src/console_line.c b/src/console_line.c index 6c31c86..6af95c6 100644 --- a/src/console_line.c +++ b/src/console_line.c @@ -21,6 +21,7 @@ #include #include #include +#include "array.h" #include "color.h" #include "console_line.h" @@ -37,7 +38,7 @@ void remove_new_line(char* line) { * @return Returns the logged in user's username. */ char *get_username() { - struct passwd *pass; + struct passwd *pass = NULL; pass = getpwuid(getuid()); if (pass == NULL) { perror("getpwuid"); @@ -67,8 +68,8 @@ char *get_hostname() { * @return Returns the current working directory. */ char *get_working_directory() { - char *cwd = NULL; - cwd = getcwd(NULL, PATH_MAX); + char *cwd = malloc(PATH_MAX * sizeof(char *)); + getcwd(cwd, PATH_MAX); if (cwd == NULL) { perror("getcwd"); exit(EXIT_FAILURE); diff --git a/src/include/array.h b/src/include/array.h index a30e90d..1b046c0 100644 --- a/src/include/array.h +++ b/src/include/array.h @@ -27,6 +27,15 @@ typedef struct { size_t size; } CleanArray; +typedef struct { + StringArray *keys; + StringArray *values; + size_t size; +} ArrayList; + +CleanArray clean; +ArrayList *variables; + StringArray *create_string_array(); void insert_string_array(StringArray *string_array, char *string); @@ -34,4 +43,14 @@ void insert_string_array(StringArray *string_array, char *string); void delete_string_array(StringArray *string_array, int index); void free_string_array(StringArray *string_array); + +ArrayList *create_array_list(); + +void set_array_list(ArrayList *array_list, char *key, char *value); + +char *get_array_list(ArrayList *array_list, char *key); + +void unset_array_list(ArrayList *array_list, char *key); + +void free_array_list(ArrayList *array_list); #endif diff --git a/src/loop.c b/src/loop.c index 5aaf20e..8860444 100644 --- a/src/loop.c +++ b/src/loop.c @@ -22,8 +22,6 @@ #include "console_line.h" #include "launch.h" -static CleanArray clean; - /** * Add memory address to array to be cleaned up later. * @param data The data to be cleaned up on exit. @@ -51,6 +49,7 @@ void exit_cleanup() { free(clean.array); clean.array = NULL; } + free_array_list(variables); } /** @@ -58,7 +57,10 @@ void exit_cleanup() { */ void loop() { clean.size = 0; + variables = create_array_list(); atexit(exit_cleanup); + set_array_list(variables, "PWD", get_working_directory()); + while (1) { print_input_line(); From 8e0fb008941d4afcd4cfc9ba5088ac3f12952c99 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Fri, 16 Jul 2021 22:54:34 -0400 Subject: [PATCH 10/27] ignore compile_commands.json --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 788e736..e3dc13e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ myshellin *.gz *.aux *.out +compile_commands.json From 8874104c4c6a4eaaeb0584560436f9c343f4dbcd Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Fri, 16 Jul 2021 23:24:24 -0400 Subject: [PATCH 11/27] ignore .clangd --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e3dc13e..ba02aa4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ myshellin *.aux *.out compile_commands.json +.clangd From 66dcc66fd98b8a8c080089b4e48a5b051024b463 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Fri, 16 Jul 2021 23:37:15 -0400 Subject: [PATCH 12/27] move comments to headers --- src/array.c | 43 ------------------- src/builtins.c | 17 -------- src/console_line.c | 23 ---------- src/include/array.h | 86 ++++++++++++++++++++++++++++++++++++++ src/include/builtins.h | 19 +++++++++ src/include/console_line.h | 25 +++++++++++ src/include/launch.h | 6 +++ src/include/loop.h | 12 ++++++ src/launch.c | 4 -- src/loop.c | 10 ----- 10 files changed, 148 insertions(+), 97 deletions(-) diff --git a/src/array.c b/src/array.c index 30d2a92..c8a21a7 100644 --- a/src/array.c +++ b/src/array.c @@ -17,10 +17,6 @@ #include #include "array.h" -/** - * Create a String Array by initializing its structure. - * @return Returns a new String Array. - */ StringArray *create_string_array() { StringArray *string_array = malloc(sizeof(StringArray)); if (string_array == NULL) { @@ -32,11 +28,6 @@ StringArray *create_string_array() { return string_array; } -/** - * Insert a string into the String Array. - * @param string_array The String Array to insert into. - * @param string The string to insert into the String Array. - */ void insert_string_array(StringArray *string_array, char *string) { if (string_array->array == NULL) { string_array->array = malloc(2 * sizeof(char *)); @@ -66,11 +57,6 @@ void insert_string_array(StringArray *string_array, char *string) { string_array->size++; } -/** - * Delete a string from the String Array. - * @param string_array The String Array to delete from. - * @param index The index in the String Array to delete. - */ void delete_string_array(StringArray *string_array, int index) { if (string_array->array != NULL && string_array->size > 0 && string_array->size > index) { for (size_t i = index; i < string_array->size - 1; i++) { @@ -100,10 +86,6 @@ void delete_string_array(StringArray *string_array, int index) { } } -/** - * Free the String Array and all of its strings. - * @param string_array The String Array to free. - */ void free_string_array(StringArray *string_array) { for (size_t i = 0; i < string_array->size; i++) { if (string_array->array[i] != NULL) { @@ -122,10 +104,6 @@ void free_string_array(StringArray *string_array) { } } -/** - * Create a new Array List. - * @return Returns the newly created Array List. - */ ArrayList *create_array_list() { ArrayList *array_list = malloc(sizeof(ArrayList)); if (array_list == NULL) { @@ -138,12 +116,6 @@ ArrayList *create_array_list() { return array_list; } -/** - * Set a key inside the Array List. - * @param array_list The Array List to work on. - * @param key The key to insert/update. - * @param value The value to insert/update. - */ void set_array_list(ArrayList *array_list, char *key, char *value) { if (array_list->keys == NULL) { array_list->keys = create_string_array(); @@ -165,12 +137,6 @@ void set_array_list(ArrayList *array_list, char *key, char *value) { array_list->size++; } -/** - * Get a value based on a key from an Array List. - * @param array_list The Array List to work on. - * @param key The key to search for. - * @return Returns the value if the key is found in the Array List otherwise it returns NULL. - */ char *get_array_list(ArrayList *array_list, char *key) { if (array_list->keys != NULL) { for (size_t i = 0; i < array_list->size; i++) { @@ -182,11 +148,6 @@ char *get_array_list(ArrayList *array_list, char *key) { return NULL; } -/** - * Remove a key from the Array List. - * @param array_list The Array List to work on. - * @param key The key to remove. - */ void unset_array_list(ArrayList *array_list, char *key) { if (array_list->keys != NULL) { for (size_t i = 0; i < array_list->size; i++) { @@ -200,10 +161,6 @@ void unset_array_list(ArrayList *array_list, char *key) { } } -/** - * Free all the memory used in the Array List. - * @param array_list The Array List to free. - */ void free_array_list(ArrayList *array_list) { if (array_list != NULL) { free_string_array(array_list->keys); diff --git a/src/builtins.c b/src/builtins.c index 586f82c..142c368 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -21,11 +21,6 @@ #include "builtins.h" #include "console_line.h" -/** - * Check if the command is a builtin or not. - * @param command String with the command name to check. - * @return Returns true if it's a builtin or false otherwise. - */ bool is_builtin(char *command) { if (strcmp(command, "exit") == 0) { return true; @@ -38,10 +33,6 @@ bool is_builtin(char *command) { return false; } -/** - * Run the builtin command. - * @param args An array of strings containing the arguments to run. - */ void run_builtin(StringArray *args) { if (strcmp(args->array[0], "exit") == 0) { exit_shell(args); @@ -54,19 +45,11 @@ void run_builtin(StringArray *args) { } } -/** - * Exit the shell. - * @param args The arguments that were used to call exit. This is used to free the memory before exit. - */ void exit_shell(StringArray *args) { free_string_array(args); exit(EXIT_SUCCESS); } -/** - * Change the directory to what the user inputs. - * @param args The arguments the user input. - */ void change_directory(StringArray *args) { if (args->size > 2) { fprintf(stderr, "Too many arguments!\n"); diff --git a/src/console_line.c b/src/console_line.c index 6af95c6..042bb07 100644 --- a/src/console_line.c +++ b/src/console_line.c @@ -25,18 +25,10 @@ #include "color.h" #include "console_line.h" -/** - * Remove new line from the end of a string. - * @param line The string to remove the new line from. - */ void remove_new_line(char* line) { line[strcspn(line, "\n")] = 0; } -/** - * Get the logged in user's username. - * @return Returns the logged in user's username. - */ char *get_username() { struct passwd *pass = NULL; pass = getpwuid(getuid()); @@ -47,10 +39,6 @@ char *get_username() { return pass->pw_name; } -/** - * Get the hostname of the machine. - * @return Returns the hostname. - */ char *get_hostname() { char hostname[HOST_NAME_MAX + 1]; gethostname(hostname, HOST_NAME_MAX + 1); @@ -63,10 +51,6 @@ char *get_hostname() { return result; } -/** - * Get the current working directory of the shell. - * @return Returns the current working directory. - */ char *get_working_directory() { char *cwd = malloc(PATH_MAX * sizeof(char *)); getcwd(cwd, PATH_MAX); @@ -77,9 +61,6 @@ char *get_working_directory() { return cwd; } -/** - * Print the console line before the user input. - */ void print_input_line() { char *username = get_username(); char *hostname = get_hostname(); @@ -95,10 +76,6 @@ void print_input_line() { } } -/** - * Get input from the console. - * @return Returns a string input by the user. - */ char *get_console_input() { size_t buffer_size = 0; char *line = NULL; diff --git a/src/include/array.h b/src/include/array.h index 1b046c0..a2b640b 100644 --- a/src/include/array.h +++ b/src/include/array.h @@ -17,40 +17,126 @@ #ifndef _MYSHELLIN_ARRAY #define _MYSHELLIN_ARRAY + +/** + * This struct houses a dynamically sized string array. + */ typedef struct { + /** + * The array. + */ char **array; + + /** + * The amount of elements in the array. + */ size_t size; } StringArray; +/** + * This struct is used to clean up memory on exit. + */ typedef struct { + /** + * The array of memory to clean. + */ void **array; + + /** + * The amount of elements in the array. + */ size_t size; } CleanArray; +/** + * This struct has an array list with key value pairs based on strings. + */ typedef struct { + /** + * The keys array. + */ StringArray *keys; + + /** + * The values array. + */ StringArray *values; + + /** + * The amount of elements in the array list. + */ size_t size; } ArrayList; +/** + * A global clean array to use on exit. + */ CleanArray clean; + +/** + * A global variables array used for environment variables and values. + */ ArrayList *variables; +/** + * Create a String Array by initializing its structure. + * @return Returns a new String Array. + */ StringArray *create_string_array(); +/** + * Insert a string into the String Array. + * @param string_array The String Array to insert into. + * @param string The string to insert into the String Array. + */ void insert_string_array(StringArray *string_array, char *string); +/** + * Delete a string from the String Array. + * @param string_array The String Array to delete from. + * @param index The index in the String Array to delete. + */ void delete_string_array(StringArray *string_array, int index); +/** + * Free the String Array and all of its strings. + * @param string_array The String Array to free. + */ void free_string_array(StringArray *string_array); +/** + * Create a new Array List. + * @return Returns the newly created Array List. + */ ArrayList *create_array_list(); +/** + * Set a key inside the Array List. + * @param array_list The Array List to work on. + * @param key The key to insert/update. + * @param value The value to insert/update. + */ void set_array_list(ArrayList *array_list, char *key, char *value); +/** + * Get a value based on a key from an Array List. + * @param array_list The Array List to work on. + * @param key The key to search for. + * @return Returns the value if the key is found in the Array List otherwise it returns NULL. + */ char *get_array_list(ArrayList *array_list, char *key); +/** + * Remove a key from the Array List. + * @param array_list The Array List to work on. + * @param key The key to remove. + */ void unset_array_list(ArrayList *array_list, char *key); +/** + * Free all the memory used in the Array List. + * @param array_list The Array List to free. + */ void free_array_list(ArrayList *array_list); + #endif diff --git a/src/include/builtins.h b/src/include/builtins.h index ed76345..e06e2c3 100644 --- a/src/include/builtins.h +++ b/src/include/builtins.h @@ -18,11 +18,30 @@ #ifndef _MYSHELLIN_BUILTINS #define _MYSHELLIN_BUILTINS + +/** + * Check if the command is a builtin or not. + * @param command String with the command name to check. + * @return Returns true if it's a builtin or false otherwise. + */ bool is_builtin(char *command); +/** + * Run the builtin command. + * @param args An array of strings containing the arguments to run. + */ void run_builtin(StringArray *args); +/** + * Exit the shell. + * @param args The arguments that were used to call exit. This is used to free the memory before exit. + */ void exit_shell(StringArray *args); +/** + * Change the directory to what the user inputs. + * @param args The arguments the user input. + */ void change_directory(StringArray *args); + #endif diff --git a/src/include/console_line.h b/src/include/console_line.h index e1f85eb..9f13e78 100644 --- a/src/include/console_line.h +++ b/src/include/console_line.h @@ -15,17 +15,42 @@ #ifndef _MYSHELLIN_CONSOLE_LINE #define _MYSHELLIN_CONSOLE_LINE + #define CONSOLE_BUFFER_SIZE 1024 +/** + * Remove new line from the end of a string. + * @param line The string to remove the new line from. + */ void remove_new_line(char *line); +/** + * Get the logged in user's username. + * @return Returns the logged in user's username. + */ char *get_username(); +/** + * Get the hostname of the machine. + * @return Returns the hostname. + */ char *get_hostname(); +/** + * Get the current working directory of the shell. + * @return Returns the current working directory. + */ char *get_working_directory(); +/** + * Print the console line before the user input. + */ void print_input_line(); +/** + * Get input from the console. + * @return Returns a string input by the user. + */ char *get_console_input(); + #endif diff --git a/src/include/launch.h b/src/include/launch.h index d259664..d8abd33 100644 --- a/src/include/launch.h +++ b/src/include/launch.h @@ -17,5 +17,11 @@ #ifndef _MYSHELLIN_LAUNCH #define _MYSHELLIN_LAUNCH + +/** + * Launch programs from the OS. + * @param args The arguments to launch. + */ void launch_program(StringArray *args); + #endif diff --git a/src/include/loop.h b/src/include/loop.h index 5b02bf2..45a606a 100644 --- a/src/include/loop.h +++ b/src/include/loop.h @@ -15,9 +15,21 @@ #ifndef _MYSHELLIN_LOOP #define _MYSHELLIN_LOOP + +/** + * Add memory address to array to be cleaned up later. + * @param data The data to be cleaned up on exit. + */ void add_to_cleanup(void *data); +/** + * Cleanup memory when exiting. + */ void exit_cleanup(); +/** + * This is the loop that checks for user input and acts on it. + */ void loop(); + #endif diff --git a/src/launch.c b/src/launch.c index 00b8938..7670ba5 100644 --- a/src/launch.c +++ b/src/launch.c @@ -20,10 +20,6 @@ #include #include "array.h" -/** - * Launch programs from the OS. - * @param args The arguments to launch. - */ void launch_program(StringArray *args) { pid_t child = 0; diff --git a/src/loop.c b/src/loop.c index 8860444..d3d275b 100644 --- a/src/loop.c +++ b/src/loop.c @@ -22,10 +22,6 @@ #include "console_line.h" #include "launch.h" -/** - * Add memory address to array to be cleaned up later. - * @param data The data to be cleaned up on exit. - */ void add_to_cleanup(void *data) { clean.array = realloc(clean.array, (clean.size + 1) * sizeof(void *)); if (clean.array == NULL) { @@ -35,9 +31,6 @@ void add_to_cleanup(void *data) { clean.array[clean.size++] = data; } -/** - * Cleanup memory when exiting. - */ void exit_cleanup() { for (size_t i = 0; i < clean.size; i++) { if (clean.array[i] != NULL) { @@ -52,9 +45,6 @@ void exit_cleanup() { free_array_list(variables); } -/** - * This is the loop that checks for user input and acts on it. - */ void loop() { clean.size = 0; variables = create_array_list(); From 3598aa79691ab04df86452313611dce717785dae Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Fri, 16 Jul 2021 23:47:07 -0400 Subject: [PATCH 13/27] remove unused define --- src/include/console_line.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/include/console_line.h b/src/include/console_line.h index 9f13e78..e0f12ad 100644 --- a/src/include/console_line.h +++ b/src/include/console_line.h @@ -16,8 +16,6 @@ #ifndef _MYSHELLIN_CONSOLE_LINE #define _MYSHELLIN_CONSOLE_LINE -#define CONSOLE_BUFFER_SIZE 1024 - /** * Remove new line from the end of a string. * @param line The string to remove the new line from. From cf4161d545fe9911e472e7cff371aafa6bf93568 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 14:15:52 -0400 Subject: [PATCH 14/27] add launch section to report --- doc/code/launch.txt | 20 ++++++++++++++++++++ doc/sections/codigo.tex | 3 ++- doc/sections/codigo/builtins.tex | 1 + doc/sections/codigo/launch.tex | 6 ++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 doc/code/launch.txt create mode 100644 doc/sections/codigo/launch.tex diff --git a/doc/code/launch.txt b/doc/code/launch.txt new file mode 100644 index 0000000..2f5c727 --- /dev/null +++ b/doc/code/launch.txt @@ -0,0 +1,20 @@ +void launch_program(StringArray *args) { + pid_t child = 0; + + child = fork(); + + if (child == 0) { + if (execvp(args->array[0], args->array) == -1) { + fprintf(stderr, "%s: command not found\n", args->array[0]); + free_string_array(args); + exit(EXIT_FAILURE); + } + } + else if (child < 0) { + perror("fork"); + } + else { + int child_status; + waitpid(child, &child_status, 0); + } +} diff --git a/doc/sections/codigo.tex b/doc/sections/codigo.tex index 1b2b97c..9ec42d2 100644 --- a/doc/sections/codigo.tex +++ b/doc/sections/codigo.tex @@ -1,3 +1,4 @@ \section{Código} \input{sections/codigo/ciclo} -\input{sections/codigo/builtins} \ No newline at end of file +\input{sections/codigo/builtins} +\input{sections/codigo/launch} \ No newline at end of file diff --git a/doc/sections/codigo/builtins.tex b/doc/sections/codigo/builtins.tex index d8c4115..2639dd3 100644 --- a/doc/sections/codigo/builtins.tex +++ b/doc/sections/codigo/builtins.tex @@ -1,3 +1,4 @@ +\newpage \subsection{Builtins} Los builtins son comandos que son parte del shell, por lo tanto el sistema operativo no los proporciona. Un ejemplo es el comando\ ''exit''. Este comando no existe en el sistema operativo, por lo tanto el shell debe actuar cuando el usuario lo escribe en vez\ diff --git a/doc/sections/codigo/launch.tex b/doc/sections/codigo/launch.tex new file mode 100644 index 0000000..267b1c4 --- /dev/null +++ b/doc/sections/codigo/launch.tex @@ -0,0 +1,6 @@ +\newpage +\subsection{Launch} +Launch(lanzar) es la parte responsable por permutar un programa que está en el sistema operativo o en PATH. Para hacer eso\ +primer hacemos un fork donde el hijo permuta la operación y el padre espera que su hijo termina. Luego pasamos un nombre\ +de programa a lanzar y sus argumentos al execvp para permutar en el hijo. +\lstinputlisting{code/launch.txt} \ No newline at end of file From f580c03ebce9ae2fa2ae40ff9cc5e350d0652583 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 14:42:27 -0400 Subject: [PATCH 15/27] add environ builtin --- src/builtins.c | 17 +++++++++++++++++ src/include/builtins.h | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/src/builtins.c b/src/builtins.c index 142c368..225ba32 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -30,6 +30,10 @@ bool is_builtin(char *command) { return true; } + if (strcmp(command, "environ") == 0) { + return true; + } + return false; } @@ -40,6 +44,9 @@ void run_builtin(StringArray *args) { else if (strcmp(args->array[0], "cd") == 0) { change_directory(args); } + else if (strcmp(args->array[0], "environ") == 0) { + print_environ(args); + } else { fprintf(stderr, "Builtin %s does not exist!\n", args->array[0]); } @@ -72,3 +79,13 @@ void change_directory(StringArray *args) { } } } + +void print_environ(StringArray *args) { + if (args->size > 1) { + fprintf(stderr, "Too many arguments!\n"); + return; + } + for (size_t i = 0; i < variables->size; i++) { + fprintf(stdout, "%s=%s\n", variables->keys->array[i], variables->values->array[i]); + } +} diff --git a/src/include/builtins.h b/src/include/builtins.h index e06e2c3..f1a5d19 100644 --- a/src/include/builtins.h +++ b/src/include/builtins.h @@ -44,4 +44,10 @@ void exit_shell(StringArray *args); */ void change_directory(StringArray *args); +/** + * Print all of the environment variables. + * @param args The arguments the user input. + */ +void print_environ(StringArray * args); + #endif From 13d46e8c60f425fc7bad1eb02dc386ebacfb0976 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 16:54:00 -0400 Subject: [PATCH 16/27] fix memory leak --- src/loop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/loop.c b/src/loop.c index d3d275b..15952e6 100644 --- a/src/loop.c +++ b/src/loop.c @@ -49,7 +49,9 @@ void loop() { clean.size = 0; variables = create_array_list(); atexit(exit_cleanup); - set_array_list(variables, "PWD", get_working_directory()); + char *cwd = get_working_directory(); + set_array_list(variables, "PWD", cwd); + free(cwd); while (1) { print_input_line(); From b1dc92ba9220055107fc2fc9a61578fa340b67d4 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 16:58:38 -0400 Subject: [PATCH 17/27] add check to free --- src/loop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/loop.c b/src/loop.c index 15952e6..5344420 100644 --- a/src/loop.c +++ b/src/loop.c @@ -51,7 +51,10 @@ void loop() { atexit(exit_cleanup); char *cwd = get_working_directory(); set_array_list(variables, "PWD", cwd); - free(cwd); + if (cwd != NULL) { + free(cwd); + cwd = NULL; + } while (1) { print_input_line(); From ce9f6a321f34010e52c048c11d33290862969bca Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 17:07:15 -0400 Subject: [PATCH 18/27] add set variable builtin --- src/builtins.c | 95 +++++++++++++++++++++++++++++++++++++++++- src/include/builtins.h | 8 +++- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index 225ba32..7d68d3a 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -13,6 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -34,6 +35,10 @@ bool is_builtin(char *command) { return true; } + if (strcmp(command, "set") == 0) { + return true; + } + return false; } @@ -47,6 +52,9 @@ void run_builtin(StringArray *args) { else if (strcmp(args->array[0], "environ") == 0) { print_environ(args); } + else if (strcmp(args->array[0], "set") == 0) { + set_variable(args); + } else { fprintf(stderr, "Builtin %s does not exist!\n", args->array[0]); } @@ -72,10 +80,15 @@ void change_directory(StringArray *args) { } else { if (chdir(args->array[1]) != 0) { - perror("cd"); + fprintf(stderr, "cd: %s \"%s\"\n", strerror(errno), args->array[1]); } else { - set_array_list(variables, "PWD", get_working_directory()); + char *cwd = get_working_directory(); + set_array_list(variables, "PWD", cwd); + if (cwd != NULL) { + free(cwd); + cwd = NULL; + } } } } @@ -89,3 +102,81 @@ void print_environ(StringArray *args) { fprintf(stdout, "%s=%s\n", variables->keys->array[i], variables->values->array[i]); } } + +void set_variable(StringArray *args) { + if (args->size < 4) { + fprintf(stderr, "Too few arguments!\n"); + return; + } + + if (strcmp(args->array[2], "=") != 0) { + fprintf(stderr, "Invalid arguments!\n"); + return; + } + + if (args->array[1][0] != '$') { + fprintf(stderr, "Invalid variable argument!\n"); + return; + } + + char *variable = malloc((strlen(args->array[1])) * sizeof(char *)); + if (variable == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(variable, 0, strlen(args->array[1])); + + // Remove the $ symbol from the string + for (size_t i = 0; i < strlen(args->array[1]); i++) { + variable[i] = args->array[1][i + 1]; + } + + // Check variable name for invalid characters + for (size_t i = 0; i < strlen(variable); i++) { + if (!((variable[i] >= 48 && variable[i] <= 57) || + (variable[i] >= 65 && variable[i] <= 90) || + (variable[i] >= 97 && variable[i] <= 122))) { + fprintf(stderr, "Invalid character \"%d\" in variable name!\n", variable[i]); + return; + } + } + + size_t value_length = 1; + for (size_t i = 3; i < args->size; i++) { + if (i != 3) { + value_length++; + } + value_length += strlen(args->array[i]); + } + + char *value = malloc(value_length * sizeof(char *)); + if (value == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(value, 0, value_length); + + for (size_t i = 3; i < args->size; i++) { + if (i != 3) { + strcat(value, " "); + } + strcat(value, args->array[i]); + } + + if (strcmp(variable, "PWD") == 0) { + StringArray *chdir_args = create_string_array(); + insert_string_array(chdir_args, "cd"); + insert_string_array(chdir_args, args->array[3]); + change_directory(chdir_args); + free_string_array(chdir_args); + free(variable); + free(value); + // return without setting the variable because change directory will set it on success. + return; + } + + set_array_list(variables, variable, value); + + free(variable); + free(value); +} diff --git a/src/include/builtins.h b/src/include/builtins.h index f1a5d19..5e0a1d0 100644 --- a/src/include/builtins.h +++ b/src/include/builtins.h @@ -48,6 +48,12 @@ void change_directory(StringArray *args); * Print all of the environment variables. * @param args The arguments the user input. */ -void print_environ(StringArray * args); +void print_environ(StringArray *args); + +/** + * Set an environment variable. + * @param args The arguments passed to set. + */ +void set_variable(StringArray *args); #endif From 71d74c33246431862041f0ac1a2c8dbc4fa46fa4 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 17:23:05 -0400 Subject: [PATCH 19/27] break in case of null terminator --- src/builtins.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/builtins.c b/src/builtins.c index 7d68d3a..19afbd7 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -133,6 +133,9 @@ void set_variable(StringArray *args) { // Check variable name for invalid characters for (size_t i = 0; i < strlen(variable); i++) { + if (variable[i] == 0) { + break; + } if (!((variable[i] >= 48 && variable[i] <= 57) || (variable[i] >= 65 && variable[i] <= 90) || (variable[i] >= 97 && variable[i] <= 122))) { From f867a46565674e88a92cac5726e32e970d9de378 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 17:36:38 -0400 Subject: [PATCH 20/27] refactor utils --- Makefile | 2 +- src/builtins.c | 2 +- src/console_line.c | 15 +-------------- src/include/console_line.h | 12 ------------ src/include/utils.h | 30 ++++++++++++++++++++++++++++++ src/loop.c | 1 + src/utils.c | 35 +++++++++++++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 28 deletions(-) create mode 100644 src/include/utils.h create mode 100644 src/utils.c diff --git a/Makefile b/Makefile index 6ea739d..28b5edb 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CC=clang CFLAGS=-Wall -Isrc/include -DDEBUG -g -std=c11 LDFLAGS= FILENAME=myshellin -SRC=src/myshellin.c src/loop.c src/console_line.c src/array.c src/builtins.c src/launch.c +SRC=src/myshellin.c src/loop.c src/console_line.c src/array.c src/builtins.c src/launch.c src/utils.c OBJ=$(SRC:.c=.o) all: myshellin diff --git a/src/builtins.c b/src/builtins.c index 19afbd7..ce14126 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -20,7 +20,7 @@ #include #include "array.h" #include "builtins.h" -#include "console_line.h" +#include "utils.h" bool is_builtin(char *command) { if (strcmp(command, "exit") == 0) { diff --git a/src/console_line.c b/src/console_line.c index 042bb07..cce2cf2 100644 --- a/src/console_line.c +++ b/src/console_line.c @@ -24,10 +24,7 @@ #include "array.h" #include "color.h" #include "console_line.h" - -void remove_new_line(char* line) { - line[strcspn(line, "\n")] = 0; -} +#include "utils.h" char *get_username() { struct passwd *pass = NULL; @@ -51,16 +48,6 @@ char *get_hostname() { return result; } -char *get_working_directory() { - char *cwd = malloc(PATH_MAX * sizeof(char *)); - getcwd(cwd, PATH_MAX); - if (cwd == NULL) { - perror("getcwd"); - exit(EXIT_FAILURE); - } - return cwd; -} - void print_input_line() { char *username = get_username(); char *hostname = get_hostname(); diff --git a/src/include/console_line.h b/src/include/console_line.h index e0f12ad..574f96c 100644 --- a/src/include/console_line.h +++ b/src/include/console_line.h @@ -16,12 +16,6 @@ #ifndef _MYSHELLIN_CONSOLE_LINE #define _MYSHELLIN_CONSOLE_LINE -/** - * Remove new line from the end of a string. - * @param line The string to remove the new line from. - */ -void remove_new_line(char *line); - /** * Get the logged in user's username. * @return Returns the logged in user's username. @@ -34,12 +28,6 @@ char *get_username(); */ char *get_hostname(); -/** - * Get the current working directory of the shell. - * @return Returns the current working directory. - */ -char *get_working_directory(); - /** * Print the console line before the user input. */ diff --git a/src/include/utils.h b/src/include/utils.h new file mode 100644 index 0000000..6129c68 --- /dev/null +++ b/src/include/utils.h @@ -0,0 +1,30 @@ +/* + * Copyright 2021 Christopher Cromer + * Copyright 2021 Raúl Hernandez + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MYSHELLIN_UTILS +#define _MYSHELLIN_UTILS + +/** + * Remove new line from the end of a string. + * @param line The string to remove the new line from. + */ +void remove_new_line(char *line); + +/** + * Get the current working directory of the shell. + * @return Returns the current working directory. + */ +char *get_working_directory(); +#endif diff --git a/src/loop.c b/src/loop.c index 5344420..caeed97 100644 --- a/src/loop.c +++ b/src/loop.c @@ -21,6 +21,7 @@ #include "builtins.h" #include "console_line.h" #include "launch.h" +#include "utils.h" void add_to_cleanup(void *data) { clean.array = realloc(clean.array, (clean.size + 1) * sizeof(void *)); diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..ff320b5 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,35 @@ +/* + * Copyright 2021 Christopher Cromer + * Copyright 2021 Raúl Hernandez + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +void remove_new_line(char* line) { + line[strcspn(line, "\n")] = 0; +} + +char *get_working_directory() { + char *cwd = malloc(PATH_MAX * sizeof(char *)); + getcwd(cwd, PATH_MAX); + if (cwd == NULL) { + perror("getcwd"); + exit(EXIT_FAILURE); + } + return cwd; +} From a41e25b12a3ae5a5f68eaeba990a60304ce06bd0 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 19:04:18 -0400 Subject: [PATCH 21/27] add echo --- src/builtins.c | 56 +++++++++++++++++++++++++++++++++++++++++- src/include/builtins.h | 6 +++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/builtins.c b/src/builtins.c index ce14126..8aac90b 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -39,6 +39,10 @@ bool is_builtin(char *command) { return true; } + if (strcmp(command, "echo") == 0) { + return true; + } + return false; } @@ -55,6 +59,9 @@ void run_builtin(StringArray *args) { else if (strcmp(args->array[0], "set") == 0) { set_variable(args); } + else if (strcmp(args->array[0], "echo") == 0) { + echo(args); + } else { fprintf(stderr, "Builtin %s does not exist!\n", args->array[0]); } @@ -174,7 +181,7 @@ void set_variable(StringArray *args) { free_string_array(chdir_args); free(variable); free(value); - // return without setting the variable because change directory will set it on success. + // Return without setting the variable because change directory will set it on success return; } @@ -183,3 +190,50 @@ void set_variable(StringArray *args) { free(variable); free(value); } + +void echo(StringArray *args) { + StringArray *no_variables = create_string_array(); + + for (size_t i = 1; i < args->size; i++) { + if (args->array[i][0] == '$') { + char *variable = malloc((strlen(args->array[i])) * sizeof(char *)); + if (variable == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(variable, 0, strlen(args->array[i])); + + // Remove the $ symbol + for (size_t j = 0; j < strlen(args->array[i]); j++) { + variable[j] = args->array[i][j + 1]; + } + + char *value = get_array_list(variables, variable); + if (value == NULL) { + insert_string_array(no_variables, variable); + } + else { + if (i != 1) { + fprintf(stdout, " "); + } + fprintf(stdout, "%s", value); + } + } + else { + if (i != 1) { + fprintf(stdout, " "); + } + fprintf(stdout, "%s", args->array[i]); + } + } + if (args->size > 0) { + fprintf(stdout, "\n"); + } + + for (size_t i = 0; i < no_variables->size; i++) { + if (i == 0) { + fprintf(stderr, "\n"); + } + fprintf(stderr, "The variable %s doesn't exist!\n", no_variables->array[i]); + } +} diff --git a/src/include/builtins.h b/src/include/builtins.h index 5e0a1d0..1eeaba6 100644 --- a/src/include/builtins.h +++ b/src/include/builtins.h @@ -56,4 +56,10 @@ void print_environ(StringArray *args); */ void set_variable(StringArray *args); +/** + * Print a message or variable. + * @param args The arguments passed to echo. + */ +void echo(StringArray *args); + #endif From 94a32f28f6c368645c78428c99337e145309d072 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 20:55:06 -0400 Subject: [PATCH 22/27] fix memory leaks --- src/builtins.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/builtins.c b/src/builtins.c index 8aac90b..8b7ed9b 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -218,6 +218,10 @@ void echo(StringArray *args) { } fprintf(stdout, "%s", value); } + if (variable != NULL) { + free(variable); + variable = NULL; + } } else { if (i != 1) { @@ -236,4 +240,5 @@ void echo(StringArray *args) { } fprintf(stderr, "The variable %s doesn't exist!\n", no_variables->array[i]); } + free_string_array(no_variables); } From daa9cf8673cd05f28e65955dbe93fc6b313f7c49 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 21:12:02 -0400 Subject: [PATCH 23/27] remove new line --- src/builtins.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index 8b7ed9b..5cff70e 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -235,9 +235,6 @@ void echo(StringArray *args) { } for (size_t i = 0; i < no_variables->size; i++) { - if (i == 0) { - fprintf(stderr, "\n"); - } fprintf(stderr, "The variable %s doesn't exist!\n", no_variables->array[i]); } free_string_array(no_variables); From 8f575019270bb4f943948e7439badb23f66edf8f Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 21:22:03 -0400 Subject: [PATCH 24/27] refactor remove $ symbol --- src/builtins.c | 38 ++++++++++++++++---------------------- src/include/builtins.h | 7 +++++++ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index 5cff70e..74078b5 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -126,17 +126,7 @@ void set_variable(StringArray *args) { return; } - char *variable = malloc((strlen(args->array[1])) * sizeof(char *)); - if (variable == NULL) { - perror("malloc"); - exit(EXIT_FAILURE); - } - memset(variable, 0, strlen(args->array[1])); - - // Remove the $ symbol from the string - for (size_t i = 0; i < strlen(args->array[1]); i++) { - variable[i] = args->array[1][i + 1]; - } + char *variable = remove_variable_symbol(args->array[1]); // Check variable name for invalid characters for (size_t i = 0; i < strlen(variable); i++) { @@ -196,17 +186,7 @@ void echo(StringArray *args) { for (size_t i = 1; i < args->size; i++) { if (args->array[i][0] == '$') { - char *variable = malloc((strlen(args->array[i])) * sizeof(char *)); - if (variable == NULL) { - perror("malloc"); - exit(EXIT_FAILURE); - } - memset(variable, 0, strlen(args->array[i])); - - // Remove the $ symbol - for (size_t j = 0; j < strlen(args->array[i]); j++) { - variable[j] = args->array[i][j + 1]; - } + char *variable = remove_variable_symbol(args->array[i]); char *value = get_array_list(variables, variable); if (value == NULL) { @@ -239,3 +219,17 @@ void echo(StringArray *args) { } free_string_array(no_variables); } + +char *remove_variable_symbol(char *original_variable) { + char *variable = malloc((strlen(original_variable)) * sizeof(char *)); + if (variable == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(variable, 0, strlen(original_variable)); + + for (size_t i = 0; i < strlen(original_variable); i++) { + variable[i] = original_variable[i + 1]; + } + return variable; +} diff --git a/src/include/builtins.h b/src/include/builtins.h index 1eeaba6..1d3fd05 100644 --- a/src/include/builtins.h +++ b/src/include/builtins.h @@ -62,4 +62,11 @@ void set_variable(StringArray *args); */ void echo(StringArray *args); +/** + * Remove the $ symbol from a variable name. + * @param original_variable The original variable name. + * @return Returns the string without the $ symbool. + */ +char *remove_variable_symbol(char *original_variable); + #endif From 56a6747e061be611ff1613bbed6a9155c6f934e6 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 21:27:39 -0400 Subject: [PATCH 25/27] move the remove variable sysmbols function to utils --- src/builtins.c | 14 -------------- src/include/builtins.h | 7 ------- src/include/utils.h | 8 ++++++++ src/utils.c | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index 74078b5..8da1578 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -219,17 +219,3 @@ void echo(StringArray *args) { } free_string_array(no_variables); } - -char *remove_variable_symbol(char *original_variable) { - char *variable = malloc((strlen(original_variable)) * sizeof(char *)); - if (variable == NULL) { - perror("malloc"); - exit(EXIT_FAILURE); - } - memset(variable, 0, strlen(original_variable)); - - for (size_t i = 0; i < strlen(original_variable); i++) { - variable[i] = original_variable[i + 1]; - } - return variable; -} diff --git a/src/include/builtins.h b/src/include/builtins.h index 1d3fd05..1eeaba6 100644 --- a/src/include/builtins.h +++ b/src/include/builtins.h @@ -62,11 +62,4 @@ void set_variable(StringArray *args); */ void echo(StringArray *args); -/** - * Remove the $ symbol from a variable name. - * @param original_variable The original variable name. - * @return Returns the string without the $ symbool. - */ -char *remove_variable_symbol(char *original_variable); - #endif diff --git a/src/include/utils.h b/src/include/utils.h index 6129c68..1ab61f2 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -27,4 +27,12 @@ void remove_new_line(char *line); * @return Returns the current working directory. */ char *get_working_directory(); + +/** + * Remove the $ symbol from a variable name. + * @param original_variable The original variable name. + * @return Returns the string without the $ symbool. + */ +char *remove_variable_symbol(char *original_variable); + #endif diff --git a/src/utils.c b/src/utils.c index ff320b5..75e0dbf 100644 --- a/src/utils.c +++ b/src/utils.c @@ -33,3 +33,17 @@ char *get_working_directory() { } return cwd; } + +char *remove_variable_symbol(char *original_variable) { + char *variable = malloc((strlen(original_variable)) * sizeof(char *)); + if (variable == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(variable, 0, strlen(original_variable)); + + for (size_t i = 0; i < strlen(original_variable); i++) { + variable[i] = original_variable[i + 1]; + } + return variable; +} From 6cbfcaee9ae450af9485642059a45d0bbd6be307 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 21:51:31 -0400 Subject: [PATCH 26/27] launch using environment variables as arugments --- src/launch.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/launch.c b/src/launch.c index 7670ba5..03929ef 100644 --- a/src/launch.c +++ b/src/launch.c @@ -19,6 +19,7 @@ #include #include #include "array.h" +#include "utils.h" void launch_program(StringArray *args) { pid_t child = 0; @@ -26,9 +27,31 @@ void launch_program(StringArray *args) { child = fork(); if (child == 0) { - if (execvp(args->array[0], args->array) == -1) { - fprintf(stderr, "%s: command not found\n", args->array[0]); + StringArray *new_args = create_string_array(); + insert_string_array(new_args, args->array[0]); + for (size_t i = 1; i < args->size; i++) { + if (args->array[i][0] == '$') { + char *variable = remove_variable_symbol(args->array[i]); + + char *value = get_array_list(variables, variable); + if (value != NULL) { + insert_string_array(new_args, value); + } + + if (variable != NULL) { + free(variable); + variable = NULL; + } + } + else { + insert_string_array(new_args, args->array[i]); + } + } + + if (execvp(new_args->array[0], new_args->array) == -1) { + fprintf(stderr, "%s: command not found\n", new_args->array[0]); free_string_array(args); + free_string_array(new_args); exit(EXIT_FAILURE); } } From a80bedf135c8afbaa1ed1d04d7f24e2d0fbf6e5f Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sat, 17 Jul 2021 22:11:11 -0400 Subject: [PATCH 27/27] make cd respect environment variables --- src/builtins.c | 63 ++++++++++++++++++++++++++++++++++++------ src/include/builtins.h | 5 ++++ 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index 8da1578..a578edf 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -78,16 +78,49 @@ void change_directory(StringArray *args) { return; } else if (args->size == 1) { - char *cwd = get_working_directory(); - fprintf(stdout, "%s\n", cwd); - if (cwd != NULL) { - free(cwd); - cwd = NULL; - } + print_current_directory(); } else { - if (chdir(args->array[1]) != 0) { - fprintf(stderr, "cd: %s \"%s\"\n", strerror(errno), args->array[1]); + char *value = NULL; + if (args->array[1][0] == '$') { + char *variable = remove_variable_symbol(args->array[1]); + + char *array_value = get_array_list(variables, variable); + + if (array_value == NULL) { + if (variable != NULL) { + free(variable); + variable = NULL; + } + print_current_directory(); + return; + } + + value = malloc((strlen(array_value) + 1) * sizeof(char *)); + if (value == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(value, 0, strlen(array_value) + 1); + strcpy(value, array_value); + + if (variable != NULL) { + free(variable); + variable = NULL; + } + } + else { + value = malloc((strlen(args->array[1]) + 1) * sizeof(char *)); + if (value == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(value, 0, strlen(args->array[1]) + 1); + strcpy(value, args->array[1]); + } + + if (chdir(value) != 0) { + fprintf(stderr, "cd: %s \"%s\"\n", strerror(errno), value); } else { char *cwd = get_working_directory(); @@ -97,6 +130,20 @@ void change_directory(StringArray *args) { cwd = NULL; } } + + if (value != NULL) { + free(value); + value = NULL; + } + } +} + +void print_current_directory() { + char *cwd = get_working_directory(); + fprintf(stdout, "%s\n", cwd); + if (cwd != NULL) { + free(cwd); + cwd = NULL; } } diff --git a/src/include/builtins.h b/src/include/builtins.h index 1eeaba6..6f4b716 100644 --- a/src/include/builtins.h +++ b/src/include/builtins.h @@ -44,6 +44,11 @@ void exit_shell(StringArray *args); */ void change_directory(StringArray *args); +/** + * Print the current working directory. + */ +void print_current_directory(); + /** * Print all of the environment variables. * @param args The arguments the user input.