1*1b25f3b0Srsc // Shell. 2*1b25f3b0Srsc 317a85657Srtm #include "types.h" 4d7b3b802Skaashoek #include "user.h" 517a85657Srtm #include "fcntl.h" 617a85657Srtm 7*1b25f3b0Srsc // Parsed command representation 8*1b25f3b0Srsc #define EXEC 1 9*1b25f3b0Srsc #define REDIR 2 10*1b25f3b0Srsc #define PIPE 3 11*1b25f3b0Srsc #define LIST 4 12*1b25f3b0Srsc #define BACK 5 13*1b25f3b0Srsc 148b58e810Skaashoek #define MAXARGS 10 158b58e810Skaashoek 1621a88dd0Skaashoek struct cmd { 17*1b25f3b0Srsc int type; 1821a88dd0Skaashoek }; 19*1b25f3b0Srsc 20*1b25f3b0Srsc struct execcmd { 21*1b25f3b0Srsc int type; 22*1b25f3b0Srsc char *argv[MAXARGS]; 23*1b25f3b0Srsc char *eargv[MAXARGS]; 24*1b25f3b0Srsc }; 25*1b25f3b0Srsc 26*1b25f3b0Srsc struct redircmd { 27*1b25f3b0Srsc int type; 28e00baa9fSkaashoek struct cmd *cmd; 29*1b25f3b0Srsc char *file; 30*1b25f3b0Srsc char *efile; 31*1b25f3b0Srsc int mode; 32*1b25f3b0Srsc int fd; 33*1b25f3b0Srsc }; 348b58e810Skaashoek 35*1b25f3b0Srsc struct pipecmd { 36*1b25f3b0Srsc int type; 37*1b25f3b0Srsc struct cmd *left; 38*1b25f3b0Srsc struct cmd *right; 39*1b25f3b0Srsc }; 408b58e810Skaashoek 41*1b25f3b0Srsc struct listcmd { 42*1b25f3b0Srsc int type; 43*1b25f3b0Srsc struct cmd *left; 44*1b25f3b0Srsc struct cmd *right; 45*1b25f3b0Srsc }; 46*1b25f3b0Srsc 47*1b25f3b0Srsc struct backcmd { 48*1b25f3b0Srsc int type; 49*1b25f3b0Srsc struct cmd *cmd; 50*1b25f3b0Srsc }; 51*1b25f3b0Srsc 52*1b25f3b0Srsc struct cmd *parsecmd(char*); 53*1b25f3b0Srsc void panic(char*); 5417a85657Srtm 5517a85657Srtm int 56*1b25f3b0Srsc fork1(void) 5717a85657Srtm { 58*1b25f3b0Srsc int pid; 59*1b25f3b0Srsc 60*1b25f3b0Srsc pid = fork(); 61*1b25f3b0Srsc if(pid == -1) 62*1b25f3b0Srsc panic("fork"); 63*1b25f3b0Srsc return pid; 64*1b25f3b0Srsc } 65*1b25f3b0Srsc 66*1b25f3b0Srsc // Execute cmd. Never returns. 67*1b25f3b0Srsc void 68*1b25f3b0Srsc runcmd(struct cmd *cmd) 69*1b25f3b0Srsc { 70*1b25f3b0Srsc int p[2]; 71*1b25f3b0Srsc struct backcmd *bcmd; 72*1b25f3b0Srsc struct execcmd *ecmd; 73*1b25f3b0Srsc struct listcmd *lcmd; 74*1b25f3b0Srsc struct pipecmd *pcmd; 75*1b25f3b0Srsc struct redircmd *rcmd; 76*1b25f3b0Srsc 77*1b25f3b0Srsc if(cmd == 0) 78*1b25f3b0Srsc return; 79*1b25f3b0Srsc 80*1b25f3b0Srsc switch(cmd->type){ 81*1b25f3b0Srsc default: 82*1b25f3b0Srsc panic("runcmd"); 83*1b25f3b0Srsc 84*1b25f3b0Srsc case EXEC: 85*1b25f3b0Srsc ecmd = (struct execcmd*)cmd; 86*1b25f3b0Srsc if(ecmd->argv[0] == 0) 87*1b25f3b0Srsc exit(); 88*1b25f3b0Srsc exec(ecmd->argv[0], ecmd->argv); 89*1b25f3b0Srsc printf(2, "exec %s failed\n", ecmd->argv[0]); 90*1b25f3b0Srsc break; 91*1b25f3b0Srsc 92*1b25f3b0Srsc case REDIR: 93*1b25f3b0Srsc rcmd = (struct redircmd*)cmd; 94*1b25f3b0Srsc close(rcmd->fd); 95*1b25f3b0Srsc if(open(rcmd->file, rcmd->mode) < 0){ 96*1b25f3b0Srsc printf(2, "open %s failed\n", rcmd->file); 97*1b25f3b0Srsc exit(); 98*1b25f3b0Srsc } 99*1b25f3b0Srsc runcmd(rcmd->cmd); 100*1b25f3b0Srsc break; 101*1b25f3b0Srsc 102*1b25f3b0Srsc case PIPE: 103*1b25f3b0Srsc pcmd = (struct pipecmd*)cmd; 104*1b25f3b0Srsc if(pipe(p) < 0) 105*1b25f3b0Srsc panic("pipe"); 106*1b25f3b0Srsc if(fork1() == 0){ 107*1b25f3b0Srsc close(1); 108*1b25f3b0Srsc dup(p[1]); 109*1b25f3b0Srsc close(p[0]); 110*1b25f3b0Srsc close(p[1]); 111*1b25f3b0Srsc runcmd(pcmd->left); 112*1b25f3b0Srsc } 113*1b25f3b0Srsc if(fork1() == 0){ 114*1b25f3b0Srsc close(0); 115*1b25f3b0Srsc dup(p[0]); 116*1b25f3b0Srsc close(p[0]); 117*1b25f3b0Srsc close(p[1]); 118*1b25f3b0Srsc runcmd(pcmd->right); 119*1b25f3b0Srsc } 120*1b25f3b0Srsc close(p[0]); 121*1b25f3b0Srsc close(p[1]); 122*1b25f3b0Srsc wait(); 123*1b25f3b0Srsc wait(); 124*1b25f3b0Srsc break; 125*1b25f3b0Srsc 126*1b25f3b0Srsc case LIST: 127*1b25f3b0Srsc lcmd = (struct listcmd*)cmd; 128*1b25f3b0Srsc if(fork1() == 0) 129*1b25f3b0Srsc runcmd(lcmd->left); 130*1b25f3b0Srsc wait(); 131*1b25f3b0Srsc runcmd(lcmd->right); 132*1b25f3b0Srsc break; 133*1b25f3b0Srsc 134*1b25f3b0Srsc case BACK: 135*1b25f3b0Srsc bcmd = (struct backcmd*)cmd; 136*1b25f3b0Srsc if(fork1() == 0) 137*1b25f3b0Srsc runcmd(bcmd->cmd); 138*1b25f3b0Srsc break; 13917a85657Srtm } 140f8f7fcbeSrsc exit(); 14117a85657Srtm } 142d7b3b802Skaashoek 1438b58e810Skaashoek int 1449736728dSrsc getcmd(char *buf, int nbuf) 1459736728dSrsc { 1461b789e1dSrsc printf(2, "$ "); 1479736728dSrsc memset(buf, 0, nbuf); 1489736728dSrsc gets(buf, nbuf); 1499736728dSrsc if(buf[0] == 0) // EOF 1509736728dSrsc return -1; 1519736728dSrsc return 0; 1529736728dSrsc } 1539736728dSrsc 1549736728dSrsc int 155*1b25f3b0Srsc main(void) 156d7b3b802Skaashoek { 157*1b25f3b0Srsc static char buf[100]; 1588b58e810Skaashoek 159*1b25f3b0Srsc while(getcmd(buf, sizeof(buf)) >= 0) { 160*1b25f3b0Srsc if(fork1() == 0) 161*1b25f3b0Srsc runcmd(parsecmd(buf)); 162*1b25f3b0Srsc wait(); 16321a88dd0Skaashoek } 164*1b25f3b0Srsc exit(); 1658b58e810Skaashoek } 1668b58e810Skaashoek 1678b58e810Skaashoek void 168*1b25f3b0Srsc panic(char *s) 1698b58e810Skaashoek { 170*1b25f3b0Srsc printf(2, "%s\n", s); 171d7b3b802Skaashoek exit(); 172d7b3b802Skaashoek } 17321a88dd0Skaashoek 174*1b25f3b0Srsc // Constructors 175*1b25f3b0Srsc 176*1b25f3b0Srsc struct cmd* 177*1b25f3b0Srsc execcmd(void) 178*1b25f3b0Srsc { 179*1b25f3b0Srsc struct execcmd *cmd; 180*1b25f3b0Srsc 181*1b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 182*1b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 183*1b25f3b0Srsc cmd->type = EXEC; 184*1b25f3b0Srsc return (struct cmd*)cmd; 18521a88dd0Skaashoek } 186*1b25f3b0Srsc 187*1b25f3b0Srsc struct cmd* 188*1b25f3b0Srsc redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd) 189*1b25f3b0Srsc { 190*1b25f3b0Srsc struct redircmd *cmd; 191*1b25f3b0Srsc 192*1b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 193*1b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 194*1b25f3b0Srsc cmd->type = REDIR; 195*1b25f3b0Srsc cmd->cmd = subcmd; 196*1b25f3b0Srsc cmd->file = file; 197*1b25f3b0Srsc cmd->efile = efile; 198*1b25f3b0Srsc cmd->mode = mode; 199*1b25f3b0Srsc cmd->fd = fd; 200*1b25f3b0Srsc return (struct cmd*)cmd; 201d7b3b802Skaashoek } 202*1b25f3b0Srsc 203*1b25f3b0Srsc struct cmd* 204*1b25f3b0Srsc pipecmd(struct cmd *left, struct cmd *right) 205*1b25f3b0Srsc { 206*1b25f3b0Srsc struct pipecmd *cmd; 207*1b25f3b0Srsc 208*1b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 209*1b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 210*1b25f3b0Srsc cmd->type = PIPE; 211*1b25f3b0Srsc cmd->left = left; 212*1b25f3b0Srsc cmd->right = right; 213*1b25f3b0Srsc return (struct cmd*)cmd; 214d7b3b802Skaashoek } 215*1b25f3b0Srsc 216*1b25f3b0Srsc struct cmd* 217*1b25f3b0Srsc listcmd(struct cmd *left, struct cmd *right) 218*1b25f3b0Srsc { 219*1b25f3b0Srsc struct listcmd *cmd; 220*1b25f3b0Srsc 221*1b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 222*1b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 223*1b25f3b0Srsc cmd->type = LIST; 224*1b25f3b0Srsc cmd->left = left; 225*1b25f3b0Srsc cmd->right = right; 226*1b25f3b0Srsc return (struct cmd*)cmd; 22721a88dd0Skaashoek } 228*1b25f3b0Srsc 229*1b25f3b0Srsc struct cmd* 230*1b25f3b0Srsc backcmd(struct cmd *subcmd) 231*1b25f3b0Srsc { 232*1b25f3b0Srsc struct backcmd *cmd; 233*1b25f3b0Srsc 234*1b25f3b0Srsc cmd = malloc(sizeof(*cmd)); 235*1b25f3b0Srsc memset(cmd, 0, sizeof(*cmd)); 236*1b25f3b0Srsc cmd->type = BACK; 237*1b25f3b0Srsc cmd->cmd = subcmd; 238*1b25f3b0Srsc return (struct cmd*)cmd; 239*1b25f3b0Srsc } 240*1b25f3b0Srsc 241*1b25f3b0Srsc // Parsing 242*1b25f3b0Srsc 243*1b25f3b0Srsc char whitespace[] = " \t\r\n\v"; 244*1b25f3b0Srsc char symbols[] = "<|>&;()"; 245*1b25f3b0Srsc 246*1b25f3b0Srsc int 247*1b25f3b0Srsc peek(char **ps, char *es, char *toks) 248*1b25f3b0Srsc { 249*1b25f3b0Srsc char *s; 250*1b25f3b0Srsc 251*1b25f3b0Srsc s = *ps; 252*1b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 253*1b25f3b0Srsc s++; 254*1b25f3b0Srsc *ps = s; 255*1b25f3b0Srsc return *s && strchr(toks, *s); 25621a88dd0Skaashoek } 2578b58e810Skaashoek 2588b58e810Skaashoek int 259*1b25f3b0Srsc gettoken(char **ps, char *es, char **q, char **eq) 2608b58e810Skaashoek { 261*1b25f3b0Srsc char *s; 262*1b25f3b0Srsc int ret; 2638b58e810Skaashoek 264*1b25f3b0Srsc s = *ps; 265*1b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 266*1b25f3b0Srsc s++; 267*1b25f3b0Srsc if(q) 268*1b25f3b0Srsc *q = s; 269*1b25f3b0Srsc ret = *s; 270*1b25f3b0Srsc switch(*s){ 271*1b25f3b0Srsc case 0: 272*1b25f3b0Srsc break; 273*1b25f3b0Srsc case '|': 274*1b25f3b0Srsc case '(': 275*1b25f3b0Srsc case ')': 276*1b25f3b0Srsc case ';': 277*1b25f3b0Srsc case '&': 2788b58e810Skaashoek case '<': 279*1b25f3b0Srsc s++; 2808b58e810Skaashoek break; 2818b58e810Skaashoek case '>': 282*1b25f3b0Srsc s++; 283*1b25f3b0Srsc if(*s == '>'){ 284*1b25f3b0Srsc ret = '+'; 285*1b25f3b0Srsc s++; 2868b58e810Skaashoek } 287*1b25f3b0Srsc break; 288*1b25f3b0Srsc default: 289*1b25f3b0Srsc ret = 'a'; 290*1b25f3b0Srsc while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s)) 291*1b25f3b0Srsc s++; 292*1b25f3b0Srsc break; 293*1b25f3b0Srsc } 294*1b25f3b0Srsc if(eq) 295*1b25f3b0Srsc *eq = s; 296*1b25f3b0Srsc 297*1b25f3b0Srsc while(s < es && strchr(whitespace, *s)) 298*1b25f3b0Srsc s++; 299*1b25f3b0Srsc *ps = s; 300*1b25f3b0Srsc return ret; 301*1b25f3b0Srsc } 302*1b25f3b0Srsc 303*1b25f3b0Srsc void nulterminate(struct cmd*); 304*1b25f3b0Srsc struct cmd *parseline(char**, char*); 305*1b25f3b0Srsc struct cmd *parsepipe(char**, char*); 306*1b25f3b0Srsc struct cmd *parseredirs(struct cmd*, char**, char*); 307*1b25f3b0Srsc struct cmd *parseblock(char**, char*); 308*1b25f3b0Srsc struct cmd *parseexec(char**, char*); 309*1b25f3b0Srsc 310*1b25f3b0Srsc struct cmd* 311*1b25f3b0Srsc parsecmd(char *s) 312*1b25f3b0Srsc { 313*1b25f3b0Srsc char *es; 314*1b25f3b0Srsc struct cmd *cmd; 315*1b25f3b0Srsc 316*1b25f3b0Srsc es = s + strlen(s); 317*1b25f3b0Srsc cmd = parseline(&s, es); 318*1b25f3b0Srsc peek(&s, es, ""); 319*1b25f3b0Srsc if(s != es){ 320*1b25f3b0Srsc printf(2, "leftovers: %s\n", s); 321*1b25f3b0Srsc panic("syntax"); 322*1b25f3b0Srsc } 323*1b25f3b0Srsc nulterminate(cmd); 324*1b25f3b0Srsc return cmd; 325*1b25f3b0Srsc } 326*1b25f3b0Srsc 327*1b25f3b0Srsc struct cmd* 328*1b25f3b0Srsc parseline(char **ps, char *es) 329*1b25f3b0Srsc { 330*1b25f3b0Srsc struct cmd *cmd; 331*1b25f3b0Srsc 332*1b25f3b0Srsc cmd = parsepipe(ps, es); 333*1b25f3b0Srsc while(peek(ps, es, "&")){ 334*1b25f3b0Srsc gettoken(ps, es, 0, 0); 335*1b25f3b0Srsc cmd = backcmd(cmd); 336*1b25f3b0Srsc } 337*1b25f3b0Srsc if(peek(ps, es, ";")){ 338*1b25f3b0Srsc gettoken(ps, es, 0, 0); 339*1b25f3b0Srsc cmd = listcmd(cmd, parseline(ps, es)); 340*1b25f3b0Srsc } 341*1b25f3b0Srsc return cmd; 342*1b25f3b0Srsc } 343*1b25f3b0Srsc 344*1b25f3b0Srsc struct cmd* 345*1b25f3b0Srsc parsepipe(char **ps, char *es) 346*1b25f3b0Srsc { 347*1b25f3b0Srsc struct cmd *cmd; 348*1b25f3b0Srsc 349*1b25f3b0Srsc cmd = parseexec(ps, es); 350*1b25f3b0Srsc if(peek(ps, es, "|")){ 351*1b25f3b0Srsc gettoken(ps, es, 0, 0); 352*1b25f3b0Srsc cmd = pipecmd(cmd, parsepipe(ps, es)); 353*1b25f3b0Srsc } 354*1b25f3b0Srsc return cmd; 355*1b25f3b0Srsc } 356*1b25f3b0Srsc 357*1b25f3b0Srsc struct cmd* 358*1b25f3b0Srsc parseblock(char **ps, char *es) 359*1b25f3b0Srsc { 360*1b25f3b0Srsc struct cmd *cmd; 361*1b25f3b0Srsc 362*1b25f3b0Srsc if(!peek(ps, es, "(")) 363*1b25f3b0Srsc panic("parseblock"); 364*1b25f3b0Srsc gettoken(ps, es, 0, 0); 365*1b25f3b0Srsc cmd = parseline(ps, es); 366*1b25f3b0Srsc if(!peek(ps, es, ")")) 367*1b25f3b0Srsc panic("syntax - missing )"); 368*1b25f3b0Srsc gettoken(ps, es, 0, 0); 369*1b25f3b0Srsc cmd = parseredirs(cmd, ps, es); 370*1b25f3b0Srsc return cmd; 371*1b25f3b0Srsc } 372*1b25f3b0Srsc 373*1b25f3b0Srsc struct cmd* 374*1b25f3b0Srsc parseredirs(struct cmd *cmd, char **ps, char *es) 375*1b25f3b0Srsc { 376*1b25f3b0Srsc int tok; 377*1b25f3b0Srsc char *q, *eq; 378*1b25f3b0Srsc 379*1b25f3b0Srsc while(peek(ps, es, "<>")){ 380*1b25f3b0Srsc tok = gettoken(ps, es, 0, 0); 381*1b25f3b0Srsc if(gettoken(ps, es, &q, &eq) != 'a') 382*1b25f3b0Srsc panic("missing file for redirection"); 383*1b25f3b0Srsc switch(tok){ 384*1b25f3b0Srsc case '<': 385*1b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_RDONLY, 0); 386*1b25f3b0Srsc break; 387*1b25f3b0Srsc case '>': 388*1b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 389*1b25f3b0Srsc break; 390*1b25f3b0Srsc case '+': // >> 391*1b25f3b0Srsc cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); 3928b58e810Skaashoek break; 3938b58e810Skaashoek } 3948b58e810Skaashoek } 395*1b25f3b0Srsc return cmd; 3968b58e810Skaashoek } 3978b58e810Skaashoek 398*1b25f3b0Srsc struct cmd* 399*1b25f3b0Srsc parseexec(char **ps, char *es) 4008b58e810Skaashoek { 401*1b25f3b0Srsc char *q, *eq; 402*1b25f3b0Srsc int tok, argc; 403*1b25f3b0Srsc struct execcmd *cmd; 404*1b25f3b0Srsc struct cmd *ret; 4058b58e810Skaashoek 406*1b25f3b0Srsc if(peek(ps, es, "(")) 407*1b25f3b0Srsc return parseblock(ps, es); 408*1b25f3b0Srsc 409*1b25f3b0Srsc ret = execcmd(); 410*1b25f3b0Srsc cmd = (struct execcmd*)ret; 411*1b25f3b0Srsc 412*1b25f3b0Srsc argc = 0; 413*1b25f3b0Srsc ret = parseredirs(ret, ps, es); 414*1b25f3b0Srsc while(!peek(ps, es, "|)&;")){ 415*1b25f3b0Srsc if((tok=gettoken(ps, es, &q, &eq)) == 0) 416*1b25f3b0Srsc break; 417*1b25f3b0Srsc if(tok != 'a') 418*1b25f3b0Srsc panic("syntax"); 419*1b25f3b0Srsc cmd->argv[argc] = q; 420*1b25f3b0Srsc cmd->eargv[argc] = eq; 421*1b25f3b0Srsc argc++; 422*1b25f3b0Srsc if(argc >= MAXARGS) 423*1b25f3b0Srsc panic("too many args"); 424*1b25f3b0Srsc ret = parseredirs(ret, ps, es); 4258b58e810Skaashoek } 426*1b25f3b0Srsc cmd->argv[argc] = 0; 427*1b25f3b0Srsc cmd->eargv[argc] = 0; 428*1b25f3b0Srsc return ret; 4298b58e810Skaashoek } 4308b58e810Skaashoek 431*1b25f3b0Srsc // NUL-terminate all the counted strings. 432*1b25f3b0Srsc void 433*1b25f3b0Srsc nulterminate(struct cmd *cmd) 4348b58e810Skaashoek { 435*1b25f3b0Srsc int i; 436*1b25f3b0Srsc struct backcmd *bcmd; 437*1b25f3b0Srsc struct execcmd *ecmd; 438*1b25f3b0Srsc struct listcmd *lcmd; 439*1b25f3b0Srsc struct pipecmd *pcmd; 440*1b25f3b0Srsc struct redircmd *rcmd; 4418b58e810Skaashoek 442*1b25f3b0Srsc if(cmd == 0) 443*1b25f3b0Srsc return; 4448b58e810Skaashoek 445*1b25f3b0Srsc switch(cmd->type){ 446*1b25f3b0Srsc case EXEC: 447*1b25f3b0Srsc ecmd = (struct execcmd*)cmd; 448*1b25f3b0Srsc for(i=0; ecmd->argv[i]; i++) 449*1b25f3b0Srsc *ecmd->eargv[i] = 0; 450*1b25f3b0Srsc break; 4518b58e810Skaashoek 452*1b25f3b0Srsc case REDIR: 453*1b25f3b0Srsc rcmd = (struct redircmd*)cmd; 454*1b25f3b0Srsc nulterminate(rcmd->cmd); 455*1b25f3b0Srsc *rcmd->efile = 0; 456*1b25f3b0Srsc break; 4578b58e810Skaashoek 458*1b25f3b0Srsc case PIPE: 459*1b25f3b0Srsc pcmd = (struct pipecmd*)cmd; 460*1b25f3b0Srsc nulterminate(pcmd->left); 461*1b25f3b0Srsc nulterminate(pcmd->right); 462*1b25f3b0Srsc break; 4638b58e810Skaashoek 464*1b25f3b0Srsc case LIST: 465*1b25f3b0Srsc lcmd = (struct listcmd*)cmd; 466*1b25f3b0Srsc nulterminate(lcmd->left); 467*1b25f3b0Srsc nulterminate(lcmd->right); 468*1b25f3b0Srsc break; 469*1b25f3b0Srsc 470*1b25f3b0Srsc case BACK: 471*1b25f3b0Srsc bcmd = (struct backcmd*)cmd; 472*1b25f3b0Srsc nulterminate(bcmd->cmd); 473*1b25f3b0Srsc break; 474*1b25f3b0Srsc } 475*1b25f3b0Srsc } 476