天天看點

linux核心實驗二實作過程

linux核心實驗two實作過程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>

#define normal         0 /*一般的指令*/
#define out_redirect   1 /*輸出重定向*/
#define in_redirect    2 /*輸入重定向*/
#define have_pipe      3 /*指令中有管道*/

int commandcounts=0;/*指令條數*/

void print_prompt();                           /*列印提示符*/
void get_input(char *);                        /*得到輸入的指令*/
void explain_input(char *,int *,char a[100][256]);   /*對輸入指令進行解析*/
void do_cmd(int ,char a[100][256]);                  /*執行指令*/
int find_command(char *);                      /*查找指令中的可執行程式*/

int main(int argc,char **argv)
{
    int i;
    int argcount = 0;
    char arglist[100][256];
    char **arg = NULL;
    char *buf = NULL;

    buf = (char *)malloc(256);
    if (buf == NULL){
        perror("malloc failed");
        exit(-1);
    }
    char* commands[10];
    while(1){
        /*将buf所指向的空間清零*/
        memset(buf,0,256);
        print_prompt();
        get_input(buf);
        /*若輸入的指令為exit或logout則退出本程式*/
        if (strcmp(buf,"exit\n") == 0 || strcmp(buf,"logout\n") == 0)
          break;
        //找出有幾條指令,多條指令以分号分割
        int index=0;
        commandcounts=1;
        for(index=0;index<strlen(buf);index++){
            if(buf[index]==';')
                commandcounts++;
            
        }
        if(commandcounts>10){
            printf("%s\n","commandcounts over.max num is 10");
            continue;
        }
        index=0;
        char *p=strtok(buf,";");
        do{
            commands[index]=p;
            index++;
        }
        while(p=strtok(NULL,";"));
        for(index=0;index<commandcounts;index++){
            for (i=0;i<100;i++){
                  arglist[i][0] = '\0';
            }
            argcount = 0;
            explain_input(commands[index],&argcount,arglist);
            do_cmd(argcount,arglist);
        }
        
    }

    if (buf != NULL){
        free(buf);
        buf = NULL;
    }
    exit(0);
}

void print_prompt()
{
    printf("myshell$$");
}

/*擷取使用者輸入*/
void get_input(char *buf)
{
    int len = 0;
    int ch;

    ch = getchar();
    while (len <256 && ch != '\n'){
        buf[len++] = ch;
        ch = getchar();
    }

    if (len ==256){
        printf("commond is too long \n");
        exit(-1); /*輸入的指令過長則退出程式*/
    }
    buf[len] = '\n';
    len++;
    buf[len] = '\0';
}

/*解析buf中的指令,将結果存入arglist中,指令以回車符号\n結束*/
/*如輸入指令為“ls -l /tmp”,則arglist[0],arglist[1],arglist[2]分别為ls,-l和/tmp*/

void explain_input(char *buf,int *argcount,char arglist[100][256])
{
    char *p = buf;
    char *q = buf;
    int number = 0;

    while(1){
        if (p[0] == '\n')
          break;
        if (p[0] == ' ')
          p++;
        else {
          q = p;
          number = 0;
          while ((q[0] != ' ') && (q[0] != '\n')){
              number++;
              q++;
          }
          strncpy(arglist[*argcount],p,number+1);
          arglist[*argcount][number] = '\0';
          *argcount = *argcount + 1;
          p = q;
        }
    }
}

void do_cmd (int argcount,char arglist[100][256])
{
    int flag = 0;
    int how = 0;           /*用于訓示指令中是否含有>,<,|*/
    int background = 0;    /*辨別指令中是否有背景運作辨別符*/
    int status;
    int i;
    int fd;
    char *arg[argcount+1];
    char *argnext[argcount+1];
    char *file;
    pid_t pid;

    /*将指令取出*/
    for (i=0;i<argcount;i++){
        arg[i] = (char *)arglist[i];
    }
    arg[argcount] = NULL;

    /*檢視指令行是否有背景運作符*/
    for (i=0;i<argcount;i++){
        if (strncmp(arg[i],"&",1) == 0){
          if (i == argcount - 1){
            background = 1;
            arg[argcount-1] = NULL;
            break;
          }
          else {
            printf("wrong command\n");
            return;
          }
        }
    }
    for (i=0;arg[i] != NULL;i++){
        if (strcmp(arg[i],">") == 0){
            flag++;
            how = out_redirect;
            if (arg[i+1] == NULL)
                flag++;
        }
        if (strcmp(arg[i],"<") == 0){
            flag++;
            how = in_redirect;
            if (i == 0)
                flag++;
        }
        if (strcmp(arg[i],"|") == 0){
          flag++;
          how = have_pipe;
          if (arg[i+1] == NULL)
              flag++;
          if (i == 0)
              flag++;
        }
    }

    /*flag大于1,說明指令中含有多個>,<,|符号,本程式是不支援這樣的指令的,
        或者指令格式不對,如“ls -l /tmp >”*/
    if (flag > 1){
        printf("wrong command\n");
        return;
    }
    if (how == out_redirect){/*指令隻含有一個輸出重定向符号>*/
        for (i=0;arg[i] != NULL;i++){
          if (strcmp(arg[i],">") == 0){
            file = arg[i+1];
            arg[i] = NULL;
          }
        }
    }

    if (how == in_redirect){/*指令隻含有一個輸入重定向符号<*/
        for (i=0;arg[i] != NULL;i++){
          if (strcmp(arg[i],"<") == 0){
            file = arg[i+1];
            arg[i] = NULL;
          }
        }
    }

    if (how == have_pipe){/*指令隻含有一個管道符号|*/
        /*把管道符号後面的部分存入argnext中,管道後面的部分是一個可執行的Shell指令*/
        for (i=0;arg[i] != NULL;i++){
          if (strcmp(arg[i],"|") == 0){
            arg[i] = NULL;
            int j;
            for (j=i+1;arg[j] != NULL;j++){
                argnext[j-i-1] =arg[j];
            }
            argnext[j-i-1] = arg[j];
            break;
          }
        }
    }

    if ((pid = fork()) < 0) {
        printf("fork error\n");
        return;
    }

    switch(how) {
        case 0:
          /*pid為0說明是子程序,在子程序中執行輸入的指令*/
          /*輸入的指令中不含>,<和|*/
          if (pid == 0){
            if (!(find_command(arg[0]))){
            printf("%s:command not found\n",arg[0]);
            exit(0);
            }
            execvp(arg[0],arg);
            exit(0);
          }
          break;
        case 1:
          if (pid == 0){
            if (!(find_command(arg[0]))){
                printf("%s: commandnot found\n",arg[0]);
                exit(0);
            }
            fd = open(file,O_RDWR|O_CREAT|O_TRUNC,0644);
            dup2(fd,1);
            execvp(arg[0],arg);
            exit(0);
          }
          break;
        case 2:
          /*輸入的指令中含有重定向符<*/
          if (pid == 0){
            if (!(find_command(arg[0]))){
                printf("%s:command not found\n",arg[0]);
                exit(0);
            }
            fd = open(file,O_RDONLY);
            dup2(fd,0);
            execvp(arg[0],arg);
            exit(0);
          }
          break;
        case 3:
          /*輸入的指令中含有管道*/
          if (pid == 0){
            int pid2;
            int status2;
            int fd2;

            if ((pid2 = fork()) < 0){
                printf("fork2 error\n");
                return;
            }
            else if (pid2 == 0){
                if (!(find_command(arg[0]))){
                    printf("%s:command not found\n",arg[0]);
                    exit(0);
                }
                fd2 = open("/tmp/youdonotknowfile",O_WRONLY|O_CREAT|O_TRUNC,0644);
                dup2(fd2,1);
                execvp(arg[0],arg);
                exit(0);//子程序在此退出
            }
            //父程序在此執行
            if (waitpid(pid2,&status2,0) == -1)
                printf("wait for child process error\n");

            if (!(find_command(argnext[0]))){
                printf("%s:command not found\n",argnext[0]);
                exit(0);
            }
            fd2 = open("/tmp/youdonotknowfile",O_RDONLY);
            dup2(fd2,0);
            execvp(argnext[0],argnext);

            if (remove("/tmp/youdonotknowfile"))
            printf("remove error\n");
            exit(0);
          }
          break;
        default:
          break;
    }

    /*若指令中有&,表示背景執行,父程序直接傳回,不等待子程序結束*/
    if (background == 1){
        printf("[process id %d]\n",pid);
        return;
    }

    /*父程序等待子程序結束*/
    if (waitpid(pid,&status,0) == -1)
        printf("wait for child process error\n");

}
/*
 * 産看這個指令是否存在
 */
int find_command(char *command)
{
    DIR *dp;
    struct dirent *dirp;
    char *path[] = {"./","/bin","/usr/bin",NULL};

    /*使目前目錄下的程式可以運作,如指令"./fork"可以被正确解釋和執行*/
    if (strncmp(command,"./",2) == 0)
        command = command + 2;

    /*分别在目前目錄、/bin和/usr/bin目錄查找要執行的程式*/
    int i = 0;
    while (path[i] != NULL){
        if ((dp = opendir(path[i])) == NULL)
          printf("can not open /bin \n");
        while((dirp = readdir(dp))!= NULL){//讀目錄中的所有的檔案
          if (strcmp(dirp->d_name,command) == 0){//有這個檔案
            closedir(dp);
            return 1;
          }
        }
        closedir(dp);
        i++;
    }
    return 0;
}
           

繼續閱讀