【问题标题】:IO redirection and buffer issues, fflush and cIO 重定向和缓冲区问题,fflush 和 c
【发布时间】:2013-03-02 04:50:48
【问题描述】:

对于我的班级,我们将实现一个带有输出重定向的 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;    
}

【问题讨论】:

  • 您可以通过向我们展示 (a) 一个失败的命令集示例,(b) 它应该在成功时的样子来为我们节省很多问题, 和 (c) 用您迄今为止所采取的任何调试步骤启发我们。输入单词“第一个命令”不是一种选择。请提供详细步骤,说明您的 shell 应该接受什么作为输入,以及它的输出应该是什么样的。
  • 会的。正如我展示的一个失败的命令集的示例是“第一个命令”,它应该告诉我“第一个”不是这样的文件或目录,而是它前面有一些垃圾。我将编辑问题以显示更多您要问的内容。就调试而言,这是我问的唯一问题:我使用什么技术来查找错误?到目前为止,我已经尝试过使用 fflush 但它没有用。

标签: c buffer io-redirection dup fflush


【解决方案1】:

垃圾的原因是您从未将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(),就像您在其他地方一样。

【讨论】:

  • @WhozCraig 我知道,我建议他使用perror(),以便他可以添加该消息。他在程序的其他部分这样做,他也应该在那里这样做。
猜你喜欢
  • 2014-09-12
  • 2021-12-19
  • 1970-01-01
  • 2016-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-08
相关资源
最近更新 更多