/*
 * duped_pipe.c
 * This program will demonstrate how to dup a file
 * descriptor and open a pipe.
 *
 * to compile:  cc -O -pipe duped_pipe.c  -o duped_pipe
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>

#define CHILD_FILE    ("child_out")
#define MODE          (S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH)
#define MAX_BUFF      (1024)
#define CAT           ("cat")

int main(int argc, char **argv)
{
	int  fds[2], log, infile;
	char buff[MAX_BUFF];
	size_t len;
	pid_t child;

	if( argc > 1 )
	{
		infile = open(argv[1], O_RDONLY);
		if( infile < 0 )
		{
			perror("Open failed!\n");
			exit(0);
		}

		/* 
		 * Create our pipe
		 */
		if( pipe(fds) == 0 )
		{
			/* open our childs log */
			log = open(CHILD_FILE, (O_RDWR | O_CREAT), MODE);
			if( log > 0 )
			{
				/*
				 * Now that we have our pipe, input file, and our log 
				 * file we need to fork, then set the log file as the
				 * childs STDOUT. Then set the read end of the pipe
				 * as the childs STDIN.
				 */
				child = fork();
				if( child == 0 )
				{
					/* Child
					 * -----
					 * Close the child's write end of the pipe because if
					 * we leave it open the child will never recieve
					 * the end-of-file marker on the read end of the pipe. 
					 */
					close(fds[1]);
					/* 
					 * Now we have to close STDIN by calling dup2 with
					 * STDIN as the newfd arg. That way dup2 will close
					 * STDIN for us and then, set STDIN to our read 
					 * end of the pipe.
					 */
					if( dup2(fds[0], STDIN_FILENO) >= 0 )
					{
						/* 
						 * Now we have to set the log file to 
						 * STDOUT. Agian calling dup2 with STDOUT
						 * as the newfd arg will cause it to be closed
						 * and STDOUT set to log file descriptor.
						 */
						if( dup2(log, STDOUT_FILENO) < 0)
						{
							perror("Cannot dup STDOUT! \n");
							exit(0);
						}
						 /* Now exec cat  */
						execlp(CAT, CAT, 0);
						/* never reached unless error */
						perror("Error cannot exec !\n");
						exit(0);

					} /* if( dup2 ) */
					else
					{
						perror("Cannot dupe STDINT !\n");
						exit(0);
					}
				} /* fork */
				else
				{
					/* Parent
					 * ------
					 * All the parent has to do is first close its
					 * read end of the pipe, and then simply read and write
					 * out the file to the child. 
					 */
					close(fds[0]);
					do
					{
						len = read(infile, buff, MAX_BUFF);
						write(fds[1], buff, len);
					}while( len > 0);
					close(fds[1]);
					close(infile);
				}

			} /* if(log) */

		}/* if(pipe) */
		else
		{
			perror("Pipe failed !");
		}

	} /* if( argc ) */
	else
	{
		printf("Error, please specify a file like so\n");
		printf(" $ %s <path to file>\n", argv[0]);
	}

	/* FIN */
	return(0);
}



syntax highlighted by Code2HTML, v. 0.9