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 10*21a88dd0Skaashoek #define MAXCMD 2 118b58e810Skaashoek 12*21a88dd0Skaashoek // an embarrassingly naive shell 13*21a88dd0Skaashoek 14*21a88dd0Skaashoek // some day a real parse tree; for now ad-hoc 15*21a88dd0Skaashoek struct ionode { 168b58e810Skaashoek int token; 178b58e810Skaashoek char *s; 188b58e810Skaashoek }; 19*21a88dd0Skaashoek struct ionode iolist[MAXNODE]; 20*21a88dd0Skaashoek int nextio; 218b58e810Skaashoek 22*21a88dd0Skaashoek struct cmd { 238b58e810Skaashoek char *argv[MAXARGS]; 248b58e810Skaashoek char argv0buf[BUFSIZ]; 258b58e810Skaashoek int argc; 26*21a88dd0Skaashoek int token; 27*21a88dd0Skaashoek }; 28*21a88dd0Skaashoek struct cmd cmdlist[MAXCMD]; 29*21a88dd0Skaashoek int nextcmd; 308b58e810Skaashoek 31*21a88dd0Skaashoek char buf[BUFSIZ]; 327a37578eSrtm int debug = 0; 338b58e810Skaashoek 348b58e810Skaashoek int parse(char *s); 358b58e810Skaashoek void runcmd(void); 368b58e810Skaashoek int ioredirection(void); 378b58e810Skaashoek int gettoken(char *s, char **token); 388b58e810Skaashoek int _gettoken(char *s, char **p1, char **p2); 39*21a88dd0Skaashoek void addio(int token, char *s); 4017a85657Srtm 4117a85657Srtm int 4217a85657Srtm main(void) 4317a85657Srtm { 4417a85657Srtm while(1){ 4543572072Srtm puts("$ "); 468787cd01Skaashoek memset (buf, '\0', sizeof(buf)); 4717a85657Srtm gets(buf, sizeof(buf)); 488b58e810Skaashoek if (parse(buf) < 0) 4917a85657Srtm continue; 508b58e810Skaashoek runcmd(); 5117a85657Srtm } 5217a85657Srtm } 53d7b3b802Skaashoek 548b58e810Skaashoek int 558b58e810Skaashoek parse(char *s) 56d7b3b802Skaashoek { 578b58e810Skaashoek char *t; 58*21a88dd0Skaashoek int c, i; 598b58e810Skaashoek 608b58e810Skaashoek gettoken(s, 0); 618b58e810Skaashoek 62*21a88dd0Skaashoek nextio = 0; 63*21a88dd0Skaashoek nextcmd = 0; 64*21a88dd0Skaashoek for (i = 0; i < MAXCMD; i++) { 65*21a88dd0Skaashoek cmdlist[i].argc = 0; 66*21a88dd0Skaashoek cmdlist[i].token = 0; 67*21a88dd0Skaashoek } 688b58e810Skaashoek while (1) { 698b58e810Skaashoek switch ((c = gettoken(0, &t))) { 708b58e810Skaashoek 718b58e810Skaashoek case 'w': // Add an argument 72*21a88dd0Skaashoek if (cmdlist[nextcmd].argc >= MAXARGS) { 738b58e810Skaashoek printf(2, "too many arguments\n"); 748b58e810Skaashoek return -1; 758b58e810Skaashoek } 76*21a88dd0Skaashoek cmdlist[nextcmd].argv[cmdlist[nextcmd].argc++] = t; 778b58e810Skaashoek break; 788b58e810Skaashoek 798b58e810Skaashoek case '<': // Input redirection 808b58e810Skaashoek // Grab the filename from the argument list 818b58e810Skaashoek if (gettoken(0, &t) != 'w') { 828b58e810Skaashoek printf(2, "syntax error: < not followed by word\n"); 838b58e810Skaashoek return -1; 848b58e810Skaashoek } 85*21a88dd0Skaashoek addio('<', t); 868b58e810Skaashoek break; 878b58e810Skaashoek 888b58e810Skaashoek case '>': // Output redirection 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 } 94*21a88dd0Skaashoek addio('>', t); 95*21a88dd0Skaashoek break; 96*21a88dd0Skaashoek 97*21a88dd0Skaashoek case ';': // command sequence 98*21a88dd0Skaashoek case '|': // pipe 99*21a88dd0Skaashoek cmdlist[nextcmd].token = c; 100*21a88dd0Skaashoek nextcmd++; 1018b58e810Skaashoek break; 1028b58e810Skaashoek 1038b58e810Skaashoek case 0: // String is complete 1048b58e810Skaashoek return 0; 1058b58e810Skaashoek 1068b58e810Skaashoek default: 1078b58e810Skaashoek printf(2, "syntax error: bad return %d from gettoken", c); 1088b58e810Skaashoek return -1; 1098b58e810Skaashoek 1108b58e810Skaashoek } 1118b58e810Skaashoek } 1128b58e810Skaashoek } 1138b58e810Skaashoek 1148b58e810Skaashoek 1158b58e810Skaashoek void 1168b58e810Skaashoek runcmd(void) 1178b58e810Skaashoek { 118*21a88dd0Skaashoek int c, i, r, pid, tfd; 119*21a88dd0Skaashoek int fdarray[2]; 1208b58e810Skaashoek 1218b58e810Skaashoek // Return immediately if command line was empty. 122*21a88dd0Skaashoek if(cmdlist[0].argc == 0) { 1238b58e810Skaashoek if (debug) 1248b58e810Skaashoek printf(2, "EMPTY COMMAND\n"); 1258b58e810Skaashoek return; 1268b58e810Skaashoek } 1278b58e810Skaashoek 128*21a88dd0Skaashoek for (c = 0; c <= nextcmd; c++) { 1298b58e810Skaashoek // Clean up command line. 1308b58e810Skaashoek // Read all commands from the filesystem: add an initial '/' to 1318b58e810Skaashoek // the command name. 1328b58e810Skaashoek // This essentially acts like 'PATH=/'. 133*21a88dd0Skaashoek if (cmdlist[c].argv[0][0] != '/') { 134*21a88dd0Skaashoek cmdlist[c].argv0buf[0] = '/'; 135*21a88dd0Skaashoek strcpy(cmdlist[c].argv0buf + 1, cmdlist[c].argv[0]); 136*21a88dd0Skaashoek cmdlist[c].argv[0] = cmdlist[c].argv0buf; 1378b58e810Skaashoek } 138*21a88dd0Skaashoek cmdlist[c].argv[cmdlist[c].argc] = 0; 1398b58e810Skaashoek 1408b58e810Skaashoek // Print the command. 1418b58e810Skaashoek if (debug) { 1428b58e810Skaashoek printf(2, "[%d] SPAWN:", getpid()); 143*21a88dd0Skaashoek for (i = 0; cmdlist[c].argv[i]; i++) 144*21a88dd0Skaashoek printf(2, " %s", cmdlist[c].argv[i]); 145*21a88dd0Skaashoek for (i = 0; i < nextio; i++) { 146*21a88dd0Skaashoek printf(2, "%c %s", iolist[i].token, iolist[i].s); 1478b58e810Skaashoek } 1488b58e810Skaashoek printf(2, "\n"); 1498b58e810Skaashoek } 1508b58e810Skaashoek 151*21a88dd0Skaashoek if (strcmp(cmdlist[c].argv[0], "/cd") == 0) { 152*21a88dd0Skaashoek if (debug) printf (2, "/cd %s is build in\n", cmdlist[c].argv[1]); 153*21a88dd0Skaashoek chdir(cmdlist[c].argv[1]); 1548b58e810Skaashoek return; 1558b58e810Skaashoek } 1568b58e810Skaashoek 157*21a88dd0Skaashoek if (cmdlist[c].token == '|') 158*21a88dd0Skaashoek if (pipe(fdarray) < 0) 159*21a88dd0Skaashoek printf(2, "cmd %d pipe failed\n", c); 160*21a88dd0Skaashoek 1618b58e810Skaashoek pid = fork(); 1628b58e810Skaashoek if (pid == 0) { 163*21a88dd0Skaashoek if (cmdlist[c].token == '|') { 164*21a88dd0Skaashoek if (close(1) < 0) 165*21a88dd0Skaashoek printf(2, "close 1 failed\n"); 166*21a88dd0Skaashoek if ((tfd = dup(fdarray[1])) < 0) 167*21a88dd0Skaashoek printf(2, "dup failed\n"); 168*21a88dd0Skaashoek if (close(fdarray[0]) < 0) 169*21a88dd0Skaashoek printf(2, "close fdarray[0] failed\n"); 170*21a88dd0Skaashoek if (close(fdarray[1]) < 0) 171*21a88dd0Skaashoek printf(2, "close fdarray[1] failed\n"); 172*21a88dd0Skaashoek } 173*21a88dd0Skaashoek if (c > 0 && cmdlist[c-1].token == '|') { 174*21a88dd0Skaashoek if (close(0) < 0) 175*21a88dd0Skaashoek printf(2, "close 0 failed\n"); 176*21a88dd0Skaashoek if ((tfd = dup(fdarray[0])) < 0) 177*21a88dd0Skaashoek printf(2, "dup failed\n"); 178*21a88dd0Skaashoek if (close(fdarray[0]) < 0) 179*21a88dd0Skaashoek printf(2, "close fdarray[0] failed\n"); 180*21a88dd0Skaashoek if (close(fdarray[1]) < 0) 181*21a88dd0Skaashoek printf(2, "close fdarray[1] failed\n"); 182*21a88dd0Skaashoek } 1838b58e810Skaashoek if (ioredirection() < 0) 1848b58e810Skaashoek exit(); 185*21a88dd0Skaashoek if ((r = exec(cmdlist[c].argv0buf, (char**) cmdlist[c].argv)) < 0) { 186*21a88dd0Skaashoek printf(2, "exec %s: %d\n", cmdlist[c].argv[0], r); 187d7b3b802Skaashoek exit(); 188d7b3b802Skaashoek } 189*21a88dd0Skaashoek } else if (pid > 0) { 190*21a88dd0Skaashoek int p; 1918b58e810Skaashoek if (debug) 192*21a88dd0Skaashoek printf(2, "[%d] FORKED child %d\n", getpid(), pid); 193*21a88dd0Skaashoek 194*21a88dd0Skaashoek if (c > 0 && cmdlist[c-1].token == '|') { 195*21a88dd0Skaashoek close(fdarray[0]); 196*21a88dd0Skaashoek close(fdarray[1]); 197*21a88dd0Skaashoek } 198*21a88dd0Skaashoek if (cmdlist[c].token != '|') { 199*21a88dd0Skaashoek if (debug) 200*21a88dd0Skaashoek printf(2, "[%d] WAIT for children\n", getpid()); 201*21a88dd0Skaashoek do { 202*21a88dd0Skaashoek p = wait(); 203*21a88dd0Skaashoek if (debug) 204*21a88dd0Skaashoek printf(2, "[%d] WAIT child %d finished\n", getpid(), p); 205*21a88dd0Skaashoek } while (p > 0); 2068b58e810Skaashoek if (debug) 2078b58e810Skaashoek printf(2, "[%d] wait finished\n", getpid()); 208d7b3b802Skaashoek } 209d7b3b802Skaashoek } 210*21a88dd0Skaashoek } 211*21a88dd0Skaashoek } 2128b58e810Skaashoek 2138b58e810Skaashoek int 2148b58e810Skaashoek ioredirection(void) 2158b58e810Skaashoek { 216*21a88dd0Skaashoek int i, fd; 2178b58e810Skaashoek 218*21a88dd0Skaashoek for (i = 0; i < nextio; i++) { 219*21a88dd0Skaashoek switch (iolist[i].token) { 2208b58e810Skaashoek case '<': 221d49a2d53Skaashoek if (close(0) < 0) 222d49a2d53Skaashoek printf(2, "close 0 failed\n"); 223*21a88dd0Skaashoek if ((fd = open(iolist[i].s, O_RDONLY)) < 0) { 224*21a88dd0Skaashoek printf(2, "failed to open %s for read: %d", iolist[i].s, fd); 2258b58e810Skaashoek return -1; 2268b58e810Skaashoek } 2278b58e810Skaashoek if (debug) 228*21a88dd0Skaashoek printf(2, "redirect 0 from %s\n", iolist[i].s); 2298b58e810Skaashoek break; 2308b58e810Skaashoek case '>': 231d49a2d53Skaashoek if (close(1) < 0) 232d49a2d53Skaashoek printf(2, "close 1 failed\n"); 233*21a88dd0Skaashoek if ((fd = open(iolist[i].s, O_WRONLY|O_CREATE)) < 0) { 234*21a88dd0Skaashoek printf(2, "failed to open %s for write: %d", iolist[i].s, fd); 2358b58e810Skaashoek exit(); 2368b58e810Skaashoek } 2378b58e810Skaashoek if (debug) 238*21a88dd0Skaashoek printf(2, "redirect 1 to %s\n", iolist[i].s); 2398b58e810Skaashoek break; 2408b58e810Skaashoek } 2418b58e810Skaashoek } 2428b58e810Skaashoek return 0; 2438b58e810Skaashoek } 2448b58e810Skaashoek 2458b58e810Skaashoek void 246*21a88dd0Skaashoek addio(int token, char *s) 2478b58e810Skaashoek { 248*21a88dd0Skaashoek if (nextio >= MAXNODE) { 249*21a88dd0Skaashoek printf(2, "addio: ran out of nodes\n"); 2508b58e810Skaashoek return; 2518b58e810Skaashoek } 2528b58e810Skaashoek 253*21a88dd0Skaashoek iolist[nextio].token = token; 254*21a88dd0Skaashoek iolist[nextio].s = s; 255*21a88dd0Skaashoek nextio++; 2568b58e810Skaashoek } 2578b58e810Skaashoek 2588b58e810Skaashoek 2598b58e810Skaashoek // gettoken(s, 0) prepares gettoken for subsequent calls and returns 0. 2608b58e810Skaashoek // gettoken(0, token) parses a shell token from the previously set string, 2618b58e810Skaashoek // null-terminates that token, stores the token pointer in '*token', 2628b58e810Skaashoek // and returns a token ID (0, '<', '>', '|', or 'w'). 2638b58e810Skaashoek // Subsequent calls to 'gettoken(0, token)' will return subsequent 2648b58e810Skaashoek // tokens from the string. 2658b58e810Skaashoek 2668b58e810Skaashoek int 2678b58e810Skaashoek gettoken(char *s, char **p1) 2688b58e810Skaashoek { 2698b58e810Skaashoek static int c, nc; 2708b58e810Skaashoek static char* np1, *np2; 2718b58e810Skaashoek 2728b58e810Skaashoek if (s) { 2738b58e810Skaashoek nc = _gettoken(s, &np1, &np2); 2748b58e810Skaashoek return 0; 2758b58e810Skaashoek } 2768b58e810Skaashoek c = nc; 2778b58e810Skaashoek *p1 = np1; 2788b58e810Skaashoek nc = _gettoken(np2, &np1, &np2); 2798b58e810Skaashoek return c; 2808b58e810Skaashoek } 2818b58e810Skaashoek 2828b58e810Skaashoek 2838b58e810Skaashoek // Get the next token from string s. 2848b58e810Skaashoek // Set *p1 to the beginning of the token and *p2 just past the token. 2858b58e810Skaashoek // Returns 2868b58e810Skaashoek // 0 for end-of-string; 2878b58e810Skaashoek // < for <; 2888b58e810Skaashoek // > for >; 2898b58e810Skaashoek // | for |; 2908b58e810Skaashoek // w for a word. 2918b58e810Skaashoek // 2928b58e810Skaashoek // Eventually (once we parse the space where the \0 will go), 2938b58e810Skaashoek // words get nul-terminated. 2948b58e810Skaashoek #define WHITESPACE " \t\r\n" 2958b58e810Skaashoek #define SYMBOLS "<|>&;()" 2968b58e810Skaashoek 2978b58e810Skaashoek int 2988b58e810Skaashoek _gettoken(char *s, char **p1, char **p2) 2998b58e810Skaashoek { 3008b58e810Skaashoek int t; 3018b58e810Skaashoek 3028b58e810Skaashoek if (s == 0) { 3038b58e810Skaashoek if (debug > 1) 3048b58e810Skaashoek printf(2, "GETTOKEN NULL\n"); 3058b58e810Skaashoek return 0; 3068b58e810Skaashoek } 3078b58e810Skaashoek 3088b58e810Skaashoek if (debug > 1) 3098b58e810Skaashoek printf(2, "GETTOKEN: %s\n", s); 3108b58e810Skaashoek 3118b58e810Skaashoek *p1 = 0; 3128b58e810Skaashoek *p2 = 0; 3138b58e810Skaashoek 3148b58e810Skaashoek while (strchr(WHITESPACE, *s)) 3158b58e810Skaashoek *s++ = 0; 3168b58e810Skaashoek if (*s == 0) { 3178b58e810Skaashoek if (debug > 1) 3188b58e810Skaashoek printf(2, "EOL\n"); 3198b58e810Skaashoek return 0; 3208b58e810Skaashoek } 3218b58e810Skaashoek if (strchr(SYMBOLS, *s)) { 3228b58e810Skaashoek t = *s; 3238b58e810Skaashoek *p1 = s; 3248b58e810Skaashoek *s++ = 0; 3258b58e810Skaashoek *p2 = s; 3268b58e810Skaashoek if (debug > 1) 3278b58e810Skaashoek printf(2, "TOK %c\n", t); 3288b58e810Skaashoek return t; 3298b58e810Skaashoek } 3308b58e810Skaashoek *p1 = s; 3318b58e810Skaashoek while (*s && !strchr(WHITESPACE SYMBOLS, *s)) 3328b58e810Skaashoek s++; 3338b58e810Skaashoek *p2 = s; 3348b58e810Skaashoek if (debug > 1) { 3358b58e810Skaashoek t = **p2; 3368b58e810Skaashoek **p2 = 0; 3378b58e810Skaashoek printf(2, "WORD: %s\n", *p1); 3388b58e810Skaashoek **p2 = t; 3398b58e810Skaashoek } 3408b58e810Skaashoek return 'w'; 3418b58e810Skaashoek } 3428b58e810Skaashoek 343