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

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