c 实现的shell

来源:互联网 发布:西门大妈知乎 编辑:程序博客网 时间:2024/05/21 14:41

project需要,所以做了一个。参考了网站:http://stephen-brennan.com/2015/01/16/write-a-shell-in-c/


实现了:执行基本命令,从PROFILE文件读取初始working directory,进程持续5秒以后可以提示杀死进程,以及一个alias功能(时间不够只写了逻辑部分,如果读写没问题的话应该能够实现),以及一个if 的条件的解析(做的不太好,日后补上)


代码:

////  main.c//  Shell_c////  Created by liuchang on 9/18/15.//  Copyright (c) 2015 liuchang. All rights reserved.//#include <stdio.h>#include <time.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <signal.h>#include <sys/types.h>#include <string.h>void show_prompt();char * read_line();int exec_command(char**);char ** split_line(char *);int launch(char ** args);int is_fileexist(char * comm);//check if exists the commandchar buffer[80];//缓存用户输入的命令#define BUFFSIZE 500#define TRUE 1int command_length=0;//builtin functionint builtin_exit(char ** args);int builtin_cd(char ** args);int builtin_if(char ** args);int builtin_alias(char ** args);int builtin_help(char ** args);int num_builtin();int check_table(char * alias);// check if the alias exist in the tablechar * builtin_str[]={"exit","cd","if","alias","help"};int (*builtin_func[])(char **) = {&builtin_exit,&builtin_cd,&builtin_if,&builtin_alias,&builtin_help};int main(int argc, const char * argv[]) {    //prepare    time_t nowtime;    struct tm *timeinfo;    time( &nowtime );    timeinfo = localtime( &nowtime );    int year, month, day;    year = timeinfo->tm_year + 1900;    month = timeinfo->tm_mon + 1;    day = timeinfo->tm_mday;    printf("welcome to my shell\n");    printf("%d-%d-%d\n", year, month, day);        //read file,switch workspace    FILE * file;int i;char buf[BUFFSIZE];            memset(buf,0,sizeof(buf));if((file = fopen("PROFILE","r")) == NULL){printf(" cannot open file, terminate immediately\n");exit(1);}i=0;while(!feof(file)){buf[i++] = fgetc(file);//??? what the fuckif(i>50){printf("buffer is not enough\n");exit(1);}}        buf[i-2]='\0';//-2??        i--;    char * user=getlogin();    int count =0;    while(count < sizeof(user)){        buf[i++] = user[count++];    }        //change directory        chdir(buf);        //printf("the user is : %s\n",user);//printf("the directory is: %s ",buf);        //main loop    char * command;    char ** args;    int status=1;    while (status) {        command_length=0;        //show propmpt        show_prompt();        //read line        command =read_line();        //printf("the input is : %s",command);        //split command        args=split_line(command);        //execute in a child process        status=exec_command(args);                free(command);        free(args);    }        }void show_prompt(){    //add user info    char * path;    char *user;    path = get_current_dir_name();    user=getlogin();    printf("%s@%s$",user, path);    }char * read_line(void){    //char *input=NULL;//用户输入命令    //int command_len=0;//输入字符个数    char *line = NULL;    size_t bufsize = 0; // have getline allocate a buffer for us    getline(&line, &bufsize, stdin);    return line;}int exec_command(char ** args){    //printf("executing command..\n");    //check several conditions..    if(args[0]==NULL){        return 1;// 比如按下 enter    }    //if it is builtin command..    int i;    //printf("the number of built in: %d",num_builtin());    for(i =0;i<num_builtin();i++){if(strcmp(args[0],builtin_str[i]) ==0){                //printf("call builtin function\n");return (*builtin_func[i])(args);           }    }    //else    //printf("using noral function\n");    return launch(args);}#define BUFFER_TOK_SIZE 64 // 节约空间的考虑?#define TOK_DELIM " \t\r\n\a" //了解下分隔符的意思char ** split_line(char * command){    //用函数截取    int buffsize = BUFFER_TOK_SIZE,position=0;    char ** tokens = malloc(buffsize * sizeof(char*));//??    char * token;    if (!tokens) {        fprintf(stderr, "allocation failed\n");        exit(EXIT_FAILURE);    }    token = strtok(command,TOK_DELIM);    command_length++;    while (token!=NULL) {        tokens[position]=token;        position++;        //如果超出缓冲区大小,增加缓冲区,使用realloc        if(position>buffsize){            buffsize +=BUFFER_TOK_SIZE;            tokens = realloc(tokens, buffsize * sizeof(char*));            if(!tokens){                fprintf(stderr, "allocate error\n");                exit(EXIT_FAILURE);            }        }        token = strtok(NULL, TOK_DELIM);        command_length++;    }    tokens[position]=NULL;    //int i;    //    for ( i=0; i<sizeof(tokens);i++) {    //        printf("command: %d, %s \n",i,tokens[i]);    //    }    return tokens;    }int launch(char ** args){    if(is_fileexist(args[0])==-1){           printf("%s:command not found\n",args[0]);           //exit(EXIT_FAILURE);           return 1;    }    pid_t pid,wpid,pid_p;    int status;    pid_p = getpid();    //printf("parend pid %d \n",pid_p);    pid = fork();    if(pid<0){        perror("fork failed");    }else if (pid ==0){        //child        if (execvp(args[0], args) == -1) {            printf("No such file or directory\n");            int error_code = errno;            //printf("error code is %d: ",error_code);        }        exit(EXIT_FAILURE);    }else{        // Parent process        clock_t start,wait;        start = clock();        pid_t pid_counter;        pid_counter = fork();        if(pid_counter<0){           perror("fork failed");         }else if(pid_counter == 0){   //child           while(1){ wait = clock();double duration = wait-start;            if(duration/CLOCKS_PER_SEC>5){                        //hint char * answer;                        while(1){                        printf("do you want to kill the child process?(y/n)\n");                        answer =read_line();if(answer[0]=='y'){kill(pid,SIGABRT);//type of signal                               printf("killed the chiled process because it last over five seconds\n");break;                        }else if(answer[0]=='n'){break;}else{printf("please enter y or n\n");}                         }                        //send signal pid_p//printf("duration: %f",duration/CLOCKS_PER_SEC); return(EXIT_SUCCESS);                    }           }}                  wpid = waitpid(pid, &status, WUNTRACED);        //wpid = waitpid(pid_counter, &status, WUNTRACED);        //printf("retrieve the child process\n");        kill(pid_counter,SIGABRT);                                     }             return 1;}int is_fileexist(char * comm)//查找命令是否存在{    char * env_path, * p;    int i=0;    /* 使用getenv函数来获取系统环境变量,用参数PATH表示获取路径*/    env_path = getenv("PATH");    p = env_path;    while(*p != '\0') {        /* 路径列表使用":"来分隔路径*/        if(*p != ':')  buffer[i ++] = *p;        else {            buffer[i ++] = '/';            buffer[i] = '\0';            /* 将指令和路径合成,形成pathname,并使用access函数来判断该文件是否存在*/            strcat(buffer, comm);            if(access(buffer, F_OK) == 0)     /* 文件被找到*/                return 0;            else                          /* 继续寻找其他路径*/                i = 0;        }        p ++;    }    /* 搜索完所有路径,依然没有找到则返回 –1*/    return -1;}//built in funcion relatedint num_builtin(){  return sizeof(builtin_str)/ sizeof(char *);//very painful }int builtin_exit(char ** args){        printf("bye-bye~\n");return 0;}int builtin_cd(char ** args){   if (args[1] == NULL) {       fprintf(stderr, "expected argument to \"cd\"\n");    } else {      if (chdir(args[1]) != 0) {       perror("chdir failed\n");    }  }  return 1;}int builtin_if(char ** args){   //parse if command1; then command2; else command3 fi   int i;   //printf("commands are:\n");   int arr[] = {0,0,0};// then, else,fi   int pos_then = 0;   int pos_else = 0;   for(i = 0;i<command_length-1;i++){     //printf(" %s ",args[i]);     if(strcmp("then",args[i])==0) {arr[0]=TRUE;pos_then=i;}     if(strcmp("else",args[i])==0) {        pos_else = i;        arr[1]=TRUE;//just in case we need to run another process      }     if(i==command_length-2){         if(strcmp("fi",args[i])==0) arr[2]=TRUE;      }    }   //printf("\n");   int j;   //for(j=0;j<3;j++) printf("array %d, %d ",j,arr[j]);   //printf("\n args before then:%s \n",args[pos_then-1]);   if( (strcmp(args[pos_then-1],";")==0) && arr[0]  && arr[2]){    //printf("valid if expression\n");        //split: command 1 , command 2 , command 3        //command1        int buffsize = BUFFER_TOK_SIZE,position=0;        char ** tokens = malloc(buffsize * sizeof(char*));         int x;        for(x =1;x<pos_then-1;x++){            tokens[position++] = args[x];            //printf("command 1 : %s\n ",args[x]);         }                           //printf("token %s",tokens[1]);         int res = launch_if(tokens);         //printf("result for command 1:%d \n",res);         //command 2         position=0;         tokens = malloc(buffsize * sizeof(char*));          //printf("command length: %d , pos_then: %d \n",command_length,pos_then);         if(!arr[1]){                for(x =pos_then+1;x<command_length-2;x++){                 tokens[position++] = args[x];                 //printf("command 2 : %s\n ",args[x]);               }         }else {  for(x =pos_then+1;x<pos_else;x++){                 tokens[position++] = args[x];                 //printf("command 2 : %s\n ",args[x]);               }         }          if(res){ // just command 2             //launch command 2              launch(tokens);         }else{              //if exist, launch command3              if(arr[1]){                //split command3                 position=0;                tokens = malloc(buffsize * sizeof(char*));                 int y;                 for(y =pos_else+1;y<command_length-2;y++){                    tokens[position++] = args[y];                    //printf("command 3 : %s\n ",args[y]);                 }                   //launch command 3                   launch_if(tokens);                               }         }                     }else{        printf("invalid expression, use like this:$ if command1 ; then command2 ; else command3 fi \n");        return 1;      }  }int launch_if(char ** args){    if(is_fileexist(args[0])==-1){           printf("%s:command not found\n",args[0]);           //exit(EXIT_FAILURE);           return 0;    }    pid_t pid,wpid,pid_p;    int status;    pid_p = getpid();    //printf("parend pid %d \n",pid_p);    pid = fork();    if(pid<0){        perror("fork failed");    }else if (pid ==0){        //child        if (execvp(args[0], args) == -1) {            printf("No such file or directory\n");            int error_code = errno;            //printf("error code is %d: ",error_code);            return 0;        }        //exit(EXIT_FAILURE);        return 1;    }else{        // Parent process        clock_t start,wait;        start = clock();        pid_t pid_counter;                wpid = waitpid(pid, &status, WUNTRACED);        //wpid = waitpid(pid_counter, &status, WUNTRACED);        //printf("retrieve the child process\n");    }             return 1;}int builtin_alias(char ** args){     //printf("builtin func alias\n");     int j;     //for(j=0;j<command_length-1;j++){       // printf("token: %s  ",args[j]);     // }     //check if the alias is not exist in the alias table     int res01;     res01=check_table(args[2]);     //printf("whether the alias exist no not: %d \n",res01);     //check if the alias is a command     int res02;     res02 = is_fileexist(args[2]);// -1 not exist; 0 exist     //printf("whether the alias is a command: %d \n",res02);     //check if the command is a existed command      int res03;     res03 = is_fileexist(args[1]);     //printf("whether the command is a existed command %d \n ",res03);          if(res01) { printf("the alias:%s is already existed ...\n ",args[command_length-2]); return 1;}     if(res02 == 0) { printf("the alias:%s itself is a command \n",args[command_length-2]); return 1;}     if(res03 == -1){ printf("the command:%s not found\n",args[1]); return 1;}          //save the command and alias to hardware     char * command;      command= (char*)malloc(BUFFSIZE);     //copy     int t;     for(t=1;t<command_length-2;t++) strcat(command,args[t]);     //printf("the command is :%s \n",command);     printf("the alias has been saved\n");     return 1;          }int check_table(char * alias){    //check if the alias exist    return 0;//not existed}int builtin_help(char ** args){    printf("there are some helpful hints:\n the builtin functions are as follows\n");    int i;     for (i = 0; i < num_builtin(); i++) {         printf("  %s ", builtin_str[i]);     }     printf("\nfor other hints please check the document.\n");}


0 0
原创粉丝点击