less behaves differently in parent and child process - Unix

This is a discussion on less behaves differently in parent and child process - Unix ; When someone asked me a question about pipe(2), I found a weird problem. The original program which may be picked from somewhere is below: #include #include int main(int argc,char **argv) { int f_des[2]; int pid; if(argc!=3) { printf("Usage: %s comand1 ...

+ Reply to Thread
Results 1 to 8 of 8

Thread: less behaves differently in parent and child process

  1. less behaves differently in parent and child process

    When someone asked me a question about pipe(2), I found a weird
    problem.

    The original program which may be picked from somewhere is below:

    #include
    #include

    int main(int argc,char **argv)
    {
    int f_des[2];
    int pid;

    if(argc!=3)
    {
    printf("Usage: %s comand1 comand2\n",argv[0]);
    return 1;
    }
    if(pipe(f_des)==-1)
    {
    perror("cannot creat the IPC pipe");
    return 1;
    }
    pid=fork();
    if(pid==-1)
    {
    perror("cannot creat new process");
    return 1;
    }
    else if(pid==0)
    {
    dup2(f_des[1],STDOUT_FILENO);
    close(f_des[0]);
    close(f_des[1]);
    if(execlp(argv[1],argv[1],NULL)==-1)
    {
    perror("in child process,cannot execute the command");
    return 0;
    }
    }
    else
    {
    dup2(f_des[0],STDIN_FILENO);
    close(f_des[0]),close(f_des[1]);
    if(execlp(argv[2],argv[2],NULL)==-1)
    {
    perror("in parent process,cannot execute the comand");
    return 0;
    }
    }
    return 0;
    }

    If we compile and then run it as './pipe ls less', it behaves
    normally. But if we change it a bit, like this:

    --- pipe.c 2008-08-13 11:39:30.000000000 +0100
    +++ pipe-modified.c 2008-08-13 11:41:13.000000000 +0100
    @@ -24,10 +24,10 @@
    }
    else if(pid==0)
    {
    - dup2(f_des[1],STDOUT_FILENO);
    + dup2(f_des[0],STDIN_FILENO);
    close(f_des[0]);
    close(f_des[1]);
    - if(execlp(argv[1],argv[1],NULL)==-1)
    + if(execlp(argv[2],argv[2],NULL)==-1)
    {
    perror("in child process,cannot execute the command");
    return 0;
    @@ -35,9 +35,9 @@
    }
    else
    {
    - dup2(f_des[0],STDIN_FILENO);
    + dup2(f_des[1],STDOUT_FILENO);
    close(f_des[0]),close(f_des[1]);
    - if(execlp(argv[2],argv[2],NULL)==-1)
    + if(execlp(argv[1],argv[1],NULL)==-1)
    {
    perror("in parent process,cannot execute the comand");
    return 0;


    That is to say we want to run 'less' (use the same arguments to run
    this as above) in child process, then I can't get any output most of
    the time....

    Can anyone please explain why we got this? It shouldn't have any
    difference, right?

    BTW, I am using Linux.

    Thanks!

  2. Re: less behaves differently in parent and child process

    On Aug 22, 10:37 am, WANG Cong wrote:
    > When someone asked me a question about pipe(2), I found a weird
    > problem.
    >
    > The original program which may be picked from somewhere is below:

    [snip]
    > That is to say we want to run 'less' (use the same arguments to run
    > this as above) in child process, then I can't get any output most of
    > the time....
    >
    > Can anyone please explain why we got this? It shouldn't have any
    > difference, right?


    I would guess less(1) checks whether its standard input is a terminal
    (probably with isatty(3)) and disables its fancy terminal display if
    not. A pipe is not a terminal. If you want it to act the same as
    when a terminal is connected, then you need a pseudo-terminal or pty.

  3. Re: less behaves differently in parent and child process

    On Aug 22, 10:37*am, WANG Cong wrote:

    > That is to say we want to run 'less' (use the same arguments to run
    > this as above) in child process, then I can't get any output most of
    > the time....


    The 'less' program is one of those fancy programs that expects to talk
    to a terminal and be able to operate on that terminal. How is it
    supposed to, for example, determine the height and width of a pipe?

    > Can anyone please explain why we got this? It shouldn't have any
    > difference, right?


    If you want to push 'less' around, you need to create your own
    terminal for 'less' to talk to. This is what pty's are for.

    DS

  4. Re: less behaves differently in parent and child process

    On Aug 22, 11:12 pm, David Schwartz wrote:
    > On Aug 22, 10:37 am, WANG Cong wrote:
    > > That is to say we want to run 'less' (use the same arguments to run
    > > this as above) in child process, then I can't get any output most of
    > > the time....

    >
    > The 'less' program is one of those fancy programs that expects to talk
    > to a terminal and be able to operate on that terminal. How is it
    > supposed to, for example, determine the height and width of a pipe?


    The 'less' process in his setup *does* have the terminal as its stdout
    and stderr. All he did was switch the parent/child relationship of
    the 'ls' and 'less' processes.

    The difference the OP is seeing is because of what happens when the
    'ls' exits. In the original setup, the 'ls' was the child of the
    'less', which was the child of the shell. When 'ls' exits there after
    writing all its output, the process which is the direct child of the
    shell, 'less', is still running so the shell continues to wait until
    'less' exits.

    In the altered setup, the 'ls' was the parent of the 'less' and the
    child of the shell. When 'ls' exits after writing its output, the
    'less' process is orphaned and the shell see that its child has
    exited, so the shell changes the foreground process-group of the
    terminal from that of the child back to the shell itself. At that
    point, attempts by 'less' to read() from the terminal or perform
    terminal ioctls will result in EIO errors. 'less' sees those and
    exits.

    That assumes a shell that's job-control aware. If you try this with
    an old version of sh that doesn't do job-control, then you'll see a
    different behavior: after the 'ls' exits, the shell will write the
    prompt and read the next command, even as 'less' shows the output and
    reads its command. With both reading from the terminal, the behavior
    becomes, IIRC, timing and order dependent. And annoying.


    Philip Guenther

  5. Re: less behaves differently in parent and child process

    On 8 24th, 6:42, "guent...@gmail.com" wrote:
    > On Aug 22, 11:12 pm, David Schwartz wrote:
    >
    > > On Aug 22, 10:37 am, WANG Cong wrote:
    > > > That is to say we want to run 'less' (use the same arguments to run
    > > > this as above) in child process, then I can't get any output most of
    > > > the time....

    >
    > > The 'less' program is one of those fancy programs that expects to talk
    > > to a terminal and be able to operate on that terminal. How is it
    > > supposed to, for example, determine the height and width of a pipe?

    >
    > The 'less' process in his setup *does* have the terminal as its stdout
    > and stderr. *All he did was switch the parent/child relationship of
    > the 'ls' and 'less' processes.
    >
    > The difference the OP is seeing is because of what happens when the
    > 'ls' exits. *In the original setup, the 'ls' was the child of the
    > 'less', which was the child of the shell. *When 'ls' exits there after
    > writing all its output, the process which is the direct child of the
    > shell, 'less', is still running so the shell continues to wait until
    > 'less' exits.
    >
    > In the altered setup, the 'ls' was the parent of the 'less' and the
    > child of the shell. *When 'ls' exits after writing its output, the
    > 'less' process is orphaned and the shell see that its child has
    > exited, so the shell changes the foreground process-group of the
    > terminal from that of the child back to the shell itself. *At that
    > point, attempts by 'less' to read() from the terminal or perform
    > terminal ioctls will result in EIO errors. *'less' sees those and
    > exits.



    Excellent answer! Thanks!

    Only one thing to mention, in this situation, 'less' looks like being
    blocked, because I didn't see the shell prompt, is this also expected?

    >
    > That assumes a shell that's job-control aware. *If you try this with
    > an old version of sh that doesn't do job-control, then you'll see a
    > different behavior: after the 'ls' exits, the shell will write the
    > prompt and read the next command, even as 'less' shows the output and
    > reads its command. *With both reading from the terminal, the behavior
    > becomes, IIRC, timing and order dependent. *And annoying.
    >


    Yes, but even I am using a recent bash, the shell prompt still behaves
    very weirdly after 'ls' exit, it looks like the shell can't read from
    keyborad,
    and doesn't know the newline. :-(


  6. Re: less behaves differently in parent and child process

    On 8 23th, 6:12, David Schwartz wrote:
    > On Aug 22, 10:37*am, WANG Cong wrote:
    >
    > > That is to say we want to run 'less' (use the same arguments to run
    > > this as above) in child process, then I can't get any output most of
    > > the time....

    >
    > The 'less' program is one of those fancy programs that expects to talk
    > to a terminal and be able to operate on that terminal. How is it
    > supposed to, for example, determine the height and width of a pipe?
    >
    > > Can anyone please explain why we got this? It shouldn't have any
    > > difference, right?

    >
    > If you want to push 'less' around, you need to create your own
    > terminal for 'less' to talk to. This is what pty's are for.


    Thanks.

    Any more details about how I can create my own terminal for 'less'?


  7. Re: less behaves differently in parent and child process

    On Aug 24, 7:20 am, WANG Cong wrote:
    > On 8 24th, 6:42, "guent...@gmail.com" wrote:
    > > In the altered setup, the 'ls' was the parent of the 'less' and the
    > > child of the shell. When 'ls' exits after writing its output, the
    > > 'less' process is orphaned and the shell see that its child has
    > > exited, so the shell changes the foreground process-group of the
    > > terminal from that of the child back to the shell itself. At that
    > > point, attempts by 'less' to read() from the terminal or perform
    > > terminal ioctls will result in EIO errors. 'less' sees those and
    > > exits.

    ....
    > Only one thing to mention, in this situation, 'less' looks like being
    > blocked, because I didn't see the shell prompt, is this also expected?


    I don't know what you mean by "looks like being blocked". Can you
    describe the output that you're seeing? What happens after you type
    return after that?

    Note that one of the simpler ways to analyze what's happening is in
    this case is to run your program (the one that creates the pipe, etc)
    under a system call tracer, like strace (Linux), truss (Solaris), or
    ktrace (*BSD). For example:
    strace -ff -o trace.out your-program ls less

    The output in 'trace.out' will show which calls by 'less' succeeded
    and which failed with what error.


    > > That assumes a shell that's job-control aware. If you try this with
    > > an old version of sh that doesn't do job-control, then you'll see a
    > > different behavior: after the 'ls' exits, the shell will write the
    > > prompt and read the next command, even as 'less' shows the
    > > output and reads its command. With both reading from the
    > > terminal, the behavior becomes, IIRC, timing and order
    > > dependent. And annoying.

    >
    > Yes, but even I am using a recent bash, the shell prompt still behaves
    > very weirdly after 'ls' exit, it looks like the shell can't read from
    > keyborad,
    > and doesn't know the newline. :-(


    'less' may have been able to change the terminal into 'raw' mode for
    character at a time processing before the 'ls' exited. In that
    situation, you can usually use control-j instead of enter. For
    example you can reset the terminal by typing
    stty sane

    (The first is the give you a new prompt, in case there's
    some thing still in the input buffer.)


    Note that some shells (ksh, IIRC) will automatically reset the most
    critical terminal settings whenever they are expecting input, so the
    behavior in this case is both system and shell dependent.


    Philip Guenther

  8. Re: less behaves differently in parent and child process

    On Aug 24, 9:08, "guent...@gmail.com" wrote:
    > On Aug 24, 7:20 am, WANG Cong wrote:
    >
    > > On 8 24th, 6:42, "guent...@gmail.com" wrote:
    > > > In the altered setup, the 'ls' was the parent of the 'less' and the
    > > > child of the shell. *When 'ls' exits after writing its output, the
    > > > 'less' process is orphaned and the shell see that its child has
    > > > exited, so the shell changes the foreground process-group of the
    > > > terminal from that of the child back to the shell itself. *At that
    > > > point, attempts by 'less' to read() from the terminal or perform
    > > > terminal ioctls will result in EIO errors. *'less' sees those and
    > > > exits.

    > ...
    > > Only one thing to mention, in this situation, 'less' looks like being
    > > blocked, because I didn't see the shell prompt, is this also expected?

    >
    > I don't know what you mean by "looks like being blocked". *Can you
    > describe the output that you're seeing? What happens after you type
    > return after that?


    I mean I can't see the shell prompt at once, thus looks like being
    blocked.
    After I type 'return', I got a shell prompt but no newline.

    >
    > Note that one of the simpler ways to analyze what's happening is in
    > this case is to run your program (the one that creates the pipe, etc)
    > under a system call tracer, like strace (Linux), truss (Solaris), or
    > ktrace (*BSD). *For example:
    > * * strace -ff -o trace.out your-program ls less
    >
    > The output in 'trace.out' will show which calls by 'less' succeeded
    > and which failed with what error.



    Yes, I did so.


    >
    > > > That assumes a shell that's job-control aware. *If you try this with
    > > > an old version of sh that doesn't do job-control, then you'll see a
    > > > different behavior: after the 'ls' exits, the shell will write the
    > > > prompt and read the next command, even as 'less' shows the
    > > > output and reads its command. *With both reading from the
    > > > terminal, the behavior becomes, IIRC, timing and order
    > > > dependent. *And annoying.

    >
    > > Yes, but even I am using a recent bash, the shell prompt still behaves
    > > very weirdly after 'ls' exit, it looks like the shell can't read from
    > > keyborad,
    > > and doesn't know the newline. :-(

    >
    > 'less' may have been able to change the terminal into 'raw' mode for
    > character at a time processing before the 'ls' exited. *In that
    > situation, you can usually use control-j instead of enter. *For
    > example you can reset the terminal by typing
    > * *stty sane
    >
    > (The first is the give you a new prompt, in case there's
    > some thing still in the input buffer.)
    >
    > Note that some shells (ksh, IIRC) will automatically reset the most
    > critical terminal settings whenever they are expecting input, so the
    > behavior in this case is both system and shell dependent.
    >


    I see. Thanks very much!


+ Reply to Thread