简体   繁体   English

自定义外壳段故障

[英]Custom Shell Seg Faulting

I'm trying to make a custom shell for a class assignment.我正在尝试为课堂作业制作自定义外壳。 The TLDR is... I don't really know what's wrong with it. TLDR 是...我真的不知道它有什么问题。 From the debugging, it looks like there's an error in the loop() function, but I don't know why, or where the error exists.从调试来看,loop()函数好像有错误,但不知道为什么,也不知道错误在哪里。

What's happening is the application executes the command correctly.发生的事情是应用程序正确执行命令。 However, on the next loop for the next command input, it segfaults.但是,在下一个命令输入的下一个循环中,它会出现段错误。 I've tried to make sure all the variables are freed so I'm not writing attempting to write into memory that I can't.我试图确保所有变量都被释放,所以我不会试图写入我不能写入的内存。 That's the major issue.这就是主要问题。 The second (much more minor) issue is that I can't get piping to work.第二个(更次要的)问题是我无法让管道工作。 I'm also not sure why.我也不知道为什么。 I thought I re-wrote stdin/stdout correctly.我以为我正确地重新编写了 stdin/stdout。 (Yes, I know strtok id deprecated. I do plan on moving to "strtok_r") (是的,我知道 strtok id 已被弃用。我确实计划转移到“strtok_r”)

Does anyone have guidance or suggestions on what I'm not doing correctly?有没有人对我没有正确做的事情有指导或建议?

Cheers, M干杯,M

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <limits.h>

#define TOK_DELIM " \t\r\n\a\v" // \a is Alert. \v is vertical tab.
#define FG_EXEC 0
#define BG_EXEC 1
#define MAXARG 20
#define CMD_MAX 100 //Some arbitrary value...

/* Set up Command Segements */
struct cmd_seg {
    char *args[MAXARG];
    struct cmd_seg *next; // Linked List. Next node
};

struct cmd {
    struct cmd_seg *root;
    int mode; //BG, FG
};

/* Helper Functions - Core Functionality */
void cd(char *path){
    int code = chdir(path); //May only return -1 (error) or 0 (success)
    if(code == -1){
        printf("\nFailed to change your path to \"%s\"\n", path);
    }
    else{
        printf("\nChanged path to: %s\n", path);
    }
}

/* Helper Functions - Job Control */
void bg(pid_t pid){
    int status;
    if(kill(pid, SIGCONT) < 0){ printf("\nBG: JNF"); }
    else{ waitpid(pid, &status, WUNTRACED); }
}

void fg(pid_t pid){
    setpgid(pid, pid);
    int status;
    if (tcsetpgrp(1, getpgid(pid)) != 0){
        printf("\nFG: JNF");    
    }
    else{
        kill(pid, SIGCONT);
        waitpid(pid, &status, WUNTRACED);
    }
}

/* Helper Functions - PID, Child, Forks, etc */
void kill_child(pid_t pid){ // What an unforunate name... Dark humour.
    kill(pid, SIGTERM); //Safe Termination. SIGKILL may ne required?
}

/*
void destroyList(struct cmd** cmd1){
    struct cmd* cmd_cur = cmd1;
    struct cmd_seg* cs_cur;
    struct cmd_seg* next;
    cs_cur = cur->root;
    while(cs_cur != NULL){
        next = cs_cur->next;
        free(cs_cur);
        cs_cur = next;
    }
    free(cs_cur);
    free(cmd1);
}
*/

/* Helper Functions - Check for Built-in Command */
int builtins(struct cmd_seg *segment){
    /* Check for Internal Commands - CD, Exit, etc */
    if(strcmp(segment->args[0], "cd") == 0){
        cd(segment->args[1]);
        char path[PATH_MAX];
        getcwd(path, sizeof(path));
        printf("%s%%", path);
        fflush(stdout);
        return 1;
    }
    else if(strcmp(segment->args[0], "exit") == 0){
        printf("\nExiting Core Application.\n\n");
        exit(0);
    }
    /*
    else if(strcmp(segment->args[0], "kill") == 0){
        pid_t pid;
        pid = atoi(segment->args[1]);
        if(pid!=0){ // if 0, implies it's not an integer, failed extraction;
            kill_child(pid);
        }
        return 1;
    }
    */
    else{
        return -1;
    }
}

int exec_cmd_seg(struct cmd_seg *segment, int in_fd, int out_fd, int mode, int pGrpID){
    int status = 1;
    int IsBuiltin = builtins(segment);

    if(IsBuiltin == 0){ return -1; }
    else if(IsBuiltin == 1){ return 1; }
        /* 
        * Not a Builtin Command, Application has not Exited
        * Therefore fork
        */
        pid_t child_pid;
        child_pid = fork();
        if(child_pid < 0){
            printf("\nForking failed - Exiting Gracefully");
            exit(0);
        }
        else if(child_pid == 0){
            /* Forked */
            int damnPIDs = getpid();
            if(mode == FG_EXEC){ printf("\nFG Execution @ PID %d", damnPIDs); }
            else{ printf("\nBG Execution @ PID %d", damnPIDs); }

            signal(SIGINT, SIG_DFL);
            signal(SIGTSTP, SIG_DFL);
            signal(SIGCONT, SIG_DFL);

            /* Re-write In-Outs */
            dup2(in_fd, 0);
            dup2(out_fd, 1);

            if(in_fd != 0){
                close(in_fd);
            }
            else if(out_fd != 1){
                close(out_fd);
            }

            /* Check args[1] */
            int result = execvp(segment->args[0], segment->args);
            if(result < 0){
                printf("\nError Executing Command: %s", segment->args[0]);
                //exit(0);
            }
        }
        else{
            signal(SIGINT, SIG_IGN);
            signal(SIGINT, SIG_IGN);
            signal(SIGINT, SIG_DFL);
            if (mode == BG_EXEC) 
                signal(SIGCHLD, SIG_IGN);
            else 
                waitpid(child_pid, &status, WUNTRACED);
            if(in_fd != 0){
                close(in_fd);
            }
            if(out_fd != 1){
                close(out_fd);
            }
        return 1;
        }
    return 1;
}

int exec_cmd(struct cmd *command){
    int status = 1;
    struct cmd_seg* cur;
    struct cmd_seg* pfree;
    int fd = 0;
    //int count = 0;
    //printf("\nEXEC_CMD: Entering For1");
    //fflush(stdout);
    for(cur = command->root; cur != NULL; cur = cur -> next){
        //printf("\nExec_CMD - Command %d: %s", count, command->root->args);
        //fflush(stdout);
        if(cur -> next){
            //printf("\nExec_CMD - Command %d: %s", count, cur->args);
            //fflush(stdout);
            int fd2[2];
            pipe(fd2);
            status = exec_cmd_seg(cur, fd, fd2[1], command->mode, 0);
            fd = fd2[0];
        }
        else{
            status = exec_cmd_seg(cur, fd, 1, command->mode, 0);
        }

        cur = command -> root;
        pfree = cur;
        while(cur != NULL){
            cur = cur -> next;
            
            /* Clear pfree before setting it */
            free(pfree);
            pfree = cur;
        }
    }
    cur = NULL;
    pfree = NULL;
    free(command);
    command = NULL;
    return status;
}

/* Fix to use strtok_r */
struct cmd* parser(char *line){
    struct cmd* command = (struct cmd*)malloc(sizeof(struct cmd));
    command->root = (struct cmd_seg*)malloc(sizeof(struct cmd_seg));
    struct cmd_seg* cur;
    struct cmd_seg* pnew;
    cur = command->root; 
    /* Check if it is background command */
    char* pStart = line; //pointer
    int count = 0;
    while ((*pStart != '\n') && (*pStart != '\0')) {
        if (*pStart == '&') {
            count = 1;
            *pStart = '\0';
            break;
        }
        pStart++;
    }
    command->mode = count;
    /* Parse line as command Link list */
    char *res = line;
    char *temp;
    int i = 0;
    temp = strsep(&res, "|");
    for (i = 0; i < MAXARG - 1 && (cur->args[i] = strtok(temp, TOK_DELIM)) != NULL; i++)
        temp  = NULL;
    cur->args[i] = NULL;
    while ((temp = strsep(&res, "|")) != NULL) {
        pnew = (struct cmd_seg*) malloc(sizeof(struct cmd_seg));
        cur->next = pnew;
        cur = pnew;
        for (i = 0; i < MAXARG - 1 && (cur->args[i] = strtok(temp, TOK_DELIM)) != NULL; i++)
            temp = NULL;
        cur->args[i] = NULL;
    }
    cur->next = NULL;
    //free(cur);
    //free(pnew);
    //free(pStart);
    return command;
}

char* readLine(){
    char *buffer = malloc(sizeof(char)*CMD_MAX);
    char ch;
    int pos = 0;
    if(buffer){
            //printf("Inside Buffer If");
            //fflush(stdout);
            while(1){
                ch = getchar();
                //printf("Inside While\n");
                //fflush(stdout);
                /* Buffer Allocated */
                if(ch == EOF || ch == '\n'){
                    printf("Command: %s\n", buffer);
                    return buffer;
                }
                else{
                    buffer[pos] = ch;
                }
                pos++;
        }
    }
    else{
        printf("Allocation Failed\n");
        fflush(stdout);
        exit(0);
    }
}

void loop(){
    
    /* Loop Command Input */
    int status = 1;
    //int l_count = 0;
    while(status >= 0){
        char *line;
        struct cmd *cmd;
        //printf("Inside Loop - 1\n");
        //fflush(stdout);

        /* Print Shell Prompt */
        char path[PATH_MAX];
        getcwd(path, sizeof(path));
        printf("%s%%", path);
        fflush(stdout);

        line = readLine();
        if(strlen(line) == 0){
            printf("Failed to read line.");
            exit(0);
        }
        else{
            cmd = parser(line);
            if(cmd!=NULL){
                //printf("\nCMD not null - executing");
                //fflush(stdout);
                status = exec_cmd(cmd);
            }
            else{
                printf("\nFailed to parse command correctly");
                fflush(stdout);
                exit(0);
            }
        }
        free(line);
        //free(cmd);
        //free(path); Not a heap device -- GCC Output
    }
}

int main(int argc, char **argv){
    loop();

    return 1;
}   

The segfault occurs in the for statement.段错误发生在for语句中。 The body of the loop has executed one time, then the loop-expression cur = cur->next is executed, but cur is NULL.循环体执行了一次,然后循环表达式cur = cur->next被执行,但cur为 NULL。

It's NULL because of the while statement, which frees all the cmd_seg s in the linked list (I suspect that code is supposed to be after the for-loop rather than inside it).它是 NULL 因为while语句,它释放了cmd_seg的所有cmd_seg s(我怀疑代码应该在 for 循环之后而不是在它内部)。

The cond-expression cur != NULL doesn't catch this because it is executed after the init-expression and then after each loop-expression . cond-expression cur != NULL没有捕捉到这一点,因为它在init-expression之后执行,然后每个loop-expression之后执行。

int exec_cmd(struct cmd *command){
    int status = 1;
    struct cmd_seg* cur;
    struct cmd_seg* pfree;

    for(cur = command->root; cur != NULL; cur = cur -> next){
        if(cur -> next){
            ...
        }

        cur = command -> root;
        pfree = cur;
        while(cur != NULL){
            cur = cur -> next;
            free(pfree);
            pfree = cur;
        }
    }
    ...
}

After I fixed this by moving the cmd_seg -freeing code to be after the for-loop, I looked at pipeline commands, but they all succeeded for me.在我通过将cmd_seg释放代码移到 for 循环之后解决了这个问题后,我查看了管道命令,但它们对我来说都成功了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM