aprocess.environment lazarus / 32-Linux ---------------------------------------------------------------------- toby · 2019-07-26 17:04 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 · 2019-07-26 19:55 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   Process.Environment.Clear;  { Copy the current environmet }  for i := 0 to EnvCount-1 do    Process.Environment.Add(EnvStr(i));  { Set LIB_PATH }  Process.Environment.Values['LD_LIBRARY_PATH'] := '/whatever'; ---------------------------------------------------------------------- toby · 2019-07-26 21:27 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 · 2019-07-26 22:05 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: Quoteso 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. Quotewhat 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. Quotethe 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. Quotethen 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. Quoteso 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! ---------------------------------------------------------------------- toby · 2019-07-26 22:14 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 · 2019-07-26 22:28 You should copy all. Otherwise the child's environment will only have that line and nothing else. Talk about "poor environments"! ---------------------------------------------------------------------- toby · 2019-07-27 00:27 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//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? --- using the dos unit envstr(   has env lenght limit of 255    while sysutls getenvironmentstring   doesn't ---------------------------------------------------------------------- lucamar · 2019-07-27 01:39 Quote from: toby on July 27, 2019, 02:27:50 amfor 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i for i := 1 to GetEnvironmentVariableCount do  Process.Environment.Add(GetEnvironmentString(i)); Quoteif 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 ---------------------------------------------------------------------- toby · 2019-07-27 02:43 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 · 2019-07-27 03:39 Quote from: toby on July 27, 2019, 04:43:54 amactually 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: QuoteEnvStr returns the Index-th Name=Value pair from the list of environment variables. The index of the first pair is zeroNuff 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. Quoteit 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. ---------------------------------------------------------------------- toby · 2019-07-28 20:49 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 ---------------------------------------------------------------------- lucamar · 2019-07-28 21:47 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. ---------------------------------------------------------------------- toby · 2019-07-28 21:58 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 · 2019-07-28 22:14 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 ---------------------------------------------------------------------- lucamar · 2019-07-28 22:24 Quote from: toby on July 29, 2019, 12:14:33 amwhere 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. ---------------------------------------------------------------------- toby · 2019-07-28 22:36 dude you are being dishonest here the discussion has alway been about the child process and not about the parent process that is what aprocess.environment does lol where are you apolgy for you code comment and for the for i := -100 to (getenvironmentvariablecount - 1) do writeln('getenvironmentstring(', i, ') : ', getenvironmentstring(i)); simplistic use of env?   lol   you are to dishonest to deal with     i was the one saying what you are now saying  and you said it wasn't true ---------------------------------------------------------------------- lucamar · 2019-07-28 23:10 You get one apology (and a correction) because DOS.EnvStr() effectively starts form one, despite what the documentation says. For some reason my previous test was giving correct results even for EnvStr(0). In a new even simpler one it just returns an empty string (as do anything other than [1..EnvCount]). As for this: Quote from: toby on July 29, 2019, 12:36:51 amthe discussion has alway been about the child process and not about the parent process that is what aprocess.environment does lol That has been exactly my contention all along! It's now clear that we have been talking at cross-purposes. If you had started by saying: "I am running env with a TProcess to check what the passed environment looks like and ..." we would not have wasted so many electrons. So let's just leave it here, forget the hot words caused by temper and close the discussion, shall we? ---------------------------------------------------------------------- toby · 2019-07-28 23:18 okay you have been very very helpful - so thanks  even the 'misunderstanding' has been greatly helpful in exploring things and understanding what is capable with the fpc coding but the only way you can use env is in a tprocess ---------------------------------------------------------------------- dsiders · 2019-07-28 23:20 Quote from: toby on July 29, 2019, 01:18:07 amokay you have been very very helpful - so thanks  even the 'misunderstanding' has been greatly helpful in exploring things and understanding what is capable with the fpc coding but the only way you can use env is in a tprocess Try decaf. ---------------------------------------------------------------------- lucamar · 2019-07-29 00:02 Quote from: toby on July 29, 2019, 01:18:07 ambut the only way you can use env is in a tprocess Or on a terminal. ---------------------------------------------------------------------- toby · 2019-07-29 00:31 yea but won't help much in working with aprocess.environment ---------------------------------------------------------------------- PascalDragon · 2019-07-29 07:17 Quote from: lucamar on July 29, 2019, 01:10:42 amYou get one apology (and a correction) because DOS.EnvStr() effectively starts form one, despite what the documentation says.That should probably be reported then... (especially as the example in the documentation starts at 1 )