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 char *cmd = buf;
162 while (*cmd == ' ' || *cmd == '\t')
163 cmd++;
164 if (*cmd == '\n')
165 continue;
166 if(cmd[0] == 'c' && cmd[1] == 'd' && cmd[2] == ' '){
167
168 cmd[strlen(cmd)-1] = 0;
169 if(chdir(cmd+3) < 0)
170 fprintf(2, "cannot cd %s\n", cmd+3);
171 } else {
172 if(fork1() == 0)
173 runcmd(parsecmd(cmd));
174 wait(0);
175 }
176 }
177 exit(0);
178 }
179
180 void
181 panic(char *s)
182 {
183 fprintf(2, "%s\n", s);
184 exit(1);
185 }
186
187 int
188 fork1(void)
189 {
190 int pid;
191
192 pid = fork();
193 if(pid == -1)
194 panic("fork");
195 return pid;
196 }
197
198
199
200
201 struct cmd*
202 execcmd(void)
203 {
204 struct execcmd *cmd;
205
206 cmd = malloc(sizeof(*cmd));
207 memset(cmd, 0, sizeof(*cmd));
208 cmd->type = EXEC;
209 return (struct cmd*)cmd;
210 }
211
212 struct cmd*
213 redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
214 {
215 struct redircmd *cmd;
216
217 cmd = malloc(sizeof(*cmd));
218 memset(cmd, 0, sizeof(*cmd));
219 cmd->type = REDIR;
220 cmd->cmd = subcmd;
221 cmd->file = file;
222 cmd->efile = efile;
223 cmd->mode = mode;
224 cmd->fd = fd;
225 return (struct cmd*)cmd;
226 }
227
228 struct cmd*
229 pipecmd(struct cmd *left, struct cmd *right)
230 {
231 struct pipecmd *cmd;
232
233 cmd = malloc(sizeof(*cmd));
234 memset(cmd, 0, sizeof(*cmd));
235 cmd->type = PIPE;
236 cmd->left = left;
237 cmd->right = right;
238 return (struct cmd*)cmd;
239 }
240
241 struct cmd*
242 listcmd(struct cmd *left, struct cmd *right)
243 {
244 struct listcmd *cmd;
245
246 cmd = malloc(sizeof(*cmd));
247 memset(cmd, 0, sizeof(*cmd));
248 cmd->type = LIST;
249 cmd->left = left;
250 cmd->right = right;
251 return (struct cmd*)cmd;
252 }
253
254 struct cmd*
255 backcmd(struct cmd *subcmd)
256 {
257 struct backcmd *cmd;
258
259 cmd = malloc(sizeof(*cmd));
260 memset(cmd, 0, sizeof(*cmd));
261 cmd->type = BACK;
262 cmd->cmd = subcmd;
263 return (struct cmd*)cmd;
264 }
265
266
267
268 char whitespace[] = " \t\r\n\v";
269 char symbols[] = "<|>&;()";
270
271 int
272 gettoken(char **ps, char *es, char **q, char **eq)
273 {
274 char *s;
275 int ret;
276
277 s = *ps;
278 while(s < es && strchr(whitespace, *s))
279 s++;
280 if(q)
281 *q = s;
282 ret = *s;
283 switch(*s){
284 case 0:
285 break;
286 case '|':
287 case '(':
288 case ')':
289 case ';':
290 case '&':
291 case '<':
292 s++;
293 break;
294 case '>':
295 s++;
296 if(*s == '>'){
297 ret = '+';
298 s++;
299 }
300 break;
301 default:
302 ret = 'a';
303 while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
304 s++;
305 break;
306 }
307 if(eq)
308 *eq = s;
309
310 while(s < es && strchr(whitespace, *s))
311 s++;
312 *ps = s;
313 return ret;
314 }
315
316 int
317 peek(char **ps, char *es, char *toks)
318 {
319 char *s;
320
321 s = *ps;
322 while(s < es && strchr(whitespace, *s))
323 s++;
324 *ps = s;
325 return *s && strchr(toks, *s);
326 }
327
328 struct cmd *parseline(char**, char*);
329 struct cmd *parsepipe(char**, char*);
330 struct cmd *parseexec(char**, char*);
331 struct cmd *nulterminate(struct cmd*);
332
333 struct cmd*
334 parsecmd(char *s)
335 {
336 char *es;
337 struct cmd *cmd;
338
339 es = s + strlen(s);
340 cmd = parseline(&s, es);
341 peek(&s, es, "");
342 if(s != es){
343 fprintf(2, "leftovers: %s\n", s);
344 panic("syntax");
345 }
346 nulterminate(cmd);
347 return cmd;
348 }
349
350 struct cmd*
351 parseline(char **ps, char *es)
352 {
353 struct cmd *cmd;
354
355 cmd = parsepipe(ps, es);
356 while(peek(ps, es, "&")){
357 gettoken(ps, es, 0, 0);
358 cmd = backcmd(cmd);
359 }
360 if(peek(ps, es, ";")){
361 gettoken(ps, es, 0, 0);
362 cmd = listcmd(cmd, parseline(ps, es));
363 }
364 return cmd;
365 }
366
367 struct cmd*
368 parsepipe(char **ps, char *es)
369 {
370 struct cmd *cmd;
371
372 cmd = parseexec(ps, es);
373 if(peek(ps, es, "|")){
374 gettoken(ps, es, 0, 0);
375 cmd = pipecmd(cmd, parsepipe(ps, es));
376 }
377 return cmd;
378 }
379
380 struct cmd*
381 parseredirs(struct cmd *cmd, char **ps, char *es)
382 {
383 int tok;
384 char *q, *eq;
385
386 while(peek(ps, es, "<>")){
387 tok = gettoken(ps, es, 0, 0);
388 if(gettoken(ps, es, &q, &eq) != 'a')
389 panic("missing file for redirection");
390 switch(tok){
391 case '<':
392 cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
393 break;
394 case '>':
395 cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
396 break;
397 case '+':
398 cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
399 break;
400 }
401 }
402 return cmd;
403 }
404
405 struct cmd*
406 parseblock(char **ps, char *es)
407 {
408 struct cmd *cmd;
409
410 if(!peek(ps, es, "("))
411 panic("parseblock");
412 gettoken(ps, es, 0, 0);
413 cmd = parseline(ps, es);
414 if(!peek(ps, es, ")"))
415 panic("syntax - missing )");
416 gettoken(ps, es, 0, 0);
417 cmd = parseredirs(cmd, ps, es);
418 return cmd;
419 }
420
421 struct cmd*
422 parseexec(char **ps, char *es)
423 {
424 char *q, *eq;
425 int tok, argc;
426 struct execcmd *cmd;
427 struct cmd *ret;
428
429 if(peek(ps, es, "("))
430 return parseblock(ps, es);
431
432 ret = execcmd();
433 cmd = (struct execcmd*)ret;
434
435 argc = 0;
436 ret = parseredirs(ret, ps, es);
437 while(!peek(ps, es, "|)&;")){
438 if((tok=gettoken(ps, es, &q, &eq)) == 0)
439 break;
440 if(tok != 'a')
441 panic("syntax");
442 cmd->argv[argc] = q;
443 cmd->eargv[argc] = eq;
444 argc++;
445 if(argc >= MAXARGS)
446 panic("too many args");
447 ret = parseredirs(ret, ps, es);
448 }
449 cmd->argv[argc] = 0;
450 cmd->eargv[argc] = 0;
451 return ret;
452 }
453
454
455 struct cmd*
456 nulterminate(struct cmd *cmd)
457 {
458 int i;
459 struct backcmd *bcmd;
460 struct execcmd *ecmd;
461 struct listcmd *lcmd;
462 struct pipecmd *pcmd;
463 struct redircmd *rcmd;
464
465 if(cmd == 0)
466 return 0;
467
468 switch(cmd->type){
469 case EXEC:
470 ecmd = (struct execcmd*)cmd;
471 for(i=0; ecmd->argv[i]; i++)
472 *ecmd->eargv[i] = 0;
473 break;
474
475 case REDIR:
476 rcmd = (struct redircmd*)cmd;
477 nulterminate(rcmd->cmd);
478 *rcmd->efile = 0;
479 break;
480
481 case PIPE:
482 pcmd = (struct pipecmd*)cmd;
483 nulterminate(pcmd->left);
484 nulterminate(pcmd->right);
485 break;
486
487 case LIST:
488 lcmd = (struct listcmd*)cmd;
489 nulterminate(lcmd->left);
490 nulterminate(lcmd->right);
491 break;
492
493 case BACK:
494 bcmd = (struct backcmd*)cmd;
495 nulterminate(bcmd->cmd);
496 break;
497 }
498 return cmd;
499 }