root/sh.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. runcmd
  2. getcmd
  3. main
  4. panic
  5. fork1
  6. execcmd
  7. redircmd
  8. pipecmd
  9. listcmd
  10. backcmd
  11. gettoken
  12. peek
  13. parsecmd
  14. parseline
  15. parsepipe
  16. parseredirs
  17. parseblock
  18. parseexec
  19. nulterminate

   1 // Shell.
   2 
   3 #include "types.h"
   4 #include "user.h"
   5 #include "fcntl.h"
   6 
   7 // Parsed command representation
   8 #define EXEC  1
   9 #define REDIR 2
  10 #define PIPE  3
  11 #define LIST  4
  12 #define BACK  5
  13 
  14 #define MAXARGS 10
  15 
  16 struct cmd {
  17   int type;
  18 };
  19 
  20 struct execcmd {
  21   int type;
  22   char *argv[MAXARGS];
  23   char *eargv[MAXARGS];
  24 };
  25 
  26 struct redircmd {
  27   int type;
  28   struct cmd *cmd;
  29   char *file;
  30   char *efile;
  31   int mode;
  32   int fd;
  33 };
  34 
  35 struct pipecmd {
  36   int type;
  37   struct cmd *left;
  38   struct cmd *right;
  39 };
  40 
  41 struct listcmd {
  42   int type;
  43   struct cmd *left;
  44   struct cmd *right;
  45 };
  46 
  47 struct backcmd {
  48   int type;
  49   struct cmd *cmd;
  50 };
  51 
  52 int fork1(void);  // Fork but panics on failure.
  53 void panic(char*);
  54 struct cmd *parsecmd(char*);
  55 
  56 // Execute cmd.  Never returns.
  57 void
  58 runcmd(struct cmd *cmd)
  59 {
  60   int p[2];
  61   struct backcmd *bcmd;
  62   struct execcmd *ecmd;
  63   struct listcmd *lcmd;
  64   struct pipecmd *pcmd;
  65   struct redircmd *rcmd;
  66 
  67   if(cmd == 0)
  68     exit();
  69   
  70   switch(cmd->type){
  71   default:
  72     panic("runcmd");
  73 
  74   case EXEC:
  75     ecmd = (struct execcmd*)cmd;
  76     if(ecmd->argv[0] == 0)
  77       exit();
  78     exec(ecmd->argv[0], ecmd->argv);
  79     printf(2, "exec %s failed\n", ecmd->argv[0]);
  80     break;
  81 
  82   case REDIR:
  83     rcmd = (struct redircmd*)cmd;
  84     close(rcmd->fd);
  85     if(open(rcmd->file, rcmd->mode) < 0){
  86       printf(2, "open %s failed\n", rcmd->file);
  87       exit();
  88     }
  89     runcmd(rcmd->cmd);
  90     break;
  91 
  92   case LIST:
  93     lcmd = (struct listcmd*)cmd;
  94     if(fork1() == 0)
  95       runcmd(lcmd->left);
  96     wait();
  97     runcmd(lcmd->right);
  98     break;
  99 
 100   case PIPE:
 101     pcmd = (struct pipecmd*)cmd;
 102     if(pipe(p) < 0)
 103       panic("pipe");
 104     if(fork1() == 0){
 105       close(1);
 106       dup(p[1]);
 107       close(p[0]);
 108       close(p[1]);
 109       runcmd(pcmd->left);
 110     }
 111     if(fork1() == 0){
 112       close(0);
 113       dup(p[0]);
 114       close(p[0]);
 115       close(p[1]);
 116       runcmd(pcmd->right);
 117     }
 118     close(p[0]);
 119     close(p[1]);
 120     wait();
 121     wait();
 122     break;
 123     
 124   case BACK:
 125     bcmd = (struct backcmd*)cmd;
 126     if(fork1() == 0)
 127       runcmd(bcmd->cmd);
 128     break;
 129   }
 130   exit();
 131 }
 132 
 133 int
 134 getcmd(char *buf, int nbuf)
 135 {
 136   printf(2, "$ ");
 137   memset(buf, 0, nbuf);
 138   gets(buf, nbuf);
 139   if(buf[0] == 0) // EOF
 140     return -1;
 141   return 0;
 142 }
 143 
 144 int
 145 main(void)
 146 {
 147   static char buf[100];
 148   int fd;
 149   
 150   // Assumes three file descriptors open.
 151   while((fd = open("console", O_RDWR)) >= 0){
 152     if(fd >= 3){
 153       close(fd);
 154       break;
 155     }
 156   }
 157   
 158   // Read and run input commands.
 159   while(getcmd(buf, sizeof(buf)) >= 0){
 160     if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
 161       // Clumsy but will have to do for now.
 162       // Chdir has no effect on the parent if run in the child.
 163       buf[strlen(buf)-1] = 0;  // chop \n
 164       if(chdir(buf+3) < 0)
 165         printf(2, "cannot cd %s\n", buf+3);
 166       continue;
 167     }
 168     if(fork1() == 0)
 169       runcmd(parsecmd(buf));
 170     wait();
 171   }
 172   exit();
 173 }
 174 
 175 void
 176 panic(char *s)
 177 {
 178   printf(2, "%s\n", s);
 179   exit();
 180 }
 181 
 182 int
 183 fork1(void)
 184 {
 185   int pid;
 186   
 187   pid = fork();
 188   if(pid == -1)
 189     panic("fork");
 190   return pid;
 191 }
 192 
 193 //PAGEBREAK!
 194 // Constructors
 195 
 196 struct cmd*
 197 execcmd(void)
 198 {
 199   struct execcmd *cmd;
 200 
 201   cmd = malloc(sizeof(*cmd));
 202   memset(cmd, 0, sizeof(*cmd));
 203   cmd->type = EXEC;
 204   return (struct cmd*)cmd;
 205 }
 206 
 207 struct cmd*
 208 redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
 209 {
 210   struct redircmd *cmd;
 211 
 212   cmd = malloc(sizeof(*cmd));
 213   memset(cmd, 0, sizeof(*cmd));
 214   cmd->type = REDIR;
 215   cmd->cmd = subcmd;
 216   cmd->file = file;
 217   cmd->efile = efile;
 218   cmd->mode = mode;
 219   cmd->fd = fd;
 220   return (struct cmd*)cmd;
 221 }
 222 
 223 struct cmd*
 224 pipecmd(struct cmd *left, struct cmd *right)
 225 {
 226   struct pipecmd *cmd;
 227 
 228   cmd = malloc(sizeof(*cmd));
 229   memset(cmd, 0, sizeof(*cmd));
 230   cmd->type = PIPE;
 231   cmd->left = left;
 232   cmd->right = right;
 233   return (struct cmd*)cmd;
 234 }
 235 
 236 struct cmd*
 237 listcmd(struct cmd *left, struct cmd *right)
 238 {
 239   struct listcmd *cmd;
 240 
 241   cmd = malloc(sizeof(*cmd));
 242   memset(cmd, 0, sizeof(*cmd));
 243   cmd->type = LIST;
 244   cmd->left = left;
 245   cmd->right = right;
 246   return (struct cmd*)cmd;
 247 }
 248 
 249 struct cmd*
 250 backcmd(struct cmd *subcmd)
 251 {
 252   struct backcmd *cmd;
 253 
 254   cmd = malloc(sizeof(*cmd));
 255   memset(cmd, 0, sizeof(*cmd));
 256   cmd->type = BACK;
 257   cmd->cmd = subcmd;
 258   return (struct cmd*)cmd;
 259 }
 260 //PAGEBREAK!
 261 // Parsing
 262 
 263 char whitespace[] = " \t\r\n\v";
 264 char symbols[] = "<|>&;()";
 265 
 266 int
 267 gettoken(char **ps, char *es, char **q, char **eq)
 268 {
 269   char *s;
 270   int ret;
 271   
 272   s = *ps;
 273   while(s < es && strchr(whitespace, *s))
 274     s++;
 275   if(q)
 276     *q = s;
 277   ret = *s;
 278   switch(*s){
 279   case 0:
 280     break;
 281   case '|':
 282   case '(':
 283   case ')':
 284   case ';':
 285   case '&':
 286   case '<':
 287     s++;
 288     break;
 289   case '>':
 290     s++;
 291     if(*s == '>'){
 292       ret = '+';
 293       s++;
 294     }
 295     break;
 296   default:
 297     ret = 'a';
 298     while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
 299       s++;
 300     break;
 301   }
 302   if(eq)
 303     *eq = s;
 304   
 305   while(s < es && strchr(whitespace, *s))
 306     s++;
 307   *ps = s;
 308   return ret;
 309 }
 310 
 311 int
 312 peek(char **ps, char *es, char *toks)
 313 {
 314   char *s;
 315   
 316   s = *ps;
 317   while(s < es && strchr(whitespace, *s))
 318     s++;
 319   *ps = s;
 320   return *s && strchr(toks, *s);
 321 }
 322 
 323 struct cmd *parseline(char**, char*);
 324 struct cmd *parsepipe(char**, char*);
 325 struct cmd *parseexec(char**, char*);
 326 struct cmd *nulterminate(struct cmd*);
 327 
 328 struct cmd*
 329 parsecmd(char *s)
 330 {
 331   char *es;
 332   struct cmd *cmd;
 333 
 334   es = s + strlen(s);
 335   cmd = parseline(&s, es);
 336   peek(&s, es, "");
 337   if(s != es){
 338     printf(2, "leftovers: %s\n", s);
 339     panic("syntax");
 340   }
 341   nulterminate(cmd);
 342   return cmd;
 343 }
 344 
 345 struct cmd*
 346 parseline(char **ps, char *es)
 347 {
 348   struct cmd *cmd;
 349 
 350   cmd = parsepipe(ps, es);
 351   while(peek(ps, es, "&")){
 352     gettoken(ps, es, 0, 0);
 353     cmd = backcmd(cmd);
 354   }
 355   if(peek(ps, es, ";")){
 356     gettoken(ps, es, 0, 0);
 357     cmd = listcmd(cmd, parseline(ps, es));
 358   }
 359   return cmd;
 360 }
 361 
 362 struct cmd*
 363 parsepipe(char **ps, char *es)
 364 {
 365   struct cmd *cmd;
 366 
 367   cmd = parseexec(ps, es);
 368   if(peek(ps, es, "|")){
 369     gettoken(ps, es, 0, 0);
 370     cmd = pipecmd(cmd, parsepipe(ps, es));
 371   }
 372   return cmd;
 373 }
 374 
 375 struct cmd*
 376 parseredirs(struct cmd *cmd, char **ps, char *es)
 377 {
 378   int tok;
 379   char *q, *eq;
 380 
 381   while(peek(ps, es, "<>")){
 382     tok = gettoken(ps, es, 0, 0);
 383     if(gettoken(ps, es, &q, &eq) != 'a')
 384       panic("missing file for redirection");
 385     switch(tok){
 386     case '<':
 387       cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
 388       break;
 389     case '>':
 390       cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
 391       break;
 392     case '+':  // >>
 393       cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
 394       break;
 395     }
 396   }
 397   return cmd;
 398 }
 399 
 400 struct cmd*
 401 parseblock(char **ps, char *es)
 402 {
 403   struct cmd *cmd;
 404 
 405   if(!peek(ps, es, "("))
 406     panic("parseblock");
 407   gettoken(ps, es, 0, 0);
 408   cmd = parseline(ps, es);
 409   if(!peek(ps, es, ")"))
 410     panic("syntax - missing )");
 411   gettoken(ps, es, 0, 0);
 412   cmd = parseredirs(cmd, ps, es);
 413   return cmd;
 414 }
 415 
 416 struct cmd*
 417 parseexec(char **ps, char *es)
 418 {
 419   char *q, *eq;
 420   int tok, argc;
 421   struct execcmd *cmd;
 422   struct cmd *ret;
 423   
 424   if(peek(ps, es, "("))
 425     return parseblock(ps, es);
 426 
 427   ret = execcmd();
 428   cmd = (struct execcmd*)ret;
 429 
 430   argc = 0;
 431   ret = parseredirs(ret, ps, es);
 432   while(!peek(ps, es, "|)&;")){
 433     if((tok=gettoken(ps, es, &q, &eq)) == 0)
 434       break;
 435     if(tok != 'a')
 436       panic("syntax");
 437     cmd->argv[argc] = q;
 438     cmd->eargv[argc] = eq;
 439     argc++;
 440     if(argc >= MAXARGS)
 441       panic("too many args");
 442     ret = parseredirs(ret, ps, es);
 443   }
 444   cmd->argv[argc] = 0;
 445   cmd->eargv[argc] = 0;
 446   return ret;
 447 }
 448 
 449 // NUL-terminate all the counted strings.
 450 struct cmd*
 451 nulterminate(struct cmd *cmd)
 452 {
 453   int i;
 454   struct backcmd *bcmd;
 455   struct execcmd *ecmd;
 456   struct listcmd *lcmd;
 457   struct pipecmd *pcmd;
 458   struct redircmd *rcmd;
 459 
 460   if(cmd == 0)
 461     return 0;
 462   
 463   switch(cmd->type){
 464   case EXEC:
 465     ecmd = (struct execcmd*)cmd;
 466     for(i=0; ecmd->argv[i]; i++)
 467       *ecmd->eargv[i] = 0;
 468     break;
 469 
 470   case REDIR:
 471     rcmd = (struct redircmd*)cmd;
 472     nulterminate(rcmd->cmd);
 473     *rcmd->efile = 0;
 474     break;
 475 
 476   case PIPE:
 477     pcmd = (struct pipecmd*)cmd;
 478     nulterminate(pcmd->left);
 479     nulterminate(pcmd->right);
 480     break;
 481     
 482   case LIST:
 483     lcmd = (struct listcmd*)cmd;
 484     nulterminate(lcmd->left);
 485     nulterminate(lcmd->right);
 486     break;
 487 
 488   case BACK:
 489     bcmd = (struct backcmd*)cmd;
 490     nulterminate(bcmd->cmd);
 491     break;
 492   }
 493   return cmd;
 494 }

/* [<][>][^][v][top][bottom][index][help] */