11b25f3b0Srsc // Shell. 21b25f3b0Srsc 317a85657Srtm #include "types.h" 4d7b3b802Skaashoek #include "user.h" 517a85657Srtm #include "fcntl.h" 617a85657Srtm 71b25f3b0Srsc // Parsed command representation 81b25f3b0Srsc #define EXEC 1 91b25f3b0Srsc #define REDIR 2 101b25f3b0Srsc #define PIPE 3 111b25f3b0Srsc #define LIST 4 121b25f3b0Srsc #define BACK 5 131b25f3b0Srsc 148b58e810Skaashoek #define MAXARGS 10 158b58e810Skaashoek 1621a88dd0Skaashoek struct cmd { 171b25f3b0Srsc int type; 1821a88dd0Skaashoek }; 191b25f3b0Srsc 201b25f3b0Srsc struct execcmd { 211b25f3b0Srsc int type; 221b25f3b0Srsc char *argv[MAXARGS]; 231b25f3b0Srsc char *eargv[MAXARGS]; 241b25f3b0Srsc }; 251b25f3b0Srsc 261b25f3b0Srsc struct redircmd { 271b25f3b0Srsc int type; 28e00baa9fSkaashoek struct cmd *cmd; 291b25f3b0Srsc char *file; 301b25f3b0Srsc char *efile; 311b25f3b0Srsc int mode; 321b25f3b0Srsc int fd; 331b25f3b0Srsc }; 348b58e810Skaashoek 351b25f3b0Srsc struct pipecmd { 361b25f3b0Srsc int type; 371b25f3b0Srsc struct cmd *left; 381b25f3b0Srsc struct cmd *right; 391b25f3b0Srsc }; 408b58e810Skaashoek 411b25f3b0Srsc struct listcmd { 421b25f3b0Srsc int type; 431b25f3b0Srsc struct cmd *left; 441b25f3b0Srsc struct cmd *right; 451b25f3b0Srsc }; 461b25f3b0Srsc 471b25f3b0Srsc struct backcmd { 481b25f3b0Srsc int type; 491b25f3b0Srsc struct cmd *cmd; 501b25f3b0Srsc }; 511b25f3b0Srsc 52a759b8a4Srsc int fork1(void); // Fork but panics on failure. 531b25f3b0Srsc void panic(char*); 54a759b8a4Srsc struct cmd *parsecmd(char*); 551b25f3b0Srsc 561b25f3b0Srsc // Execute cmd. Never returns. 571b25f3b0Srsc void 581b25f3b0Srsc runcmd(struct cmd *cmd) 591b25f3b0Srsc { 601b25f3b0Srsc int p[2]; 611b25f3b0Srsc struct backcmd *bcmd; 621b25f3b0Srsc struct execcmd *ecmd; 631b25f3b0Srsc struct listcmd *lcmd; 641b25f3b0Srsc struct pipecmd *pcmd; 651b25f3b0Srsc struct redircmd *rcmd; 661b25f3b0Srsc 671b25f3b0Srsc if(cmd == 0) 68b52dea08Srsc exit(); 691b25f3b0Srsc 701b25f3b0Srsc switch(cmd->type){ 711b25f3b0Srsc default: 721b25f3b0Srsc panic("runcmd"); 731b25f3b0Srsc 741b25f3b0Srsc case EXEC: 751b25f3b0Srsc ecmd = (struct execcmd*)cmd; 761b25f3b0Srsc if(ecmd->argv[0] == 0) 771b25f3b0Srsc exit(); 781b25f3b0Srsc exec(ecmd->argv[0], ecmd->argv); 791b25f3b0Srsc printf(2, "exec %s failed\n", ecmd->argv[0]); 801b25f3b0Srsc break; 811b25f3b0Srsc 821b25f3b0Srsc case REDIR: 831b25f3b0Srsc rcmd = (struct redircmd*)cmd; 841b25f3b0Srsc close(rcmd->fd); 851b25f3b0Srsc if(open(rcmd->file, rcmd->mode) < 0){ 861b25f3b0Srsc printf(2, "open %s failed\n", rcmd->file); 871b25f3b0Srsc exit(); 881b25f3b0Srsc } 891b25f3b0Srsc runcmd(rcmd->cmd); 901b25f3b0Srsc break; 911b25f3b0Srsc 92a759b8a4Srsc case LIST: 93a759b8a4Srsc lcmd = (struct listcmd*)cmd; 94a759b8a4Srsc if(fork1() == 0) 95a759b8a4Srsc runcmd(lcmd->left); 96a759b8a4Srsc wait(); 97a759b8a4Srsc runcmd(lcmd->right); 98a759b8a4Srsc break; 99a759b8a4Srsc 1001b25f3b0Srsc case PIPE: 1011b25f3b0Srsc pcmd = (struct pipecmd*)cmd; 1021b25f3b0Srsc if(pipe(p) < 0) 1031b25f3b0Srsc panic("pipe"); 1041b25f3b0Srsc if(fork1() == 0){ 1051b25f3b0Srsc close(1); 1061b25f3b0Srsc dup(p[1]); 1071b25f3b0Srsc close(p[0]); 1081b25f3b0Srsc close(p[1]); 1091b25f3b0Srsc runcmd(pcmd->left); 1101b25f3b0Srsc } 1111b25f3b0Srsc if(fork1() == 0){ 1121b25f3b0Srsc close(0); 1131b25f3b0Srsc dup(p[0]); 1141b25f3b0Srsc close(p[0]); 1151b25f3b0Srsc close(p[1]); 1161b25f3b0Srsc runcmd(pcmd->right); 1171b25f3b0Srsc } 1181b25f3b0Srsc close(p[0]); 1191b25f3b0Srsc close(p[1]); 1201b25f3b0Srsc wait(); 1211b25f3b0Srsc wait(); 1221b25f3b0Srsc break; 1231b25f3b0Srsc 1241b25f3b0Srsc case BACK: 1251b25f3b0Srsc bcmd = (struct backcmd*)cmd; 1261b25f3b0Srsc if(fork1() == 0) 1271b25f3b0Srsc runcmd(bcmd->cmd); 1281b25f3b0Srsc break; 12917a85657Srtm } 130f8f7fcbeSrsc exit(); 13117a85657Srtm } 132d7b3b802Skaashoek 1338b58e810Skaashoek int 1349736728dSrsc getcmd(char *buf, int nbuf) 1359736728dSrsc { 1361b789e1dSrsc printf(2, "$ "); 1379736728dSrsc memset(buf, 0, nbuf); 1389736728dSrsc gets(buf, nbuf); 1399736728dSrsc if(buf[0] == 0) // EOF 1409736728dSrsc return -1; 1419736728dSrsc return 0; 1429736728dSrsc } 1439736728dSrsc 1449736728dSrsc int 1451b25f3b0Srsc main(void) 146d7b3b802Skaashoek { 1471b25f3b0Srsc static char buf[100]; 148a759b8a4Srsc int fd; 1498b58e810Skaashoek 150*0a4a4230SRobert Morris // Ensure that three file descriptors are open. 151a759b8a4Srsc while((fd = open("console", O_RDWR)) >= 0){ 152a759b8a4Srsc if(fd >= 3){ 153a759b8a4Srsc close(fd); 154a759b8a4Srsc break; 155a759b8a4Srsc } 156a759b8a4Srsc } 157a759b8a4Srsc 158a759b8a4Srsc // Read and run input commands. 1591b25f3b0Srsc while(getcmd(buf, sizeof(buf)) >= 0){ 1609863fea7Srsc if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){ 161*0a4a4230SRobert Morris // Chdir must be called by the parent, not the child. 1629863fea7Srsc buf[strlen(buf)-1] = 0; // chop \n 1639863fea7Srsc if(chdir(buf+3) < 0) 1649863fea7Srsc printf(2, "cannot cd %s\n", buf+3); 1659863fea7Srsc continue; 1669863fea7Srsc } 1671b25f3b0Srsc if(fork1() == 0) 1681b25f3b0Srsc runcmd(parsecmd(buf)); 1691b25f3b0Srsc wait(); 17021a88dd0Skaashoek } 1711b25f3b0Srsc exit(); 1728b58e810Skaashoek } 1738b58e810Skaashoek 1748b58e810Skaashoek void 1751b25f3b0Srsc panic(char *s) 1768b58e810Skaashoek { 1771b25f3b0Srsc printf(2, "%s\n", s); 178d7b3b802Skaashoek exit(); 179d7b3b802Skaashoek } 18021a88dd0Skaashoek 181a759b8a4Srsc int 182a759b8a4Srsc fork1(void) 183a759b8a4Srsc { 184a759b8a4Srsc int pid; 185a759b8a4Srsc 186a759b8a4Srsc pid = fork(); 187a759b8a4Srsc if(pid == -1) 188a759b8a4Srsc panic("fork"); 189a759b8a4Srsc return pid; 190a759b8a4Srsc } 191a759b8a4Srsc 192a759b8a4Srsc //PAGEBREAK! 1931b25f3b0Srsc // Constructors 1941b25f3b0Srsc 1951b25f3b0Srsc struct cmd* 1961b25f3b0Srsc execcmd(void) 1971b25f3b0Srsc { 1981b25f3b0Srsc struct execcmd *cmd; 1991b25f3b0Srsc 2001b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2011b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2021b25f3b0Srsc cmd->type = EXEC; 2031b25f3b0Srsc return (struct cmd*)cmd; 20421a88dd0Skaashoek } 2051b25f3b0Srsc 2061b25f3b0Srsc struct cmd* 2071b25f3b0Srsc redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd) 2081b25f3b0Srsc { 2091b25f3b0Srsc struct redircmd *cmd; 2101b25f3b0Srsc 2111b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2121b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2131b25f3b0Srsc cmd->type = REDIR; 2141b25f3b0Srsc cmd->cmd = subcmd; 2151b25f3b0Srsc cmd->file = file; 2161b25f3b0Srsc cmd->efile = efile; 2171b25f3b0Srsc cmd->mode = mode; 2181b25f3b0Srsc cmd->fd = fd; 2191b25f3b0Srsc return (struct cmd*)cmd; 220d7b3b802Skaashoek } 2211b25f3b0Srsc 2221b25f3b0Srsc struct cmd* 2231b25f3b0Srsc pipecmd(struct cmd *left, struct cmd *right) 2241b25f3b0Srsc { 2251b25f3b0Srsc struct pipecmd *cmd; 2261b25f3b0Srsc 2271b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2281b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2291b25f3b0Srsc cmd->type = PIPE; 2301b25f3b0Srsc cmd->left = left; 2311b25f3b0Srsc cmd->right = right; 2321b25f3b0Srsc return (struct cmd*)cmd; 233d7b3b802Skaashoek } 2341b25f3b0Srsc 2351b25f3b0Srsc struct cmd* 2361b25f3b0Srsc listcmd(struct cmd *left, struct cmd *right) 2371b25f3b0Srsc { 2381b25f3b0Srsc struct listcmd *cmd; 2391b25f3b0Srsc 2401b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2411b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2421b25f3b0Srsc cmd->type = LIST; 2431b25f3b0Srsc cmd->left = left; 2441b25f3b0Srsc cmd->right = right; 2451b25f3b0Srsc return (struct cmd*)cmd; 24621a88dd0Skaashoek } 2471b25f3b0Srsc 2481b25f3b0Srsc struct cmd* 2491b25f3b0Srsc backcmd(struct cmd *subcmd) 2501b25f3b0Srsc { 2511b25f3b0Srsc struct backcmd *cmd; 2521b25f3b0Srsc 2531b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2541b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2551b25f3b0Srsc cmd->type = BACK; 2561b25f3b0Srsc cmd->cmd = subcmd; 2571b25f3b0Srsc return (struct cmd*)cmd; 2581b25f3b0Srsc } 259a759b8a4Srsc //PAGEBREAK! 2601b25f3b0Srsc // Parsing 2611b25f3b0Srsc 2621b25f3b0Srsc char whitespace[] = " \t\r\n\v"; 2631b25f3b0Srsc char symbols[] = "<|>&;()"; 2641b25f3b0Srsc 2651b25f3b0Srsc int 2661b25f3b0Srsc gettoken(char **ps, char *es, char **q, char **eq) 2678b58e810Skaashoek { 2681b25f3b0Srsc char *s; 2691b25f3b0Srsc int ret; 2708b58e810Skaashoek 2711b25f3b0Srsc s = *ps; 2721b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 2731b25f3b0Srsc s++; 2741b25f3b0Srsc if(q) 2751b25f3b0Srsc *q = s; 2761b25f3b0Srsc ret = *s; 2771b25f3b0Srsc switch(*s){ 2781b25f3b0Srsc case 0: 2791b25f3b0Srsc break; 2801b25f3b0Srsc case '|': 2811b25f3b0Srsc case '(': 2821b25f3b0Srsc case ')': 2831b25f3b0Srsc case ';': 2841b25f3b0Srsc case '&': 2858b58e810Skaashoek case '<': 2861b25f3b0Srsc s++; 2878b58e810Skaashoek break; 2888b58e810Skaashoek case '>': 2891b25f3b0Srsc s++; 2901b25f3b0Srsc if(*s == '>'){ 2911b25f3b0Srsc ret = '+'; 2921b25f3b0Srsc s++; 2938b58e810Skaashoek } 2941b25f3b0Srsc break; 2951b25f3b0Srsc default: 2961b25f3b0Srsc ret = 'a'; 2971b25f3b0Srsc while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s)) 2981b25f3b0Srsc s++; 2991b25f3b0Srsc break; 3001b25f3b0Srsc } 3011b25f3b0Srsc if(eq) 3021b25f3b0Srsc *eq = s; 3031b25f3b0Srsc 3041b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 3051b25f3b0Srsc s++; 3061b25f3b0Srsc *ps = s; 3071b25f3b0Srsc return ret; 3081b25f3b0Srsc } 3091b25f3b0Srsc 310a759b8a4Srsc int 311a759b8a4Srsc peek(char **ps, char *es, char *toks) 312a759b8a4Srsc { 313a759b8a4Srsc char *s; 314a759b8a4Srsc 315a759b8a4Srsc s = *ps; 316a759b8a4Srsc while(s < es && strchr(whitespace, *s)) 317a759b8a4Srsc s++; 318a759b8a4Srsc *ps = s; 319a759b8a4Srsc return *s && strchr(toks, *s); 320a759b8a4Srsc } 321a759b8a4Srsc 3221b25f3b0Srsc struct cmd *parseline(char**, char*); 3231b25f3b0Srsc struct cmd *parsepipe(char**, char*); 3241b25f3b0Srsc struct cmd *parseexec(char**, char*); 325a759b8a4Srsc struct cmd *nulterminate(struct cmd*); 3261b25f3b0Srsc 3271b25f3b0Srsc struct cmd* 3281b25f3b0Srsc parsecmd(char *s) 3291b25f3b0Srsc { 3301b25f3b0Srsc char *es; 3311b25f3b0Srsc struct cmd *cmd; 3321b25f3b0Srsc 3331b25f3b0Srsc es = s + strlen(s); 3341b25f3b0Srsc cmd = parseline(&s, es); 3351b25f3b0Srsc peek(&s, es, ""); 3361b25f3b0Srsc if(s != es){ 3371b25f3b0Srsc printf(2, "leftovers: %s\n", s); 3381b25f3b0Srsc panic("syntax"); 3391b25f3b0Srsc } 3401b25f3b0Srsc nulterminate(cmd); 3411b25f3b0Srsc return cmd; 3421b25f3b0Srsc } 3431b25f3b0Srsc 3441b25f3b0Srsc struct cmd* 3451b25f3b0Srsc parseline(char **ps, char *es) 3461b25f3b0Srsc { 3471b25f3b0Srsc struct cmd *cmd; 3481b25f3b0Srsc 3491b25f3b0Srsc cmd = parsepipe(ps, es); 3501b25f3b0Srsc while(peek(ps, es, "&")){ 3511b25f3b0Srsc gettoken(ps, es, 0, 0); 3521b25f3b0Srsc cmd = backcmd(cmd); 3531b25f3b0Srsc } 3541b25f3b0Srsc if(peek(ps, es, ";")){ 3551b25f3b0Srsc gettoken(ps, es, 0, 0); 3561b25f3b0Srsc cmd = listcmd(cmd, parseline(ps, es)); 3571b25f3b0Srsc } 3581b25f3b0Srsc return cmd; 3591b25f3b0Srsc } 3601b25f3b0Srsc 3611b25f3b0Srsc struct cmd* 3621b25f3b0Srsc parsepipe(char **ps, char *es) 3631b25f3b0Srsc { 3641b25f3b0Srsc struct cmd *cmd; 3651b25f3b0Srsc 3661b25f3b0Srsc cmd = parseexec(ps, es); 3671b25f3b0Srsc if(peek(ps, es, "|")){ 3681b25f3b0Srsc gettoken(ps, es, 0, 0); 3691b25f3b0Srsc cmd = pipecmd(cmd, parsepipe(ps, es)); 3701b25f3b0Srsc } 3711b25f3b0Srsc return cmd; 3721b25f3b0Srsc } 3731b25f3b0Srsc 3741b25f3b0Srsc struct cmd* 3751b25f3b0Srsc parseredirs(struct cmd *cmd, char **ps, char *es) 3761b25f3b0Srsc { 3771b25f3b0Srsc int tok; 3781b25f3b0Srsc char *q, *eq; 3791b25f3b0Srsc 3801b25f3b0Srsc while(peek(ps, es, "<>")){ 3811b25f3b0Srsc tok = gettoken(ps, es, 0, 0); 3821b25f3b0Srsc if(gettoken(ps, es, &q, &eq) != 'a') 3831b25f3b0Srsc panic("missing file for redirection"); 3841b25f3b0Srsc switch(tok){ 3851b25f3b0Srsc case '<': 3861b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_RDONLY, 0); 3871b25f3b0Srsc break; 3881b25f3b0Srsc case '>': 3891b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 3901b25f3b0Srsc break; 3911b25f3b0Srsc case '+': // >> 3921b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 3938b58e810Skaashoek break; 3948b58e810Skaashoek } 3958b58e810Skaashoek } 3961b25f3b0Srsc return cmd; 3978b58e810Skaashoek } 3988b58e810Skaashoek 3991b25f3b0Srsc struct cmd* 400a759b8a4Srsc parseblock(char **ps, char *es) 401a759b8a4Srsc { 402a759b8a4Srsc struct cmd *cmd; 403a759b8a4Srsc 404a759b8a4Srsc if(!peek(ps, es, "(")) 405a759b8a4Srsc panic("parseblock"); 406a759b8a4Srsc gettoken(ps, es, 0, 0); 407a759b8a4Srsc cmd = parseline(ps, es); 408a759b8a4Srsc if(!peek(ps, es, ")")) 409a759b8a4Srsc panic("syntax - missing )"); 410a759b8a4Srsc gettoken(ps, es, 0, 0); 411a759b8a4Srsc cmd = parseredirs(cmd, ps, es); 412a759b8a4Srsc return cmd; 413a759b8a4Srsc } 414a759b8a4Srsc 415a759b8a4Srsc struct cmd* 4161b25f3b0Srsc parseexec(char **ps, char *es) 4178b58e810Skaashoek { 4181b25f3b0Srsc char *q, *eq; 4191b25f3b0Srsc int tok, argc; 4201b25f3b0Srsc struct execcmd *cmd; 4211b25f3b0Srsc struct cmd *ret; 4228b58e810Skaashoek 4231b25f3b0Srsc if(peek(ps, es, "(")) 4241b25f3b0Srsc return parseblock(ps, es); 4251b25f3b0Srsc 4261b25f3b0Srsc ret = execcmd(); 4271b25f3b0Srsc cmd = (struct execcmd*)ret; 4281b25f3b0Srsc 4291b25f3b0Srsc argc = 0; 4301b25f3b0Srsc ret = parseredirs(ret, ps, es); 4311b25f3b0Srsc while(!peek(ps, es, "|)&;")){ 4321b25f3b0Srsc if((tok=gettoken(ps, es, &q, &eq)) == 0) 4331b25f3b0Srsc break; 4341b25f3b0Srsc if(tok != 'a') 4351b25f3b0Srsc panic("syntax"); 4361b25f3b0Srsc cmd->argv[argc] = q; 4371b25f3b0Srsc cmd->eargv[argc] = eq; 4381b25f3b0Srsc argc++; 4391b25f3b0Srsc if(argc >= MAXARGS) 4401b25f3b0Srsc panic("too many args"); 4411b25f3b0Srsc ret = parseredirs(ret, ps, es); 4428b58e810Skaashoek } 4431b25f3b0Srsc cmd->argv[argc] = 0; 4441b25f3b0Srsc cmd->eargv[argc] = 0; 4451b25f3b0Srsc return ret; 4468b58e810Skaashoek } 4478b58e810Skaashoek 4481b25f3b0Srsc // NUL-terminate all the counted strings. 4491baead53Srsc struct cmd* 4501b25f3b0Srsc nulterminate(struct cmd *cmd) 4518b58e810Skaashoek { 4521b25f3b0Srsc int i; 4531b25f3b0Srsc struct backcmd *bcmd; 4541b25f3b0Srsc struct execcmd *ecmd; 4551b25f3b0Srsc struct listcmd *lcmd; 4561b25f3b0Srsc struct pipecmd *pcmd; 4571b25f3b0Srsc struct redircmd *rcmd; 4588b58e810Skaashoek 4591b25f3b0Srsc if(cmd == 0) 460a759b8a4Srsc return 0; 4618b58e810Skaashoek 4621b25f3b0Srsc switch(cmd->type){ 4631b25f3b0Srsc case EXEC: 4641b25f3b0Srsc ecmd = (struct execcmd*)cmd; 4651b25f3b0Srsc for(i=0; ecmd->argv[i]; i++) 4661b25f3b0Srsc *ecmd->eargv[i] = 0; 4671b25f3b0Srsc break; 4688b58e810Skaashoek 4691b25f3b0Srsc case REDIR: 4701b25f3b0Srsc rcmd = (struct redircmd*)cmd; 4711b25f3b0Srsc nulterminate(rcmd->cmd); 4721b25f3b0Srsc *rcmd->efile = 0; 4731b25f3b0Srsc break; 4748b58e810Skaashoek 4751b25f3b0Srsc case PIPE: 4761b25f3b0Srsc pcmd = (struct pipecmd*)cmd; 4771b25f3b0Srsc nulterminate(pcmd->left); 4781b25f3b0Srsc nulterminate(pcmd->right); 4791b25f3b0Srsc break; 4808b58e810Skaashoek 4811b25f3b0Srsc case LIST: 4821b25f3b0Srsc lcmd = (struct listcmd*)cmd; 4831b25f3b0Srsc nulterminate(lcmd->left); 4841b25f3b0Srsc nulterminate(lcmd->right); 4851b25f3b0Srsc break; 4861b25f3b0Srsc 4871b25f3b0Srsc case BACK: 4881b25f3b0Srsc bcmd = (struct backcmd*)cmd; 4891b25f3b0Srsc nulterminate(bcmd->cmd); 4901b25f3b0Srsc break; 4911b25f3b0Srsc } 492a759b8a4Srsc return cmd; 4931b25f3b0Srsc } 494