00001
00002
00003 #include "types.h"
00004 #include "user.h"
00005 #include "fcntl.h"
00006
00007
00008 #define EXEC 1
00009 #define REDIR 2
00010 #define PIPE 3
00011 #define LIST 4
00012 #define BACK 5
00013
00014 #define MAXARGS 10
00015
00016 struct cmd {
00017 int type;
00018 };
00019
00020 struct execcmd {
00021 int type;
00022 char *argv[MAXARGS];
00023 char *eargv[MAXARGS];
00024 };
00025
00026 struct redircmd {
00027 int type;
00028 struct cmd *cmd;
00029 char *file;
00030 char *efile;
00031 int mode;
00032 int fd;
00033 };
00034
00035 struct pipecmd {
00036 int type;
00037 struct cmd *left;
00038 struct cmd *right;
00039 };
00040
00041 struct listcmd {
00042 int type;
00043 struct cmd *left;
00044 struct cmd *right;
00045 };
00046
00047 struct backcmd {
00048 int type;
00049 struct cmd *cmd;
00050 };
00051
00052 int fork1(void);
00053 void panic(char*);
00054 struct cmd *parsecmd(char*);
00055
00056
00057 void
00058 runcmd(struct cmd *cmd)
00059 {
00060 int p[2];
00061 struct backcmd *bcmd;
00062 struct execcmd *ecmd;
00063 struct listcmd *lcmd;
00064 struct pipecmd *pcmd;
00065 struct redircmd *rcmd;
00066
00067 if(cmd == 0)
00068 exit();
00069
00070 switch(cmd->type){
00071 default:
00072 panic("runcmd");
00073
00074 case EXEC:
00075 ecmd = (struct execcmd*)cmd;
00076 if(ecmd->argv[0] == 0)
00077 exit();
00078 exec(ecmd->argv[0], ecmd->argv);
00079 printf(2, "exec %s failed\n", ecmd->argv[0]);
00080 break;
00081
00082 case REDIR:
00083 rcmd = (struct redircmd*)cmd;
00084 close(rcmd->fd);
00085 if(open(rcmd->file, rcmd->mode) < 0){
00086 printf(2, "open %s failed\n", rcmd->file);
00087 exit();
00088 }
00089 runcmd(rcmd->cmd);
00090 break;
00091
00092 case LIST:
00093 lcmd = (struct listcmd*)cmd;
00094 if(fork1() == 0)
00095 runcmd(lcmd->left);
00096 wait();
00097 runcmd(lcmd->right);
00098 break;
00099
00100 case PIPE:
00101 pcmd = (struct pipecmd*)cmd;
00102 if(pipe(p) < 0)
00103 panic("pipe");
00104 if(fork1() == 0){
00105 close(1);
00106 dup(p[1]);
00107 close(p[0]);
00108 close(p[1]);
00109 runcmd(pcmd->left);
00110 }
00111 if(fork1() == 0){
00112 close(0);
00113 dup(p[0]);
00114 close(p[0]);
00115 close(p[1]);
00116 runcmd(pcmd->right);
00117 }
00118 close(p[0]);
00119 close(p[1]);
00120 wait();
00121 wait();
00122 break;
00123
00124 case BACK:
00125 bcmd = (struct backcmd*)cmd;
00126 if(fork1() == 0)
00127 runcmd(bcmd->cmd);
00128 break;
00129 }
00130 exit();
00131 }
00132
00133 int
00134 getcmd(char *buf, int nbuf)
00135 {
00136 printf(2, "$ ");
00137 memset(buf, 0, nbuf);
00138 gets(buf, nbuf);
00139 if(buf[0] == 0)
00140 return -1;
00141 return 0;
00142 }
00143
00144 int
00145 main(void)
00146 {
00147 static char buf[100];
00148 int fd;
00149
00150
00151 while((fd = open("console", O_RDWR)) >= 0){
00152 if(fd >= 3){
00153 close(fd);
00154 break;
00155 }
00156 }
00157
00158
00159 while(getcmd(buf, sizeof(buf)) >= 0){
00160 if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
00161
00162
00163 buf[strlen(buf)-1] = 0;
00164 if(chdir(buf+3) < 0)
00165 printf(2, "cannot cd %s\n", buf+3);
00166 continue;
00167 }
00168 if(fork1() == 0)
00169 runcmd(parsecmd(buf));
00170 wait();
00171 }
00172 exit();
00173 }
00174
00175 void
00176 panic(char *s)
00177 {
00178 printf(2, "%s\n", s);
00179 exit();
00180 }
00181
00182 int
00183 fork1(void)
00184 {
00185 int pid;
00186
00187 pid = fork();
00188 if(pid == -1)
00189 panic("fork");
00190 return pid;
00191 }
00192
00193
00194
00195 struct cmd*
00196 execcmd(void)
00197 {
00198 struct execcmd *cmd;
00199
00200 cmd = malloc(sizeof(*cmd));
00201 memset(cmd, 0, sizeof(*cmd));
00202 cmd->type = EXEC;
00203 return (struct cmd*)cmd;
00204 }
00205
00206 struct cmd*
00207 redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
00208 {
00209 struct redircmd *cmd;
00210
00211 cmd = malloc(sizeof(*cmd));
00212 memset(cmd, 0, sizeof(*cmd));
00213 cmd->type = REDIR;
00214 cmd->cmd = subcmd;
00215 cmd->file = file;
00216 cmd->efile = efile;
00217 cmd->mode = mode;
00218 cmd->fd = fd;
00219 return (struct cmd*)cmd;
00220 }
00221
00222 struct cmd*
00223 pipecmd(struct cmd *left, struct cmd *right)
00224 {
00225 struct pipecmd *cmd;
00226
00227 cmd = malloc(sizeof(*cmd));
00228 memset(cmd, 0, sizeof(*cmd));
00229 cmd->type = PIPE;
00230 cmd->left = left;
00231 cmd->right = right;
00232 return (struct cmd*)cmd;
00233 }
00234
00235 struct cmd*
00236 listcmd(struct cmd *left, struct cmd *right)
00237 {
00238 struct listcmd *cmd;
00239
00240 cmd = malloc(sizeof(*cmd));
00241 memset(cmd, 0, sizeof(*cmd));
00242 cmd->type = LIST;
00243 cmd->left = left;
00244 cmd->right = right;
00245 return (struct cmd*)cmd;
00246 }
00247
00248 struct cmd*
00249 backcmd(struct cmd *subcmd)
00250 {
00251 struct backcmd *cmd;
00252
00253 cmd = malloc(sizeof(*cmd));
00254 memset(cmd, 0, sizeof(*cmd));
00255 cmd->type = BACK;
00256 cmd->cmd = subcmd;
00257 return (struct cmd*)cmd;
00258 }
00259
00260
00261 char whitespace[] = " \t\r\n\v";
00262 char symbols[] = "<|>&;()";
00263
00264 int
00265 gettoken(char **ps, char *es, char **q, char **eq)
00266 {
00267 char *s;
00268 int ret;
00269
00270 s = *ps;
00271 while(s < es && strchr(whitespace, *s))
00272 s++;
00273 if(q)
00274 *q = s;
00275 ret = *s;
00276 switch(*s){
00277 case 0:
00278 break;
00279 case '|':
00280 case '(':
00281 case ')':
00282 case ';':
00283 case '&':
00284 case '<':
00285 s++;
00286 break;
00287 case '>':
00288 s++;
00289 if(*s == '>'){
00290 ret = '+';
00291 s++;
00292 }
00293 break;
00294 default:
00295 ret = 'a';
00296 while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
00297 s++;
00298 break;
00299 }
00300 if(eq)
00301 *eq = s;
00302
00303 while(s < es && strchr(whitespace, *s))
00304 s++;
00305 *ps = s;
00306 return ret;
00307 }
00308
00309 int
00310 peek(char **ps, char *es, char *toks)
00311 {
00312 char *s;
00313
00314 s = *ps;
00315 while(s < es && strchr(whitespace, *s))
00316 s++;
00317 *ps = s;
00318 return *s && strchr(toks, *s);
00319 }
00320
00321 struct cmd *parseline(char**, char*);
00322 struct cmd *parsepipe(char**, char*);
00323 struct cmd *parseexec(char**, char*);
00324 struct cmd *nulterminate(struct cmd*);
00325
00326 struct cmd*
00327 parsecmd(char *s)
00328 {
00329 char *es;
00330 struct cmd *cmd;
00331
00332 es = s + strlen(s);
00333 cmd = parseline(&s, es);
00334 peek(&s, es, "");
00335 if(s != es){
00336 printf(2, "leftovers: %s\n", s);
00337 panic("syntax");
00338 }
00339 nulterminate(cmd);
00340 return cmd;
00341 }
00342
00343 struct cmd*
00344 parseline(char **ps, char *es)
00345 {
00346 struct cmd *cmd;
00347
00348 cmd = parsepipe(ps, es);
00349 while(peek(ps, es, "&")){
00350 gettoken(ps, es, 0, 0);
00351 cmd = backcmd(cmd);
00352 }
00353 if(peek(ps, es, ";")){
00354 gettoken(ps, es, 0, 0);
00355 cmd = listcmd(cmd, parseline(ps, es));
00356 }
00357 return cmd;
00358 }
00359
00360 struct cmd*
00361 parsepipe(char **ps, char *es)
00362 {
00363 struct cmd *cmd;
00364
00365 cmd = parseexec(ps, es);
00366 if(peek(ps, es, "|")){
00367 gettoken(ps, es, 0, 0);
00368 cmd = pipecmd(cmd, parsepipe(ps, es));
00369 }
00370 return cmd;
00371 }
00372
00373 struct cmd*
00374 parseredirs(struct cmd *cmd, char **ps, char *es)
00375 {
00376 int tok;
00377 char *q, *eq;
00378
00379 while(peek(ps, es, "<>")){
00380 tok = gettoken(ps, es, 0, 0);
00381 if(gettoken(ps, es, &q, &eq) != 'a')
00382 panic("missing file for redirection");
00383 switch(tok){
00384 case '<':
00385 cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
00386 break;
00387 case '>':
00388 cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
00389 break;
00390 case '+':
00391 cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
00392 break;
00393 }
00394 }
00395 return cmd;
00396 }
00397
00398 struct cmd*
00399 parseblock(char **ps, char *es)
00400 {
00401 struct cmd *cmd;
00402
00403 if(!peek(ps, es, "("))
00404 panic("parseblock");
00405 gettoken(ps, es, 0, 0);
00406 cmd = parseline(ps, es);
00407 if(!peek(ps, es, ")"))
00408 panic("syntax - missing )");
00409 gettoken(ps, es, 0, 0);
00410 cmd = parseredirs(cmd, ps, es);
00411 return cmd;
00412 }
00413
00414 struct cmd*
00415 parseexec(char **ps, char *es)
00416 {
00417 char *q, *eq;
00418 int tok, argc;
00419 struct execcmd *cmd;
00420 struct cmd *ret;
00421
00422 if(peek(ps, es, "("))
00423 return parseblock(ps, es);
00424
00425 ret = execcmd();
00426 cmd = (struct execcmd*)ret;
00427
00428 argc = 0;
00429 ret = parseredirs(ret, ps, es);
00430 while(!peek(ps, es, "|)&;")){
00431 if((tok=gettoken(ps, es, &q, &eq)) == 0)
00432 break;
00433 if(tok != 'a')
00434 panic("syntax");
00435 cmd->argv[argc] = q;
00436 cmd->eargv[argc] = eq;
00437 argc++;
00438 if(argc >= MAXARGS)
00439 panic("too many args");
00440 ret = parseredirs(ret, ps, es);
00441 }
00442 cmd->argv[argc] = 0;
00443 cmd->eargv[argc] = 0;
00444 return ret;
00445 }
00446
00447
00448 struct cmd*
00449 nulterminate(struct cmd *cmd)
00450 {
00451 int i;
00452 struct backcmd *bcmd;
00453 struct execcmd *ecmd;
00454 struct listcmd *lcmd;
00455 struct pipecmd *pcmd;
00456 struct redircmd *rcmd;
00457
00458 if(cmd == 0)
00459 return 0;
00460
00461 switch(cmd->type){
00462 case EXEC:
00463 ecmd = (struct execcmd*)cmd;
00464 for(i=0; ecmd->argv[i]; i++)
00465 *ecmd->eargv[i] = 0;
00466 break;
00467
00468 case REDIR:
00469 rcmd = (struct redircmd*)cmd;
00470 nulterminate(rcmd->cmd);
00471 *rcmd->efile = 0;
00472 break;
00473
00474 case PIPE:
00475 pcmd = (struct pipecmd*)cmd;
00476 nulterminate(pcmd->left);
00477 nulterminate(pcmd->right);
00478 break;
00479
00480 case LIST:
00481 lcmd = (struct listcmd*)cmd;
00482 nulterminate(lcmd->left);
00483 nulterminate(lcmd->right);
00484 break;
00485
00486 case BACK:
00487 bcmd = (struct backcmd*)cmd;
00488 nulterminate(bcmd->cmd);
00489 break;
00490 }
00491 return cmd;
00492 }