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 52*a759b8a4Srsc int fork1(void); // Fork but panics on failure. 531b25f3b0Srsc void panic(char*); 54*a759b8a4Srsc 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) 681b25f3b0Srsc return; 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 92*a759b8a4Srsc case LIST: 93*a759b8a4Srsc lcmd = (struct listcmd*)cmd; 94*a759b8a4Srsc if(fork1() == 0) 95*a759b8a4Srsc runcmd(lcmd->left); 96*a759b8a4Srsc wait(); 97*a759b8a4Srsc runcmd(lcmd->right); 98*a759b8a4Srsc break; 99*a759b8a4Srsc 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]; 148*a759b8a4Srsc int fd; 1498b58e810Skaashoek 150*a759b8a4Srsc // Assumes three file descriptors open. 151*a759b8a4Srsc while((fd = open("console", O_RDWR)) >= 0){ 152*a759b8a4Srsc if(fd >= 3){ 153*a759b8a4Srsc close(fd); 154*a759b8a4Srsc break; 155*a759b8a4Srsc } 156*a759b8a4Srsc } 157*a759b8a4Srsc 158*a759b8a4Srsc // Read and run input commands. 1591b25f3b0Srsc while(getcmd(buf, sizeof(buf)) >= 0) { 1601b25f3b0Srsc if(fork1() == 0) 1611b25f3b0Srsc runcmd(parsecmd(buf)); 1621b25f3b0Srsc wait(); 16321a88dd0Skaashoek } 1641b25f3b0Srsc exit(); 1658b58e810Skaashoek } 1668b58e810Skaashoek 1678b58e810Skaashoek void 1681b25f3b0Srsc panic(char *s) 1698b58e810Skaashoek { 1701b25f3b0Srsc printf(2, "%s\n", s); 171d7b3b802Skaashoek exit(); 172d7b3b802Skaashoek } 17321a88dd0Skaashoek 174*a759b8a4Srsc int 175*a759b8a4Srsc fork1(void) 176*a759b8a4Srsc { 177*a759b8a4Srsc int pid; 178*a759b8a4Srsc 179*a759b8a4Srsc pid = fork(); 180*a759b8a4Srsc if(pid == -1) 181*a759b8a4Srsc panic("fork"); 182*a759b8a4Srsc return pid; 183*a759b8a4Srsc } 184*a759b8a4Srsc 185*a759b8a4Srsc //PAGEBREAK! 1861b25f3b0Srsc // Constructors 1871b25f3b0Srsc 1881b25f3b0Srsc struct cmd* 1891b25f3b0Srsc execcmd(void) 1901b25f3b0Srsc { 1911b25f3b0Srsc struct execcmd *cmd; 1921b25f3b0Srsc 1931b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 1941b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 1951b25f3b0Srsc cmd->type = EXEC; 1961b25f3b0Srsc return (struct cmd*)cmd; 19721a88dd0Skaashoek } 1981b25f3b0Srsc 1991b25f3b0Srsc struct cmd* 2001b25f3b0Srsc redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd) 2011b25f3b0Srsc { 2021b25f3b0Srsc struct redircmd *cmd; 2031b25f3b0Srsc 2041b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2051b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2061b25f3b0Srsc cmd->type = REDIR; 2071b25f3b0Srsc cmd->cmd = subcmd; 2081b25f3b0Srsc cmd->file = file; 2091b25f3b0Srsc cmd->efile = efile; 2101b25f3b0Srsc cmd->mode = mode; 2111b25f3b0Srsc cmd->fd = fd; 2121b25f3b0Srsc return (struct cmd*)cmd; 213d7b3b802Skaashoek } 2141b25f3b0Srsc 2151b25f3b0Srsc struct cmd* 2161b25f3b0Srsc pipecmd(struct cmd *left, struct cmd *right) 2171b25f3b0Srsc { 2181b25f3b0Srsc struct pipecmd *cmd; 2191b25f3b0Srsc 2201b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2211b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2221b25f3b0Srsc cmd->type = PIPE; 2231b25f3b0Srsc cmd->left = left; 2241b25f3b0Srsc cmd->right = right; 2251b25f3b0Srsc return (struct cmd*)cmd; 226d7b3b802Skaashoek } 2271b25f3b0Srsc 2281b25f3b0Srsc struct cmd* 2291b25f3b0Srsc listcmd(struct cmd *left, struct cmd *right) 2301b25f3b0Srsc { 2311b25f3b0Srsc struct listcmd *cmd; 2321b25f3b0Srsc 2331b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2341b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2351b25f3b0Srsc cmd->type = LIST; 2361b25f3b0Srsc cmd->left = left; 2371b25f3b0Srsc cmd->right = right; 2381b25f3b0Srsc return (struct cmd*)cmd; 23921a88dd0Skaashoek } 2401b25f3b0Srsc 2411b25f3b0Srsc struct cmd* 2421b25f3b0Srsc backcmd(struct cmd *subcmd) 2431b25f3b0Srsc { 2441b25f3b0Srsc struct backcmd *cmd; 2451b25f3b0Srsc 2461b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 2471b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 2481b25f3b0Srsc cmd->type = BACK; 2491b25f3b0Srsc cmd->cmd = subcmd; 2501b25f3b0Srsc return (struct cmd*)cmd; 2511b25f3b0Srsc } 252*a759b8a4Srsc //PAGEBREAK! 2531b25f3b0Srsc // Parsing 2541b25f3b0Srsc 2551b25f3b0Srsc char whitespace[] = " \t\r\n\v"; 2561b25f3b0Srsc char symbols[] = "<|>&;()"; 2571b25f3b0Srsc 2581b25f3b0Srsc int 2591b25f3b0Srsc gettoken(char **ps, char *es, char **q, char **eq) 2608b58e810Skaashoek { 2611b25f3b0Srsc char *s; 2621b25f3b0Srsc int ret; 2638b58e810Skaashoek 2641b25f3b0Srsc s = *ps; 2651b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 2661b25f3b0Srsc s++; 2671b25f3b0Srsc if(q) 2681b25f3b0Srsc *q = s; 2691b25f3b0Srsc ret = *s; 2701b25f3b0Srsc switch(*s){ 2711b25f3b0Srsc case 0: 2721b25f3b0Srsc break; 2731b25f3b0Srsc case '|': 2741b25f3b0Srsc case '(': 2751b25f3b0Srsc case ')': 2761b25f3b0Srsc case ';': 2771b25f3b0Srsc case '&': 2788b58e810Skaashoek case '<': 2791b25f3b0Srsc s++; 2808b58e810Skaashoek break; 2818b58e810Skaashoek case '>': 2821b25f3b0Srsc s++; 2831b25f3b0Srsc if(*s == '>'){ 2841b25f3b0Srsc ret = '+'; 2851b25f3b0Srsc s++; 2868b58e810Skaashoek } 2871b25f3b0Srsc break; 2881b25f3b0Srsc default: 2891b25f3b0Srsc ret = 'a'; 2901b25f3b0Srsc while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s)) 2911b25f3b0Srsc s++; 2921b25f3b0Srsc break; 2931b25f3b0Srsc } 2941b25f3b0Srsc if(eq) 2951b25f3b0Srsc *eq = s; 2961b25f3b0Srsc 2971b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 2981b25f3b0Srsc s++; 2991b25f3b0Srsc *ps = s; 3001b25f3b0Srsc return ret; 3011b25f3b0Srsc } 3021b25f3b0Srsc 303*a759b8a4Srsc int 304*a759b8a4Srsc peek(char **ps, char *es, char *toks) 305*a759b8a4Srsc { 306*a759b8a4Srsc char *s; 307*a759b8a4Srsc 308*a759b8a4Srsc s = *ps; 309*a759b8a4Srsc while(s < es && strchr(whitespace, *s)) 310*a759b8a4Srsc s++; 311*a759b8a4Srsc *ps = s; 312*a759b8a4Srsc return *s && strchr(toks, *s); 313*a759b8a4Srsc } 314*a759b8a4Srsc 3151b25f3b0Srsc struct cmd *parseline(char**, char*); 3161b25f3b0Srsc struct cmd *parsepipe(char**, char*); 3171b25f3b0Srsc struct cmd *parseexec(char**, char*); 318*a759b8a4Srsc struct cmd *nulterminate(struct cmd*); 3191b25f3b0Srsc 3201b25f3b0Srsc struct cmd* 3211b25f3b0Srsc parsecmd(char *s) 3221b25f3b0Srsc { 3231b25f3b0Srsc char *es; 3241b25f3b0Srsc struct cmd *cmd; 3251b25f3b0Srsc 3261b25f3b0Srsc es = s + strlen(s); 3271b25f3b0Srsc cmd = parseline(&s, es); 3281b25f3b0Srsc peek(&s, es, ""); 3291b25f3b0Srsc if(s != es){ 3301b25f3b0Srsc printf(2, "leftovers: %s\n", s); 3311b25f3b0Srsc panic("syntax"); 3321b25f3b0Srsc } 3331b25f3b0Srsc nulterminate(cmd); 3341b25f3b0Srsc return cmd; 3351b25f3b0Srsc } 3361b25f3b0Srsc 3371b25f3b0Srsc struct cmd* 3381b25f3b0Srsc parseline(char **ps, char *es) 3391b25f3b0Srsc { 3401b25f3b0Srsc struct cmd *cmd; 3411b25f3b0Srsc 3421b25f3b0Srsc cmd = parsepipe(ps, es); 3431b25f3b0Srsc while(peek(ps, es, "&")){ 3441b25f3b0Srsc gettoken(ps, es, 0, 0); 3451b25f3b0Srsc cmd = backcmd(cmd); 3461b25f3b0Srsc } 3471b25f3b0Srsc if(peek(ps, es, ";")){ 3481b25f3b0Srsc gettoken(ps, es, 0, 0); 3491b25f3b0Srsc cmd = listcmd(cmd, parseline(ps, es)); 3501b25f3b0Srsc } 3511b25f3b0Srsc return cmd; 3521b25f3b0Srsc } 3531b25f3b0Srsc 3541b25f3b0Srsc struct cmd* 3551b25f3b0Srsc parsepipe(char **ps, char *es) 3561b25f3b0Srsc { 3571b25f3b0Srsc struct cmd *cmd; 3581b25f3b0Srsc 3591b25f3b0Srsc cmd = parseexec(ps, es); 3601b25f3b0Srsc if(peek(ps, es, "|")){ 3611b25f3b0Srsc gettoken(ps, es, 0, 0); 3621b25f3b0Srsc cmd = pipecmd(cmd, parsepipe(ps, es)); 3631b25f3b0Srsc } 3641b25f3b0Srsc return cmd; 3651b25f3b0Srsc } 3661b25f3b0Srsc 3671b25f3b0Srsc struct cmd* 3681b25f3b0Srsc parseredirs(struct cmd *cmd, char **ps, char *es) 3691b25f3b0Srsc { 3701b25f3b0Srsc int tok; 3711b25f3b0Srsc char *q, *eq; 3721b25f3b0Srsc 3731b25f3b0Srsc while(peek(ps, es, "<>")){ 3741b25f3b0Srsc tok = gettoken(ps, es, 0, 0); 3751b25f3b0Srsc if(gettoken(ps, es, &q, &eq) != 'a') 3761b25f3b0Srsc panic("missing file for redirection"); 3771b25f3b0Srsc switch(tok){ 3781b25f3b0Srsc case '<': 3791b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_RDONLY, 0); 3801b25f3b0Srsc break; 3811b25f3b0Srsc case '>': 3821b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 3831b25f3b0Srsc break; 3841b25f3b0Srsc case '+': // >> 3851b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 3868b58e810Skaashoek break; 3878b58e810Skaashoek } 3888b58e810Skaashoek } 3891b25f3b0Srsc return cmd; 3908b58e810Skaashoek } 3918b58e810Skaashoek 3921b25f3b0Srsc struct cmd* 393*a759b8a4Srsc parseblock(char **ps, char *es) 394*a759b8a4Srsc { 395*a759b8a4Srsc struct cmd *cmd; 396*a759b8a4Srsc 397*a759b8a4Srsc if(!peek(ps, es, "(")) 398*a759b8a4Srsc panic("parseblock"); 399*a759b8a4Srsc gettoken(ps, es, 0, 0); 400*a759b8a4Srsc cmd = parseline(ps, es); 401*a759b8a4Srsc if(!peek(ps, es, ")")) 402*a759b8a4Srsc panic("syntax - missing )"); 403*a759b8a4Srsc gettoken(ps, es, 0, 0); 404*a759b8a4Srsc cmd = parseredirs(cmd, ps, es); 405*a759b8a4Srsc return cmd; 406*a759b8a4Srsc } 407*a759b8a4Srsc 408*a759b8a4Srsc struct cmd* 4091b25f3b0Srsc parseexec(char **ps, char *es) 4108b58e810Skaashoek { 4111b25f3b0Srsc char *q, *eq; 4121b25f3b0Srsc int tok, argc; 4131b25f3b0Srsc struct execcmd *cmd; 4141b25f3b0Srsc struct cmd *ret; 4158b58e810Skaashoek 4161b25f3b0Srsc if(peek(ps, es, "(")) 4171b25f3b0Srsc return parseblock(ps, es); 4181b25f3b0Srsc 4191b25f3b0Srsc ret = execcmd(); 4201b25f3b0Srsc cmd = (struct execcmd*)ret; 4211b25f3b0Srsc 4221b25f3b0Srsc argc = 0; 4231b25f3b0Srsc ret = parseredirs(ret, ps, es); 4241b25f3b0Srsc while(!peek(ps, es, "|)&;")){ 4251b25f3b0Srsc if((tok=gettoken(ps, es, &q, &eq)) == 0) 4261b25f3b0Srsc break; 4271b25f3b0Srsc if(tok != 'a') 4281b25f3b0Srsc panic("syntax"); 4291b25f3b0Srsc cmd->argv[argc] = q; 4301b25f3b0Srsc cmd->eargv[argc] = eq; 4311b25f3b0Srsc argc++; 4321b25f3b0Srsc if(argc >= MAXARGS) 4331b25f3b0Srsc panic("too many args"); 4341b25f3b0Srsc ret = parseredirs(ret, ps, es); 4358b58e810Skaashoek } 4361b25f3b0Srsc cmd->argv[argc] = 0; 4371b25f3b0Srsc cmd->eargv[argc] = 0; 4381b25f3b0Srsc return ret; 4398b58e810Skaashoek } 4408b58e810Skaashoek 4411b25f3b0Srsc // NUL-terminate all the counted strings. 442*a759b8a4Srsc struct cmd: 4431b25f3b0Srsc nulterminate(struct cmd *cmd) 4448b58e810Skaashoek { 4451b25f3b0Srsc int i; 4461b25f3b0Srsc struct backcmd *bcmd; 4471b25f3b0Srsc struct execcmd *ecmd; 4481b25f3b0Srsc struct listcmd *lcmd; 4491b25f3b0Srsc struct pipecmd *pcmd; 4501b25f3b0Srsc struct redircmd *rcmd; 4518b58e810Skaashoek 4521b25f3b0Srsc if(cmd == 0) 453*a759b8a4Srsc return 0; 4548b58e810Skaashoek 4551b25f3b0Srsc switch(cmd->type){ 4561b25f3b0Srsc case EXEC: 4571b25f3b0Srsc ecmd = (struct execcmd*)cmd; 4581b25f3b0Srsc for(i=0; ecmd->argv[i]; i++) 4591b25f3b0Srsc *ecmd->eargv[i] = 0; 4601b25f3b0Srsc break; 4618b58e810Skaashoek 4621b25f3b0Srsc case REDIR: 4631b25f3b0Srsc rcmd = (struct redircmd*)cmd; 4641b25f3b0Srsc nulterminate(rcmd->cmd); 4651b25f3b0Srsc *rcmd->efile = 0; 4661b25f3b0Srsc break; 4678b58e810Skaashoek 4681b25f3b0Srsc case PIPE: 4691b25f3b0Srsc pcmd = (struct pipecmd*)cmd; 4701b25f3b0Srsc nulterminate(pcmd->left); 4711b25f3b0Srsc nulterminate(pcmd->right); 4721b25f3b0Srsc break; 4738b58e810Skaashoek 4741b25f3b0Srsc case LIST: 4751b25f3b0Srsc lcmd = (struct listcmd*)cmd; 4761b25f3b0Srsc nulterminate(lcmd->left); 4771b25f3b0Srsc nulterminate(lcmd->right); 4781b25f3b0Srsc break; 4791b25f3b0Srsc 4801b25f3b0Srsc case BACK: 4811b25f3b0Srsc bcmd = (struct backcmd*)cmd; 4821b25f3b0Srsc nulterminate(bcmd->cmd); 4831b25f3b0Srsc break; 4841b25f3b0Srsc } 485*a759b8a4Srsc return cmd; 4861b25f3b0Srsc } 487