•  
  • 首页
  •  

 

2010
04-27
编写一个微型shell
分类: | 查看: 294 | 评论(0)

这个版本的Shell支持管道功能和I/O重定向.
下一个版本将增加对内建(buildins)命令的支持,如if ..then else等控制语句的支持.
-------------CODE-------------------
 
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#define OPEN_MAX 10
#define MAXNAME 100
#define FALSE 0
#define TRUE 1
char *readcmd( FILE *fp );                   //读入命令行字符串
char **getarg(char *argv);                    //把命令行字符串分解成字符数组指针
void getfile(char *name);                      //获得重定向文件名
void freearg(char **arg);                      //释放内存

char *buf;                                  //存放用户输入的字符串
char *p;                                    //指向buf的指针
int  cmdnum;                                //记录命令个数
int  pipefd[2];                               //保存管道文件描述符
int wait_pid;                                 //记录父进程PID
char infile[MAXNAME+1];                     //输入重定向文件
char outfile[MAXNAME+1];                    //输出重定向文件
int background;                              //记录命令是否在后台执行
int append;                                  //记录是否写入文件末尾
struct cmd{
char ** argv;                               //命令行参数
int   infd;                                  //输入文件描述符
int   outfd;                                 // 输出文件描述符
}cmdline[BUFSIZ];                           //命令行结构数组
int main()
{
   pid_t   pid;
   int     status;
   int     i, fd;
   signal(SIGINT, SIG_DFL);
   signal(SIGQUIT, SIG_IGN);               //处理中断(Ctrl-C)和推出(Ctrl-\)信号
   printf("%% ");
  
    
     while( (buf = readcmd(stdin)) != NULL ){  
        //-----------初始化-----------------
        int k;
        cmdnum = 0;
        background = FALSE;
        infile[0] = '\0';
        outfile[0] = '\0';
        append = FALSE;
        for( k = 0; k < OPEN_MAX; k++ )
        {
         cmdline[k].infd = 0;
         cmdline[k].outfd = 1;
        }
        for( k = 3; k < OPEN_MAX; k++ )
          close(k);
        fflush(stdout);                  //清空输出缓冲区      
        p = buf;   
        //-----------计算命令个数并获得命令参数----------
        for(i = 0; i <= cmdnum; i++)
          cmdline[i].argv = getarg(buf);
         
        if( infile[0] != '\0' )
           cmdline[0].infd = open(infile, O_RDONLY);
        if( outfile[0] != '\0' )
           if( append == FALSE )
              cmdline[cmdnum].outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
           else
              cmdline[cmdnum].outfd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, 0666);
        if( background == TRUE )
              signal(SIGCHLD, SIG_IGN);
        else
              signal(SIGCHLD, SIG_DFL);
        //-----------执行命令行-------------
        for(i = 0; i <= cmdnum; i++)
        { 
        //-----------处理管道-------------
          if( i < cmdnum  )
          {
            pipe(pipefd);
            cmdline[i+1].infd = pipefd[0];
            cmdline[i].outfd = pipefd[1];
          }
         
         
           
          if ( pid = fork() )
            wait_pid = pid;
          else if ( pid == 0 ){
             if( cmdline[i].infd == 0 && background == TRUE )
                cmdline[i].infd = open("/dev/null", O_RDONLY);
             if(cmdline[i].infd != 0)
             {
                close(0);
                dup(cmdline[i].infd);
               
             }
             if(cmdline[i].outfd != 1)
             {
                close(1);
                dup(cmdline[i].outfd);
               
             }
            
             if( background == FALSE )
             {
                signal(SIGINT, SIG_DFL);
                signal(SIGQUIT, SIG_DFL);
             }
             for( k = 3; k < OPEN_MAX; ++k)
                close(k);
             execvp(cmdline[i].argv[0], cmdline[i].argv);
             
          }
          if(fd =  cmdline[i].infd)
                close(fd);
          if((fd = cmdline[i].outfd) != 1)
                close(fd);
       }
          if( background == FALSE )
            while (  waitpid(pid, &status, 0) != wait_pid )
               ;
         
          printf("%% ");
    //-------释放内存-----------   
    for(i = 0; i <= cmdnum; i++)
      freearg(cmdline[i].argv);
    free(buf);
 }
       
        exit(0);
}
void freearg(char **arg)
{
   char **cp = arg;
   while(*cp)
      free(*cp++);
   free(arg);
}

char *readcmd(FILE *fp)
{
    char  *buf;
    int   buflen = 0;
    int   i = 0;
    int   c;
   
    while( (c = getc(fp)) != EOF ){
       if( i +1 >= buflen ){
          if( buflen == 0 ){
            buf = (char*) malloc( BUFSIZ );
            if( buf == NULL )
               return NULL;
          }
          else{
            buf = (char *)realloc(buf, buflen + BUFSIZ);
            if( buf == NULL )
               return NULL;
          }
          buflen += BUFSIZ;
       }
       if ( c == '\n' )
          break;
       buf[i++] = c;
    }
    if( c == EOF && i == 0 )
      return NULL;
    buf[i] = '\0';
    return buf;
}
char **getarg(char * argv)
{
   char **args;
   if( (args = (void *)malloc(BUFSIZ)) == NULL )
   {
      printf("out of memory\n");
      return NULL;
   }
  
   int bufsize = sizeof(argv)/sizeof(argv[0]);
   char argbuf[bufsize];
   char *cp = argbuf;
   char *end;
   char *start = argbuf;
   char * tempstr;
   int len;
   int i = 0;
   while( *p != '\0' )
  
   {
      while( *p == ' ' || *p == '\t' )
        p++;                            //去掉多余的空格
      if( *p == '\0' )
        break;
      if( *p == '|')                      //管道,使命令数加1
      {
         if( *(p+1) == ' ' )
           p +=2;                      //跳过空格
         else
           p++;
         cmdnum++;
         break;
      }
      if( *p == '<' )                    //输入重定向
      {
         if( *(p+1) == ' ' )
            p +=2;
         else
            p++;
         getfile(infile);
         break;
      }
      if( *p == '>' )                  //输出重定向
      {
        if( *(p+1) == ' ' )
            p +=2;
        else
            p++;
        if( *p == '>' )               //追加到文件末尾
        {
           if( *(p+1) == ' ' )
              p +=2;
           else
              p++;
           append = TRUE;
        }
        getfile(outfile);
        break;
      }
      if( *p == '&' )                //后台执行命令
      {
        if( *(p+1) == ' ' )
            p +=2;
        else
            p++;
        background = TRUE;
        break;
      }
      *cp++ = *p++;
      if( *p == ' ' || *p == '\0' )
      {
         *cp = '\0';
         end = cp;
         len = end - start;
         if( (tempstr = (char *)malloc(len + 1)) == NULL )
         {
             printf("out of memory\n");
             return NULL;
         }
         strncpy(tempstr, start, len);
         tempstr[len] = '\0';
         if( i + 1 > BUFSIZ )
         {
             if( (args = (void *)realloc(args, BUFSIZ * 2)) == NULL )
             {
                printf("out of memory\n");
                return NULL;
             }
         }
         args[i++] = tempstr;
         start = end;
         if( *p == '\0')
            break;
         p++;
      }
   }
   args[i] = NULL;
  
   return args;
}
void getfile(char *name)
{
  int i;
  for( i = 0; i < MAXNAME; ++i )
  {
    if( *p == ' ' || *p == '|' || *p == '>' || *p == '\0' ||
         *p == '<' || *p == '&' || *p == '\t' )
    {
          *name = '\0';
          return;
    }
    else
        *name++ = *p++;
   
  }
  *name = '\0';
}

正在加载评论列表...
正在加载评论页面















































...