1 // Shell. 2 3 #include "types.h" 4 #include "user.h" 5 #include "fcntl.h" 6 7 // Parsed command representation 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 int fork1(void); // Fork but panics on failure. 52 void panic(char*); 53 struct cmd *parsecmd(char*); 54 55 // Execute cmd. Never returns. 56 void 57 runcmd(struct cmd *cmd) 58 { 59 int p[2]; 60 struct backcmd *bcmd; 61 struct execcmd *ecmd; 62 struct listcmd *lcmd; 63 struct pipecmd *pcmd; 64 struct redircmd *rcmd; 65 66 if(cmd == 0) 67 exit(); 68 69 switch(cmd->type){ 70 default: 71 panic("runcmd"); 72 73 case EXEC: 74 ecmd = (struct execcmd*)cmd; 75 if(ecmd->argv[0] == 0) 76 exit(); 77 exec(ecmd->argv[0], ecmd->argv); 78 printf(2, "exec %s failed\n", ecmd->argv[0]); 79 break; 80 81 case REDIR: 82 rcmd = (struct redircmd*)cmd; 83 close(rcmd->fd); 84 if(open(rcmd->file, rcmd->mode) < 0){ 85 printf(2, "open %s failed\n", rcmd->file); 86 exit(); 87 } 88 runcmd(rcmd->cmd); 89 break; 90 91 case LIST: 92 lcmd = (struct listcmd*)cmd; 93 if(fork1() == 0) 94 runcmd(lcmd->left); 95 wait(); 96 runcmd(lcmd->right); 97 break; 98 99 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(); 122 wait(); 123 break; 124 125 case BACK: 126 bcmd = (struct backcmd*)cmd; 127 if(fork1() == 0) 128 runcmd(bcmd->cmd); 129 break; 130 } 131 exit(); 132 } 133 134 int 135 getcmd(char *buf, int nbuf) 136 { 137 printf(2, "$ "); 138 memset(buf, 0, nbuf); 139 gets(buf, nbuf); 140 if(buf[0] == 0) // EOF 141 return -1; 142 return 0; 143 } 144 145 int 146 main(void) 147 { 148 static char buf[100]; 149 int fd; 150 151 // Assumes three file descriptors open. 152 while((fd = open("console", O_RDWR)) >= 0){ 153 if(fd >= 3){ 154 close(fd); 155 break; 156 } 157 } 158 159 // Read and run input commands. 160 while(getcmd(buf, sizeof(buf)) >= 0){ 161 if(buf[0] == ’c’ && buf[1] == ’d’ && buf[2] == ’ ’){ 162 // Clumsy but will have to do for now. 163 // Chdir has no effect on the parent if run in the child. 164 buf[strlen(buf)-1] = 0; // chop \n 165 if(chdir(buf+3) < 0) 166 printf(2, "cannot cd %s\n", buf+3); 167 continue; 168 } 169 if(fork1() == 0) 170 runcmd(parsecmd(buf)); 171 wait(); 172 } 173 exit(); 174 } 175 176 void 177 panic(char *s) 178 { 179 printf(2, "%s\n", s); 180 exit(); 181 } 182 183 int 184 fork1(void) 185 { 186 int pid; 187 188 pid = fork(); 189 if(pid == -1) 190 panic("fork"); 191 return pid; 192 } 193 194 // Constructors 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 // Parsing 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 printf(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, 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 // NUL-terminate all the counted strings. 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 }
时间: 2024-10-24 19:43:54