Skip to content
Snippets Groups Projects
Select Git revision
  • 7bfca4ca162073e104e0548bdf8cb7e10ec693c8
  • main default
2 results

makefile

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 <errno.h>
    #include "dshlib.h"
    
    /*
     * 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 last_rc = 0;
    
    int execute_pipeline(command_list_t *clist) {
        if (!clist->num) return OK;
        
        if (clist->num == 1) {
            char *cmd = clist->commands[0].argv[0];
            if (clist->commands[0].argc > 0) {
                if (!strcmp(cmd, EXIT_CMD)) return OK_EXIT;
                if (!strcmp(cmd, "cd")) {
                    handle_cd(clist->commands[0].argc > 1 ? clist->commands[0].argv[1] : NULL);
                    return OK;
                }
                if (!strcmp(cmd, "rc")) {
                    printf("%d\n", last_rc);
                    return OK;
                }
            }
        }
        
        pid_t *child_pids = malloc(clist->num * sizeof(pid_t));
        if (!child_pids) {
            fprintf(stderr, "Memory allocation failed\n");
            return ERR_MEMORY;
        }
        
        int pipes[CMD_MAX - 1][2];
        for (int i = 0; i < clist->num - 1; i++) {
            if (pipe(pipes[i]) == -1) {
                perror("pipe");
                while (i--) close(pipes[i][0]), close(pipes[i][1]);
                free(child_pids);
                return ERR_EXEC_CMD;
            }
        }
        
        for (int i = 0; i < clist->num; i++) {
            pid_t pid = fork();
            if (pid < 0) {
                perror("fork");
                for (int j = 0; j < clist->num - 1; j++) close(pipes[j][0]), close(pipes[j][1]);
                free(child_pids);
                return ERR_EXEC_CMD;
            }
            
            if (!pid) {
                if (i > 0) dup2(pipes[i - 1][0], STDIN_FILENO);
                if (i < clist->num - 1) dup2(pipes[i][1], STDOUT_FILENO);
                for (int j = 0; j < clist->num - 1; j++) close(pipes[j][0]), close(pipes[j][1]);
                execvp(clist->commands[i].argv[0], clist->commands[i].argv);
                perror("execvp");
                exit(errno);
            }
            child_pids[i] = pid;
        }
        
        for (int i = 0; i < clist->num - 1; i++) close(pipes[i][0]), close(pipes[i][1]);
        
        for (int i = 0, status; i < clist->num; i++) {
            waitpid(child_pids[i], &status, 0);
            if (i == clist->num - 1) last_rc = WEXITSTATUS(status);
        }
        
        free(child_pids);
        return OK;
    }
    
    int build_cmd_list(char *cmd_line, command_list_t *clist) {
        int ret = OK;
        char *cmd_copy = strdup(cmd_line);
        if (!cmd_copy) {
            fprintf(stderr, "Memory allocation failed\n");
            return ERR_MEMORY;
        }
    
        clist->num = 0;
        char *token = NULL, *context = NULL;
        token = strtok_r(cmd_copy, PIPE_STRING, &context);
    
        while (token != NULL) {
            if (clist->num >= CMD_MAX) {
                ret = ERR_TOO_MANY_COMMANDS;
                fprintf(stderr, CMD_ERR_PIPE_LIMIT, CMD_MAX);
                break;
            }
    
            if (alloc_cmd_buff(&clist->commands[clist->num]) != OK) {
                ret = ERR_MEMORY;
                break;
            }
    
            /* Copy token into the command buffer */
            strncpy(clist->commands[clist->num]._cmd_buffer, token, SH_CMD_MAX);
            clist->commands[clist->num]._cmd_buffer[SH_CMD_MAX] = '\0';
    
            if (build_cmd_buff(clist->commands[clist->num]._cmd_buffer,
                               &clist->commands[clist->num]) != OK) {
                free_cmd_buff(&clist->commands[clist->num]);
                ret = ERR_CMD_ARGS_BAD;
                break;
            }
    
            clist->num++;
            token = strtok_r(NULL, PIPE_STRING, &context);
        }
    
        free(cmd_copy);
    
        if (ret != OK) {
            for (int i = 0; i < clist->num; i++) {
                free_cmd_buff(&clist->commands[i]);
            }
            return ret;
        }
    
        if (clist->num == 0) {
            fprintf(stderr, CMD_WARN_NO_CMD);
            return WARN_NO_CMDS;
        }
    
        return OK;
    }
    
    
    int free_cmd_list(command_list_t *clist) {
        if (clist == NULL) {
            return ERR_MEMORY;
        }
        
        for (int i = 0; i < clist->num; i++) {
            free_cmd_buff(&clist->commands[i]);
        }
        
        clist->num = 0;
        return OK;
    }
    
    int exec_local_cmd_loop() {
        cmd_buff_t cmd;
        command_list_t cmd_list;
        int rc;
    
        if ((rc = alloc_cmd_buff(&cmd)) != OK) {
            fprintf(stderr, "Memory allocation failed\n");
            return ERR_MEMORY;
        }
    
        for (;;) {
            printf("%s", SH_PROMPT);
    
            if (!fgets(cmd._cmd_buffer, SH_CMD_MAX, stdin)) {
                putchar('\n');
                break;
            }
    
            cmd._cmd_buffer[strcspn(cmd._cmd_buffer, "\n")] = '\0';
            char *trimmed = cmd._cmd_buffer;
            while (*trimmed && isspace((unsigned char)*trimmed)) trimmed++;
            
            if (!*trimmed) {
                puts(CMD_WARN_NO_CMD);
                continue;
            }
    
            if (!strcmp(trimmed, EXIT_CMD)) break;
            if (!strcmp(trimmed, "dragon")) {
                print_dragon();
                continue;
            }
    
            if ((rc = build_cmd_list(trimmed, &cmd_list)) != OK) {
                if (rc != WARN_NO_CMDS) fprintf(stderr, "Error parsing command: %d\n", rc);
                continue;
            }
    
            rc = execute_pipeline(&cmd_list);
            free_cmd_list(&cmd_list);
            if (rc == OK_EXIT) break;
        }
        
        free_cmd_buff(&cmd);
        return OK;
    }
    
    int handle_cd(char *path) {
        if (path == NULL)
            return 0;
        if (chdir(path) != 0) {
            perror("cd");
            return -1;
        }
        return 0;
    }
    
    int alloc_cmd_buff(cmd_buff_t *cmd) {
        if (cmd == NULL) return ERR_MEMORY;
        cmd->_cmd_buffer = malloc(SH_CMD_MAX + 1); // +1 for the null terminator
        if (cmd->_cmd_buffer == NULL) return ERR_MEMORY;
        return OK;
    }
    
    int free_cmd_buff(cmd_buff_t *cmd) {
        if (cmd == NULL) return ERR_MEMORY;
        free(cmd->_cmd_buffer);
        cmd->_cmd_buffer = NULL;
        return OK;
    }
    
    int clear_cmd_buff(cmd_buff_t *cmd) {
        if (cmd == NULL) return ERR_MEMORY;
        cmd->argc = 0;
        for (int i = 0; i < CMD_ARGV_MAX; i++) {
            cmd->argv[i] = NULL;
        }
        return OK;
    }
    
    int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd) {
        if (cmd_line == NULL || cmd == NULL)
            return ERR_MEMORY;
        clear_cmd_buff(cmd);
        int tokenCount = 0;
        char *ptr = cmd_line;
        
        while (*ptr) {
            while (*ptr && isspace((unsigned char)*ptr))
                ptr++;
            if (!*ptr)
                break;
            
            char *token = ptr;
            if (*ptr == '"' || *ptr == '\'') {
                char quote = *ptr;
                ptr++;
                token = ptr;
                while (*ptr && *ptr != quote)
                    ptr++;
                if (*ptr == quote) {
                    *ptr = '\0';
                    ptr++;
                }
            } else {
                while (*ptr && !isspace((unsigned char)*ptr))
                    ptr++;
                if (*ptr) {
                    *ptr = '\0';
                    ptr++;
                }
            }
            
            cmd->argv[tokenCount++] = token;
            if (tokenCount >= CMD_ARGV_MAX - 1)
                break;
        }
        
        cmd->argv[tokenCount] = NULL;
        cmd->argc = tokenCount;
        return tokenCount == 0 ? WARN_NO_CMDS : OK;
    }