简体   繁体   English

IO重定向和缓冲区问题,fflush和c

[英]IO redirection and buffer issues, fflush and c

for my class we are to implement a shell with output redirection. 对于我的类,我们将实现一个带有输出重定向的shell。 I have the output redirection working, except my first command is always corrupted see: 我有输出重定向工作,除了我的第一个命令总是被损坏看到:

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

but every command afterwards seems fine. 但事后的每一个命令似乎都很好。 What technique do I use to find the bug that is causing this problem? 我使用什么技术来查找导致此问题的错误?

I think it has something to do with not fflushing properly. 我认为这与正确的fflushing有关。 I sprinkled it around my code (which was stupid) to see if it would help during the loop but it did not. 我把它洒在我的代码周围(这是愚蠢的),看看它是否会在循环中有所帮助,但事实并非如此。 I've also tried printing out my OrderedIds list which is just a list of commands to check if I could find H<@?4 anywhere, but even when I initialized it, it did not work. 我也尝试打印出我的OrderedIds列表,它只是一个命令列表,用于检查我是否可以在任何地方找到H <@?4,但即使我初始化它也没有用。

Thanks for your help. 谢谢你的帮助。

#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;    
}

The reason for the garbage is that you never initialized temp to an empty string at the beginning of main() . 垃圾的原因是你从未在main()的开头将temp初始化为空字符串。 You call init(temp) after processing each command. 在处理每个命令后调用init(temp)

There are lots of other problems in your code: 您的代码中还有许多其他问题:

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

Since orderedIds[i] is an array of char, not char*, you should multiply the size by sizeof(char) . 由于orderedIds[i]是char的数组,而不是char *,因此您应该将sizeof(char)乘以sizeof(char) Also, it's not clear why you're using MAXCMD as the size -- on the previous line this was the maximum number of words on a line, not the number of characters in a word. 此外,还不清楚为什么使用MAXCMD作为大小 - 在前一行中,这是一行中的最大字数,而不是单词中的字符数。

strcpy(orderedIds[k], tok);

You should use strncpy() to ensure that you don't copy more than the size of orderedIds[k] . 您应该使用strncpy()来确保不要复制大于orderedIds[k]的大小。

Another option would be not to preallocate all the orderedIds[i] in the first place. 另一个选择是首先预先分配所有orderedIds[i] Instead of using strcpy() , use strdup() and assign this to orderedIds[k] ; 而不是使用strcpy() ,使用strdup()并将其赋值给orderedIds[k] ; if you do this, you have to remember to free() all these strings. 如果你这样做,你必须记住free()所有这些字符串。

A third option is not to copy the strings at all. 第三种选择是根本不复制字符串。 Just assign the pointers returned by strtok() to orderedIds[k] . 只需将strtok()返回的指针分配给orderedIds[k] But in this case you mustn't call init(tmp) until after you've forked. 但是在这种情况下,你必须在分叉之后才调用init(tmp)

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

The limit should be the size of outputFile , not the length of orderedIds[numFile] . 限制应该是outputFile的大小,而不是orderedIds[numFile]的长度。 strncpy() will never copy more than the length of the source, you need to tell it the maximum size of the destination to prevent a buffer overflow. strncpy()永远不会复制超过源的长度,你需要告诉它目的地的最大大小,以防止缓冲区溢出。

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

You should call perror() to report the reason that open() failed. 您应该调用perror()来报告open()失败的原因。

puts(strerror(errno));

Call perror() , like you do elsewhere. 像其他地方一样调用perror()

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

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