Skip to content
Snippets Groups Projects
Select Git revision
  • main
1 result

sdbsc.c

Blame
  • dshlib.c NaN GiB
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdbool.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    
    #include "dshlib.h"
    
    
    int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) {
        if (cmd_line == NULL || cmd_buff == NULL) {
            return ERR_CMD_OR_ARGS_TOO_BIG;
        }
    
        char *original_line = strdup(cmd_line);
        if (original_line == NULL) {
            return ERR_MEMORY;
        }
    
        cmd_buff->argc = 0;
        cmd_buff->_cmd_buffer = original_line;
    
        char *ptr = original_line;
        char *arg_start = NULL;
        bool in_quotes = false;//For quotes 
        char quote_char = '\0';
    
        while (*ptr != '\0') {
            if ((isspace((unsigned char)*ptr) && !in_quotes)) {
                if (arg_start != NULL) {
                    *ptr = '\0';
                    cmd_buff->argv[cmd_buff->argc++] = arg_start;
                    arg_start = NULL;
                }
            } else if (*ptr == '"' || *ptr == '\'') {
                if (in_quotes && *ptr == quote_char) {
                    in_quotes = false;
                    quote_char = '\0';
                    *ptr = '\0';  // End the argument at the closing quote
                } else if (!in_quotes) {
                    in_quotes = true;
                    quote_char = *ptr;
                    arg_start = ptr + 1;  // Start the argument after the opening quote
                }
            } else {
                if (arg_start == NULL) {
                    arg_start = ptr;
                }
            }
            ptr++;
        }
    
        if (arg_start != NULL) {
            cmd_buff->argv[cmd_buff->argc++] = arg_start;
        }
    
        cmd_buff->argv[cmd_buff->argc] = NULL;
    
    	 // Debugging output to verify parsing
    	 // printf("Parsed command:\n");
    	 // for (int i = 0; i < cmd_buff->argc; i++) {
    	 //     printf("  argv[%d]: %s\n", i, cmd_buff->argv[i]);
    	 // }
    
    
    
        return OK;
    }
    
    char *trim_whitespace(char *str) { //Had to make a new function for readability
        char *end;
    
        while (isspace((unsigned char)*str)) str++;
    
        if (*str == 0)  // All spaces?
            return str;
    
        // Trim trailing space
        end = str + strlen(str) - 1;
        while (end > str && isspace((unsigned char)*end)) end--;
    
        // new null terminator
        *(end + 1) = '\0';
    
        return str;
    }
    
    
    
    
    int parse_pipeline(const char *cmd_line, command_list_t *clist) {
        if (cmd_line == NULL || clist == NULL) {
            return ERR_CMD_OR_ARGS_TOO_BIG;
        }
    
        char *line_copy = strdup(cmd_line);
        if (line_copy == NULL) {
            return ERR_MEMORY;
        }
    	 //Parsing using pipe.
        clist->num = 0;
        char *saveptr;
        char *command = strtok_r(line_copy, "|", &saveptr);
    
        while (command != NULL) {
            if (clist->num >= CMD_MAX) {
                free(line_copy);
                return ERR_TOO_MANY_COMMANDS;
            }
    
            cmd_buff_t *cmd_buff = &clist->commands[clist->num];
            int result = build_cmd_buff(command, cmd_buff);
            if (result != OK) {
                free(line_copy);
                return result;
            }
    
            clist->num++;
            command = strtok_r(NULL, "|", &saveptr);
        }
    
        free(line_copy);
        return OK;
    }
    
    
    
    int execute_pipeline(command_list_t *clist) {
        int num_commands = clist->num;
        int pipefd[2 * (num_commands - 1)];
        pid_t pids[num_commands];
    	
    	 // for (int i = 0; i < clist->num; i++) {
        //     printf("Command %d:\n", i);
    	 //     for (int j = 0; clist->commands[i].argv[j] != NULL; j++) {
    	 //         printf("  argv[%d]: %s\n", j, clist->commands[i].argv[j]);
    	 //     }
    	 // }
    
    
    
    
        for (int i = 0; i < num_commands - 1; i++) {
            if (pipe(pipefd + 2 * i) == -1) {
                perror("pipe");
                return ERR_MEMORY;
            }
        }
    
        // Fork processes for each command
        for (int i = 0; i < num_commands; i++) {
            pids[i] = fork();
            if (pids[i] == -1) {
                perror("fork");
                return ERR_MEMORY;
            }
    
            if (pids[i] == 0) {  // Child process
                // if not first moves input
                if (i > 0) {
                    if (dup2(pipefd[2 * (i - 1)], STDIN_FILENO) == -1) {
                        perror("dup2 stdin");
                        exit(EXIT_FAILURE);
                    }
                }
    
                // Redirect output if not the last command
                if (i < num_commands - 1) {
                    if (dup2(pipefd[2 * i + 1], STDOUT_FILENO) == -1) {
                        perror("dup2 stdout");
                        exit(EXIT_FAILURE);
                    }
                }
    
                // Close all pipe file descriptors. Very important stuff
                for (int j = 0; j < 2 * (num_commands - 1); j++) {
                    close(pipefd[j]);
                }
    
                // Execute the command
                execvp(clist->commands[i].argv[0], clist->commands[i].argv);
                perror("execvp");
                exit(EXIT_FAILURE);
            }
        }
    
        // Closes all pipe
        for (int i = 0; i < 2 * (num_commands - 1); i++) {
            close(pipefd[i]);
        }
    
        // waitpid so everyhting is smooth
        for (int i = 0; i < num_commands; i++) {
            int status;
            waitpid(pids[i], &status, 0);
            if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
                fprintf(stderr, "Command %d exited with status %d\n", i, WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                fprintf(stderr, "Command %d terminated by signal %d\n", i, WTERMSIG(status));
            }
        }
    
        return OK;
    }
    
    static void start_server() {
        int listen_socket;
        int ret;
    
    }
    
    /**** 
     **** FOR REMOTE SHELL USE YOUR SOLUTION FROM SHELL PART 3 HERE
     **** THE MAIN FUNCTION CALLS THIS ONE AS ITS ENTRY POINT TO
     **** EXECUTE THE SHELL LOCALLY
     ****
     */
    
    /*
     * Implement your exec_local_cmd_loop function by building a loop that prompts the 
     * user for input.  Use the SH_PROMPT constant from dshlib.h and then
     * use fgets to accept user input.
     * 
     *      while(1){
     *        printf("%s", SH_PROMPT);
     *        if (fgets(cmd_buff, ARG_MAX, stdin) == NULL){
     *           printf("\n");
     *           break;
     *        }
     *        //remove the trailing \n from cmd_buff
     *        cmd_buff[strcspn(cmd_buff,"\n")] = '\0';
     * 
     *        //IMPLEMENT THE REST OF THE REQUIREMENTS
     *      }
     * 
     *   Also, use the constants in the dshlib.h in this code.  
     *      SH_CMD_MAX              maximum buffer size for user input
     *      EXIT_CMD                constant that terminates the dsh program
     *      SH_PROMPT               the shell prompt
     *      OK                      the command was parsed properly
     *      WARN_NO_CMDS            the user command was empty
     *      ERR_TOO_MANY_COMMANDS   too many pipes used
     *      ERR_MEMORY              dynamic memory management failure
     * 
     *   errors returned
     *      OK                     No error
     *      ERR_MEMORY             Dynamic memory management failure
     *      WARN_NO_CMDS           No commands parsed
     *      ERR_TOO_MANY_COMMANDS  too many pipes used
     *   
     *   console messages
     *      CMD_WARN_NO_CMD        print on WARN_NO_CMDS
     *      CMD_ERR_PIPE_LIMIT     print on ERR_TOO_MANY_COMMANDS
     *      CMD_ERR_EXECUTE        print on execution failure of external command
     * 
     *  Standard Library Functions You Might Want To Consider Using (assignment 1+)
     *      malloc(), free(), strlen(), fgets(), strcspn(), printf()
     * 
     *  Standard Library Functions You Might Want To Consider Using (assignment 2+)
     *      fork(), execvp(), exit(), chdir()
     */
    
    
    
    int exec_local_cmd_loop() {
        char cmd_buff[SH_CMD_MAX];
        int rc = OK;
    
        while (1) {
            printf("%s", SH_PROMPT);
    
            if (fgets(cmd_buff, SH_CMD_MAX, stdin) == NULL) {
                printf("\n");
                break;
            }
    
            cmd_buff[strcspn(cmd_buff, "\n")] = '\0';
    
            if (strlen(cmd_buff) == 0) {
                printf("%s\n", CMD_WARN_NO_CMD);
                rc = WARN_NO_CMDS;
                continue;
            }
    
            if (strstr(cmd_buff, "|") != NULL) {
                command_list_t cmd_list;
                if (parse_pipeline(cmd_buff, &cmd_list) != OK) {
                    fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
                    rc = ERR_TOO_MANY_COMMANDS;
                    continue;
                }
    
                // Execute the pipeline
    
                execute_pipeline(&cmd_list);
    
                // Free memory for each command's buffer
                for (int i = 0; i < cmd_list.num; i++) {
                    free(cmd_list.commands[i]._cmd_buffer);
                }
            } else {
                cmd_buff_t cmd;
                if (build_cmd_buff(cmd_buff, &cmd) != OK) {
                    fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
                    rc = ERR_MEMORY;
                    continue;
                }
    
                if (strcmp(cmd.argv[0], EXIT_CMD) == 0) {
                    free(cmd._cmd_buffer);
                    break;
                }
    
                if (strcmp(cmd.argv[0], "cd") == 0) {
                    if (cmd.argc == 1) {
                        chdir(getenv("HOME"));
                    } else if (cmd.argc == 2) {
                        if (chdir(cmd.argv[1]) != 0) {
                            perror("cd");
                        }
                    } else {
                        fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
                    }
                    free(cmd._cmd_buffer);
                    continue;
                }
    
                pid_t pid = fork();
                if (pid < 0) {
                    perror("fork failed");
                    rc = ERR_MEMORY;
                } else if (pid == 0) {
                    execvp(cmd.argv[0], cmd.argv);
                    perror("execvp failed");
                    exit(EXIT_FAILURE);
                } else {
                    int status;
                    wait(&status);
    
                    if (WIFEXITED(status)) {
                        if (WEXITSTATUS(status) != 0) {
                            fprintf(stderr, "Command failed with exit code %d\n", WEXITSTATUS(status));
                        }
                    }
                }
    
                free(cmd._cmd_buffer);
            }
        }
    
        return rc;
    }