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 */
  }
}
Ejemplo n.º 2
0
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;
}