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
", 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
", 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 int
135 getcmd(char *buf, int nbuf)
136 {
137     printf(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     // 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 

165             if(chdir(buf+3) < 0)
166                 printf(2, "cannot cd %s
", buf+3);
167             continue;
168         }
169         if(fork1() == 0)
170             runcmd(parsecmd(buf));
171         wait();
172     }
173     exit();
174 }
175 
176 void
177 panic(char *s)
178 {
179     printf(2, "%s
", s);
180     exit();
181 }
182 
183 int
184 fork1(void)
185 {
186     int pid;
187 
188     pid = fork();
189     if(pid == -1)
190         panic("fork");
191     return pid;
192 }
193 
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 
261 // Parsing
262 
263 char whitespace[] = " 	
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
", 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 }
原文地址:https://www.cnblogs.com/LinKArftc/p/5814402.html