0

我在 C 中创建了一个 shell,这是代码。我还对代码进行了注释。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

#define PATH        "path="  //just a constant string
#define DELIM       ":"     //just a constant string    


typedef void (*sighandler_t)(int);
char* cwdtemp = "";
int false=0;

/*structure of functions*/

char* readLine(char* line, size_t len);
void split(char* input, char *argv[]);
int checkpipe( char *input);
void run (char* argv[]);
void runPipe(char *argv[], char *argv2[]);
void setPath(char* inputLine);
char* getPath();
void changedir(char*  dir);
char* strcasestr(const char *haystack, const char *needle);
void handle_signal(int signo);



int main(){ 
    char* input=NULL;  //string to save user input
    char* input2;       //string to save the 2nd command if theres a pipe
    char *argv[50];     //array to sabe the user input after spliting by spaces
    char *argv2[30];    //array to save the second command if thrs a pipe
    char argv3[100];    //array for the use of getcwd function
    int i;              //varibale to save the index of the pipe
    char* cwd;          //variable to save the current working directory


    while (1) {                     //infinite while loop


        signal(SIGINT, SIG_IGN);        //capture teh signal and ignore its default action
        signal(SIGINT, handle_signal);  //capture the signal and parse it to handle signal function

        cwd=getcwd(argv3,100);      // get the current working directory and save it to cwd
        cwdtemp=cwd;                //save current directory as string to cwdtemp
        printf("%s",cwd);           //print cwd
        printf(":~mosh:~$ ");       //show a prompt     
        input=readLine(input, 0);   //read the user input and save it as a string(char array)   

        if(strcasestr(input, PATH) == input){   //strcasesrt function will check user input and see if it has "path="(substring matching)
            setPath(input);                     //pass user input to setpath function       
        }else{  
            i=checkpipe(input);                 //saves the index of the ' | ' charactor in user input string 
            if(i==0){                           //if theres no  pipe
                split(input, argv);             //split the user input by spaces and save them in argv array
                if(argv[0] == NULL) {           //if user input is null continue the loop
                    continue;
                }



                /* exit this shell when "exit" is inputed */
                if(strcmp(argv[0], "exit") == 0) {                  
                    exit(0);
                }




                if(strcmp(argv[0], "cd") == 0) {    //if the user entered cd command(its not found in /bin)             
                    changedir(argv[1]);             //pass the name of the directory that should be changed to the changedir function 
                }



                run(argv);              //pass argv array to run function
                /*checks if the command is valid*/
                   if(false==-1 ){
                    if(strcmp(argv[0], "exit") == 0){}
                    else if(strcmp(argv[0], "cd") == 0){}
                    else{
                    printf("no such mosh command\n");}

                    false=0;
                    }
            }


            else{                       //if thers a pipe
                input2=&input[i+1];     //points input2 to the memory location of the charactor after charactor '|'  
                input[i]='\0';          //adds the escape charatctor to the charactor before '|' charactor of the input and signal the end of input string
                split(input, argv);     //split input by spaces and save in argv array  
                split(input2, argv2);   //split input2 by spaces and save in argv2 array

                if(fork()){             //creates a child process
                    wait(NULL);         //wait till the child process terminates
                }

                else{                       //else execute the pipe in parent process 
                    runPipe(argv, argv2);               
                }


            }
        }               
    }   
}

/*split the input by space and fill to the given array*/
void split(char* input, char *argv[]){
    char* p;                   //char array
    int argc;                   
    argc=0;                                 
    p=strtok(input, " ");       //torkanize user input by spaces and save to p  

    while(p!=NULL){         //until thrs charactors in p
        argv[argc]=p;           
        argc++;
        p=strtok(NULL, " ");    //points the torkanizer to the point where it stoped before and torkanize p
    }   
    argv[argc]='\0';            //adds end of string to the last index of argv
}

/* read a line */
char* readLine(char* line, size_t len){ 
    getline(&line, &len, stdin);            
    *(line+strlen(line)-1)='\0';
    return line;
}

/*return the array index of | character if any, otherwise 0*/
int checkpipe( char *input){
    int i = 0;
    int returnvalue = 0;
    for ( ; i < strlen ( input ) ; i++ ){
        if ( input[i] == '|' ){             //find the index where '|' in userinput and retuen the index ,if not found return 0
            returnvalue = i;
            break;
        }   
    }
    return returnvalue;
}

/*execute a command without | in another process*/
void run (char* argv[]){
    pid_t pid = fork();     //creats a fork and save its pid in pid variable        
    if(pid == -1) {                         
        perror("fork");
        exit(1);
    } else if(pid == 0) {               //if child process was created successfully
        false=execvp(argv[0], argv);            //execute the command by execcvp function
        //exit(0);
    } else {                        
        wait(NULL);                     //wait till child process terminates
    }   
}

/*execute a command with a | in two processes*/
void runPipe(char *argv[], char *argv2[]){  
    int pfds[2];            //int array to be used in file descriptors 
    pipe(pfds);             //creates the pipe
    int stdin_bak = dup(0); 
    if (fork()==0) {            //if the creation of fork successfull
        close(1);               //close current stdout
        dup(pfds[1]);           //duplicate stdout to the write end of the pipe
        close(pfds[0]);         //close stdin
        printf("i'm child\n");
        execvp(argv[0], argv);  //execute teh command
        exit(0);
    } else {                    //else in parent
        close(0);               //close current stdin
        dup(pfds[0]);           //duplicate stdin to the read end of the pipe
        close(pfds[1]);         //close stdout
        wait(NULL);             //wait till child process terminates
        execvp(argv2[0], argv2);//execute command               
    }
}

/*add a given path to the environmental variable PATH*/
void setPath(char* inputLine){  
    char* pathIn = &inputLine[strlen(PATH)];                    //save the input path that was given by user(without path=)
    char* oldPath = getenv("PATH");                             //get the current path from getenv function and save to oldpath
    int lenPath = strlen(oldPath) + strlen(pathIn) + 1 + 1;     
    char* pathOut = malloc(sizeof(char) * lenPath);         //allocate memoery to pathout by malloc
    strcat(pathOut, oldPath);                                   //combine oldpath and pathout and save to pathout by strcat function
    strcat(pathOut, DELIM);                                     //combine oldpath and DELIM(constant string) and save to pathout
    strcat(pathOut, pathIn);                                    //combine oldpath and pathinand save to pathout 
    pathOut[lenPath - 1] = '\0';    
    setenv("PATH", pathOut, 1);                                 //set the new path by setenv function
    free(pathOut);                                              //free the memory allocated by malloc   
}

/*change directory if possible*/
void changedir(char* dir){
    if(dir=='\0'){              //if user entered nothing after cd
        chdir( "/home/" );      //change to home
    }else{
        if(chdir(dir)==-1){     //if chdir function returned error  
            printf("%s:Cannot find the directory\n",dir);
        }
    }
}



void handle_signal(int signo)
{
    printf("\n");
    printf("%s",cwdtemp);
    printf(":~mosh:~$ ");
    fflush(stdout); //flush the stdout or printf will be in sameline

}

这是我的问题。编译这段代码后,我给出了一个错误的命令,如“hdgdg”。所以输出是“找不到命令”。但是当我运行像“hakka|akjk”这样的命令(这是一个管道命令)时,我有一个无限循环作为输出。那么我该如何解决这个问题?谢谢你。

4

0 回答 0