int main(void) { pid_t pid; int argc, status; char command[MAXLINE], *argv[MAXARGS], path[MAXPATH]; printf("Welcome to the mini-shell, msh!\n"); for (;;) { printf("msh > "); fflush(stdout); fgets(command, MAXLINE, stdin); argc = parse_input(command, argv); /* if nothing is entered do nothing */ if (*argv == NULL) continue; /* exit */ if (strcmp("exit", argv[0]) == 0) exit(EXIT_SUCCESS); /* print working directory */ if (strcmp("pwd", argv[0]) == 0) { printf("%s\n", getenv("PWD")); continue; } /* error handling for invalid commands */ if (*argv[0] == '<' || *argv[0] == '>') { _exit_error("No command.", false); continue; } /* cd */ if (strcmp("cd", argv[0]) == 0) { // not Kansas if (argc > 1) chdir(argv[1]); // Kansas, there is no place like home Toto. else chdir(getenv("HOME")); // lets make sure to update PWD. getcwd(path, MAXPATH); setenv("PWD", path, 1); continue; } pid = fork(); /* Unable to fork, reached fork limit? */ if (pid == -1) perror("Shell programming error, unable to fork.\n"); /* inside the child process */ else if (pid == 0) process_input(argc, argv); /* inside the parent process, waiting on child */ else { if (wait(&status) == -1) perror("Shell program error"); else printf("Child returned status: %d\n", status); } } return 0; }
/* Executes a simple command that is not a builtin function, redirecting input * and output as appropriate. As with all exec_XXX() functions, assumes that * the parent has forked if necessary. Does not return. * * @simple = CMD to be executed */ void exec_simple(CMD* simple) { if (simple->fromFile && redirect_input(simple) < 0) _exit(EXIT_FAILURE); if (simple->toFile && redirect_output(simple) < 0) _exit(EXIT_FAILURE); assert(simple && simple->type == SIMPLE); execvp(simple->argv[0], &simple->argv[0]); _exit_error(EXIT_FAILURE); // execvp only returns on an error }
/* Executes a stage that is not a builtin command. Delegates to exec_simple() * and exec_subcmd() as appropriate. As with all exec_XXX() functions, assumes * that the parent has forked if necessary. Does not return. * * @stage = CMD to be executed */ void exec_stage(CMD* stage) { assert(!is_builtin(stage)); if (stage->type == SIMPLE) { exec_simple(stage); } else if (stage->type == SUBCMD) { exec_subcmd(stage); } else { // Should never hit here assert(false); _exit_error(EXIT_FAILURE); } }
void process_input(int argc, char **argv) { int fd; bool flag = false; for (int i = 0; i < argc; i++) { if (argv[i][0] == '<') { // error checking if (flag) _exit_error("Can't have two input redirects.", true); if (argv[i + 1] == NULL) _exit_error("No input redictions file specified.", true); // open a fd if((fd = open(argv[i + 1], O_RDONLY)) < 0) perror("open"); // dup the fd and close the fd if(dup2(fd, 0) < 0) perror("dup2"); close(fd); argv[i] = NULL; flag = true; } else if (strcmp(">", argv[i]) == 0) { if (argv[i + 1] == NULL) _exit_error("No output file specified.", true); if ((fd = open(argv[i + 1], O_TRUNC | O_WRONLY | O_CREAT, 0666)) < 0) perror("open"); if (dup2(fd, 1) < 0) perror("dup2"); close(fd); argv[i] = NULL; } else if (strcmp(">>", argv[i]) == 0) { if (argv[i + 1] == NULL) _exit_error("No output file specified.", true); if ((fd = open(argv[i + 1], O_APPEND | O_WRONLY | O_CREAT, 0666)) < 0) perror("open"); if (dup2(fd, 1) < 0) perror("dup2"); close(fd); argv[i] = NULL; } } if (execvp(*argv, argv) == -1) { perror("process_input, shell program."); _exit(-1); } }