Xv6 with picoc & Linkage editor
v1.0
The project delineate mutual cohesion between c library, linkage editor ( linker), interpreter and operating system by porting the same on xv6 kernel
|
00001 // Shell. 00002 00003 #include "types.h" 00004 #include "user.h" 00005 #include "fcntl.h" 00006 00007 // Parsed command representation 00008 #define EXEC 1 00009 #define REDIR 2 00010 #define PIPE 3 00011 #define LIST 4 00012 #define BACK 5 00013 00014 #define MAXARGS 10 00015 00016 struct cmd { 00017 int type; 00018 }; 00019 00020 struct execcmd { 00021 int type; 00022 char *argv[MAXARGS]; 00023 char *eargv[MAXARGS]; 00024 }; 00025 00026 struct redircmd { 00027 int type; 00028 struct cmd *cmd; 00029 char *file; 00030 char *efile; 00031 int mode; 00032 int fd; 00033 }; 00034 00035 struct pipecmd { 00036 int type; 00037 struct cmd *left; 00038 struct cmd *right; 00039 }; 00040 00041 struct listcmd { 00042 int type; 00043 struct cmd *left; 00044 struct cmd *right; 00045 }; 00046 00047 struct backcmd { 00048 int type; 00049 struct cmd *cmd; 00050 }; 00051 00052 int fork1(void); // Fork but panics on failure. 00053 void panic(char*); 00054 struct cmd *parsecmd(char*); 00055 00056 // Execute cmd. Never returns. 00057 void 00058 runcmd(struct cmd *cmd) 00059 { 00060 int p[2]; 00061 char buf[512]; // *added for /bin 00062 struct backcmd *bcmd; 00063 struct execcmd *ecmd; 00064 struct listcmd *lcmd; 00065 struct pipecmd *pcmd; 00066 struct redircmd *rcmd; 00067 00068 if(cmd == 0) 00069 exit(1); 00070 00071 switch(cmd->type){ 00072 default: 00073 panic("runcmd"); 00074 00075 case EXEC: 00076 ecmd = (struct execcmd*)cmd; 00077 if(ecmd->argv[0] == 0) 00078 exit(1); 00079 execve(ecmd->argv[0], ecmd->argv,(void*)-1); 00080 strcpy(buf,"/bin/"); //*added for simulation of PATH variables 00081 strcat(buf, ecmd->argv[0]); 00082 exec(buf, ecmd->argv); 00083 printf( "exec %s failed\n", buf); 00084 break; 00085 00086 case REDIR: 00087 rcmd = (struct redircmd*)cmd; 00088 close(rcmd->fd); 00089 if(open(rcmd->file, rcmd->mode) < 0){ 00090 printf( "open %s failed\n", rcmd->file); 00091 exit(1); 00092 } 00093 runcmd(rcmd->cmd); 00094 break; 00095 00096 case LIST: 00097 lcmd = (struct listcmd*)cmd; 00098 if(fork1() == 0) 00099 runcmd(lcmd->left); 00100 wait(); 00101 runcmd(lcmd->right); 00102 break; 00103 00104 case PIPE: 00105 pcmd = (struct pipecmd*)cmd; 00106 if(pipe(p) < 0) 00107 panic("pipe"); 00108 if(fork1() == 0){ 00109 close(1); 00110 dup(p[1]); 00111 close(p[0]); 00112 close(p[1]); 00113 runcmd(pcmd->left); 00114 } 00115 if(fork1() == 0){ 00116 close(0); 00117 dup(p[0]); 00118 close(p[0]); 00119 close(p[1]); 00120 runcmd(pcmd->right); 00121 } 00122 close(p[0]); 00123 close(p[1]); 00124 wait(); 00125 wait(); 00126 break; 00127 00128 case BACK: 00129 bcmd = (struct backcmd*)cmd; 00130 if(fork1() == 0) 00131 runcmd(bcmd->cmd); 00132 break; 00133 } 00134 exit(1); 00135 } 00136 00137 int 00138 getcmd(char *buf, int nbuf) 00139 { 00140 printf( "$ "); 00141 memset(buf, 0, nbuf); 00142 gets(buf, nbuf); 00143 if(buf[0] == 0) // EOF 00144 return -1; 00145 return 0; 00146 } 00147 00148 int 00149 main(void) 00150 { 00151 static char buf[100]; 00152 int fd; 00153 00154 // Assumes three file descriptors open. 00155 while((fd = open("console", O_RDWR)) >= 0){ 00156 if(fd >= 3){ 00157 close(fd); 00158 break; 00159 } 00160 } 00161 chdir("/doc/"); // *added drop to home folder 00162 // Read and run input commands. 00163 while(getcmd(buf, sizeof(buf)) >= 0){ 00164 if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){ 00165 // Clumsy but will have to do for now. 00166 // Chdir has no effect on the parent if run in the child. 00167 buf[strlen(buf)-1] = 0; // chop \n 00168 if(chdir(buf+3) < 0) 00169 printf( "cannot cd %s\n", buf+3); 00170 continue; 00171 } 00172 if(fork1() == 0) 00173 runcmd(parsecmd(buf)); 00174 wait(); 00175 } 00176 exit(1); 00177 } 00178 00179 void 00180 panic(char *s) 00181 { 00182 printf( "%s\n", s); 00183 exit(1); 00184 } 00185 00186 int 00187 fork1(void) 00188 { 00189 int pid; 00190 00191 pid = fork(); 00192 if(pid == -1) 00193 panic("fork"); 00194 return pid; 00195 } 00196 00197 //PAGEBREAK! 00198 // Constructors 00199 00200 struct cmd* 00201 execcmd(void) 00202 { 00203 struct execcmd *cmd; 00204 00205 cmd = malloc(sizeof(*cmd)); 00206 memset(cmd, 0, sizeof(*cmd)); 00207 cmd->type = EXEC; 00208 return (struct cmd*)cmd; 00209 } 00210 00211 struct cmd* 00212 redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd) 00213 { 00214 struct redircmd *cmd; 00215 00216 cmd = malloc(sizeof(*cmd)); 00217 memset(cmd, 0, sizeof(*cmd)); 00218 cmd->type = REDIR; 00219 cmd->cmd = subcmd; 00220 cmd->file = file; 00221 cmd->efile = efile; 00222 cmd->mode = mode; 00223 cmd->fd = fd; 00224 return (struct cmd*)cmd; 00225 } 00226 00227 struct cmd* 00228 pipecmd(struct cmd *left, struct cmd *right) 00229 { 00230 struct pipecmd *cmd; 00231 00232 cmd = malloc(sizeof(*cmd)); 00233 memset(cmd, 0, sizeof(*cmd)); 00234 cmd->type = PIPE; 00235 cmd->left = left; 00236 cmd->right = right; 00237 return (struct cmd*)cmd; 00238 } 00239 00240 struct cmd* 00241 listcmd(struct cmd *left, struct cmd *right) 00242 { 00243 struct listcmd *cmd; 00244 00245 cmd = malloc(sizeof(*cmd)); 00246 memset(cmd, 0, sizeof(*cmd)); 00247 cmd->type = LIST; 00248 cmd->left = left; 00249 cmd->right = right; 00250 return (struct cmd*)cmd; 00251 } 00252 00253 struct cmd* 00254 backcmd(struct cmd *subcmd) 00255 { 00256 struct backcmd *cmd; 00257 00258 cmd = malloc(sizeof(*cmd)); 00259 memset(cmd, 0, sizeof(*cmd)); 00260 cmd->type = BACK; 00261 cmd->cmd = subcmd; 00262 return (struct cmd*)cmd; 00263 } 00264 //PAGEBREAK! 00265 // Parsing 00266 00267 char whitespace[] = " \t\r\n\v"; 00268 char symbols[] = "<|>&;()"; 00269 00270 int 00271 gettoken(char **ps, char *es, char **q, char **eq) 00272 { 00273 char *s; 00274 int ret; 00275 00276 s = *ps; 00277 while(s < es && strchr(whitespace, *s)) 00278 s++; 00279 if(q) 00280 *q = s; 00281 ret = *s; 00282 switch(*s){ 00283 case 0: 00284 break; 00285 case '|': 00286 case '(': 00287 case ')': 00288 case ';': 00289 case '&': 00290 case '<': 00291 s++; 00292 break; 00293 case '>': 00294 s++; 00295 if(*s == '>'){ 00296 ret = '+'; 00297 s++; 00298 } 00299 break; 00300 default: 00301 ret = 'a'; 00302 while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s)) 00303 s++; 00304 break; 00305 } 00306 if(eq) 00307 *eq = s; 00308 00309 while(s < es && strchr(whitespace, *s)) 00310 s++; 00311 *ps = s; 00312 return ret; 00313 } 00314 00315 int 00316 peek(char **ps, char *es, char *toks) 00317 { 00318 char *s; 00319 00320 s = *ps; 00321 while(s < es && strchr(whitespace, *s)) 00322 s++; 00323 *ps = s; 00324 return *s && strchr(toks, *s); 00325 } 00326 00327 struct cmd *parseline(char**, char*); 00328 struct cmd *parsepipe(char**, char*); 00329 struct cmd *parseexec(char**, char*); 00330 struct cmd *nulterminate(struct cmd*); 00331 00332 struct cmd* 00333 parsecmd(char *s) 00334 { 00335 char *es; 00336 struct cmd *cmd; 00337 00338 es = s + strlen(s); 00339 cmd = parseline(&s, es); 00340 peek(&s, es, ""); 00341 if(s != es){ 00342 printf( "leftovers: %s\n", s); 00343 panic("syntax"); 00344 } 00345 nulterminate(cmd); 00346 return cmd; 00347 } 00348 00349 struct cmd* 00350 parseline(char **ps, char *es) 00351 { 00352 struct cmd *cmd; 00353 00354 cmd = parsepipe(ps, es); 00355 while(peek(ps, es, "&")){ 00356 gettoken(ps, es, 0, 0); 00357 cmd = backcmd(cmd); 00358 } 00359 if(peek(ps, es, ";")){ 00360 gettoken(ps, es, 0, 0); 00361 cmd = listcmd(cmd, parseline(ps, es)); 00362 } 00363 return cmd; 00364 } 00365 00366 struct cmd* 00367 parsepipe(char **ps, char *es) 00368 { 00369 struct cmd *cmd; 00370 00371 cmd = parseexec(ps, es); 00372 if(peek(ps, es, "|")){ 00373 gettoken(ps, es, 0, 0); 00374 cmd = pipecmd(cmd, parsepipe(ps, es)); 00375 } 00376 return cmd; 00377 } 00378 00379 struct cmd* 00380 parseredirs(struct cmd *cmd, char **ps, char *es) 00381 { 00382 int tok; 00383 char *q, *eq; 00384 00385 while(peek(ps, es, "<>")){ 00386 tok = gettoken(ps, es, 0, 0); 00387 if(gettoken(ps, es, &q, &eq) != 'a') 00388 panic("missing file for redirection"); 00389 switch(tok){ 00390 case '<': 00391 cmd = redircmd(cmd, q, eq, O_RDONLY, 0); 00392 break; 00393 case '>': 00394 cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 00395 break; 00396 case '+': // >> 00397 cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 00398 break; 00399 } 00400 } 00401 return cmd; 00402 } 00403 00404 struct cmd* 00405 parseblock(char **ps, char *es) 00406 { 00407 struct cmd *cmd; 00408 00409 if(!peek(ps, es, "(")) 00410 panic("parseblock"); 00411 gettoken(ps, es, 0, 0); 00412 cmd = parseline(ps, es); 00413 if(!peek(ps, es, ")")) 00414 panic("syntax - missing )"); 00415 gettoken(ps, es, 0, 0); 00416 cmd = parseredirs(cmd, ps, es); 00417 return cmd; 00418 } 00419 00420 struct cmd* 00421 parseexec(char **ps, char *es) 00422 { 00423 char *q, *eq; 00424 int tok, argc; 00425 struct execcmd *cmd; 00426 struct cmd *ret; 00427 00428 if(peek(ps, es, "(")) 00429 return parseblock(ps, es); 00430 00431 ret = execcmd(); 00432 cmd = (struct execcmd*)ret; 00433 00434 argc = 0; 00435 ret = parseredirs(ret, ps, es); 00436 while(!peek(ps, es, "|)&;")){ 00437 if((tok=gettoken(ps, es, &q, &eq)) == 0) 00438 break; 00439 if(tok != 'a') 00440 panic("syntax"); 00441 cmd->argv[argc] = q; 00442 cmd->eargv[argc] = eq; 00443 argc++; 00444 if(argc >= MAXARGS) 00445 panic("too many args"); 00446 ret = parseredirs(ret, ps, es); 00447 } 00448 cmd->argv[argc] = 0; 00449 cmd->eargv[argc] = 0; 00450 return ret; 00451 } 00452 00453 // NUL-terminate all the counted strings. 00454 struct cmd* 00455 nulterminate(struct cmd *cmd) 00456 { 00457 int i; 00458 struct backcmd *bcmd; 00459 struct execcmd *ecmd; 00460 struct listcmd *lcmd; 00461 struct pipecmd *pcmd; 00462 struct redircmd *rcmd; 00463 00464 if(cmd == 0) 00465 return 0; 00466 00467 switch(cmd->type){ 00468 case EXEC: 00469 ecmd = (struct execcmd*)cmd; 00470 for(i=0; ecmd->argv[i]; i++) 00471 *ecmd->eargv[i] = 0; 00472 break; 00473 00474 case REDIR: 00475 rcmd = (struct redircmd*)cmd; 00476 nulterminate(rcmd->cmd); 00477 *rcmd->efile = 0; 00478 break; 00479 00480 case PIPE: 00481 pcmd = (struct pipecmd*)cmd; 00482 nulterminate(pcmd->left); 00483 nulterminate(pcmd->right); 00484 break; 00485 00486 case LIST: 00487 lcmd = (struct listcmd*)cmd; 00488 nulterminate(lcmd->left); 00489 nulterminate(lcmd->right); 00490 break; 00491 00492 case BACK: 00493 bcmd = (struct backcmd*)cmd; 00494 nulterminate(bcmd->cmd); 00495 break; 00496 } 00497 return cmd; 00498 }