首页 > 代码库 > xv6/sh.c

xv6/sh.c

  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 int fork1(void); // Fork but panics on failure. 52 void panic(char*); 53 struct cmd *parsecmd(char*); 54  55 // Execute cmd. Never returns. 56 void 57 runcmd(struct cmd *cmd) 58 { 59     int p[2]; 60     struct backcmd *bcmd; 61     struct execcmd *ecmd; 62     struct listcmd *lcmd; 63     struct pipecmd *pcmd; 64     struct redircmd *rcmd; 65  66     if(cmd == 0) 67         exit(); 68  69     switch(cmd->type){ 70         default: 71             panic("runcmd"); 72  73         case EXEC: 74             ecmd = (struct execcmd*)cmd; 75             if(ecmd->argv[0] == 0) 76                 exit(); 77             exec(ecmd->argv[0], ecmd->argv); 78             printf(2, "exec %s failed\n", ecmd->argv[0]); 79             break; 80  81         case REDIR: 82             rcmd = (struct redircmd*)cmd; 83             close(rcmd->fd); 84             if(open(rcmd->file, rcmd->mode) < 0){ 85                 printf(2, "open %s failed\n", rcmd->file); 86                 exit(); 87             } 88             runcmd(rcmd->cmd); 89             break; 90  91         case LIST: 92             lcmd = (struct listcmd*)cmd; 93             if(fork1() == 0) 94                 runcmd(lcmd->left); 95             wait(); 96             runcmd(lcmd->right); 97             break; 98  99 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();122             wait();123             break;124 125         case BACK:126             bcmd = (struct backcmd*)cmd;127             if(fork1() == 0)128                 runcmd(bcmd->cmd);129             break;130     }131     exit();132 }133 134 int135 getcmd(char *buf, int nbuf)136 {137     printf(2, "$ ");138     memset(buf, 0, nbuf);139     gets(buf, nbuf);140     if(buf[0] == 0) // EOF141         return -1;142     return 0;143 }144 145 int146 main(void)147 {148     static char buf[100];149     int fd;150 151     // Assumes three file descriptors 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             // Clumsy but will have to do for now.163             // Chdir has no effect on the parent if run in the child.164             buf[strlen(buf)-1] = 0; // chop \n165             if(chdir(buf+3) < 0)166                 printf(2, "cannot cd %s\n", buf+3);167             continue;168         }169         if(fork1() == 0)170             runcmd(parsecmd(buf));171         wait();172     }173     exit();174 }175 176 void177 panic(char *s)178 {179     printf(2, "%s\n", s);180     exit();181 }182 183 int184 fork1(void)185 {186     int pid;187 188     pid = fork();189     if(pid == -1)190         panic("fork");191     return pid;192 }193 194 // Constructors195 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 261 // Parsing262 263 char whitespace[] = " \t\r\n\v";264 char symbols[] = "<|>&;()";265 266 int267 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 int312 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 }

 

xv6/sh.c