Recent

Author Topic: aprocess.environment  (Read 1089 times)

toby

  • Jr. Member
  • **
  • Posts: 66
aprocess.environment
« on: July 26, 2019, 07:04:41 pm »

in this example from
http://free-pascal-general.1045716.n5.nabble.com/Something-like-TProcess-Environment-for-libraries-td5727468.html
with
AProcess.Environment.Text := 'LD_LIBRARY_PATH=' + alibrarypath;

it adds just one like   shouldn it be a  '+='  thing?
AProcess.Environment.Text := AProcess.Environment.Text + 'LD_LIBRARY_PATH=' + alibrarypath;

---

and in my code trying to use aprocess.environment

var ts : tstrings
    s : ansistring;

..

ts := aprocess.environment;
s := ansistring(ts);
//writeln(s); // get output looks like env  then get  unhandled exception occurred at $08049252:  EAccessViolation: Access violation
// with above commented
writeln(length(s)); // 508001

s := aprocess.environment.text;
write(s); // nothing
writeln(length(s)); // 0

aprocess.environment.text := 'LD_LIBRARY_PATH=' + '/lib1'; // addes #10

ts := aprocess.environment;
s := ansistring(ts);
//writeln(s); // bad output but looks like   shortened env   then get above exception
writeln(length(s)); // 508001  same number above

s := aprocess.environment.text;
write(s); // LD_LIBRARY_PATH=/lib1
writeln(length(s)); // 22

---

from docs-3.0.4/html/fcl/process/tprocess.environment.html
Environment contains the environment for the new process; it's a list of Name=Value pairs, one per line.
If it is empty, the environment of the current process is passed on to the new process.

qyestion since aprocess.environment doesn't 'look' empty - what am i doing wrong and about the += situation above


lucamar

  • Hero Member
  • *****
  • Posts: 2147
Re: aprocess.environment
« Reply #1 on: July 26, 2019, 09:55:03 pm »
Environment is a TStrings object; you can not go around happily typecasting it to a string (as you have, no doubt, discovered).

As for your question, it all depends on what you want to do. If you want the environment for the process to have only that line, then set Environment.Text and you're done.

If what you want is to add that line to the current environment and pass that environment to the process then you'll have to copy it first. A possible way of doing it would be:
Code: Pascal  [Select]
  1.   Process.Environment.Clear;
  2.   { Copy the current environmet }
  3.   for i := 0 to EnvCount-1 do
  4.     Process.Environment.Add(EnvStr(i));
  5.   { Set LIB_PATH }
  6.   Process.Environment.Values['LD_LIBRARY_PATH'] := '/whatever';
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

toby

  • Jr. Member
  • **
  • Posts: 66
Re: aprocess.environment
« Reply #2 on: July 26, 2019, 11:27:49 pm »

so the aprocess.environment.text starts out empty then?

what is all the stuff in the tstrings variable?
is it happen to be just 'allocated memory' that still has my prior env stuff in it?
the size (length in the code) stays the same cause it is the size of the allocated memory? (when the .text is empty or just has one line in it)

from the manpage
If it is empty, the environment of the current process is passed on to the new process.

then where is the actually environment of the new process stored?
in the sysutils.getenvironmentstring or dos.envstr and the tprocess.environment is in addition or in substitution of these?

so what is the purpose of the aprocess.envirment

lucamar

  • Hero Member
  • *****
  • Posts: 2147
Re: aprocess.environment
« Reply #3 on: July 27, 2019, 12:05:10 am »
You can get a more detailed view by diving into the source code of the process unit but very basically, what it does is build the parameters needed for the system functions calls it uses to run a command according to the set of properties of TProcess.

To some of those system functions one can pass a pre-built environment, which is basicaly a chunk of memory whose bytes just happen to spell, some way or other, those strings we are used to. If Environment is not empty then that chunk of memory is built anew and set from the strings in it; otherwise the system usually just makes a copy of the parent's one by itself.

Now, your questions:

Quote
so the aprocess.environment.text starts out empty then?

Yes. It's only needed to change the default, which is to use the parent's (your program's) environment.

Quote
what is all the stuff in the tstrings variable?
is it happen to be just 'allocated memory' that still has my prior env stuff in it?

Yes, it's just garbage. And note that it's *not* in the TStrings variable: you're seeing it because the typecast of TStrings to String is causing you to access random zones of memory.

Quote
the size (length in the code) stays the same cause it is the size of the allocated memory? (when the .text is empty or just has one line in it)

No. When you ask for the length of a string, it's taken from a field of the internal "header" of the AnsiString (there's where the codepage and other info is stored). Since your "string" points to random memory, that "length" just represents whatever was in that memory chunk, with no relation whatever to any real string length.

Quote
then where is the actually environment of the new process stored?
in the sysutils.getenvironmentstring or dos.envstr and the tprocess.environment is in addition or in substitution of these?

The actual environment is stored in a chunk of memory controlled by the OS. What those functions in sysutils, dos, etc. do is read it from there and "massage" it to a form more suitable to be used in a Pascal program.

The environment for a new process is actually created by the system after the fork/exec/whatever call that prepares it. Some of those calls allow you to tell the system: "Hey, I have a pre-built environment you can use", but it's usually not needed unless you want the child process to use a specific one.

Quote
so what is the purpose of the aprocess.envirment

To make the child process use a environment with something other than what the parent's has. In this case, for example, a different "LD_LIBRARY_PATH".


Ultra long post, isn't it? Hope all this helps! :)
« Last Edit: July 27, 2019, 12:09:39 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

toby

  • Jr. Member
  • **
  • Posts: 66
Re: aprocess.environment
« Reply #4 on: July 27, 2019, 12:14:07 am »
it sure does

so if want to add something like the LD_LIB  should i copy all the getenv into it (like in your code example or just the add the one LD line?


lucamar

  • Hero Member
  • *****
  • Posts: 2147
Re: aprocess.environment
« Reply #5 on: July 27, 2019, 12:28:13 am »
You should copy all. Otherwise the child's environment will only have that line and nothing else.

Talk about "poor environments"! :)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

toby

  • Jr. Member
  • **
  • Posts: 66
Re: aprocess.environment
« Reply #6 on: July 27, 2019, 02:27:50 am »
your code is good except

for i := 0 to envcount-1 do   ->   for i := 1 to envcount do

---

the aprocess.environment 'adjusts' the results of /bin/env for the local process

i would guess that /bin/env lives in the /proc but a grep never finished so can only guess
edit : it lives in      cat /proc/<pid>/environ


---

if you don't use

aprocess.environment.add('LD_LIBRARY_PATH=' + '/lib1');

and at any time use    aprocess.environment.text := 'LD_LIBRARY_PATH=' + '/lib1';              or getenv(0) :) in the loop in your code

there is a 'minimum' /bin/env that results


LD_LIBRARY_PATH=/lib1
PWD=/fpc/current/envar
SHLVL=1
_=/bin/env

thanks this is pretty interesting and comes from the other env post interest   
https://forum.lazarus.freepascal.org/index.php/topic,45987.0.html?PHPSESSID=dccs1i13d4mhur093dgev7bsa7

---

using the dos unit envstr(   has env lenght limit of 255     
while sysutls getenvironmentstring   doesn't

« Last Edit: July 27, 2019, 03:37:32 am by toby »

lucamar

  • Hero Member
  • *****
  • Posts: 2147
Re: aprocess.environment
« Reply #7 on: July 27, 2019, 03:39:39 am »
for i := 0 to envcount-1 do   ->   for i := 1 to envcount do

Are you sure? Both the documentation and my tests agree: EnvStr() is zero-based, so its argument goes from 0 to EnvCount-1

ETA: I see where the confussion arises. I'm using the old-style functions in the dos unit which work as I said above, but if one uses the functions in sysutils it's indeed:
Code: Pascal  [Select]
  1. for i := 1 to GetEnvironmentVariableCount do
  2.   Process.Environment.Add(GetEnvironmentString(i));


Quote
if you don't use
aprocess.environment.add('LD_LIBRARY_PATH=' + '/lib1');
and at any time use    aprocess.environment.text := 'LD_LIBRARY_PATH=' + '/lib1';
or getenv(0)  in the loop in your code there is a 'minimum' /bin/env that results [... etc...]

Huh? env is a normal command (usually at /usr/bin, not /bin), useful in its way if you want to do what we are talking about with, say, a bash script. Beyond that, it has no relation at all with this thread and it matters little what it does or doesn't: it doesn't affects how you use TProcess
« Last Edit: July 27, 2019, 04:06:19 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

toby

  • Jr. Member
  • **
  • Posts: 66
Re: aprocess.environment
« Reply #8 on: July 27, 2019, 04:43:54 am »

actually envstr is 1 based and the dos functions give the exact results as sysutils functions except for the 255 length limit on vars length

https://www.freepascal.org/docs-html/rtl/dos/envstr.html

i do all my linux from source so configure coreutils with  prefix=/      hence the /bin/env

it is all about env  and   the aprocess.environment affects what the env command produces 

if you have nothing in the aprocess.environment from doing nothing with a clean process or clearing it
where length(aprocess.environment.text) is 0
then you get what the env is  (even says this in the man page)

if you do anything to the aprocess.environment,  env gets what you do to the aprocess.environment with minimum of

PWD=/fpc/current/envar
SHLVL=1
_=/bin/env

you can add just a letter L but it won't show in the env  if what you add is a valid  (name=value)xn  then that is in env
the aprocess.environment is just a tstrings



lucamar

  • Hero Member
  • *****
  • Posts: 2147
Re: aprocess.environment
« Reply #9 on: July 27, 2019, 05:39:23 am »
actually envstr is 1 based and the dos functions give the exact results as sysutils functions except for the 255 length limit on vars length
https://www.freepascal.org/docs-html/rtl/dos/envstr.html

Did you actually test? I did. But let's quote that same page you point to:
Quote
EnvStr returns the Index-th Name=Value pair from the list of environment variables. The index of the first pair is zero
Nuff said, me thinks ;)
Except to point out that the dos functions return an AnsiString (in platforms other than Plain DOS), so no 255 limit either.


Quote
it is all about env  and   the aprocess.environment affects what the env command produces 
[... long etc snipped ...]

Let's repeat: env is just a command, like rm, cp, ls, apropos, which, whereis, whoami, ... I has nothing at all to do with how TProcess works.

The only relation is a conceptual one: it's a program to execute other programs with a tailored environment, which you can also do (in your own program) with TProcess. Beyond that? No relation at all.
« Last Edit: July 27, 2019, 05:44:20 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

toby

  • Jr. Member
  • **
  • Posts: 66
Re: aprocess.environment
« Reply #10 on: July 28, 2019, 10:49:28 pm »
i suggest you don't believe everything you read in the almost perfect man pages - the only real way is to run code and see what it really does

both the envstr and getenviromentstring   don't current have a real index origin (where using wrong index gives error) i have -Cr in the /etc/fpc.cfg and that should do it??

you can run  for i := -100 to envcount do

with  i <= 1  it gives  envstr[1]  that means envstr[0] gives what the envst[1] is - the real first envstr is envstr(1) and not envstr(0)
and if you also use the i top bound with (envcount - 1) then you don't get the last one

the example on the envstr man page gives the correct indices

---

you might want to   do   man env   it is pefect to use here to see what the env variables are in the child process
using env with aprocess.execute is the only way i can find to see what the real environment is in the process once aprocess.environment is changed

the envstr variables are not affected by the aprocess.environment changes here and can only be used to setup an aprocess.environment

so you comments about env not being proper here is completely wrong


« Last Edit: July 28, 2019, 11:11:09 pm by toby »

lucamar

  • Hero Member
  • *****
  • Posts: 2147
Re: aprocess.environment
« Reply #11 on: July 28, 2019, 11:47:38 pm »
You're mixing quite a lot of completely unrelated things: man pages and FPC documentation, Unix commands and FPC functions, oranges and pearls, ...

And despite your snide suggestion about running code, you don't seem to have done any tests to respald your affirmations or you'd have seen you're wrong.

I give up. It's not worth the effort.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

toby

  • Jr. Member
  • **
  • Posts: 66
Re: aprocess.environment
« Reply #12 on: July 28, 2019, 11:58:06 pm »
i have written several programs to test this - you haven't dude   so stop the nonsense

and you have no clue about env or what it does so again stop the nonsense

toby

  • Jr. Member
  • **
  • Posts: 66
Re: aprocess.environment
« Reply #13 on: July 29, 2019, 12:14:33 am »
program test1;

uses classes, sysutils, process;

var aprocess : tprocess;
    astringlist : tstringlist;
    cli, s : ansistring;
    i : longint;

begin

aprocess := tprocess.create(nil);
astringlist := tstringlist.create;

writeln;

for i := -100 to (getenvironmentvariablecount - 1) do writeln('getenvironmentstring(', i, ') : ', getenvironmentstring(i));

writeln;

//cli := '/bin/bash -c "/bin/env | /bin/grep -rn SHLVL 2> /dev/null"';
//cli := '/bin/bash -c "/bin/env | /bin/grep -rn LESS 2> /dev/null"';
cli := '/bin/bash -c "/bin/env"';
writeln(cli); //
aprocess.commandline := cli;
aprocess.options := aprocess.options + [powaitonexit, pousepipes];
aprocess.execute;
astringlist.loadfromstream(aprocess.output);
s := astringlist.text;
writeln(s);

writeln;

writeln('aprocess.environment.text');
writeln(aprocess.environment.text);

writeln;

writeln('aprocess.environment.values[''LD_LIBRARY_PATH''] := ''-MMM''');
aprocess.environment.values['LD_LIBRARY_PATH'] := '-MMM';

writeln;

writeln('aprocess.environment.text');
writeln(aprocess.environment.text);

writeln;

//cli := '/bin/bash -c "/bin/env | /bin/grep -rn SHLVL 2> /dev/null"';
//cli := '/bin/bash -c "/bin/env | /bin/grep -rn LESS 2> /dev/null"';
cli := '/bin/bash -c "/bin/env"';
writeln(cli); //
aprocess.commandline := cli;
aprocess.options := aprocess.options + [powaitonexit, pousepipes];
aprocess.execute;
astringlist.loadfromstream(aprocess.output);
s := astringlist.text;
writeln(s);

for i := 1 to getenvironmentvariablecount do writeln('getenvironmentstring(', i, ') : ', getenvironmentstring(i));

astringlist.free;
aprocess.free;

end.

where is the change to aprocess.environment in the    fetenvironmentstring ?   it isn't there is it
only the env shows that changes made to the aprocess.environment

« Last Edit: July 29, 2019, 12:31:04 am by toby »

lucamar

  • Hero Member
  • *****
  • Posts: 2147
Re: aprocess.environment
« Reply #14 on: July 29, 2019, 12:24:56 am »
where is the change to aprocess.environment in the getenvironmentstring ?   it isn't there is it
only the env shows that changes made to the aprocess.environment

Do you realize that AProcess.Environment is the environment for the child (as demonstrated by your simplistic use of env) but that GetEnvironmentString returns the program's own environment?

That's what TProcess.Environment is for: to pass a different environment to the children, not to modify the parent's one.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.