Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Sep 1998 00:47:00 -0400
From:      Leo Papandreou <leo@talcom.net>
To:        Mark Ovens <marko@uk.radan.com>
Cc:        questions@FreeBSD.ORG
Subject:   Re: Help needed with fork(), pipe() & dup2()
Message-ID:  <19980911004700.52247@talcom.net>
In-Reply-To: <35F85DAF.2B23FC42@uk.radan.com>; from Mark Ovens on Fri, Sep 11, 1998 at 12:15:59AM %2B0100
References:  <35F6EE38.7DC97F21@uk.radan.com> <19980909182820.16714@talcom.net> <35F77884.E4FEAA21@uk.radan.com> <19980910173817.42597@talcom.net> <35F85DAF.2B23FC42@uk.radan.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, Sep 11, 1998 at 12:15:59AM +0100, Mark Ovens wrote:
> Leo Papandreou wrote:
> > 
> > > Ah, that makes sense. In order to prove this could I add sleep() or
> > > usleep() before the while(gets())?
> 
> Tried it...doesn't work :-(
> 
> > 
> > I'd try this, yes.
> > 
> > I dont remember the code you posted but It also just occurred to me
> > that files() will not work as expected if the close-on-exec flag is
> > set.
> 
> close-on-exec flag?? please explain.

close(2) but that isnt the case here. Neither is parent/child com-
munications since (see pipe(2)) reading from a pipe will return 0
only when the pipe widowed.

> 
> Perhaps I should explain the context a bit further. The program is a
> clone of Sun's Open Look file manager and foo() is called everytime you
> change directory (by double clicking on a dir icon). This means that the
> pipe is created everytime you change dir, i.e. it isn't persistent for
> the duration the prog is running.
> 
> arg 2 in execvp() is a global char* that holds a list of filenames

char **, you mean?

> (delimited by \n and starts with "file", the name of the prog, and is
> terminated by a NULL) that the prog can't identify so it passes them to
> file(1) to try to id them.

I'm not sure I understand the \n part. file(1) will interpret the
'\n' literally.

> 
> What puzzles me is that the Linux binary works OK under FreeBSD (2.2.7)
> Linux emulation. I'm building it with gcc 2.8.1.
> 
> I've re-quoted the code below....

I rewrote foo() and embedded it into a short main() stub. It *did*
work under Linux but it only worked under FreeBSD for the first
call to foo():

#include	<stdio.h>
#include	<unistd.h>
#include	<err.h>
#include	<fcntl.h>

#define	MAX_LINE	4096

FILE	*logfile;

char	*files[] =
{
"files",
"/etc/XF86Config",
"/etc/aliases",
"/etc/aliases.db",
"/etc/amd.map",
"/etc/crontab",
"/etc/csh.cshrc",
"/etc/csh.login",
"/etc/csh.logout",
0
};

void foo()
{
	char   line[MAX_LINE];
        int    fd[2];
        pid_t  pid;


        if (pipe(fd) < 0)
		err(1, NULL);

        if ((pid = fork()) < 0)
		err(1, NULL);
        else if (pid > 0)
		{  /* parent */
                close(fd[1]);
                if (fd[0] != STDIN_FILENO)
			{
                        if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
				err(1, NULL);
                        }
		/*
		 * read from the pipe
		 */
                while (gets(line) != NULL)
			{
			/*
			gets(line) will not equal NULL until the child
			closes the write end of the pipe (see pipe(2))
			so parent-child communication doesnt seem to be
			an issue here.
			*/
			fprintf(logfile, "%s\n", line);
			}
                close(fd[0]);
		}
	else
                {  /* child */
                close (fd[0]);
                if (fd[1] != STDOUT_FILENO)
			{
                        if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
				err(1, NULL);
                        }
		if (execvp("file", files) < 0)
			err(1, NULL);
                }
}


main(int argc, char *argv[])
{
	if (argc != 2)
		return 1;

	if ((logfile = fopen(argv[1], "w")) == 0)
		err(1, NULL);

	fprintf(logfile, ">>> FOO(1) <<<\n");
	foo();
	fflush(logfile);

	fprintf(logfile, ">>> FOO(2) <<<\n");
	foo();
	fflush(logfile);

	fprintf(logfile, ">>> FOO(3) <<<\n");
	foo();
	fflush(logfile);

	return 0;
}

Produced this output:

>>> FOO(1) <<<
/etc/XF86Config: English text
/etc/aliases:    English text
/etc/aliases.db: Berkeley DB Hash file (Version 2, Little Endian, Bucket Size 8192, Bucket Shift 13, Directory Size 256, Segment Size 256, Segment Shift 8, Overflow Point 1, Last Freed 2, Max Bucket 1, High Mask 0x3, Low Mask 0x1, Fill Factor 65536, Number of Keys 18)
/etc/amd.map:    ASCII text
/etc/crontab:    ASCII text
/etc/csh.cshrc:  ASCII text
/etc/csh.login:  English text
/etc/csh.logout: ASCII text
>>> FOO(2) <<<
>>> FOO(3) <<<


> What puzzles me is that the Linux binary works OK under FreeBSD (2.2.7)
> Linux emulation. I'm building it with gcc 2.8.1.
> 

Yeah, the above code produces the "expected" results on a RedHat machine.
I'd love to know why and where the difference in semantics lies.

> I've re-quoted the code below....
> 
> Thanks for your help with this Leo.

Thank Brian Sommers. His sol'n was correct. 

void foo()
{

[...]
        else if (pid > 0)
		{  /* parent */
		FILE	*in;

                close(fd[1]);
		if ((in = fdopen(fd[0], "r")) == NULL)
			{
			close(fd[0]);   /* child gets SIGPIPE */
			err(1, NULL);
			}

		/*
		 * read from the pipe
		 */
                while (fgets(line, MAX_LINE, in) != NULL)
			fprintf(logfile, "%s", line);
		fclose(in);
                close(fd[0]);
		}
	else
                {  /* child */

[...]

}

>>> FOO(1) <<<
/etc/XF86Config: English text
/etc/aliases:    English text
/etc/aliases.db: Berkeley DB Hash file (Version 2, Little Endian, Bucket Size 8192, Bucket Shift 13, Directory Size 256, Segment Size 256, Segment Shift 8, Overflow Point 1, Last Freed 2, Max Bucket 1, High Mask 0x3, Low Mask 0x1, Fill Factor 65536, Number of Keys 18)
/etc/amd.map:    ASCII text
/etc/crontab:    ASCII text
/etc/csh.cshrc:  ASCII text
/etc/csh.login:  English text
/etc/csh.logout: ASCII text
>>> FOO(2) <<<
/etc/XF86Config: English text
/etc/aliases:    English text
/etc/aliases.db: Berkeley DB Hash file (Version 2, Little Endian, Bucket Size 8192, Bucket Shift 13, Directory Size 256, Segment Size 256, Segment Shift 8, Overflow Point 1, Last Freed 2, Max Bucket 1, High Mask 0x3, Low Mask 0x1, Fill Factor 65536, Number of Keys 18)
/etc/amd.map:    ASCII text
/etc/crontab:    ASCII text
/etc/csh.cshrc:  ASCII text
/etc/csh.login:  English text
/etc/csh.logout: ASCII text
>>> FOO(3) <<<
/etc/XF86Config: English text
/etc/aliases:    English text
/etc/aliases.db: Berkeley DB Hash file (Version 2, Little Endian, Bucket Size 8192, Bucket Shift 13, Directory Size 256, Segment Size 256, Segment Shift 8, Overflow Point 1, Last Freed 2, Max Bucket 1, High Mask 0x3, Low Mask 0x1, Fill Factor 65536, Number of Keys 18)
/etc/amd.map:    ASCII text
/etc/crontab:    ASCII text
/etc/csh.cshrc:  ASCII text
/etc/csh.login:  English text
/etc/csh.logout: ASCII text


> > void foo()
> >         {
> >         char   line [MAX_LINE];
> >         int    fd [2];
> >         pid_t  pid;
> > 
> >         pipe(fd);
> >         if ((pid = fork ()) < 0)
> >                 error_message();
> >         else
> >                 if (pid > 0)
> >                         {  /* parent */
> >                         close (fd [1]);
> >                         if (fd [0] != STDIN_FILENO)
> >                                 {
> >                                 dup2(fd [0], STDIN_FILENO)
> >                                 close (fd [0]);
> >                                 }
> >                                         /* read file names from pipe */
> >                         while (gets (line) != NULL)
> >                                  {
> >                                         .
> >                                         .
> >                                 code to process "line" here
> >                                         .
> >                                         .
> >                                  }
> > 
> >                         close (fd [0]);
> > 
> >                         }  /* parent */
> >                 else
> >                         {  /* child */
> >                         close (fd [0]);
> >                         if (fd [1] != STDOUT_FILENO)
> >                                 {
> >                                 dup2(fd [1], STDOUT_FILENO)
> >                                 close (fd [1]);
> >                                 }
> >                         if (execvp ("file", files) < 0)
> >                                 error_message ();
> >                         close (fd [1]);
> >                         }  /* child */
> >         }
> >

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19980911004700.52247>