int main(int argc, char *argv[]) { int readpipe[2], writepipe[2]; pid_t cpid; assert(1 < argc && argc < 64); if (pipe(readpipe) == -1 || pipe(writepipe) == -1) { perror("pipe"); exit(EXIT_FAILURE); } cpid = fork(); if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (cpid == 0) { /* Forked Child with STDIN forwarding */ char *cmd = argv[1]; char *exec_args[64] = {0}; int i; for (i = 0; i < argc - 1; i++) { /* args to stdin_forcer are the program and optional args to exec. Here we copy pointers pointing to strings of cmd/args. exec_args is indexed one lower than argv. */ exec_args[i] = argv[i+1]; } close(PARENT_READ); /* We aren't the parent. Decrement fd refcounts. */ close(PARENT_WRITE); /* CHILD_READ = STDIN to the exec'd process. CHILD_WRITE = STDOUT to the exec'd process. */ if (!DUP2CLOSE(CHILD_READ, STDIN_FILENO) && DUP2CLOSE(CHILD_WRITE, STDOUT_FILENO)) { perror("dup2 or close"); _exit(EXIT_FAILURE); } /* At this point, the execv'd program's STDIN and STDOUT are the pipe */ if (execv(cmd, exec_args) == -1) { perror("execve"); } _exit(EXIT_FAILURE); /* Silence a warning */ } else { /* Original Parent Process */ char buf; close(CHILD_READ); /* We aren't the child. Close its read/write. */ close(CHILD_WRITE); /* We should catch the child's exit signal if it dies before we send STDIN*/ while (read(STDIN_FILENO, &buf, 1) > 0 && buf != 0x0) { write(PARENT_WRITE, &buf, 1); } close(PARENT_WRITE); /* closing PARENT_WRITE sends EOF to CHILD_READ */ wait(NULL); /* Wait for child to exit */ while (read(PARENT_READ, &buf, 1) > 0) { write(STDOUT_FILENO, &buf, 1); /* Vomit forth our output on STDOUT */ } close(PARENT_READ); /* done reading from writepipe */ exit(EXIT_SUCCESS); /* This was a triumph */ } }
int remap_pipe_stdin_stdout(int rpipe, int wpipe) { /*------------------------------------------------------------------ * CASE [A] * * This is the trivial case that probably never happens: the two FDs * are already in the right place and we have nothing to do. Though * this probably doesn't happen much, it's guaranteed that *doing* * any shufflingn would close descriptors that shouldn't have been. */ if ( rpipe == 0 && wpipe == 1 ) return TRUE; /*---------------------------------------------------------------- * CASE [B] and [C] * * These two have the same handling but not the same rules. In case * [C] where both FDs are "out of the way", it doesn't matter which * of the FDs is closed first, but in case [B] it MUST be done in * this order. */ if ( rpipe >= 1 && wpipe > 1 ) { return DUP2CLOSE(rpipe, 0) && DUP2CLOSE(wpipe, 1); } /*---------------------------------------------------------------- * CASE [D] * CASE [E] * * In these cases, *one* of the FDs is already correct and the other * one can just be dup'd to the right place: */ if ( rpipe == 0 && wpipe >= 1 ) return DUP2CLOSE(wpipe, 1); if ( rpipe >= 1 && wpipe == 1 ) return DUP2CLOSE(rpipe, 0); /*---------------------------------------------------------------- * CASE [F] * * Here we have the write pipe in the read slot, but the read FD * is out of the way: this means we can do this in just two steps * but they MUST be in this order. */ if ( rpipe >= 1 && wpipe == 0 ) { return DUP2CLOSE(wpipe, 1) && DUP2CLOSE(rpipe, 0); } /*---------------------------------------------------------------- * CASE [G] * * This is the trickiest case because the two file descriptors are * *backwards*, and the only way to make it right is to make a * third temporary FD during the swap. */ if ( rpipe == 1 && wpipe == 0 ) { const int tmp = dup(wpipe); /* NOTE! this is not dup2() ! */ return tmp > 1 && close(wpipe) == 0 && DUP2CLOSE(rpipe, 0) && DUP2CLOSE(tmp, 1); } /* SHOULD NEVER GET HERE */ return FALSE; }