More on how to do a pipe (was re: system() problem)
Maarten Litmaath
maart at nat.vu.nl
Fri Mar 8 10:20:37 AEST 1991
In article <2506 at travis.csd.harris.com>,
brad at SSD.CSD.HARRIS.COM (Brad Appleton) writes:
>[...]
>I hate to be critical but I didnt care for the way the status codes from
>dup2 and pipe were ignored.
Really? Amazing...
>I have a piece of code from a while back that
>was created specifically for the purpose of illustrating how to use fork and
>how to redirect parent/child i/o. Its a bit longer than yours but is cleaner
>(IMHO) and is easy to read. (BTW let me know ASAP of any errors - I thought
>they were all worked out be now but who knows):
OK, I've patched up your program a little, especially your dup2()
alternative, which was completely wrong in various ways; you wrote:
># define dup2(to,from) ( (close(from) || (to = dup()) < 0) ? -1 : 0 )
1) the call is dup2(from, to);
2) dup() is supposed to have an argument (!);
3) upon success dup2() returns the new descriptor,
instead of always 0;
4) the return value of close() is unimportant (its argument
must be checked for validity, though);
5) if its arguments are equal, dup2() is not to perform the
close() at all.
Right, compare the new version with the original code!
--------------------cut here for the patched version--------------------
/* I/O Redirection example */
#include <stdio.h>
#define BUF_LEN 256
#define NULLSTR (char *)NULL
/* read & write ends of a pipe */
#define READ_END 0
#define WRITE_END 1
/*
** function to replace the dup2 system call (if it's not present)
*/
#ifdef DONT_HAVE_DUP2_SYSTEM_CALL
#include <sys/param.h>
#include <errno.h>
#ifndef NOFILE
#define NOFILE 20
#endif /* !NOFILE */
int dup2(old, new)
int old, new;
{
int fd;
void _dup2();
if ((unsigned) new >= NOFILE) {
errno = EBADF;
return -1;
}
if ((fd = dup(old)) < 0) {
if (errno == EBADF)
return -1;
} else if (fd == new)
return new;
if (old != new) {
close(new);
_dup2(old, new);
}
if (fd >= 0)
close(fd);
return new;
}
static void _dup2(old, new)
int old, new;
{
int fd;
if ((fd = dup(old)) != new) {
_dup2(old, new);
close(fd);
}
}
#endif
main( argc, argv )
int argc;
char *argv[];
{
int nbytes, /* number of bytes read */
status, /* return-code/status for various system calls */
pid, /* process id of child */
pipe_fd[2]; /* pipe file-descriptor array */
char buf[ BUF_LEN ]; /* character buffer*/
/* open a pipe */
if ( pipe(pipe_fd) < 0 ) {
perror( "unable to open unnamed pipe\n" );
exit( 1 );
}
switch ( pid = fork() ) {
case -1: /* failure */
perror( "Unable to fork off a process" );
exit( 1 );
break;
case 0: /* child */
/* redirect stdout to the write end of the pipe */
if ( dup2( pipe_fd[ WRITE_END ], fileno(stdout) ) < 0 ) {
perror( "unable to redirect STDOUT to write end of pipe" );
exit( 1 );
}
/*
** The following close() is not necessary in this particular case,
** but it definitely is in general! Else the reader of the pipe
** may hang later (think about it!).
*/
close( pipe_fd[ WRITE_END ] );
/*
** Likewise for the read end of the pipe: as long as there is
** a potential reader, a writer will not receive a SIGPIPE.
*/
close( pipe_fd[ READ_END ] );
fprintf( stderr, "Child: Going to exec uptime (pid=%d).\n", getpid() );
fflush( stderr );
execl( "/usr/ucb/uptime", "uptime", NULLSTR );
break;
default: /* parent */
/*
** The following close() is not necessary in this particular case,
** but it definitely is in general! Else the reader of the pipe
** may hang later (think about it!).
*/
close( pipe_fd[ WRITE_END ] );
do { /* read output from child (until see '\n' ) */
printf( "\n\nParent: reading from pipe\n\n" );
fflush( stdout );
if ( (nbytes=read( pipe_fd[ READ_END ], buf, BUF_LEN )) <0 ) {
perror( "failed on pipe read" );
exit( 1 );
}
if ( write( fileno(stdout), buf, nbytes ) != nbytes ) {
perror( "failed on STDOUT write" );
exit( 1 );
}
} while ( buf[ nbytes-1 ] != '\n' );
printf( "Parent: Waiting for child (childpid=%d).\n", pid );
fflush( stdout );
wait( &status );
printf( "Parent: Child died (status=0x%x).\n", status );
fflush( stdout );
close( pipe_fd[ READ_END ] );
break;
}
exit( 0 );
}
More information about the Comp.unix.programmer
mailing list