added base src
[xv6-db.git] / sh.c
blobcbcb8b24677889b3f1f2557ba81d65e183f0a836
1 // Shell.
3 #include "types.h"
4 #include "user.h"
5 #include "fcntl.h"
7 // Parsed command representation
8 #define EXEC 1
9 #define REDIR 2
10 #define PIPE 3
11 #define LIST 4
12 #define BACK 5
14 #define MAXARGS 10
16 struct cmd {
17 int type;
20 struct execcmd {
21 int type;
22 char *argv[MAXARGS];
23 char *eargv[MAXARGS];
26 struct redircmd {
27 int type;
28 struct cmd *cmd;
29 char *file;
30 char *efile;
31 int mode;
32 int fd;
35 struct pipecmd {
36 int type;
37 struct cmd *left;
38 struct cmd *right;
41 struct listcmd {
42 int type;
43 struct cmd *left;
44 struct cmd *right;
47 struct backcmd {
48 int type;
49 struct cmd *cmd;
52 int fork1(void); // Fork but panics on failure.
53 void panic(char*);
54 struct cmd *parsecmd(char*);
56 // Execute cmd. Never returns.
57 void
58 runcmd(struct cmd *cmd)
60 int p[2];
61 struct backcmd *bcmd;
62 struct execcmd *ecmd;
63 struct listcmd *lcmd;
64 struct pipecmd *pcmd;
65 struct redircmd *rcmd;
67 if(cmd == 0)
68 exit();
70 switch(cmd->type){
71 default:
72 panic("runcmd");
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;
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();
89 runcmd(rcmd->cmd);
90 break;
92 case LIST:
93 lcmd = (struct listcmd*)cmd;
94 if(fork1() == 0)
95 runcmd(lcmd->left);
96 wait();
97 runcmd(lcmd->right);
98 break;
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);
111 if(fork1() == 0){
112 close(0);
113 dup(p[0]);
114 close(p[0]);
115 close(p[1]);
116 runcmd(pcmd->right);
118 close(p[0]);
119 close(p[1]);
120 wait();
121 wait();
122 break;
124 case BACK:
125 bcmd = (struct backcmd*)cmd;
126 if(fork1() == 0)
127 runcmd(bcmd->cmd);
128 break;
130 exit();
134 getcmd(char *buf, int nbuf)
136 printf(2, "$ ");
137 memset(buf, 0, nbuf);
138 gets(buf, nbuf);
139 if(buf[0] == 0) // EOF
140 return -1;
141 return 0;
145 main(void)
147 static char buf[100];
148 int fd;
150 // Assumes three file descriptors open.
151 while((fd = open("console", O_RDWR)) >= 0){
152 if(fd >= 3){
153 close(fd);
154 break;
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;
168 if(fork1() == 0)
169 runcmd(parsecmd(buf));
170 wait();
172 exit();
175 void
176 panic(char *s)
178 printf(2, "%s\n", s);
179 exit();
183 fork1(void)
185 int pid;
187 pid = fork();
188 if(pid == -1)
189 panic("fork");
190 return pid;
193 // Constructors
195 struct cmd*
196 execcmd(void)
198 struct execcmd *cmd;
200 cmd = malloc(sizeof(*cmd));
201 memset(cmd, 0, sizeof(*cmd));
202 cmd->type = EXEC;
203 return (struct cmd*)cmd;
206 struct cmd*
207 redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
209 struct redircmd *cmd;
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;
222 struct cmd*
223 pipecmd(struct cmd *left, struct cmd *right)
225 struct pipecmd *cmd;
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;
235 struct cmd*
236 listcmd(struct cmd *left, struct cmd *right)
238 struct listcmd *cmd;
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;
248 struct cmd*
249 backcmd(struct cmd *subcmd)
251 struct backcmd *cmd;
253 cmd = malloc(sizeof(*cmd));
254 memset(cmd, 0, sizeof(*cmd));
255 cmd->type = BACK;
256 cmd->cmd = subcmd;
257 return (struct cmd*)cmd;
259 // Parsing
261 char whitespace[] = " \t\r\n\v";
262 char symbols[] = "<|>&;()";
265 gettoken(char **ps, char *es, char **q, char **eq)
267 char *s;
268 int ret;
270 s = *ps;
271 while(s < es && strchr(whitespace, *s))
272 s++;
273 if(q)
274 *q = s;
275 ret = *s;
276 switch(*s){
277 case 0:
278 break;
279 case '|':
280 case '(':
281 case ')':
282 case ';':
283 case '&':
284 case '<':
285 s++;
286 break;
287 case '>':
288 s++;
289 if(*s == '>'){
290 ret = '+';
291 s++;
293 break;
294 default:
295 ret = 'a';
296 while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
297 s++;
298 break;
300 if(eq)
301 *eq = s;
303 while(s < es && strchr(whitespace, *s))
304 s++;
305 *ps = s;
306 return ret;
310 peek(char **ps, char *es, char *toks)
312 char *s;
314 s = *ps;
315 while(s < es && strchr(whitespace, *s))
316 s++;
317 *ps = s;
318 return *s && strchr(toks, *s);
321 struct cmd *parseline(char**, char*);
322 struct cmd *parsepipe(char**, char*);
323 struct cmd *parseexec(char**, char*);
324 struct cmd *nulterminate(struct cmd*);
326 struct cmd*
327 parsecmd(char *s)
329 char *es;
330 struct cmd *cmd;
332 es = s + strlen(s);
333 cmd = parseline(&s, es);
334 peek(&s, es, "");
335 if(s != es){
336 printf(2, "leftovers: %s\n", s);
337 panic("syntax");
339 nulterminate(cmd);
340 return cmd;
343 struct cmd*
344 parseline(char **ps, char *es)
346 struct cmd *cmd;
348 cmd = parsepipe(ps, es);
349 while(peek(ps, es, "&")){
350 gettoken(ps, es, 0, 0);
351 cmd = backcmd(cmd);
353 if(peek(ps, es, ";")){
354 gettoken(ps, es, 0, 0);
355 cmd = listcmd(cmd, parseline(ps, es));
357 return cmd;
360 struct cmd*
361 parsepipe(char **ps, char *es)
363 struct cmd *cmd;
365 cmd = parseexec(ps, es);
366 if(peek(ps, es, "|")){
367 gettoken(ps, es, 0, 0);
368 cmd = pipecmd(cmd, parsepipe(ps, es));
370 return cmd;
373 struct cmd*
374 parseredirs(struct cmd *cmd, char **ps, char *es)
376 int tok;
377 char *q, *eq;
379 while(peek(ps, es, "<>")){
380 tok = gettoken(ps, es, 0, 0);
381 if(gettoken(ps, es, &q, &eq) != 'a')
382 panic("missing file for redirection");
383 switch(tok){
384 case '<':
385 cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
386 break;
387 case '>':
388 cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
389 break;
390 case '+': // >>
391 cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
392 break;
395 return cmd;
398 struct cmd*
399 parseblock(char **ps, char *es)
401 struct cmd *cmd;
403 if(!peek(ps, es, "("))
404 panic("parseblock");
405 gettoken(ps, es, 0, 0);
406 cmd = parseline(ps, es);
407 if(!peek(ps, es, ")"))
408 panic("syntax - missing )");
409 gettoken(ps, es, 0, 0);
410 cmd = parseredirs(cmd, ps, es);
411 return cmd;
414 struct cmd*
415 parseexec(char **ps, char *es)
417 char *q, *eq;
418 int tok, argc;
419 struct execcmd *cmd;
420 struct cmd *ret;
422 if(peek(ps, es, "("))
423 return parseblock(ps, es);
425 ret = execcmd();
426 cmd = (struct execcmd*)ret;
428 argc = 0;
429 ret = parseredirs(ret, ps, es);
430 while(!peek(ps, es, "|)&;")){
431 if((tok=gettoken(ps, es, &q, &eq)) == 0)
432 break;
433 if(tok != 'a')
434 panic("syntax");
435 cmd->argv[argc] = q;
436 cmd->eargv[argc] = eq;
437 argc++;
438 if(argc >= MAXARGS)
439 panic("too many args");
440 ret = parseredirs(ret, ps, es);
442 cmd->argv[argc] = 0;
443 cmd->eargv[argc] = 0;
444 return ret;
447 // NUL-terminate all the counted strings.
448 struct cmd*
449 nulterminate(struct cmd *cmd)
451 int i;
452 struct backcmd *bcmd;
453 struct execcmd *ecmd;
454 struct listcmd *lcmd;
455 struct pipecmd *pcmd;
456 struct redircmd *rcmd;
458 if(cmd == 0)
459 return 0;
461 switch(cmd->type){
462 case EXEC:
463 ecmd = (struct execcmd*)cmd;
464 for(i=0; ecmd->argv[i]; i++)
465 *ecmd->eargv[i] = 0;
466 break;
468 case REDIR:
469 rcmd = (struct redircmd*)cmd;
470 nulterminate(rcmd->cmd);
471 *rcmd->efile = 0;
472 break;
474 case PIPE:
475 pcmd = (struct pipecmd*)cmd;
476 nulterminate(pcmd->left);
477 nulterminate(pcmd->right);
478 break;
480 case LIST:
481 lcmd = (struct listcmd*)cmd;
482 nulterminate(lcmd->left);
483 nulterminate(lcmd->right);
484 break;
486 case BACK:
487 bcmd = (struct backcmd*)cmd;
488 nulterminate(bcmd->cmd);
489 break;
491 return cmd;