一个Shell程序

功能如下:
1、运行程序
2、解析命令参数
3、支持后台运行
4、支持一个管道
5、支持重定向操作符
6、支持目录转换命令‘cd’
程序代码:
000001     /*
000002     Description:A very simple shell , its function follow:
000003     1.Can run programs
000004     2.Support command arguments
000005     3.Support background running command '&'
000006     4.Support one pipe
000007     5.Support redirection '<' and '>'
000008                    6.Support 'cd'                
000009     Author:Hengxi Luo
000010        Create Date:Dec 27 , 2005
000011        Compile:gcc/cc -o <exefilename> <sourcefilename>
000012        Usage:<Exefile>
000013        NOTE:you can input any command.
000014             Fox example:
000015                         wc<work4.c>ss
000016                        wc < work4.c > ss
000017                        wc <work4> ss
000018                        ...
000019                        ls -l -a|more
000020                        ls -la |more
000021                        ls -al | more
000022                        ...
000023        Enjoy it!
000024    */

000025    
000026     #include <sys/types.h>
000027     #include <sys/stat.h>
000028     #include <fcntl.h>
000029     #include <unistd.h>
000030     #include <errno.h>
000031     #include <limits.h>
000032     #include <stdio.h>
000033     #include <signal.h>
000034    
000035     #ifdef    PATH_MAX
000036     static int    pathmax = PATH_MAX;
000037     #else
000038     static int    pathmax = 0;
000039     #endif
000040    
000041     #define    PATH_MAX_GUESS    1024     /* if PATH_MAX is indeterminate */
000042                             /* we're not guaranteed this is adequate */
000043     #define ARGC     50         /*argument limits*/    
000044     #define BUFFERSIZE 1024     /*command buffer size*/
000045     #define errprint(errmsg) {fprintf(stderr , errmsg); return(1);}
000046    
000047     char* path_alloc( int*);             /*alloc a path buffer*/
000048     void execkernel( char * const[] , const int); /*execute command handler*/
000049    
000050     int main( void)
000051    {
000052         char cmdbuf[BUFFERSIZE];          /*command buffer*/
000053         char *argv[ARGC] = {0};             /*argument-string pointer array*/
000054         char* path;
000055         int pathsize;
000056         int nchar , i , j , argc = 0 , nri , nro , np , nb;
000057        pid_t pid;
000058         void sig_int( int);                 /*catch SIGINT*/
000059    
000060         if(signal(SIGINT , sig_int) == SIG_ERR)
000061            errprint("can't catch SIGINT/n")
000062        
000063        printf("########Welcome to X-SHELL V1.0########/n");
000064        printf("Author:Hengxi Luo/nE-Mail:lodger007@csdn.net/nNOTE:This shell only support one pipe!/n");
000065        printf("#######################################/n");
000066         while(1)
000067        {
000068            path = path_alloc(&pathsize);
000069            
000070             if(getcwd(path , pathsize) == NULL)
000071                errprint("can't get current path!/n")
000072            printf("[x-shell-1.0 %s]%c " , path , geteuid() ? '$' : '#');
000073         
000074             if(argc > 0)         /*release unused space*/
000075                 for(i = 0;i < argc;i++)
000076                    free(argv[i]);
000077            
000078            memset(argv , 0 , sizeof( char*)*ARGC);
000079            
000080            nri = 0;             /*redirect input symbol count , '<' can appear only once*/
000081            nro = 0;             /*redirect output symbol count , '>' can appear only once*/    
000082            np = 0;                 /*pipe symbol count*/
000083            nb = 0;                 /*background-running symbol count*/
000084                
000085             for(nchar = 0;;)     /*receive input*/
000086            {
000087                cmdbuf[nchar] = getchar();
000088                 if(cmdbuf[nchar] == '/n')
000089                {
000090                    cmdbuf[nchar] = '/0';
000091                     break;
000092                }
000093                 else nchar++;
000094                 if(nchar > BUFFERSIZE - 1)
000095                {
000096                    printf("too long command!/n");
000097                     break;
000098                }
000099            }
000100                    
000101             /*resolve arguments*/
000102             for(i = j = 0 , argc = 0;i <= nchar;i++)
000103            {
000104                 if(cmdbuf[i] == ' ' || cmdbuf[i] == '/t' || cmdbuf[i] == '/0')
000105                {
000106                     if(j == 0) continue;
000107                     else
000108                    {    
000109                        cmdbuf[i] = '/0';
000110                        argv[argc] = ( char*)malloc(sizeof( char) * j + 1);
000111                        strcpy(argv[argc++] , cmdbuf + i - j);
000112                        j = 0;
000113                    }
000114                }
000115                 else
000116                {
000117                     if(cmdbuf[i] == '>' || cmdbuf[i] == '<' ||
000118                     cmdbuf[i] == '|' || cmdbuf[i] == '&')     /*contain redirection , pipe or background-running symbol*/
000119                    {
000120                         if(cmdbuf[i] == '|') np++;
000121                         else if(cmdbuf[i] == '<') nri++;
000122                             else if(cmdbuf[i] == '>') nro++;
000123                                 else nb++;                            
000124                        
000125                         if(j != 0)
000126                        {
000127                            argv[++argc]      = ( char*)malloc(sizeof( char) * 2);
000128                            argv[argc][0] = cmdbuf[i];
000129                            argv[argc][1] = '/0';
000130                            cmdbuf[i] = '/0';
000131                            argv[--argc] = ( char*)malloc(sizeof( char) * j + 1);
000132                            strcpy(argv[argc] , cmdbuf + i - j);
000133                            argc += 2;
000134                            j = 0;
000135                            i--;
000136                        }
000137                         else
000138                        {
000139                            argv[argc]           = ( char*)malloc(sizeof( char) * 2);
000140                            argv[argc][0] = cmdbuf[i];
000141                            argv[argc++][1] = '/0';
000142                            cmdbuf[i--] = '/0';                        
000143                        }
000144                    }
000145                     else j++;
000146                }
000147            }
000148    
000149             if(!strcmp(argv[0] , "exit"))     /*if cmd=exit,then quit shell*/
000150                 break;
000151             else if(!strcmp(argv[0] , "cd"))
000152            {
000153                 if(argc == 1)     /*just only display current path*/
000154                    printf("%s/n" , path);
000155                 else if(argc == 2)
000156                {
000157                     if(chdir(argv[1]) == -1)
000158                        printf("can't change directory to %s!/n" , argv[1]);
000159                }
000160                     else
000161                        printf("command 'cd' format error!/n");
000162                 continue;
000163            }
000164                
000165             if(nri >1 || nro >1 || np > 1 || nb > 1)
000166            {
000167                printf("command-line format error!/n");
000168                 continue;
000169            }
000170    
000171            execkernel(argv , argc);            
000172     }
000173    
000174     free(path);
000175    
000176        printf("Good bye!/n");
000177        
000178     return 0;
000179    }
000180    
000181     char* path_alloc( int* size)     /* also return allocated size, if nonnull */
000182    {
000183         char*    ptr;
000184    
000185         if(pathmax == 0)
000186        {                         /* first time through */
000187            errno = 0;
000188             if((pathmax = pathconf("/", _PC_PATH_MAX)) < 0)
000189            {
000190                 if (errno == 0)
000191                    pathmax = PATH_MAX_GUESS;     /* it's indeterminate */
000192                 else
000193                {
000194                    fprintf(stderr , "pathconf error for _PC_PATH_MAX!/n");
000195                     return NULL;
000196                }
000197            } else
000198                pathmax++;         /* add one since it's relative to root */
000199        }
000200    
000201         if((ptr = ( char*)malloc(pathmax + 1)) == NULL)
000202        {
000203            fprintf(stderr , "malloc error for pathname!/n");
000204             return NULL;
000205        }
000206        
000207    
000208         if (size != NULL)
000209            *size = pathmax + 1;
000210         return(ptr);
000211    }
000212    
000213     void sig_int( int signo)
000214    {
000215        printf("/nplease input 'exit' to quit!/n");
000216    }
000217    
000218     void execkernel( char * const argv[] , const int argc)
000219    {
000220        pid_t pid[2];                     /*maybe, contain a pipe*/
000221         int pipeID[2];                 /*pipe id*/
000222         int fd[2][2];                     /*file descriptor*/
000223         char* argvs[2][ARGC] = {0};         /*fetch valid arguments. if there is a pipe, there will are two command*/
000224         char* redfilename[2][2] = {0};     /*redirect filename for two command, first for stdin, second for stdout*/
000225         int vargc1 , vargc2;             /*valid arguments count*/
000226         int is_bgrun;                     /*background-running flag*/
000227         char pc_end[2];                 /*pipe end flag*/
000228         int i , j , k;
000229        
000230         /*arguments re-arrangement*/
000231         for(i = 0 , j=0 , vargc1 = 0 , vargc2 = 0 , is_bgrun = 0;i < argc;i++)
000232        {
000233             if(argv[i][0] == '<')
000234            {
000235                redfilename[j][0] = ( char*)malloc(strlen(argv[++i]) + 1);
000236                strcpy(redfilename[j][0] , argv[i]);
000237            }
000238             else if(argv[i][0] == '>')
000239            {
000240                redfilename[j][1] = ( char*)malloc(strlen(argv[++i]) + 1);
000241                strcpy(redfilename[j][1] , argv[i]);            
000242            }
000243                 else if(argv[i][0] == '|')     /*begin to fetch second command*/
000244                    j++;
000245                     else if(argv[i][0] == '&')
000246                        is_bgrun = 1;
000247                         else
000248                        {
000249                             if(j == 0)
000250                            {
000251                                argvs[j][vargc1] = ( char*)malloc(strlen(argv[i]) + 1);
000252                                strcpy(argvs[j][vargc1++] , argv[i]);
000253                            }
000254                             else
000255                            {                            
000256                                argvs[j][vargc2] = ( char*)malloc(strlen(argv[i]) + 1);
000257                                strcpy(argvs[j][vargc2++] , argv[i]);
000258                            }
000259                        }
000260        }
000261    
000262         if(j != 0)     /*need to create pipe*/
000263             if(pipe(pipeID) == -1)    
000264            {
000265                printf("open pipe error!/n");
000266                 return;
000267            }
000268        
000269         for(i = 0;i <= j;i++)
000270        {
000271             if((pid[i] = fork()) < 0)
000272            {
000273                fprintf(stderr , "fork error!/n");
000274                _exit(1);
000275            }
000276             else if(pid[i] == 0)             /*child process*/
000277            {            
000278                 if(j != 0 && i == 0)         /*struct pipe write-port*/
000279                {
000280                    close(pipeID[0]);         /*close read-port*/
000281                     if(pipeID[0] != STDOUT_FILENO)
000282                    {
000283                         if(dup2(pipeID[1] , STDOUT_FILENO) == -1)
000284                        {
000285                            printf("redirect standard output to pipe's write-port/n");
000286                            _exit(1);
000287                        }
000288                        
000289                        close(pipeID[1]);     /*close write-port*/
000290                    }                
000291                }
000292                 else if(j != 0 && i == 1)     /*struct pipe read-port*/
000293                {
000294                    close(pipeID[1]);         /*close write-port*/
000295                     if(pipeID[1] != STDIN_FILENO)
000296                    {
000297                         if(dup2(pipeID[0] , STDIN_FILENO) == -1)
000298                        {
000299                            printf("redirect standard input to pipe's read-port/n");
000300                            _exit(1);
000301                        }
000302                        
000303                        close(pipeID[0]);     /*close read-port*/
000304                    }                                
000305                }
000306    
000307                 if(redfilename[i][0] != NULL)         /*redirect input*/
000308                {
000309                     if((fd[i][0] = open(redfilename[i][0] , O_RDONLY, S_IRUSR | S_IWUSR)) == -1)
000310                    {
000311                        printf("open input file %s error!/n" , redfilename[i][0]);
000312                        _exit(1);
000313                    }
000314    
000315                     if(dup2(fd[i][0] , STDIN_FILENO) == -1)
000316                    {
000317                        printf("redirect standard input error!/n");
000318                        _exit(1);
000319                    }
000320                }
000321                 if(redfilename[i][1] != NULL)     /*redirect output*/
000322                {
000323                     if((fd[i][1] = open(redfilename[i][1] , O_WRONLY | O_CREAT | O_TRUNC , S_IRUSR | S_IWUSR)) == -1)
000324                    {
000325                        printf("open output file %s error!/n" , redfilename[i][1]);
000326                        _exit(1);
000327                    }                
000328    
000329                     if(dup2(fd[i][1] , STDOUT_FILENO) == -1)
000330                    {
000331                        printf("redirect standard output error!/n");
000332                        _exit(1);
000333                    }
000334                }
000335                            
000336     /*            for(k = 0;k < (i != 0 ? vargc2 : vargc1);k++)
000337                    printf("%s/n" , argvs[i][k]); */ /*display arguments*/

000338                
000339                 if(execvp(argvs[i][0] , argvs[i]) < 0)
000340                {
000341                    fprintf(stderr , "no such file:%s/n" , argv[0]);
000342                    _exit(1);
000343                }
000344                
000345                 for(k = 0;k < (i != 0 ? vargc2 : vargc1);k++)
000346                    free(argvs[i][k]);
000347                 for(k = 0; k < 2;k++)
000348                     if(redfilename[i][k] != NULL)
000349                    {
000350                        free(redfilename[i][k]);
000351                        close(fd[i][k]);
000352                    }
000353                _exit(0);                
000354                            
000355            }
000356             else
000357            {
000358                 if(!is_bgrun)
000359                     if(waitpid(pid[i] , NULL , 0) < 0)
000360                    {
000361                        fprintf(stderr , "wait error!/n");
000362                        _exit(1);
000363                    }
000364                 if(j != 0 && i == 0)     /*notify reader that write complete*/
000365                {
000366                    pc_end[0] = '/n';
000367                    write(pipeID[1] , pc_end , 1);
000368                    close(pipeID[1]);
000369                }
000370            }
000371        }
000372    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值