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
sh.c
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 }
 All Data Structures