Mercurial > hg > Members > tobaru > CbC_xv6
comparison src/usr/sh.c @ 0:83c23a36980d
Init
author | Tatsuki IHA <e125716@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 26 May 2017 23:11:05 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:83c23a36980d |
---|---|
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 } |