#include #include #include #include #include #include #include #include #include // For reference // ~cpen212/Public/lab5/crash-ref #define MAXJOBS 32 #define MAXLINE 1024 char **environ; struct job { pid_t pid; char cmd[MAXLINE]; }; struct job job_list[MAXJOBS]; int num_jobs = 0; void handle_sigchld(int sig) { // TODO } void handle_sigtstp(int sig) { // TODO } void handle_sigint(int sig) { // TODO } void handle_sigquit(int sig) { // TODO } void install_signal_handlers() { // TODO } void spawn(const char **toks, bool bg) { // bg is true iff command ended with & pid_t pid = fork(); // create a new process int status; if (pid < 0) { fprintf(stderr, "ERROR: failed to fork\n"); exit(1); } else if (pid == 0) { // child process execvp(toks[0], (char * const *)toks); // execute the command fprintf(stderr, "ERROR: cannot run %s\n", toks[0]); // executes only if execvp fails exit(1); } else { // parent process if (bg) { // if running in background, add job to list if (num_jobs == MAXJOBS) { // fprintf(stderr, "ERROR: too many jobs\n"); } else { job_list[num_jobs].pid = pid; strncpy(job_list[num_jobs].cmd, *toks, MAXLINE); num_jobs++; } } else { // waits if running in foreground waitpid(pid, &status, 0); } } } void cmd_jobs(const char **toks) { if (toks[1] != NULL) { fprintf(stderr, "ERROR: jobs takes no arguments\n"); } else { for (int i = 0; i < num_jobs; i++) { printf("[%d] (%d) %s\n", i + 1, job_list[i].pid, job_list[i].cmd); } } } void cmd_fg(const char **toks) { // TODO } void cmd_bg(const char **toks) { // TODO } void cmd_nuke(const char **toks) { // TODO } void cmd_quit(const char **toks) { if (toks[1] != NULL) { fprintf(stderr, "ERROR: quit takes no arguments\n"); } else { exit(0); } } void eval(const char **toks, bool bg) { // bg is true iff command ended with & assert(toks); if (*toks == NULL) return; if (strcmp(toks[0], "quit") == 0) { cmd_quit(toks); } else if (strcmp(toks[0], "jobs") == 0) { cmd_jobs(toks); } else { spawn(toks, bg); } } // you don't need to touch this unless you want to add debugging void parse_and_eval(char *s) { assert(s); const char *toks[MAXLINE + 1]; while (*s != '\0') { bool end = false; bool bg = false; int t = 0; while (*s != '\0' && !end) { while (*s == '\n' || *s == '\t' || *s == ' ') ++s; if (*s != ';' && *s != '&' && *s != '\0') toks[t++] = s; while (strchr("&;\n\t ", *s) == NULL) ++s; switch (*s) { case '&': bg = true; end = true; break; case ';': end = true; break; } if (*s) *s++ = '\0'; } toks[t] = NULL; eval(toks, bg); } } // you don't need to touch this unless you want to add debugging void prompt() { printf("crash> "); fflush(stdout); } // you don't need to touch this unless you want to add debugging int repl() { char *buf = NULL; size_t len = 0; while (prompt(), getline(&buf, &len, stdin) != -1) { parse_and_eval(buf); } if (buf != NULL) free(buf); if (ferror(stdin)) { perror("ERROR"); return 1; } return 0; } // you don't need to touch this unless you want to add debugging options int main(int argc, char **argv) { install_signal_handlers(); return repl(); }