Lazarus

Programming => General => Topic started by: salamander on December 10, 2013, 10:25:16 pm

Title: Tprocess behaviour
Post by: salamander on December 10, 2013, 10:25:16 pm
With Tprocess I can succesfully read from Stderr if the app being running was mine, however if I was executing bash (which displays its prompt to Stderr) I receive nothing on Stderr!

I think, it's bash only problem.

Any clues?


Code: [Select]
{$mode objfpc}{$H+}
program proc_sh;
uses process, math, classes, sysutils;
var
        p1: TProcess;
        msg: string;
        buf: array[1..1024] of char;
        count, c: integer;
        resp: TStrings;
begin
        p1 := TProcess.Create(nil);
        p1.Executable := '/bin/sh';
        p1.Options := [{poStderrToOutPut,} poUsePipes];
        p1.Execute;

        while (p1.Running) or (p1.Stderr.NumBytesAvailable > 0) do
        begin
                ReadLn(msg);
                msg := msg + #10;
                p1.Input.Write(msg[1], Length(msg));
                Sleep(100);
                while p1.Stderr.NumBytesAvailable > 0 do
                begin
                        WriteLn('Got: ', p1.Stderr.NumBytesAvailable);
                        count := Min(p1.Stderr.NumBytesAvailable, SizeOf(buf));
                        WriteLn('Min: ', count);
                        p1.Stderr.Read(buf[1], count);
                        WriteLn(Copy(buf, 1, count));
                end;
        end;
        c := p1.ExitStatus;
        p1.Free;
end.

Code: http://pastebin.com/URw2hacm
Title: Re: Tprocess behaviour
Post by: marcov on December 11, 2013, 10:43:30 am

A small guess:

Probably the shell is started with an empty environment and thus an empty prompt. Maybe you must do some work to make sure that sh inherits the parent's environment.

stderr is read, because

ls --crazy-param=1

gives a nice stderr msg.
Title: Re: Tprocess behaviour
Post by: salamander on December 12, 2013, 07:39:04 am
Looks like you are correct. When I tried to type ls --somecrazy, it redirected stderr correctly. I can even confirm that with C. However, the strange problem is where does bash redirect its command prompt if it's not stdout or stderr?

I thought bash used stderr for displaying its prompt, because:
/bin/sh 2> /dev/null
everything will work fine, except no prompt will be displayed.
While:
/bin/sh > /dev/null
only the prompt will be displayed.

I started to believe that it has something to do with pty. (bash might be writing directly to /dev/pts/x instead of stdout/stderr) Can anyone confirm that???
Title: Re: Tprocess behaviour
Post by: marcov on December 12, 2013, 10:01:48 am
Looks like you are correct. When I tried to type ls --somecrazy, it redirected stderr correctly. I can even confirm that with C. However, the strange problem is where does bash redirect its command prompt if it's not stdout or stderr?

It's more that if you don't set the prompt enviroment variable, there is none.
 
Title: Re: Tprocess behaviour
Post by: salamander on December 12, 2013, 10:31:53 am
It's more that if you don't set the prompt enviroment variable, there is none.
I tried to set PS1 to [\u@\h \W]\$ but the problem still exist.
Looks like in order to execute shell interpreters correctly, one should use openpty()/forkpty().
Title: Re: Tprocess behaviour
Post by: marcov on December 12, 2013, 10:38:42 am
It's more that if you don't set the prompt enviroment variable, there is none.
I tried to set PS1 to [\u@\h \W]\$ but the problem still exist.

Where? In TProcess, in the spawned shell, or somewhere before executing the FPC/Lazarus program?
Title: Re: Tprocess behaviour
Post by: salamander on December 12, 2013, 11:29:30 am
Where? In TProcess, in the spawned shell, or somewhere before executing the FPC/Lazarus program?
I tried in the spawned shell.
Title: Re: Tprocess behaviour
Post by: salamander on December 13, 2013, 09:02:46 pm
According to this blog post http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/ (http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/):

Quote
Can't I just use pipes?
No, you can’t. Of course, pseudo terminals do use pipes. But for terminals (and pseudo terminals), the kernel stores special information such as the window size of the terminal. If you just use pipes, a clever child process will be able to detect that its stdin and stdout streams are pipes and do not belong to a terminal. Some programs will change how they output results based on this fact.

From that, I can deduce that bash (or any other shell) can detect that its stdin/out/err are pipes and act differently. Thus, the correct way to go, is to use forkpty() and its siblings.

I am posting this because it might be useful to others.
Title: Re: Tprocess behaviour
Post by: Leledumbo on December 14, 2013, 07:28:19 am
Quote
According to this blog post http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/:
Ah... so that's why I can't wrap python interpreter either...
TinyPortal © 2005-2018