Newsgroup: it.comp.os.linux.development
Titolo: Printf and output redirection.

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void sys_err(const char *str)
{
    perror(str);
    exit(1);
}
int main ()
{
    pid_t child;
    char *array[3] = {"arg1", "arg2", "arg3"};
    if ((child = fork()) < 0)
        sys_err("Fork error!");
    else if (child == 0)
    {
        printf("Child process; parent has PID = %d\n", getppid());
        if (execvp("figlio", array) < 0)
            sys_err("Exec error");
    }
    else
    {
        /* Parent process */
        printf("Processo padre .... pid_t = %d\n", getpid());
        sleep(1);
    }
    return 0;
}
Could anyone help me answering to the following question?
If output is redirected on a file, first printf of parent process 
could print two times the same message, while if output is printed on 
the screen (stdout) this never happen.
Can you explain why? 

    }
    Ack! Your 'printf' operates on the context it inherited from the parent. 
If that context includes data in the buffer, that may get written twice 
(once by the parent, once by the child). You must be *very* careful what you 
do between a 'fork' and an 'exec'.
    DS

Excuse me but I've not understood and I try to explain my question 
better:
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void sys_err(const char *str)
{
    perror(str);
    exit(1);
}
int main ()
{
    pid_t child;
    char *array[3] = {"arg1", "arg2", "arg3"};
    if ((child = fork()) < 0)
        sys_err("Fork error!");
    else if (child == 0)
    {
        printf("Child process; parent has PID = %d\n", getppid());
        if (execvp("figlio", array) < 0)
            sys_err("Exec error");
    }
    else
    {
        /* Parent process */
        /* If output is redirected on a file this printf */
        /* could be printed two times, while writing */
        /* to stdout this doesn't happen. Why??? */
        printf("Parent process PID: %d\n", getpid());
        sleep(1);
    }
    return 0;
}
Your answer is that child's printf, operating on parent's buffer, 
could write the same thing of the parent (contained in the buffer 
before fork)?
Someone knows the answer to my why (the why in this message)?
Thanks,
            Luigi. 

 Someone knows the answer to my why (the why in this message)?
    The answer to why you see different behavior with a file instead of a 
terminal is because terminals and files have different buffering by default. 
(You are doing something whose behavior is undefined, so it can differ in 
strange and unpredictable ways. Don't obsess over this, just fix the bug. 
Trying to understand why undefined behavior sometimes does one things and 
sometimes does another leads to either madness or broken fixes. The fix is 
to remove the undefined behavior.)
    A 'printf' to a file may just update the file's internal buffer managed 
by the standard I/O libarary. When you 'fork', each child gets a copy of 
that buffer. If you then flush the buffer in both the parent and the 
child -- ouch.
    DS

 
I see the opposite.  If I redirect to a file, the child doesn't print 
out, but the parent does.  Without redirection both appear.  It looks 
like the stdout file descriptor has FD_CLOEXEC flag set, so the fd is 
closed when the child calls call exec.
This has the effect of discarding the printf output that occurs before 
the exec because it is in a buffer build on top of the fd.  When I added 
fflush(stdout) before the printf, the child's printf (before the exec) 
shows up in a redirected file.
Is this what you were asking?
John

 Is this what you were asking?
    I don't think this explains the OP's problem for two reaons. First, 
FD_CLOEXEC would work exactly the same on a regular file as on a terminal. 
Second, I think he's talking about output that takes place before the call 
to 'exec'.
    DS

 wrote:
:#include <sys/types.h>

Sure.  If stdout is going to a terminal, the default buffering method
is "line buffered" (_IOLBF) and the message is flushed out immediately.
If stdout is going to a file, the default buffering method is "fully
buffered" (_IOFBF) and the child process inherits a copy of the dirty
buffer, 
-- 
Bob Nichols         AT 
comcast.net
 I am "rnichols42"


True. But the exec closes fd 1 from underneath stdout.
I don't know if this is documented anywhere, but every Unix I have used 
sets stdout's buffering differently depending on whether the output is a 
terminal or not.  The setvbuf manpage describes what I am talking about. 
  When the output is a terminal, the buffering flag is set to_IOLBF so 
that stdout is flushed with every newline.  When the output is not a 
terminal, the buffering flag is set to _IOFBF, which flushes only when 
the buffer is full.
That explains why the output appears on the terminal, but not when it's 
redirected.  On the terminal stdout is flushed with the newline, before 
exec is called.  When the output is redirected, the printf is never 
flushed and exec closes fd 1 while stdout still has data in the buffer.
John