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     if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
 162       // Chdir must be called by the parent, not the child.
 163       buf[strlen(buf)-1] = 0;  // chop \n
 164       if(chdir(buf+3) < 0)
 165         fprintf(2, "cannot cd %s\n", buf+3);
 166       continue;
 167     }
 168     if(fork1() == 0)
 169       runcmd(parsecmd(buf));
 170     wait(0);
 171   }
 172   exit(0);
 173 }
 174 
 175 void
 176 panic(char *s)
 177 {
 178   fprintf(2, "%s\n", s);
 179   exit(1);
 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     fprintf(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|O_TRUNC, 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] */