繁体   English   中英

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

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

对于我的类,我们将实现一个带有输出重定向的shell。 我有输出重定向工作,除了我的第一个命令总是被损坏看到:

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

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

我认为这与正确的fflushing有关。 我把它洒在我的代码周围(这是愚蠢的),看看它是否会在循环中有所帮助,但事实并非如此。 我也尝试打印出我的OrderedIds列表,它只是一个命令列表,用于检查我是否可以在任何地方找到H <@?4,但即使我初始化它也没有用。

谢谢你的帮助。

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

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

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

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

由于orderedIds[i]是char的数组,而不是char *,因此您应该将sizeof(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()

暂无
暂无

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

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