Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!sdd.hp.com!spool.mu.edu!uunet!mcsun!hp4nl!nat.vu.nl!maart From: maart@nat.vu.nl (Maarten Litmaath) Newsgroups: comp.unix.programmer Subject: Re: More on how to do a pipe (was re: system() problem) Message-ID: <1991Mar8.012037.812@nat.vu.nl> Date: 8 Mar 91 00:20:37 GMT References: <1991Mar6.025034.8697@csusac.csus.edu> <2506@travis.csd.harris.com> Organization: Dept. of Physics, Vrije University, Amsterdam, The Netherlands Lines: 181 In article <2506@travis.csd.harris.com>, brad@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 #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 #include #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 ); }