This source file includes following definitions.
- runcmd
- getcmd
- main
- panic
- fork1
- execcmd
- redircmd
- pipecmd
- listcmd
- backcmd
- gettoken
- peek
- parsecmd
- parseline
- parsepipe
- parseredirs
- parseblock
- parseexec
- nulterminate
1
2
3 #include "kernel/types.h"
4 #include "user/user.h"
5 #include "kernel/fcntl.h"
6
7
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);
53 void panic(char*);
54 struct cmd *parsecmd(char*);
55 void runcmd(struct cmd*) __attribute__((noreturn));
56
57
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)
141 return -1;
142 return 0;
143 }
144
145 int
146 main(void)
147 {
148 static char buf[100];
149 int fd;
150
151
152 while((fd = open("console", O_RDWR)) >= 0){
153 if(fd >= 3){
154 close(fd);
155 break;
156 }
157 }
158
159
160 while(getcmd(buf, sizeof(buf)) >= 0){
161 if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
162
163 buf[strlen(buf)-1] = 0;
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
194
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
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
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 }