diff --git a/Main.c b/Main.c index dc945ef525eb701af3769e418befbcb3b1267188..f382d96c3fb56e054f621cdd8bc6e28848a0525c 100644 --- a/Main.c +++ b/Main.c @@ -19,13 +19,19 @@ * At the very least, up to four pipes (such as the following) * ls -l | grep a | grep b | grep c | grep v * appears to work with no issues or memory leaks. + * + * Adding a single & (seperated by spaces) at the end of a command enables backgrounding. + * The parent will create a child that runs off to do provided command. + * Parent will meanwhile forget about child and prompt for further input. */ /** * Known Issues: * Does not handle < or > symbols. - * Does not handle backgrounding (& symbol). + + * Backgrounding slightly messes up user interface display. + * Should correct after inputing another command. */ @@ -70,6 +76,8 @@ typedef struct{ int argc; char*** argv; } makeargv_struct; +int run_program; // Holds if program should continue to run. +char* user_input; // Holds user input value. makeargv_struct* line_argv; // Pointer to makeargv struct. makeargv_struct* command_argv; // Pointer to/array of makeargv structs. @@ -77,6 +85,7 @@ makeargv_struct* command_argv; // Pointer to/array of makeargv structs. // Method Declaration. int makeargv(); // Creates argv using passed line. +void main_loop(); // Main program loop. void parse_line(); // Parses provided line into commands. void parse_command(); // Further parses line into smaller subsections. void execute_command(); // Executes provided command. @@ -86,7 +95,11 @@ char* get_directory_path(); // Gets full pathname of current directory. void get_umask(); // Gets current umask value. void set_umask(); // Sets umask value. void interupt_handler(); // Handler for ctrl+c signal. +int check_for_backgrounding(); // Check for backgrounding (&) at end of input. +void run_backgrounding(); // Runs child processes in background. void free_memory(); // Frees memory of vars. +void free_line_argv(); // Frees memory of line_argv. +void free_command_argv(); // Frees memory of line_argv. void make_arg_example(); @@ -96,16 +109,16 @@ void make_arg_example(); * Initializes and runs program. */ int main(int argc, char* argv[]) { - int run_program = 1; - char* user_input; + int backgrounding_bool; char* current_directory; - struct sigaction action; + //struct sigaction action; + run_program = 1; // Set ctrl+c signal interupt. - memset(&action, '\0', sizeof(action)); - action.sa_handler = interupt_handler; - action.sa_flags = SA_RESTART; - sigaction(SIGINT, &action, NULL); + // memset(&action, '\0', sizeof(action)); + // action.sa_handler = interupt_handler; + // action.sa_flags = SA_RESTART; + // sigaction(SIGINT, &action, NULL); // parse_line(""); // free_memory(); @@ -142,81 +155,99 @@ int main(int argc, char* argv[]) { // Run until user willingly quits. while (run_program == 1) { - current_directory = get_directory_path(); + // Get user input and output current dir. + current_directory = get_directory_path(); printf(ANSI_COLOR_BLUE "%s$ " ANSI_COLOR_RESET, current_directory); user_input = get_user_input_with_prompt(""); free(current_directory); - parse_line(user_input); - free(user_input); - // Make sure at least one command is present. - if (line_argv->argc > 0) { - parse_command(); + // Check for backgrounding. + backgrounding_bool = check_for_backgrounding(); - // Check if exit program. - if (strcmp(**command_argv->argv, "exit") == 0) { - run_program = 0; + // Run based on backgrounding bool. + if (backgrounding_bool == 1) { + run_backgrounding(); + } else { + parse_line(); + free(user_input); + main_loop(); + } + } - // Check for cd command. - } else if (strcmp(**command_argv->argv, "cd") == 0) { - if (line_argv->argc > 1) { - err_msg("Too many arguments."); - } else { - if (command_argv->argc < 2) { - err_msg("Need path argument."); - } else if (command_argv->argc > 2) { - err_msg("Too many arguments."); - } else { - change_directory(*(*command_argv->argv + 1)); - } - } + return 0; +} - // Check for pwd command. - } else if (strcmp(**command_argv->argv, "pwd") == 0) { - if (line_argv->argc > 1) { - err_msg("Too many arguments."); - } else if (command_argv->argc > 1) { + +void main_loop() { + char* current_directory; + + // Make sure at least one command is present. + if (line_argv->argc > 0) { + parse_command(); + + // Check if exit program. + if (strcmp(**command_argv->argv, "exit") == 0) { + run_program = 0; + + // Check for cd command. + } else if (strcmp(**command_argv->argv, "cd") == 0) { + if (line_argv->argc > 1) { + err_msg("Too many arguments."); + } else { + if (command_argv->argc < 2) { + err_msg("Need path argument."); + } else if (command_argv->argc > 2) { err_msg("Too many arguments."); } else { - current_directory = get_directory_path(); - printf("%s\n", current_directory); - free(current_directory); + change_directory(*(*command_argv->argv + 1)); } + } - // Check for umask command. - } else if (strcmp(**command_argv->argv, "umask") == 0) { - if (line_argv->argc > 1) { + // Check for pwd command. + } else if (strcmp(**command_argv->argv, "pwd") == 0) { + if (line_argv->argc > 1) { + err_msg("Too many arguments."); + } else if (command_argv->argc > 1) { + err_msg("Too many arguments."); + } else { + current_directory = get_directory_path(); + printf("%s\n", current_directory); + free(current_directory); + } + + // Check for umask command. + } else if (strcmp(**command_argv->argv, "umask") == 0) { + if (line_argv->argc > 1) { + err_msg("Too many arguments."); + } else { + if (command_argv->argc > 2) { err_msg("Too many arguments."); + } else if (command_argv->argc < 2) { + get_umask(); } else { - if (command_argv->argc > 2) { - err_msg("Too many arguments."); - } else if (command_argv->argc < 2) { - get_umask(); - } else { - set_umask(*(*command_argv->argv + 1)); - } + set_umask(*(*command_argv->argv + 1)); } - - // Attempt to exec command. - } else { - execute_command(); } - free_memory(); + + // Attempt to exec command. + } else { + execute_command(); } + //free_memory(); + free_command_argv(); + free_line_argv(); } - - return 0; } /** * Parses given line into subsections, separated by pipes. */ -void parse_line(char* command_line) { +void parse_line() { line_argv = calloc(1, sizeof(makeargv_struct)); line_argv->argv = calloc(1, sizeof(char***)); - line_argv->argc = makeargv(command_line, "|", line_argv->argv); + line_argv->argc = makeargv(user_input, "|", line_argv->argv); // Check for errors. if (line_argv->argc < 0) { @@ -322,9 +353,12 @@ void recursive_execute(int argc, makeargv_struct* args, int current_arg) { ++temp_pointer; index++; } + if (execvp(**temp_pointer->argv, *temp_pointer->argv) == -1) { err_msg("Invalid exec arg(s)."); - free_memory(); + //free_memory(); + free_command_argv(); + free_line_argv(); exit(-1); } } @@ -442,6 +476,72 @@ void interupt_handler() { } +/** + * Checks for "&" char at end of user's input. + */ +int check_for_backgrounding() { + int index = 0; + int backgrounding_bool = 0; + char* token; + char* temp_string; + + // Go to last index of string. + while (index < strlen(user_input)) { + index++; + } + + // Check for backgrounding char as last "valid" char. + while ((user_input[index] == '\0') || + (user_input[index] == '\n') || + (user_input[index] == ' ') || + (user_input[index] == '&')) { + if (user_input[index] == '&') { + if (user_input[index - 1] == ' ') { + backgrounding_bool = 1; + } + } + index--; + } + index++; + + // If background char was found, seperate out token. + if (backgrounding_bool == 1) { + token = strtok_r(user_input, "&", &temp_string); + } + + return backgrounding_bool; +} + + +/** + * Starts a child process to run given commands. + * Parent can still continue as normal. + */ +void run_backgrounding() { + pid_t pid; + + parse_line(); + free(user_input); + + switch(pid = fork()) { + case 0: // Child. + printf("\n"); + main_loop(); + exit(-1); + break; + + case -1: // Error. + err_sys("Fork Error."); + break; + + default: // Parent. + // Do nothing. Want to progress regardless of child. + break; + } + free_line_argv(); +} + + /** * Frees memory of main program variables. */ @@ -471,6 +571,37 @@ void free_memory() { } +/** + * Frees all line_argv values. + */ +void free_line_argv() { + free(**line_argv->argv); + free(*line_argv->argv); + free(line_argv->argv); + free(line_argv); +} + + +/** + * Frees all command_argv values. + */ +void free_command_argv() { + makeargv_struct* temp_pointer; + makeargv_struct* orig_pointer = command_argv; + + while (line_argv->argc > 0) { + temp_pointer = command_argv; + ++temp_pointer; + free(*(*command_argv->argv)); + free(*(command_argv->argv)); + free(command_argv->argv); + command_argv = temp_pointer; + line_argv->argc--; + } + free(orig_pointer); +} + + /** * Example of using makeargv. */