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