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 150a759b8a4Srsc // Assumes three file descriptors 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){ 160*9863fea7Srsc if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){ 161*9863fea7Srsc // Clumsy but will have to do for now. 162*9863fea7Srsc // Chdir has no effect on the parent if run in the child. 163*9863fea7Srsc buf[strlen(buf)-1] = 0; // chop \n 164*9863fea7Srsc if(chdir(buf+3) < 0) 165*9863fea7Srsc printf(2, "cannot cd %s\n", buf+3); 166*9863fea7Srsc continue; 167*9863fea7Srsc } 1681b25f3b0Srsc if(fork1() == 0) 1691b25f3b0Srsc runcmd(parsecmd(buf)); 1701b25f3b0Srsc wait(); 17121a88dd0Skaashoek } 1721b25f3b0Srsc exit(); 1738b58e810Skaashoek } 1748b58e810Skaashoek 1758b58e810Skaashoek void 1761b25f3b0Srsc panic(char *s) 1778b58e810Skaashoek { 1781b25f3b0Srsc printf(2, "%s\n", s); 179d7b3b802Skaashoek exit(); 180d7b3b802Skaashoek } 18121a88dd0Skaashoek 182a759b8a4Srsc int 183a759b8a4Srsc fork1(void) 184a759b8a4Srsc { 185a759b8a4Srsc int pid; 186a759b8a4Srsc 187a759b8a4Srsc pid = fork(); 188a759b8a4Srsc if(pid == -1) 189a759b8a4Srsc panic("fork"); 190a759b8a4Srsc return pid; 191a759b8a4Srsc } 192a759b8a4Srsc 193a759b8a4Srsc //PAGEBREAK! 1941b25f3b0Srsc // Constructors 1951b25f3b0Srsc 1961b25f3b0Srsc struct cmd* 1971b25f3b0Srsc execcmd(void) 1981b25f3b0Srsc { 1991b25f3b0Srsc struct execcmd *cmd; 2001b25f3b0Srsc 2011b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2021b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2031b25f3b0Srsc cmd->type = EXEC; 2041b25f3b0Srsc return (struct cmd*)cmd; 20521a88dd0Skaashoek } 2061b25f3b0Srsc 2071b25f3b0Srsc struct cmd* 2081b25f3b0Srsc redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd) 2091b25f3b0Srsc { 2101b25f3b0Srsc struct redircmd *cmd; 2111b25f3b0Srsc 2121b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2131b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2141b25f3b0Srsc cmd->type = REDIR; 2151b25f3b0Srsc cmd->cmd = subcmd; 2161b25f3b0Srsc cmd->file = file; 2171b25f3b0Srsc cmd->efile = efile; 2181b25f3b0Srsc cmd->mode = mode; 2191b25f3b0Srsc cmd->fd = fd; 2201b25f3b0Srsc return (struct cmd*)cmd; 221d7b3b802Skaashoek } 2221b25f3b0Srsc 2231b25f3b0Srsc struct cmd* 2241b25f3b0Srsc pipecmd(struct cmd *left, struct cmd *right) 2251b25f3b0Srsc { 2261b25f3b0Srsc struct pipecmd *cmd; 2271b25f3b0Srsc 2281b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2291b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2301b25f3b0Srsc cmd->type = PIPE; 2311b25f3b0Srsc cmd->left = left; 2321b25f3b0Srsc cmd->right = right; 2331b25f3b0Srsc return (struct cmd*)cmd; 234d7b3b802Skaashoek } 2351b25f3b0Srsc 2361b25f3b0Srsc struct cmd* 2371b25f3b0Srsc listcmd(struct cmd *left, struct cmd *right) 2381b25f3b0Srsc { 2391b25f3b0Srsc struct listcmd *cmd; 2401b25f3b0Srsc 2411b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2421b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2431b25f3b0Srsc cmd->type = LIST; 2441b25f3b0Srsc cmd->left = left; 2451b25f3b0Srsc cmd->right = right; 2461b25f3b0Srsc return (struct cmd*)cmd; 24721a88dd0Skaashoek } 2481b25f3b0Srsc 2491b25f3b0Srsc struct cmd* 2501b25f3b0Srsc backcmd(struct cmd *subcmd) 2511b25f3b0Srsc { 2521b25f3b0Srsc struct backcmd *cmd; 2531b25f3b0Srsc 2541b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2551b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2561b25f3b0Srsc cmd->type = BACK; 2571b25f3b0Srsc cmd->cmd = subcmd; 2581b25f3b0Srsc return (struct cmd*)cmd; 2591b25f3b0Srsc } 260a759b8a4Srsc //PAGEBREAK! 2611b25f3b0Srsc // Parsing 2621b25f3b0Srsc 2631b25f3b0Srsc char whitespace[] = " \t\r\n\v"; 2641b25f3b0Srsc char symbols[] = "<|>&;()"; 2651b25f3b0Srsc 2661b25f3b0Srsc int 2671b25f3b0Srsc gettoken(char **ps, char *es, char **q, char **eq) 2688b58e810Skaashoek { 2691b25f3b0Srsc char *s; 2701b25f3b0Srsc int ret; 2718b58e810Skaashoek 2721b25f3b0Srsc s = *ps; 2731b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 2741b25f3b0Srsc s++; 2751b25f3b0Srsc if(q) 2761b25f3b0Srsc *q = s; 2771b25f3b0Srsc ret = *s; 2781b25f3b0Srsc switch(*s){ 2791b25f3b0Srsc case 0: 2801b25f3b0Srsc break; 2811b25f3b0Srsc case '|': 2821b25f3b0Srsc case '(': 2831b25f3b0Srsc case ')': 2841b25f3b0Srsc case ';': 2851b25f3b0Srsc case '&': 2868b58e810Skaashoek case '<': 2871b25f3b0Srsc s++; 2888b58e810Skaashoek break; 2898b58e810Skaashoek case '>': 2901b25f3b0Srsc s++; 2911b25f3b0Srsc if(*s == '>'){ 2921b25f3b0Srsc ret = '+'; 2931b25f3b0Srsc s++; 2948b58e810Skaashoek } 2951b25f3b0Srsc break; 2961b25f3b0Srsc default: 2971b25f3b0Srsc ret = 'a'; 2981b25f3b0Srsc while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s)) 2991b25f3b0Srsc s++; 3001b25f3b0Srsc break; 3011b25f3b0Srsc } 3021b25f3b0Srsc if(eq) 3031b25f3b0Srsc *eq = s; 3041b25f3b0Srsc 3051b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 3061b25f3b0Srsc s++; 3071b25f3b0Srsc *ps = s; 3081b25f3b0Srsc return ret; 3091b25f3b0Srsc } 3101b25f3b0Srsc 311a759b8a4Srsc int 312a759b8a4Srsc peek(char **ps, char *es, char *toks) 313a759b8a4Srsc { 314a759b8a4Srsc char *s; 315a759b8a4Srsc 316a759b8a4Srsc s = *ps; 317a759b8a4Srsc while(s < es && strchr(whitespace, *s)) 318a759b8a4Srsc s++; 319a759b8a4Srsc *ps = s; 320a759b8a4Srsc return *s && strchr(toks, *s); 321a759b8a4Srsc } 322a759b8a4Srsc 3231b25f3b0Srsc struct cmd *parseline(char**, char*); 3241b25f3b0Srsc struct cmd *parsepipe(char**, char*); 3251b25f3b0Srsc struct cmd *parseexec(char**, char*); 326a759b8a4Srsc struct cmd *nulterminate(struct cmd*); 3271b25f3b0Srsc 3281b25f3b0Srsc struct cmd* 3291b25f3b0Srsc parsecmd(char *s) 3301b25f3b0Srsc { 3311b25f3b0Srsc char *es; 3321b25f3b0Srsc struct cmd *cmd; 3331b25f3b0Srsc 3341b25f3b0Srsc es = s + strlen(s); 3351b25f3b0Srsc cmd = parseline(&s, es); 3361b25f3b0Srsc peek(&s, es, ""); 3371b25f3b0Srsc if(s != es){ 3381b25f3b0Srsc printf(2, "leftovers: %s\n", s); 3391b25f3b0Srsc panic("syntax"); 3401b25f3b0Srsc } 3411b25f3b0Srsc nulterminate(cmd); 3421b25f3b0Srsc return cmd; 3431b25f3b0Srsc } 3441b25f3b0Srsc 3451b25f3b0Srsc struct cmd* 3461b25f3b0Srsc parseline(char **ps, char *es) 3471b25f3b0Srsc { 3481b25f3b0Srsc struct cmd *cmd; 3491b25f3b0Srsc 3501b25f3b0Srsc cmd = parsepipe(ps, es); 3511b25f3b0Srsc while(peek(ps, es, "&")){ 3521b25f3b0Srsc gettoken(ps, es, 0, 0); 3531b25f3b0Srsc cmd = backcmd(cmd); 3541b25f3b0Srsc } 3551b25f3b0Srsc if(peek(ps, es, ";")){ 3561b25f3b0Srsc gettoken(ps, es, 0, 0); 3571b25f3b0Srsc cmd = listcmd(cmd, parseline(ps, es)); 3581b25f3b0Srsc } 3591b25f3b0Srsc return cmd; 3601b25f3b0Srsc } 3611b25f3b0Srsc 3621b25f3b0Srsc struct cmd* 3631b25f3b0Srsc parsepipe(char **ps, char *es) 3641b25f3b0Srsc { 3651b25f3b0Srsc struct cmd *cmd; 3661b25f3b0Srsc 3671b25f3b0Srsc cmd = parseexec(ps, es); 3681b25f3b0Srsc if(peek(ps, es, "|")){ 3691b25f3b0Srsc gettoken(ps, es, 0, 0); 3701b25f3b0Srsc cmd = pipecmd(cmd, parsepipe(ps, es)); 3711b25f3b0Srsc } 3721b25f3b0Srsc return cmd; 3731b25f3b0Srsc } 3741b25f3b0Srsc 3751b25f3b0Srsc struct cmd* 3761b25f3b0Srsc parseredirs(struct cmd *cmd, char **ps, char *es) 3771b25f3b0Srsc { 3781b25f3b0Srsc int tok; 3791b25f3b0Srsc char *q, *eq; 3801b25f3b0Srsc 3811b25f3b0Srsc while(peek(ps, es, "<>")){ 3821b25f3b0Srsc tok = gettoken(ps, es, 0, 0); 3831b25f3b0Srsc if(gettoken(ps, es, &q, &eq) != 'a') 3841b25f3b0Srsc panic("missing file for redirection"); 3851b25f3b0Srsc switch(tok){ 3861b25f3b0Srsc case '<': 3871b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_RDONLY, 0); 3881b25f3b0Srsc break; 3891b25f3b0Srsc case '>': 3901b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 3911b25f3b0Srsc break; 3921b25f3b0Srsc case '+': // >> 3931b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 3948b58e810Skaashoek break; 3958b58e810Skaashoek } 3968b58e810Skaashoek } 3971b25f3b0Srsc return cmd; 3988b58e810Skaashoek } 3998b58e810Skaashoek 4001b25f3b0Srsc struct cmd* 401a759b8a4Srsc parseblock(char **ps, char *es) 402a759b8a4Srsc { 403a759b8a4Srsc struct cmd *cmd; 404a759b8a4Srsc 405a759b8a4Srsc if(!peek(ps, es, "(")) 406a759b8a4Srsc panic("parseblock"); 407a759b8a4Srsc gettoken(ps, es, 0, 0); 408a759b8a4Srsc cmd = parseline(ps, es); 409a759b8a4Srsc if(!peek(ps, es, ")")) 410a759b8a4Srsc panic("syntax - missing )"); 411a759b8a4Srsc gettoken(ps, es, 0, 0); 412a759b8a4Srsc cmd = parseredirs(cmd, ps, es); 413a759b8a4Srsc return cmd; 414a759b8a4Srsc } 415a759b8a4Srsc 416a759b8a4Srsc struct cmd* 4171b25f3b0Srsc parseexec(char **ps, char *es) 4188b58e810Skaashoek { 4191b25f3b0Srsc char *q, *eq; 4201b25f3b0Srsc int tok, argc; 4211b25f3b0Srsc struct execcmd *cmd; 4221b25f3b0Srsc struct cmd *ret; 4238b58e810Skaashoek 4241b25f3b0Srsc if(peek(ps, es, "(")) 4251b25f3b0Srsc return parseblock(ps, es); 4261b25f3b0Srsc 4271b25f3b0Srsc ret = execcmd(); 4281b25f3b0Srsc cmd = (struct execcmd*)ret; 4291b25f3b0Srsc 4301b25f3b0Srsc argc = 0; 4311b25f3b0Srsc ret = parseredirs(ret, ps, es); 4321b25f3b0Srsc while(!peek(ps, es, "|)&;")){ 4331b25f3b0Srsc if((tok=gettoken(ps, es, &q, &eq)) == 0) 4341b25f3b0Srsc break; 4351b25f3b0Srsc if(tok != 'a') 4361b25f3b0Srsc panic("syntax"); 4371b25f3b0Srsc cmd->argv[argc] = q; 4381b25f3b0Srsc cmd->eargv[argc] = eq; 4391b25f3b0Srsc argc++; 4401b25f3b0Srsc if(argc >= MAXARGS) 4411b25f3b0Srsc panic("too many args"); 4421b25f3b0Srsc ret = parseredirs(ret, ps, es); 4438b58e810Skaashoek } 4441b25f3b0Srsc cmd->argv[argc] = 0; 4451b25f3b0Srsc cmd->eargv[argc] = 0; 4461b25f3b0Srsc return ret; 4478b58e810Skaashoek } 4488b58e810Skaashoek 4491b25f3b0Srsc // NUL-terminate all the counted strings. 4501baead53Srsc struct cmd* 4511b25f3b0Srsc nulterminate(struct cmd *cmd) 4528b58e810Skaashoek { 4531b25f3b0Srsc int i; 4541b25f3b0Srsc struct backcmd *bcmd; 4551b25f3b0Srsc struct execcmd *ecmd; 4561b25f3b0Srsc struct listcmd *lcmd; 4571b25f3b0Srsc struct pipecmd *pcmd; 4581b25f3b0Srsc struct redircmd *rcmd; 4598b58e810Skaashoek 4601b25f3b0Srsc if(cmd == 0) 461a759b8a4Srsc return 0; 4628b58e810Skaashoek 4631b25f3b0Srsc switch(cmd->type){ 4641b25f3b0Srsc case EXEC: 4651b25f3b0Srsc ecmd = (struct execcmd*)cmd; 4661b25f3b0Srsc for(i=0; ecmd->argv[i]; i++) 4671b25f3b0Srsc *ecmd->eargv[i] = 0; 4681b25f3b0Srsc break; 4698b58e810Skaashoek 4701b25f3b0Srsc case REDIR: 4711b25f3b0Srsc rcmd = (struct redircmd*)cmd; 4721b25f3b0Srsc nulterminate(rcmd->cmd); 4731b25f3b0Srsc *rcmd->efile = 0; 4741b25f3b0Srsc break; 4758b58e810Skaashoek 4761b25f3b0Srsc case PIPE: 4771b25f3b0Srsc pcmd = (struct pipecmd*)cmd; 4781b25f3b0Srsc nulterminate(pcmd->left); 4791b25f3b0Srsc nulterminate(pcmd->right); 4801b25f3b0Srsc break; 4818b58e810Skaashoek 4821b25f3b0Srsc case LIST: 4831b25f3b0Srsc lcmd = (struct listcmd*)cmd; 4841b25f3b0Srsc nulterminate(lcmd->left); 4851b25f3b0Srsc nulterminate(lcmd->right); 4861b25f3b0Srsc break; 4871b25f3b0Srsc 4881b25f3b0Srsc case BACK: 4891b25f3b0Srsc bcmd = (struct backcmd*)cmd; 4901b25f3b0Srsc nulterminate(bcmd->cmd); 4911b25f3b0Srsc break; 4921b25f3b0Srsc } 493a759b8a4Srsc return cmd; 4941b25f3b0Srsc } 495