c 实现的shell

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 command
char buffer[80];//缓存用户输入的命令
#define BUFFSIZE 500
#define TRUE 1
int command_length=0;

//builtin function
int 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 table

char * 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 fuck
		if(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 related
int 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");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值