117a85657Srtm #include "types.h" 2d7b3b802Skaashoek #include "stat.h" 3d7b3b802Skaashoek #include "user.h" 417a85657Srtm #include "fs.h" 517a85657Srtm #include "fcntl.h" 617a85657Srtm 78b58e810Skaashoek #define BUFSIZ 512 88b58e810Skaashoek #define MAXARGS 10 944e6909aSkaashoek #define MAXIO 2 1021a88dd0Skaashoek #define MAXCMD 2 118b58e810Skaashoek 1221a88dd0Skaashoek // an embarrassingly naive shell 1321a88dd0Skaashoek 1421a88dd0Skaashoek // some day a real parse tree; for now ad-hoc 1521a88dd0Skaashoek struct ionode { 168b58e810Skaashoek int token; 178b58e810Skaashoek char *s; 188b58e810Skaashoek }; 198b58e810Skaashoek 2021a88dd0Skaashoek struct cmd { 218b58e810Skaashoek char *argv[MAXARGS]; 228b58e810Skaashoek char argv0buf[BUFSIZ]; 238b58e810Skaashoek int argc; 2421a88dd0Skaashoek int token; 2544e6909aSkaashoek struct ionode iolist[MAXIO]; 26e00baa9fSkaashoek struct ionode *io; 2721a88dd0Skaashoek }; 2821a88dd0Skaashoek struct cmd cmdlist[MAXCMD]; 29e00baa9fSkaashoek struct cmd *cmd; 308b58e810Skaashoek 3121a88dd0Skaashoek char buf[BUFSIZ]; 32*9736728dSrsc int debug; 338b58e810Skaashoek 348b58e810Skaashoek int parse(char *s); 358b58e810Skaashoek void runcmd(void); 36*9736728dSrsc int getcmd(char *buf, int nbuf); 37e00baa9fSkaashoek int ioredirection(struct ionode *iolist, int nio); 388b58e810Skaashoek int gettoken(char *s, char **token); 398b58e810Skaashoek int _gettoken(char *s, char **p1, char **p2); 4017a85657Srtm 4117a85657Srtm int 4217a85657Srtm main(void) 4317a85657Srtm { 44*9736728dSrsc while(getcmd(buf, sizeof buf) >= 0) { 45*9736728dSrsc if(parse(buf) >= 0) 468b58e810Skaashoek runcmd(); 4717a85657Srtm } 48f8f7fcbeSrsc exit(); 4917a85657Srtm } 50d7b3b802Skaashoek 518b58e810Skaashoek int 52*9736728dSrsc getcmd(char *buf, int nbuf) 53*9736728dSrsc { 54*9736728dSrsc puts("$ "); 55*9736728dSrsc memset(buf, 0, nbuf); 56*9736728dSrsc gets(buf, nbuf); 57*9736728dSrsc if(buf[0] == 0) // EOF 58*9736728dSrsc return -1; 59*9736728dSrsc return 0; 60*9736728dSrsc } 61*9736728dSrsc 62*9736728dSrsc int 638b58e810Skaashoek parse(char *s) 64d7b3b802Skaashoek { 658b58e810Skaashoek char *t; 6621a88dd0Skaashoek int c, i; 678b58e810Skaashoek 688b58e810Skaashoek gettoken(s, 0); 698b58e810Skaashoek 70*9736728dSrsc cmd = &cmdlist[0]; 7121a88dd0Skaashoek for(i = 0; i < MAXCMD; i++) { 7221a88dd0Skaashoek cmdlist[i].argc = 0; 7321a88dd0Skaashoek cmdlist[i].token = 0; 74e00baa9fSkaashoek cmdlist[i].io = cmdlist[i].iolist; 7521a88dd0Skaashoek } 76*9736728dSrsc for(;;){ 778b58e810Skaashoek switch((c = gettoken(0, &t))) { 788b58e810Skaashoek 798b58e810Skaashoek case 'w': // Add an argument 80e00baa9fSkaashoek if(cmd->argc >= MAXARGS) { 818b58e810Skaashoek printf(2, "too many arguments\n"); 828b58e810Skaashoek return -1; 838b58e810Skaashoek } 84e00baa9fSkaashoek cmd->argv[cmd->argc++] = t; 858b58e810Skaashoek break; 868b58e810Skaashoek 8744e6909aSkaashoek case '>': // Input and output redirection 8844e6909aSkaashoek case '<': 898b58e810Skaashoek // Grab the filename from the argument list 908b58e810Skaashoek if(gettoken(0, &t) != 'w') { 918b58e810Skaashoek printf(2, "syntax error: > not followed by word\n"); 928b58e810Skaashoek return -1; 938b58e810Skaashoek } 9444e6909aSkaashoek if(cmd->io - cmd->iolist >= MAXIO) { 9544e6909aSkaashoek printf(2, "too many redirections\n"); 9644e6909aSkaashoek return -1; 9744e6909aSkaashoek } 9844e6909aSkaashoek cmd->io->token = c; 99e00baa9fSkaashoek cmd->io->s = t; 100e00baa9fSkaashoek cmd->io++; 10121a88dd0Skaashoek break; 10221a88dd0Skaashoek 10321a88dd0Skaashoek case ';': // command sequence 10421a88dd0Skaashoek case '|': // pipe 10544e6909aSkaashoek if(cmd->io - cmd->iolist >= MAXIO) { 10644e6909aSkaashoek printf(2, "too many redirections\n"); 10744e6909aSkaashoek return -1; 10844e6909aSkaashoek } 109e00baa9fSkaashoek cmd->token = c; 110e00baa9fSkaashoek cmd++; 1118b58e810Skaashoek break; 1128b58e810Skaashoek 1138b58e810Skaashoek case 0: // String is complete 1148b58e810Skaashoek return 0; 1158b58e810Skaashoek 1168b58e810Skaashoek default: 1178b58e810Skaashoek printf(2, "syntax error: bad return %d from gettoken", c); 1188b58e810Skaashoek return -1; 1198b58e810Skaashoek 1208b58e810Skaashoek } 1218b58e810Skaashoek } 1228b58e810Skaashoek } 1238b58e810Skaashoek 1248b58e810Skaashoek void 1258b58e810Skaashoek runcmd(void) 1268b58e810Skaashoek { 127e00baa9fSkaashoek int i, r, pid, tfd; 12821a88dd0Skaashoek int fdarray[2]; 129e00baa9fSkaashoek struct cmd *c; 130e00baa9fSkaashoek struct ionode *io; 1318b58e810Skaashoek 1328b58e810Skaashoek // Return immediately if command line was empty. 13321a88dd0Skaashoek if(cmdlist[0].argc == 0) { 1348b58e810Skaashoek if(debug) 1358b58e810Skaashoek printf(2, "EMPTY COMMAND\n"); 1368b58e810Skaashoek return; 1378b58e810Skaashoek } 1388b58e810Skaashoek 139e00baa9fSkaashoek for(c = &cmdlist[0]; c <= cmd; c++) { 1408b58e810Skaashoek // Clean up command line. 1418b58e810Skaashoek // Read all commands from the filesystem: add an initial '/' to 1428b58e810Skaashoek // the command name. 1438b58e810Skaashoek // This essentially acts like 'PATH=/'. 144e00baa9fSkaashoek if(c->argv[0][0] != '/') { 145e00baa9fSkaashoek c->argv0buf[0] = '/'; 146e00baa9fSkaashoek strcpy(c->argv0buf + 1, c->argv[0]); 147e00baa9fSkaashoek c->argv[0] = c->argv0buf; 1488b58e810Skaashoek } 149e00baa9fSkaashoek c->argv[c->argc] = 0; 1508b58e810Skaashoek 1518b58e810Skaashoek // Print the command. 1528b58e810Skaashoek if(debug) { 1538b58e810Skaashoek printf(2, "[%d] SPAWN:", getpid()); 154e00baa9fSkaashoek for(i = 0; c->argv[i]; i++) 155e00baa9fSkaashoek printf(2, " %s", c->argv[i]); 156e00baa9fSkaashoek for(io = c->iolist; io <= c->io; io++) { 157e00baa9fSkaashoek printf(2, "%c %s", io->token, io->s); 1588b58e810Skaashoek } 1598b58e810Skaashoek printf(2, "\n"); 1608b58e810Skaashoek } 1618b58e810Skaashoek 162e00baa9fSkaashoek if(strcmp(c->argv[0], "/cd") == 0) { 16348b82470Srsc if(debug) 164e00baa9fSkaashoek printf (2, "/cd %s is build in\n", c->argv[1]); 165e00baa9fSkaashoek chdir(c->argv[1]); 1668b58e810Skaashoek return; 1678b58e810Skaashoek } 1688b58e810Skaashoek 169e00baa9fSkaashoek if(c->token == '|') 17021a88dd0Skaashoek if(pipe(fdarray) < 0) 17121a88dd0Skaashoek printf(2, "cmd %d pipe failed\n", c); 17221a88dd0Skaashoek 1738b58e810Skaashoek pid = fork(); 1748b58e810Skaashoek if(pid == 0) { 175e00baa9fSkaashoek if(c->token == '|') { 17621a88dd0Skaashoek if(close(1) < 0) 17721a88dd0Skaashoek printf(2, "close 1 failed\n"); 17821a88dd0Skaashoek if((tfd = dup(fdarray[1])) < 0) 17921a88dd0Skaashoek printf(2, "dup failed\n"); 18021a88dd0Skaashoek if(close(fdarray[0]) < 0) 18121a88dd0Skaashoek printf(2, "close fdarray[0] failed\n"); 18221a88dd0Skaashoek if(close(fdarray[1]) < 0) 18321a88dd0Skaashoek printf(2, "close fdarray[1] failed\n"); 18421a88dd0Skaashoek } 185e00baa9fSkaashoek if(c > cmdlist && (c-1)->token == '|') { 18621a88dd0Skaashoek if(close(0) < 0) 18721a88dd0Skaashoek printf(2, "close 0 failed\n"); 18821a88dd0Skaashoek if((tfd = dup(fdarray[0])) < 0) 18921a88dd0Skaashoek printf(2, "dup failed\n"); 19021a88dd0Skaashoek if(close(fdarray[0]) < 0) 19121a88dd0Skaashoek printf(2, "close fdarray[0] failed\n"); 19221a88dd0Skaashoek if(close(fdarray[1]) < 0) 19321a88dd0Skaashoek printf(2, "close fdarray[1] failed\n"); 19421a88dd0Skaashoek } 195e00baa9fSkaashoek if(ioredirection(c->iolist, c->io - c->iolist) < 0) 1968b58e810Skaashoek exit(); 197e00baa9fSkaashoek if((r = exec(c->argv0buf, (char**) c->argv)) < 0) { 198e00baa9fSkaashoek printf(2, "exec %s: %d\n", c->argv[0], r); 199d7b3b802Skaashoek exit(); 200d7b3b802Skaashoek } 20121a88dd0Skaashoek } else if(pid > 0) { 20221a88dd0Skaashoek int p; 2038b58e810Skaashoek if(debug) 20421a88dd0Skaashoek printf(2, "[%d] FORKED child %d\n", getpid(), pid); 20521a88dd0Skaashoek 206e00baa9fSkaashoek if(c > cmdlist && (c-1)->token == '|') { 20721a88dd0Skaashoek close(fdarray[0]); 20821a88dd0Skaashoek close(fdarray[1]); 20921a88dd0Skaashoek } 210e00baa9fSkaashoek if(c->token != '|') { 21121a88dd0Skaashoek if(debug) 21221a88dd0Skaashoek printf(2, "[%d] WAIT for children\n", getpid()); 21321a88dd0Skaashoek do { 21421a88dd0Skaashoek p = wait(); 21521a88dd0Skaashoek if(debug) 21621a88dd0Skaashoek printf(2, "[%d] WAIT child %d finished\n", getpid(), p); 21721a88dd0Skaashoek } while(p > 0); 2188b58e810Skaashoek if(debug) 2198b58e810Skaashoek printf(2, "[%d] wait finished\n", getpid()); 220d7b3b802Skaashoek } 221d7b3b802Skaashoek } 22221a88dd0Skaashoek } 22321a88dd0Skaashoek } 2248b58e810Skaashoek 2258b58e810Skaashoek int 226e00baa9fSkaashoek ioredirection(struct ionode *iolist, int nio) 2278b58e810Skaashoek { 228e00baa9fSkaashoek int fd; 229e00baa9fSkaashoek struct ionode *io; 2308b58e810Skaashoek 231e00baa9fSkaashoek for(io = iolist; io < &iolist[nio]; io++) { 232e00baa9fSkaashoek switch(io->token) { 2338b58e810Skaashoek case '<': 234d49a2d53Skaashoek if(close(0) < 0) 235d49a2d53Skaashoek printf(2, "close 0 failed\n"); 236e00baa9fSkaashoek if((fd = open(io->s, O_RDONLY)) < 0) { 237e00baa9fSkaashoek printf(2, "failed to open %s for read: %d", io->s, fd); 2388b58e810Skaashoek return -1; 2398b58e810Skaashoek } 2408b58e810Skaashoek if(debug) 241e00baa9fSkaashoek printf(2, "redirect 0 from %s\n", io->s); 2428b58e810Skaashoek break; 2438b58e810Skaashoek case '>': 244d49a2d53Skaashoek if(close(1) < 0) 245d49a2d53Skaashoek printf(2, "close 1 failed\n"); 246e00baa9fSkaashoek if((fd = open(io->s, O_WRONLY|O_CREATE)) < 0) { 247e00baa9fSkaashoek printf(2, "failed to open %s for write: %d", io->s, fd); 2488b58e810Skaashoek exit(); 2498b58e810Skaashoek } 2508b58e810Skaashoek if(debug) 251e00baa9fSkaashoek printf(2, "redirect 1 to %s\n", io->s); 2528b58e810Skaashoek break; 2538b58e810Skaashoek } 2548b58e810Skaashoek } 2558b58e810Skaashoek return 0; 2568b58e810Skaashoek } 2578b58e810Skaashoek 2588b58e810Skaashoek // gettoken(s, 0) prepares gettoken for subsequent calls and returns 0. 2598b58e810Skaashoek // gettoken(0, token) parses a shell token from the previously set string, 2608b58e810Skaashoek // null-terminates that token, stores the token pointer in '*token', 2618b58e810Skaashoek // and returns a token ID (0, '<', '>', '|', or 'w'). 2628b58e810Skaashoek // Subsequent calls to 'gettoken(0, token)' will return subsequent 2638b58e810Skaashoek // tokens from the string. 2648b58e810Skaashoek 2658b58e810Skaashoek int 2668b58e810Skaashoek gettoken(char *s, char **p1) 2678b58e810Skaashoek { 2688b58e810Skaashoek static int c, nc; 2698b58e810Skaashoek static char *np1, *np2; 2708b58e810Skaashoek 2718b58e810Skaashoek if(s) { 2728b58e810Skaashoek nc = _gettoken(s, &np1, &np2); 2738b58e810Skaashoek return 0; 2748b58e810Skaashoek } 2758b58e810Skaashoek c = nc; 2768b58e810Skaashoek *p1 = np1; 2778b58e810Skaashoek nc = _gettoken(np2, &np1, &np2); 2788b58e810Skaashoek return c; 2798b58e810Skaashoek } 2808b58e810Skaashoek 2818b58e810Skaashoek 2828b58e810Skaashoek // Get the next token from string s. 2838b58e810Skaashoek // Set *p1 to the beginning of the token and *p2 just past the token. 2848b58e810Skaashoek // Returns 2858b58e810Skaashoek // 0 for end-of-string; 2868b58e810Skaashoek // < for <; 2878b58e810Skaashoek // > for >; 2888b58e810Skaashoek // | for |; 2898b58e810Skaashoek // w for a word. 2908b58e810Skaashoek // 2918b58e810Skaashoek // Eventually (once we parse the space where the \0 will go), 2928b58e810Skaashoek // words get nul-terminated. 2938b58e810Skaashoek #define WHITESPACE " \t\r\n" 2948b58e810Skaashoek #define SYMBOLS "<|>&;()" 2958b58e810Skaashoek 2968b58e810Skaashoek int 2978b58e810Skaashoek _gettoken(char *s, char **p1, char **p2) 2988b58e810Skaashoek { 2998b58e810Skaashoek int t; 3008b58e810Skaashoek 3018b58e810Skaashoek if(s == 0) { 3028b58e810Skaashoek if(debug > 1) 30389ebd895Srsc printf(2, "GETTOKEN 0\n"); 3048b58e810Skaashoek return 0; 3058b58e810Skaashoek } 3068b58e810Skaashoek 3078b58e810Skaashoek if(debug > 1) 3088b58e810Skaashoek printf(2, "GETTOKEN: %s\n", s); 3098b58e810Skaashoek 3108b58e810Skaashoek *p1 = 0; 3118b58e810Skaashoek *p2 = 0; 3128b58e810Skaashoek 3138b58e810Skaashoek while(strchr(WHITESPACE, *s)) 3148b58e810Skaashoek *s++ = 0; 3158b58e810Skaashoek if(*s == 0) { 3168b58e810Skaashoek if(debug > 1) 3178b58e810Skaashoek printf(2, "EOL\n"); 3188b58e810Skaashoek return 0; 3198b58e810Skaashoek } 3208b58e810Skaashoek if(strchr(SYMBOLS, *s)) { 3218b58e810Skaashoek t = *s; 3228b58e810Skaashoek *p1 = s; 3238b58e810Skaashoek *s++ = 0; 3248b58e810Skaashoek *p2 = s; 3258b58e810Skaashoek if(debug > 1) 3268b58e810Skaashoek printf(2, "TOK %c\n", t); 3278b58e810Skaashoek return t; 3288b58e810Skaashoek } 3298b58e810Skaashoek *p1 = s; 3308b58e810Skaashoek while(*s && !strchr(WHITESPACE SYMBOLS, *s)) 3318b58e810Skaashoek s++; 3328b58e810Skaashoek *p2 = s; 3338b58e810Skaashoek if(debug > 1) { 3348b58e810Skaashoek t = **p2; 3358b58e810Skaashoek **p2 = 0; 3368b58e810Skaashoek printf(2, "WORD: %s\n", *p1); 3378b58e810Skaashoek **p2 = t; 3388b58e810Skaashoek } 3398b58e810Skaashoek return 'w'; 3408b58e810Skaashoek } 3418b58e810Skaashoek 342