0

私のクラスでは、出力リダイレクトを備えたシェルを実装します。最初のコマンドが常に破損していることを除いて、出力リダイレクトが機能しています。

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

しかし、その後のすべてのコマンドは問題ないようです。この問題の原因となっているバグを見つけるには、どのような手法を使用すればよいですか?

うまく流せていないことが関係していると思います。ループ中に役立つかどうかを確認するために、コードの周りにそれを振りかけましたが(これはばかげていました)、そうではありませんでした。また、どこでも H<@?4 を見つけることができるかどうかを確認するためのコマンドのリストである OrderedIds リストを印刷しようとしましたが、初期化しても機能しませんでした。

ご協力いただきありがとうございます。

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

1 に答える 1

2

ガベージの理由はtemp、の先頭で空の文字列に初期化していないためですmain()init(temp)各コマンドを処理した後に呼び出します。

コードには他にも多くの問題があります。

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

は char* ではなく char の配列であるためorderedIds[i]、サイズに を掛ける必要がありますsizeof(char)。また、サイズとして使用している理由が明確ではありません。MAXCMD前の行では、これは単語の文字数ではなく、行の最大単語数でした。

strcpy(orderedIds[k], tok);

strncpy()のサイズを超えてコピーしないようにするには、 を使用する必要がありorderedIds[k]ます。

別のオプションは、最初からすべてを事前に割り当てないことです。orderedIds[i]を使用する代わりに、これをstrcpy()使用strdup()して割り当てorderedIds[k]ます。free()これを行う場合、これらすべての文字列を覚えておく必要があります。

3 番目のオプションは、文字列をまったくコピーしないことです。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()他の場所と同じように、 に電話してください。

于 2013-03-02T06:08:42.010 に答える