对于我的课程,我们将实现带有输出重定向的shell。我的输出重定向正常工作,但我的第一个命令始终损坏,请参见:

$ echo this doesn't work
H<@?4echo
No such file or directory
$ echo this does work
this does work


但此后的每个命令似乎都很好。我使用什么技术来查找导致此问题的错误?

我认为这与无法正确冲洗有关。我将其撒在我的代码周围(这很愚蠢),以查看它在循环中是否有帮助,但没有帮助。我还尝试打印出我的OrderedIds列表,该列表只是检查是否可以在任何地方找到H
谢谢你的帮助。

#define LENGTH 1000
#define MAXCMD 11
#define MAX_STR_LEN 20
void init(char *temp);
void clean(char **orderedIds);
void init_pid(int *temp);
void reap(int *temp,int ret_status);
void jobs(int *pid_list, char **orderedIds);
int ioRedir(char **orderedIds);
void reap(int *temp,int ret_status){//chainsaws all zombies
    int a;
    for (a=0; a<LENGTH; a++ ){
        waitpid(temp[a],&ret_status,WNOHANG) == temp[a];
    }
}
void init(char *temp){//Function to initialize/reset the cmd array
    int i;
    for(i=0; i<LENGTH; i++){
        temp[i] = 0;
    }
}
void init_pid(int *temp){//Function to initialize/reset the pid list
    int i;
    for(i=0; i<LENGTH; i++){
        temp[i] = -777;
    }
}
void clean(char **orderedIds){//garbage collection
    int i;
    for(i=0; i<MAXCMD; i++){
        free(orderedIds[i]);
    }
    free(orderedIds);
}
void jobs(int *pid_list, char **orderedIds){//function to check for background proccesses
    printf("Jobs:\n");
    int y;
    for(y=0; y<LENGTH; y++){
        if(kill(pid_list[y], 0) == 0){
            printf("%d\n", pid_list[y]);
        }
    }
    clean(orderedIds);
    printf("$ ");
}
int ioRedir(char **orderedIds){
    int i;
    for ( i = 0; i<MAXCMD; i++){
        if(orderedIds[i] == NULL){
            return -1;
        }
        if(strcmp(orderedIds[i],">")==0){
            return (i+1);
        }

    }
}

int main (int argc, char *argv[], char *envp[])
{
    char temp[LENGTH];
    char * tok;
    char c = '\0';
    int saved_stdout;
    int pid_list[LENGTH];
    int ret_status;
    int numFile;
    int pid_counter = 0;
    int outputfd = -1;
    char outputFile[MAX_STR_LEN];
    pid_t pid;
    printf("$ ");
    int i, j, y, background= 0;
    init_pid(pid_list);
    while(c !=EOF) { //while not ^D // Source: LinuxGazzette Ramankutty
        outputfd = -1;
        fflush(0);
        c = getchar();
        if(c=='\n'){ //entered command
            reap(pid_list, ret_status);
            char **orderedIds = malloc(MAXCMD * sizeof(char*));
            for (i=0; i<MAXCMD; i++){
                 orderedIds[i] = malloc(MAXCMD * sizeof(char*));
            }
            int k=0;
            tok = strtok(temp, " \n\t\r");
            while (tok !=NULL){
                strcpy(orderedIds[k], tok);
                k++;
                tok = strtok (NULL, " \n\t\r");
            }
            orderedIds[k] = NULL; //END with NULL
            init(temp); //initialize the array
            if(orderedIds[0] ==NULL){
                printf("\n$ ");
                continue;
            }
            numFile = ioRedir(orderedIds);
            if(strcmp(orderedIds[0],"exit")==0){// if exit
                printf("now exiting...\n");
                break;
            }
            if(strcmp(orderedIds[k-1], "&")==0){//if background
                 orderedIds[k-1] = NULL;
                 background = 1;
            }else background = 0;

            if(strcmp(orderedIds[0], "jobs") == 0){//if jobs command
                jobs(pid_list, orderedIds);
                continue;
            }
            if(strcmp(orderedIds[0], "cd") == 0){ //if change directory command
                chdir(orderedIds[1]);
                printf("$ ");
                continue;
            }
            pid = fork();
            if (pid!=0 && background == 1)
            {
                //go to end of list in pid and put it in
                pid_list[pid_counter] = pid;
                pid_counter++;
                printf("To the background: %d\n", pid);
            } else if (pid==0 && background == 1) {
                    fclose(stdin); //close child's stdin
                    fopen("/dev/null", "r"); //open a new stdin that is always empty.
                if(execvp(orderedIds[0], orderedIds)){
                    printf("%s\n", orderedIds[0]);
                    puts(strerror(errno));
                    exit(127);
                }
            }
            if (pid != 0 && !background){
                //printf("Waiting for child (%d)\n", pid);
                fflush(0);
                pid = wait(&ret_status);
            }  else if (pid == 0 && !background) {
                    if(numFile > 0){
                        strncpy(outputFile, orderedIds[numFile], strlen(orderedIds[numFile]));
                        numFile = 0;
                        //open the output file
                        outputfd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IROTH);
                        if (outputfd < 0) {
                            exit(EXIT_FAILURE);
                        }
                        //close STDOUT
                        if(close(STDOUT_FILENO) < 0 ){
                            perror("close(2) file: STDOUT_FILENO");
                            close(outputfd);
                            exit(EXIT_FAILURE);
                        }
                        //use dup to rerout the output
                        if(saved_stdout = dup(outputfd) != STDOUT_FILENO){
                            perror("dup(2)");
                            close(outputfd);
                            exit(EXIT_FAILURE);
                        }
                        close(outputfd);

                    }

                if (execvp(orderedIds[0], orderedIds)){
                    printf("%s\n", orderedIds[0]);
                    puts(strerror(errno));
                    exit(127);
                }
            }
            dup2(saved_stdout,outputfd);
            clean(orderedIds);
            fflush(0);
            printf("$ ");
        } else {
            strncat(temp, &c, 1);
        }
    }
    fflush(0);
    return 0;
}

最佳答案

产生垃圾的原因是,您从未在temp的开头将main()初始化为空字符串。您在处理每个命令后调用init(temp)

您的代码中还有许多其他问题:

orderedIds[i] = malloc(MAXCMD * sizeof(char*));


由于orderedIds[i]是char而不是char *的数组,因此应将大小乘以sizeof(char)。另外,不清楚为什么使用MAXCMD作为大小-在上一行中,这是一行中的最大单词数,而不是单词中的字符数。

strcpy(orderedIds[k], tok);


您应使用strncpy()来确保所复制的内容不超过orderedIds[k]的大小。

另一种选择是不首先分配所有orderedIds[i]。代替使用strcpy(),使用strdup()并将其分配给orderedIds[k];如果这样做,则必须记住free()所有这些字符串。

第三种选择是根本不复制字符串。只需将strtok()返回的指针分配给orderedIds[k]。但是在这种情况下,您必须等到分叉之后才能调用init(tmp)

strncpy(outputFile, orderedIds[numFile], strlen(orderedIds[numFile]));


限制应为outputFile的大小,而不是orderedIds[numFile]的长度。 strncpy()复制的长度绝不会超过源的长度,您需要告诉它目标的最大大小,以防止缓冲区溢出。

outputfd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IROTH);
if (outputfd < 0) {
   exit(EXIT_FAILURE);
}


您应该致电perror()报告open()失败的原因。

puts(strerror(errno));


像在其他地方一样,呼叫perror()

10-06 04:16