static void fork_exec_wait (const char *command) { char buf [255]; pid_t forked; int status; switch ((int) (forked = fork ())) { case -1: sprintf (buf, "%s: couldn't fork", progname); perror (buf); return; case 0: exec_simple_command (command); exit (1); /* exits child fork */ break; default: waitpid (forked, &status, 0); break; } }
void execute_command (command_t c, bool time_travel) { int exitStatus; //use this variable to store return value of call to exec_simple_command //store the value into the command's status data member switch(c->type) { // AND, OR, SEQUENCE, and PIPE commands (passed into this function as parameter c) // store their arguments in their data member command_t *command[2] (located in the union --> u.command) // the way the command tree works, the pointers to commands stored in command[0] and command[1] // are simple commands --> to pass them into exec_simple_command, pass in the u.word data member of // the simple commands //c->(u.command[0])->(u.word) // AND: only attempt to execute the second argument if the first succeeds case AND_COMMAND: { if(c->u.command[0]->type == SIMPLE_COMMAND) { exitStatus = exec_simple_command(c->u.command[0]->u.word, c->u.command[0]); c->u.command[0]->status = exitStatus; } else { execute_command(c->u.command[0], 0); exitStatus = c->u.command[0]->status; } //if the first argument was successfully executed, try to execute the second if(exitStatus == 0) { if(c->u.command[1]->type == SIMPLE_COMMAND) { exitStatus = exec_simple_command(c->u.command[1]->u.word, c->u.command[1]); c->u.command[1]->status = exitStatus; } else { execute_command (c->u.command[1], 0); exitStatus = c->u.command[1]->status; } } //if the first argument of AND failed, immediately set c->status to the fail status //if the first argument succeeded, the second argument was executed, and c->status will be the //status of the second argument c->status = exitStatus; } break; // OR: only attempt to execute the second argument if the first argument fails case OR_COMMAND: { if(c->u.command[0]->type == SIMPLE_COMMAND) { exitStatus = exec_simple_command(c->u.command[0]->u.word, c->u.command[0]); c->u.command[0]->status = exitStatus; } else { execute_command(c->u.command[0], 0); exitStatus = c->u.command[0]->status; } //if the first argument was unsuccessful, execute the second if(exitStatus != 0) { if(c->u.command[1]->type == SIMPLE_COMMAND) { //c->u.command[1]->status = exec_simple_command(c->u.command[1]->u.word, c->u.command[1]); exitStatus = exec_simple_command(c->u.command[1]->u.word, c->u.command[1]); c->u.command[1]->status = exitStatus; } else { execute_command (c->u.command[1], 0); exitStatus = c->u.command[1]->status; } } //if the first argument of OR succeeded, immediately set c->status to the success status //if the first argument failed, the second argument was executed, and c->status will be the //status of the second argument c->status = exitStatus; } break; // SEQUENCE: will always have 2 arguments (decision when implementing in make_command_stream) // always execute the second argument even if the first one fails // sequence command status will be the status of the second argument case SEQUENCE_COMMAND: { if(c->u.command[0]->type == SIMPLE_COMMAND) { c->u.command[0]->status = exec_simple_command(c->u.command[0]->u.word, c->u.command[0]); } else { execute_command (c->u.command[0], 0); } if(c->u.command[1]->type == SIMPLE_COMMAND) { c->u.command[1]->status = exec_simple_command(c->u.command[1]->u.word, c->u.command[1]); } else { execute_command (c->u.command[1], 0); } c->status = c->u.command[1]->status; } break; // PIPE: regardless of whether or not the first argument succeeds or fails, the second argument //will execute. Therefore, the status of the pipe command is the same as the status of the second argument case PIPE_COMMAND: { int pid; int secondpid; int returnpid; int status; int saved_stdout = dup(1); int saved_stdin = dup(0); int pipefd[2]; pipe(pipefd); pid = fork(); if(pid == 0) // 0 if child process { close(pipefd[1]); dup2(pipefd[0], 0); if(c->u.command[1]->type == SIMPLE_COMMAND) { exec_simple_command(c->u.command[1]->u.word, c->u.command[1]); } else { execute_command (c->u.command[1], 0); } exit(c->u.command[1]->status); } else { secondpid = fork(); if (secondpid == 0) //0 if child process { close(pipefd[0]); dup2(pipefd[1], 1); if(c->u.command[0]->type == SIMPLE_COMMAND) { exec_simple_command(c->u.command[0]->u.word, c->u.command[0]); } else { execute_command (c->u.command[0], 0); } exit(c->u.command[0]->status); } else { close(pipefd[0]); close(pipefd[1]); dup2(saved_stdin, 0); dup2(saved_stdout, 1); returnpid = waitpid(-1, &status, 0); if(returnpid == secondpid) { waitpid(pid, &status, 0); c->u.command[0]->status = WEXITSTATUS(status); } if(returnpid == pid) { waitpid(secondpid, &status, 0); if(c->u.command[1]->type == SIMPLE_COMMAND) { c->u.command[1]->status = WEXITSTATUS(status); } else { execute_command (c->u.command[1], 0); } c->status = c->u.command[1]->status; } } } } break; case SIMPLE_COMMAND: c->status = exec_simple_command(c->u.word, c); break; case SUBSHELL_COMMAND: { int pid; // 0 if child process int status; int in; int out; int saved_stdout = dup(1); int saved_stdin = dup(0); pid = fork(); // child process if(pid == 0) { // REDIRECTIONS // restoring stdout with dup2 in case there are redirections if(c->input != 0) { in = open(c->input, O_CREAT | O_RDONLY, 0644); dup2(in, 0); close(in); } if(c->output != 0) { out = open(c->output, O_CREAT | O_TRUNC | O_WRONLY, 0622); dup2(out, 1); close(out); } execute_command(c->u.subshell_command, 0); exit(c->u.subshell_command->status); } // parent process else { dup2(saved_stdout, 1); dup2(saved_stdin, 0); // wait for child to terminate // store in variable status lots of info about the child process // pid_t waitpid(pid_t pid, int *status, int options); // The waitpid() system call suspends execution of the calling process // until a child specified by pid argument has changed state. waitpid(pid, &status, 0); //take the last 8 bits of variable status --> data that we want for the exit status c->status = WEXITSTATUS(status); } } break; default: { fprintf(stderr, "Invalid command type."); exit(1); } } }
static void fork_exec_cb (const char *command, Screen *screen, Window window, Drawable drawable, void (*callback) (Screen *, Window, Drawable, const char *name, XRectangle *geom, void *closure), void *closure) { XtAppContext app = XtDisplayToApplicationContext (DisplayOfScreen (screen)); grabclient_data *data; char buf [255]; pid_t forked; int fds [2]; if (pipe (fds)) { sprintf (buf, "%s: creating pipe", progname); perror (buf); exit (1); } data = (grabclient_data *) calloc (1, sizeof(*data)); data->callback = callback; data->closure = closure; data->screen = screen; data->window = window; data->drawable = drawable; data->read_pipe = fdopen (fds[0], "r"); data->write_pipe = fdopen (fds[1], "w"); if (!data->read_pipe || !data->write_pipe) { sprintf (buf, "%s: fdopen", progname); perror (buf); exit (1); } data->pipe_id = XtAppAddInput (app, fileno (data->read_pipe), (XtPointer) (XtInputReadMask | XtInputExceptMask), finalize_cb, (XtPointer) data); forked = fork (); switch ((int) forked) { case -1: sprintf (buf, "%s: couldn't fork", progname); perror (buf); return; case 0: /* child */ fclose (data->read_pipe); data->read_pipe = 0; /* clone the write pipe onto stdout so that it gets closed when the fork exits. This will shut down the pipe and signal the parent. */ close (fileno (stdout)); dup2 (fds[1], fileno (stdout)); close (fds[1]); close (fileno (stdin)); /* for kicks */ exec_simple_command (command); exit (1); /* exits child fork */ break; default: /* parent */ fclose (data->write_pipe); data->write_pipe = 0; data->pid = forked; break; } }