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>