/* Executes a subcommand, redirecting input and output as appropriate. As with * all exec_XXX() functions, assumes that the parent has forked if necessary. * Does not return. * * @subcmd = CMD to be executed */ void exec_subcmd(CMD* subcmd) { if (subcmd->fromFile && redirect_input(subcmd) < 0) _exit(EXIT_FAILURE); if (subcmd->toFile && redirect_output(subcmd) < 0) _exit(EXIT_FAILURE); // Subcommands don't wait for backgrounded processes. They will be // reparented to init and be reaped accordingly int ret_val = process(subcmd->left); _exit(ret_val); // Any error messages will be produced during process }
/* 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 builtin command, redirecting input and output as appropriate. * and output as appropriate. As with all exec_XXX() functions, assumes that * the parent has forked if necessary, but unlike the others, returns the status * of the command executed. * * @simple = CMD to be executed * * Returns: Status of command executed */ int exec_builtin(CMD* simple) { // Keep track of old stdin, stdout, stderr for after execution of built-in int old_stdin = dup(0); int old_stdout = dup(1); int old_stderr = dup(2); // Failures for built-in commands to redirect should not cause the command // to abort, but it should set ? appropriately int redirect_status = 0; if (simple->fromFile && redirect_input(simple) < 0) redirect_status = errno; if (simple->toFile && redirect_output(simple) < 0) { int fd_devnull = open("/dev/null", O_WRONLY); dup2(fd_devnull, 1); if (ISREDERR(simple->toType)) dup2(fd_devnull, 2); close(fd_devnull); redirect_status = errno; } char* cmd_name = simple->argv[0]; int builtin_status = 0; if (!strcmp(cmd_name, "cd")) { builtin_status = cd(simple->argc, simple->argv); } else if (!strcmp(cmd_name, "pushd")) { builtin_status = pushd(simple->argc, simple->argv); } else if (!strcmp(cmd_name, "popd")) { builtin_status = popd(simple->argc, simple->argv); } else { builtin_status = 1; } dup2(old_stdin, 0); close(old_stdin); dup2(old_stdout, 1); close(old_stdout); dup2(old_stderr, 2); close(old_stderr); return builtin_status ? builtin_status : redirect_status; }
/* * Do the command */ int do_command(char **args, int in, int out, int pipe, int block) { char *input_filename, *output_filename; // Check for redirected input int input = redirect_input(args, &input_filename); switch(input) { case -1: printf("Syntax error!\n"); return -1; break; case 0: break; case 1: printf("Redirecting input from: %s\n", input_filename); break; } // check for append int append = check_append(args, &output_filename); // Check for redirected output int output = redirect_output(args, &output_filename); switch(append) { case -1: printf("Syntax error!\n"); return -1; break; case 0: break; case 1: printf("Redirecting and appending output to: %s\n", output_filename); break; } switch(output) { case -1: printf("Syntax error!\n"); return -1; break; case 0: break; case 1: printf("Redirecting output to: %s\n", output_filename); break; } int result; pid_t child_id; // Fork the child process child_id = fork(); // Check for errors in fork() switch(child_id) { case EAGAIN: perror("Error EAGAIN: "); return child_id; case ENOMEM: perror("Error ENOMEM: "); return child_id; } if(child_id == 0) { // Set up redirection in the child process if(out != 1) { dup2(out, 1); close(out); } if(in != 0) { dup2(in, 0); close(in); } if(input) freopen(input_filename, "r", stdin); if(output) freopen(output_filename, "w+", stdout); if(append) freopen(output_filename, "a", stdout); result = execvp(args[0], args); exit(1); }else { return child_id; } return result; }
/* * The main shell function */ main() { int i; char **args; int result; int block; int output; int input; char *output_filename; char *input_filename; // Set up the signal handler sigset(SIGCHLD, sig_handler); // Setup the signal handler struct sigaction sa; // Setup the SIGPROCMASK sigset_t blockmask; // Make sure the signal handlers are setup if(sigprocmask(SIG_BLOCK, &blockmask, NULL) == -1) { perror("Failed to setup signal handler."); return 1; } // Loop forever while(1) { // Print out the prompt and get the input printf("->"); args = getline(); // No input, continue if(args[0] == NULL) continue; // Check for internal shell commands, such as exit if(internal_command(args)) continue; // Check for an ampersand block = (ampersand(args) == 0); // Check for redirected input input = redirect_input(args, &input_filename); switch(input) { case -1: printf("Syntax error!\n"); continue; break; case 0: break; case 1: printf("Redirecting input from: %s\n", input_filename); break; } // Check for redirected output output = redirect_output(args, &output_filename); switch(output) { case -1: printf("Syntax error!\n"); continue; break; case 0: break; case 1: printf("Redirecting output to: %s\n", output_filename); break; case 2: printf("Appending output to: %s\n", output_filename); break; } // Do the command do_command(args, block, input, input_filename, output, output_filename, sigaction, blockmask, 0, 0); } }
/* * The main shell function */ main() { int i; char **args; int result; int block; int output; int input; char *output_filename; char *input_filename; // Set up the signal handler sigset(SIGCHLD, sig_handler); // Loop forever while(1) { // Print out the prompt and get the input printf("->"); args = my_getline(); // No input, continue if(args[0] == NULL) continue; // Check for internal shell commands, such as exit if(internal_command(args)) continue; // Check for tilde (~) tilde(args); // Check for an ampersand block = (ampersand(args) == 0); // Check for redirected input input = redirect_input(args, &input_filename); switch(input) { case -1: printf("Syntax error!\n"); continue; break; case 0: break; case 1: if (DEBUG) printf("Redirecting input from: %s\n", input_filename); break; } // Check for redirected output output = redirect_output(args, &output_filename); switch(output) { case -1: printf("Syntax error!\n"); continue; break; case 0: break; case 1: if (DEBUG) printf("Redirecting (Overriding) output to: %s\n", output_filename); break; case 2: if (DEBUG) printf("Redirecting (Appending) output to: %s\n", output_filename); break; } // Do the command do_command(args, block, input, input_filename, output, output_filename); for (i = 0; args[i] != NULL; i++) free(args[i]); } }