一个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@youkuaiyun.com/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、付费专栏及课程。

余额充值