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 98b58e810Skaashoek #define MAXNODE 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; 25*e00baa9fSkaashoek struct ionode iolist[MAXNODE]; 26*e00baa9fSkaashoek struct ionode *io; 2721a88dd0Skaashoek }; 2821a88dd0Skaashoek struct cmd cmdlist[MAXCMD]; 29*e00baa9fSkaashoek struct cmd *cmd; 308b58e810Skaashoek 3121a88dd0Skaashoek char buf[BUFSIZ]; 327a37578eSrtm int debug = 0; 338b58e810Skaashoek 348b58e810Skaashoek int parse(char *s); 358b58e810Skaashoek void runcmd(void); 36*e00baa9fSkaashoek int ioredirection(struct ionode *iolist, int nio); 378b58e810Skaashoek int gettoken(char *s, char **token); 388b58e810Skaashoek int _gettoken(char *s, char **p1, char **p2); 3917a85657Srtm 4017a85657Srtm int 4117a85657Srtm main(void) 4217a85657Srtm { 4317a85657Srtm while(1){ 4443572072Srtm puts("$ "); 458787cd01Skaashoek memset(buf, '\0', sizeof(buf)); 4617a85657Srtm gets(buf, sizeof(buf)); 478b58e810Skaashoek if(parse(buf) < 0) 4817a85657Srtm continue; 498b58e810Skaashoek runcmd(); 5017a85657Srtm } 5117a85657Srtm } 52d7b3b802Skaashoek 538b58e810Skaashoek int 548b58e810Skaashoek parse(char *s) 55d7b3b802Skaashoek { 568b58e810Skaashoek char *t; 5721a88dd0Skaashoek int c, i; 588b58e810Skaashoek 598b58e810Skaashoek gettoken(s, 0); 608b58e810Skaashoek 61*e00baa9fSkaashoek cmd = &cmdlist[0];; 6221a88dd0Skaashoek for(i = 0; i < MAXCMD; i++) { 6321a88dd0Skaashoek cmdlist[i].argc = 0; 6421a88dd0Skaashoek cmdlist[i].token = 0; 65*e00baa9fSkaashoek cmdlist[i].io = cmdlist[i].iolist; 6621a88dd0Skaashoek } 678b58e810Skaashoek while(1) { 688b58e810Skaashoek switch((c = gettoken(0, &t))) { 698b58e810Skaashoek 708b58e810Skaashoek case 'w': // Add an argument 71*e00baa9fSkaashoek if(cmd->argc >= MAXARGS) { 728b58e810Skaashoek printf(2, "too many arguments\n"); 738b58e810Skaashoek return -1; 748b58e810Skaashoek } 75*e00baa9fSkaashoek cmd->argv[cmd->argc++] = t; 768b58e810Skaashoek break; 778b58e810Skaashoek 788b58e810Skaashoek case '<': // Input redirection 798b58e810Skaashoek // Grab the filename from the argument list 808b58e810Skaashoek if(gettoken(0, &t) != 'w') { 818b58e810Skaashoek printf(2, "syntax error: < not followed by word\n"); 828b58e810Skaashoek return -1; 838b58e810Skaashoek } 84*e00baa9fSkaashoek cmd->io->token = '<'; 85*e00baa9fSkaashoek cmd->io->s = t; 86*e00baa9fSkaashoek cmd->io++; 878b58e810Skaashoek break; 888b58e810Skaashoek 898b58e810Skaashoek case '>': // Output redirection 908b58e810Skaashoek // Grab the filename from the argument list 918b58e810Skaashoek if(gettoken(0, &t) != 'w') { 928b58e810Skaashoek printf(2, "syntax error: > not followed by word\n"); 938b58e810Skaashoek return -1; 948b58e810Skaashoek } 95*e00baa9fSkaashoek cmd->io->token = '>'; 96*e00baa9fSkaashoek cmd->io->s = t; 97*e00baa9fSkaashoek cmd->io++; 9821a88dd0Skaashoek break; 9921a88dd0Skaashoek 10021a88dd0Skaashoek case ';': // command sequence 10121a88dd0Skaashoek case '|': // pipe 102*e00baa9fSkaashoek cmd->token = c; 103*e00baa9fSkaashoek cmd++; 1048b58e810Skaashoek break; 1058b58e810Skaashoek 1068b58e810Skaashoek case 0: // String is complete 1078b58e810Skaashoek return 0; 1088b58e810Skaashoek 1098b58e810Skaashoek default: 1108b58e810Skaashoek printf(2, "syntax error: bad return %d from gettoken", c); 1118b58e810Skaashoek return -1; 1128b58e810Skaashoek 1138b58e810Skaashoek } 1148b58e810Skaashoek } 1158b58e810Skaashoek } 1168b58e810Skaashoek 1178b58e810Skaashoek 1188b58e810Skaashoek void 1198b58e810Skaashoek runcmd(void) 1208b58e810Skaashoek { 121*e00baa9fSkaashoek int i, r, pid, tfd; 12221a88dd0Skaashoek int fdarray[2]; 123*e00baa9fSkaashoek struct cmd *c; 124*e00baa9fSkaashoek struct ionode *io; 1258b58e810Skaashoek 1268b58e810Skaashoek // Return immediately if command line was empty. 12721a88dd0Skaashoek if(cmdlist[0].argc == 0) { 1288b58e810Skaashoek if(debug) 1298b58e810Skaashoek printf(2, "EMPTY COMMAND\n"); 1308b58e810Skaashoek return; 1318b58e810Skaashoek } 1328b58e810Skaashoek 133*e00baa9fSkaashoek for(c = &cmdlist[0]; c <= cmd; c++) { 1348b58e810Skaashoek // Clean up command line. 1358b58e810Skaashoek // Read all commands from the filesystem: add an initial '/' to 1368b58e810Skaashoek // the command name. 1378b58e810Skaashoek // This essentially acts like 'PATH=/'. 138*e00baa9fSkaashoek if(c->argv[0][0] != '/') { 139*e00baa9fSkaashoek c->argv0buf[0] = '/'; 140*e00baa9fSkaashoek strcpy(c->argv0buf + 1, c->argv[0]); 141*e00baa9fSkaashoek c->argv[0] = c->argv0buf; 1428b58e810Skaashoek } 143*e00baa9fSkaashoek c->argv[c->argc] = 0; 1448b58e810Skaashoek 1458b58e810Skaashoek // Print the command. 1468b58e810Skaashoek if(debug) { 1478b58e810Skaashoek printf(2, "[%d] SPAWN:", getpid()); 148*e00baa9fSkaashoek for(i = 0; c->argv[i]; i++) 149*e00baa9fSkaashoek printf(2, " %s", c->argv[i]); 150*e00baa9fSkaashoek for(io = c->iolist; io <= c->io; io++) { 151*e00baa9fSkaashoek printf(2, "%c %s", io->token, io->s); 1528b58e810Skaashoek } 1538b58e810Skaashoek printf(2, "\n"); 1548b58e810Skaashoek } 1558b58e810Skaashoek 156*e00baa9fSkaashoek if(strcmp(c->argv[0], "/cd") == 0) { 15748b82470Srsc if(debug) 158*e00baa9fSkaashoek printf (2, "/cd %s is build in\n", c->argv[1]); 159*e00baa9fSkaashoek chdir(c->argv[1]); 1608b58e810Skaashoek return; 1618b58e810Skaashoek } 1628b58e810Skaashoek 163*e00baa9fSkaashoek if(c->token == '|') 16421a88dd0Skaashoek if(pipe(fdarray) < 0) 16521a88dd0Skaashoek printf(2, "cmd %d pipe failed\n", c); 16621a88dd0Skaashoek 1678b58e810Skaashoek pid = fork(); 1688b58e810Skaashoek if(pid == 0) { 169*e00baa9fSkaashoek if(c->token == '|') { 17021a88dd0Skaashoek if(close(1) < 0) 17121a88dd0Skaashoek printf(2, "close 1 failed\n"); 17221a88dd0Skaashoek if((tfd = dup(fdarray[1])) < 0) 17321a88dd0Skaashoek printf(2, "dup failed\n"); 17421a88dd0Skaashoek if(close(fdarray[0]) < 0) 17521a88dd0Skaashoek printf(2, "close fdarray[0] failed\n"); 17621a88dd0Skaashoek if(close(fdarray[1]) < 0) 17721a88dd0Skaashoek printf(2, "close fdarray[1] failed\n"); 17821a88dd0Skaashoek } 179*e00baa9fSkaashoek if(c > cmdlist && (c-1)->token == '|') { 18021a88dd0Skaashoek if(close(0) < 0) 18121a88dd0Skaashoek printf(2, "close 0 failed\n"); 18221a88dd0Skaashoek if((tfd = dup(fdarray[0])) < 0) 18321a88dd0Skaashoek printf(2, "dup failed\n"); 18421a88dd0Skaashoek if(close(fdarray[0]) < 0) 18521a88dd0Skaashoek printf(2, "close fdarray[0] failed\n"); 18621a88dd0Skaashoek if(close(fdarray[1]) < 0) 18721a88dd0Skaashoek printf(2, "close fdarray[1] failed\n"); 18821a88dd0Skaashoek } 189*e00baa9fSkaashoek if(ioredirection(c->iolist, c->io - c->iolist) < 0) 1908b58e810Skaashoek exit(); 191*e00baa9fSkaashoek if((r = exec(c->argv0buf, (char**) c->argv)) < 0) { 192*e00baa9fSkaashoek printf(2, "exec %s: %d\n", c->argv[0], r); 193d7b3b802Skaashoek exit(); 194d7b3b802Skaashoek } 19521a88dd0Skaashoek } else if(pid > 0) { 19621a88dd0Skaashoek int p; 1978b58e810Skaashoek if(debug) 19821a88dd0Skaashoek printf(2, "[%d] FORKED child %d\n", getpid(), pid); 19921a88dd0Skaashoek 200*e00baa9fSkaashoek if(c > cmdlist && (c-1)->token == '|') { 20121a88dd0Skaashoek close(fdarray[0]); 20221a88dd0Skaashoek close(fdarray[1]); 20321a88dd0Skaashoek } 204*e00baa9fSkaashoek if(c->token != '|') { 20521a88dd0Skaashoek if(debug) 20621a88dd0Skaashoek printf(2, "[%d] WAIT for children\n", getpid()); 20721a88dd0Skaashoek do { 20821a88dd0Skaashoek p = wait(); 20921a88dd0Skaashoek if(debug) 21021a88dd0Skaashoek printf(2, "[%d] WAIT child %d finished\n", getpid(), p); 21121a88dd0Skaashoek } while(p > 0); 2128b58e810Skaashoek if(debug) 2138b58e810Skaashoek printf(2, "[%d] wait finished\n", getpid()); 214d7b3b802Skaashoek } 215d7b3b802Skaashoek } 21621a88dd0Skaashoek } 21721a88dd0Skaashoek } 2188b58e810Skaashoek 2198b58e810Skaashoek int 220*e00baa9fSkaashoek ioredirection(struct ionode *iolist, int nio) 2218b58e810Skaashoek { 222*e00baa9fSkaashoek int fd; 223*e00baa9fSkaashoek struct ionode *io; 2248b58e810Skaashoek 225*e00baa9fSkaashoek for(io = iolist; io < &iolist[nio]; io++) { 226*e00baa9fSkaashoek switch(io->token) { 2278b58e810Skaashoek case '<': 228d49a2d53Skaashoek if(close(0) < 0) 229d49a2d53Skaashoek printf(2, "close 0 failed\n"); 230*e00baa9fSkaashoek if((fd = open(io->s, O_RDONLY)) < 0) { 231*e00baa9fSkaashoek printf(2, "failed to open %s for read: %d", io->s, fd); 2328b58e810Skaashoek return -1; 2338b58e810Skaashoek } 2348b58e810Skaashoek if(debug) 235*e00baa9fSkaashoek printf(2, "redirect 0 from %s\n", io->s); 2368b58e810Skaashoek break; 2378b58e810Skaashoek case '>': 238d49a2d53Skaashoek if(close(1) < 0) 239d49a2d53Skaashoek printf(2, "close 1 failed\n"); 240*e00baa9fSkaashoek if((fd = open(io->s, O_WRONLY|O_CREATE)) < 0) { 241*e00baa9fSkaashoek printf(2, "failed to open %s for write: %d", io->s, fd); 2428b58e810Skaashoek exit(); 2438b58e810Skaashoek } 2448b58e810Skaashoek if(debug) 245*e00baa9fSkaashoek printf(2, "redirect 1 to %s\n", io->s); 2468b58e810Skaashoek break; 2478b58e810Skaashoek } 2488b58e810Skaashoek } 2498b58e810Skaashoek return 0; 2508b58e810Skaashoek } 2518b58e810Skaashoek 2528b58e810Skaashoek // gettoken(s, 0) prepares gettoken for subsequent calls and returns 0. 2538b58e810Skaashoek // gettoken(0, token) parses a shell token from the previously set string, 2548b58e810Skaashoek // null-terminates that token, stores the token pointer in '*token', 2558b58e810Skaashoek // and returns a token ID (0, '<', '>', '|', or 'w'). 2568b58e810Skaashoek // Subsequent calls to 'gettoken(0, token)' will return subsequent 2578b58e810Skaashoek // tokens from the string. 2588b58e810Skaashoek 2598b58e810Skaashoek int 2608b58e810Skaashoek gettoken(char *s, char **p1) 2618b58e810Skaashoek { 2628b58e810Skaashoek static int c, nc; 2638b58e810Skaashoek static char *np1, *np2; 2648b58e810Skaashoek 2658b58e810Skaashoek if(s) { 2668b58e810Skaashoek nc = _gettoken(s, &np1, &np2); 2678b58e810Skaashoek return 0; 2688b58e810Skaashoek } 2698b58e810Skaashoek c = nc; 2708b58e810Skaashoek *p1 = np1; 2718b58e810Skaashoek nc = _gettoken(np2, &np1, &np2); 2728b58e810Skaashoek return c; 2738b58e810Skaashoek } 2748b58e810Skaashoek 2758b58e810Skaashoek 2768b58e810Skaashoek // Get the next token from string s. 2778b58e810Skaashoek // Set *p1 to the beginning of the token and *p2 just past the token. 2788b58e810Skaashoek // Returns 2798b58e810Skaashoek // 0 for end-of-string; 2808b58e810Skaashoek // < for <; 2818b58e810Skaashoek // > for >; 2828b58e810Skaashoek // | for |; 2838b58e810Skaashoek // w for a word. 2848b58e810Skaashoek // 2858b58e810Skaashoek // Eventually (once we parse the space where the \0 will go), 2868b58e810Skaashoek // words get nul-terminated. 2878b58e810Skaashoek #define WHITESPACE " \t\r\n" 2888b58e810Skaashoek #define SYMBOLS "<|>&;()" 2898b58e810Skaashoek 2908b58e810Skaashoek int 2918b58e810Skaashoek _gettoken(char *s, char **p1, char **p2) 2928b58e810Skaashoek { 2938b58e810Skaashoek int t; 2948b58e810Skaashoek 2958b58e810Skaashoek if(s == 0) { 2968b58e810Skaashoek if(debug > 1) 29789ebd895Srsc printf(2, "GETTOKEN 0\n"); 2988b58e810Skaashoek return 0; 2998b58e810Skaashoek } 3008b58e810Skaashoek 3018b58e810Skaashoek if(debug > 1) 3028b58e810Skaashoek printf(2, "GETTOKEN: %s\n", s); 3038b58e810Skaashoek 3048b58e810Skaashoek *p1 = 0; 3058b58e810Skaashoek *p2 = 0; 3068b58e810Skaashoek 3078b58e810Skaashoek while(strchr(WHITESPACE, *s)) 3088b58e810Skaashoek *s++ = 0; 3098b58e810Skaashoek if(*s == 0) { 3108b58e810Skaashoek if(debug > 1) 3118b58e810Skaashoek printf(2, "EOL\n"); 3128b58e810Skaashoek return 0; 3138b58e810Skaashoek } 3148b58e810Skaashoek if(strchr(SYMBOLS, *s)) { 3158b58e810Skaashoek t = *s; 3168b58e810Skaashoek *p1 = s; 3178b58e810Skaashoek *s++ = 0; 3188b58e810Skaashoek *p2 = s; 3198b58e810Skaashoek if(debug > 1) 3208b58e810Skaashoek printf(2, "TOK %c\n", t); 3218b58e810Skaashoek return t; 3228b58e810Skaashoek } 3238b58e810Skaashoek *p1 = s; 3248b58e810Skaashoek while(*s && !strchr(WHITESPACE SYMBOLS, *s)) 3258b58e810Skaashoek s++; 3268b58e810Skaashoek *p2 = s; 3278b58e810Skaashoek if(debug > 1) { 3288b58e810Skaashoek t = **p2; 3298b58e810Skaashoek **p2 = 0; 3308b58e810Skaashoek printf(2, "WORD: %s\n", *p1); 3318b58e810Skaashoek **p2 = t; 3328b58e810Skaashoek } 3338b58e810Skaashoek return 'w'; 3348b58e810Skaashoek } 3358b58e810Skaashoek 336