您的位置:首页 > 运维架构 > Shell

一个Shell程序

2006-07-25 09:42 218 查看
功能如下:
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 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: