Hi!
I need to set up LIBOVERLAY_SCROLLBAR=0 on Ubuntu 64bit, but there LIBC is not supported and therefore I am looking for SetEnv which I can use on 64bit Linux.
SysUtils contains only GetEnvironmentVariable, but not Set...
Thx, f.

Mailing lists / lazarus / 2012-04
22 messages · 7 people · –
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
Hi!
I need to set up LIBOVERLAY_SCROLLBAR=0 on Ubuntu 64bit, but there LIBC is not supported and therefore I am looking for SetEnv which I can use on 64bit Linux.
SysUtils contains only GetEnvironmentVariable, but not Set...
Thx, f.
That's not how it works on Unix/Linux.
You must always set up environment variables before a program starts. When starting a process, the environment for that process is started and is then immutable for the duration of the process.
What you can do is execute the same binary again, but with the environment variable added to the environment of the new process.
Michael.
(and even if you manage to change the copy of the process, the libraries startup code will have already been run before you make that change to the copy of the environment)
Hence the 'immutable'...
Michael.
Hi guys,
I try to start itself again with this code, but it doesn't work:
IF GetEnvironmentVariable('LIBOVERLAY_SCROLLBAR') '0' THEN begin
mProc := TProcess.Create(NIL);
mProc.CommandLine := GetExeName;
mProc.Environment.Add('LIBOVERLAY_SCROLLBAR=0');
mProc.Environment.Add('UBUNTU_MENUPROXY=');
mProc.Options := mProc.Options + [poNoConsole];
mProc.Execute;
mProc.Free;
halt; //close itself
END;What's wrong with this code?
Tnx, f.
That's not how it works on Unix/Linux. You must always set up environment variables…
ewww... so no "fancy" capabilities like we could do in the old DOS days where we could change the base environment as well as cloning it with changes for child processes??? if so, that's blows several of my porting projects up :? :(
What you can do is execute the same binary again, but with the environment variable added to the environment of the new process.
so, like the cloning process i mention above? that would have two copies of the app in memory at once, right?
Not possible on Posix platforms.
If you do an fpExec() without first a fpFork() you'll have only 1 copy in memory. fpExec replaces the current process with a new process, and a new environment can be specified for the new process.
Michael.
I try to start itself again with this code, but it doesn't work: IF…
I'm can't say for sure that this is your problem but in the past I have observed that TProcess dumps all the inherited environment vairables as soon as you add something to it. On linux this means that the DISPLAY environment variable is not set.
You'll need something like this:
for i := 0 to GetEnvironmentVariableCount-1 do
begin
EnvVarName := GetEnvironmentString(i);
EnvVarValue := GetEnvironmentVariable(EnvVarName);
mProc.Environment.Add(EnvVarName+'='+EnvVarValue);
end;
mProc.Environment.Add('LIBOVERLAY_SCROLLBAR=0');Regards,
Andrew Haines
That's not how it works on Unix/Linux. You must always set up environment variables…
How does setenv work in libc? For instance you need to use that at runtime to embed a SDL window into your application. (only one sdl window per application works)
Regards,
Andrew Haines
Not possible on Posix platforms. If you do an fpExec() without first a fpFork() you'll…
so i've been hearing over the years :( but i've kept on searching for a solution :P
that is seemingly like the clone of the initial environment plus modifications... yes... maybe my historical project ports are not all blown up :)
Not possible on Posix platforms. If you do an fpExec() without first a fpFork() you'll…
2012/4/3 Michael Van Canneyt :
Now I'm confused. AFAICS
(http://pubs.opengroup.org/onlinepubs/007904975/functions/setenv.html) Posix setenv() allows a process to mutate its environment variables.
I probably misunderstood something, can someone enlighten me please?
-- jan
You can always modify them (it's just data in memory), but modifying them will only change your private view of the variables. The changes you make will not propagate to libraries or newly started processes.
Therefor it makes no sense to change them, and the FPC runtime does not allow it. If we did allow it, people would expect DOS/Windows like behaviour, which we simply cannot provide.
If you read the second part of the provided URL, you'll see that the POSIX group recognises that the behaviour of setenv() is problematical.
The URL points - for restrictions - to the exec function
http://pubs.opengroup.org/onlinepubs/007904975/functions/exec.html
Where it says:
"For those forms not containing an envp pointer ( execl(), execv(), execlp(), and execvp()), the environment for the new process image shall be taken from the external variable environ in the calling process."
Etc etc etc.
Michael.
2012/4/4 :
Thank you for the help. Unfortunately I'm now confused even more. I believe it's my fault, not yours.
You can always modify them (it's just data in memory), but modifying them will only change your private view of the variables. The changes you make will not propagate to libraries or newly started processes.
If "library" means a .so (or .dll, but Windows are not that much of a Posix system), then it is in in-process space, so I would think the change *does* propagate, i.e. the change is observable by a call to getenv() from inside a library function. About started processes see below.
The extrn char **environ (just environ from now on) points to the environment variables of the executing process. Setenv may mutates this environment. The various forms of exec do have either explicit envp, so one can create any required environment vars set, or pass the current environ, effectively enabling the inheritance of the (posibly mutated) environment as an option.
The other forms, w/o envp, are defined to do exactly that, i.e. they will use the current environ as their environment vars pointer, effectively forcing the inheritance of the (possibly mutated) environment. ("the environment for the new process image shall be taken from the external variable environ in the calling process")
I honestly presume I'm extra dumb today, anyway it still seems to me like the opposite of what was said in this thread is true:
Environment variables can be mutated, the changes are visible in a library (.so or and maybe in a .dll too) and with exec() one can choose if to pass a new environment or if the current one is to be inherited.
Apologies, I don't want to sound like a troll, I just want to figure out why the same Posix specs can be seen/interpreted in two mutually exclusive ways and naturally - which one is the correct interpretation.
PS: I've just cross-checked with some other language (Go if you are curious) and its std library and there seems to work all like I think the Posix specs says (http://golang.org/pkg/os/#Setenv and http://golang.org/pkg/os/exec/#Cmd) and I think the high level (and cross platform, Go programs should behave identically on Linux and Windows) wrapper of the Go 'os' package just reiterates the standard Posix behavior in a libc independent way.
-- jan
Typically, libraries will read the environment subsequent change to the environment will not have any effect.
Not the current.
The EXTERNAL variable environ, i.e. the one that the kernel passed on, which cannot be modified. You can only modify your local copy.
Michael.
2012/4/4 :
Not the current. The EXTERNAL variable environ, i.e. the one that the kernel passed on, which cannot be modified. You can only modify your local copy.
14:00 myname at tux64:~/tmp/c$ ls
a.c b.c
14:00 myname at tux64:~/tmp/c$ cat a.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
main() {
char *e = getenv("MYVAR");
printf("a1: %s\n", e);
setenv("MYVAR", "MYVALUE", 1);
e = getenv("MYVAR");
printf("a2: %s\n", e);
execv("./b.out", NULL);
}
14:00 myname at tux64:~/tmp/c$ cat b.c
#include <stdlib.h>
#include <stdio.h>
main() {
char *e = getenv("MYVAR");
printf("b: %s\n", e);
}14:00 myname at tux64:~/tmp/c$ gcc -o a.out a.c && gcc -o b.out b.c && ls a.c a.out b.c b.out
14:00 myname at tux64:~/tmp/c$ ./a.out
a1: (null)
a2: MYVALUE
b: MYVALUE
14:00 myname at tux64:~/tmp/c$
-- jan
Output of strace:
brk(0) = 0x21a5000 brk(0x21c6000) = 0x21c6000 write(1, "a2: MYVALUE\n", 12a2: MYVALUE
) = 12
execve("./b.out", [0], [/* 57 vars */]) = 0
brk(0) = 0x189e000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
As you can see, it uses execve() behind the scenes to be able to pass the modified local environment.
This is libc-specific behaviour.
Michael.
2012/4/4 :
I think I cannot agree. IMO its a POSIX specified behavior. libc, at least in this case, just implements the POSIX specs: http://pubs.opengroup.org/onlinepubs/007904975/functions/exec.html
And as the ouptut of executing a.out shows, libc implements it correctly: "For those forms not containing an envp pointer ( execl(), execv(), execlp(), and execvp()), the environment for the new process image shall be taken from the external variable environ in the calling process.", which libc achieves by calling execve() with the current environ, effectively just filling the prescribed default.
'extern **char environ' is no [kernel] magic*, it's just an ordinary pointer variable sitting in the process address space, it's only special in that it gets set (by means which are not important to this discussion) before main() starts executing.
-- jan
(*) One can e.g. happily set it directly to any other value:
14:41 myname at tux64:~/tmp/c$ cat a.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
extern char **environ;
main() {
char *e = getenv("MYVAR");
printf("a1: %s\n", e);
setenv("MYVAR", "MYVALUE", 1);
e = getenv("MYVAR");
printf("a2: %s\n", e);
environ = NULL;
e = getenv("MYVAR");
printf("a3: %s\n", e);
}
14:41 myname at tux64:~/tmp/c$ gcc a.c && ./a.out
a1: (null)
a2: MYVALUE
a3: (null)
14:41 myname at tux64:~/tmp/c$I do not agree with this interpretation.
First of all, you are calling execv() in your code, not execve(). That libc changes this to execve() is IMHO not permissible. So all bets and conclusions are off from that point onwards.
Secondly, we interpret differently 'external variable environ'. (note the 'external'). For me this clearly means the original environment as passed on to the current process. Which probably is what happens if you'd call the execv() kernel function, although that would need testing.
Thirdly, the 2 referenced pages clearly indicate that the whole environment handling is hairy at best in corner cases like this.
And lastly: We on purpose do not follow Libc;
Otherwise we'd simply have built the whole RTL on top of it. So we are not under any obligation to mimic its behaviour.
Michael.
2012/4/4 : 14:00 myname at tux64:~/tmp/c$ ls a.c b.c 14:00 myname at tux64:~/tmp/c$ cat…
[trim]
your example shows a shell... i may have added to the confusion because a trick i recall us doing in the DOS days was to change the master environment... after running ./a.out, do you see your MYVAR in the environment via "set | more" or "export | more" or whatever?? most likely you will not see your MYVAR at that point after a.out finishes execution... i believe this is what was being pointed to as not supported...
my apologies if i added confusion...
I do not agree with this interpretation. First of all, you are calling execv() in your…
2012/4/4 :
Why not permissible? The POSIX specs describe what the semantics and/or effects of executing a defined function are. The semantics and effects of libc's execv() are what is said about it in POSIX. I don't see any 'off' conclusion derivable ;-)
current environment. Initially, as it was passed, after any mutation well, that mutated state. No copy of the original environment of a process exists anywhere in the process nor in the kernel. A copy might still exists, though not necessarily, in the originating process, but that is anyway not accessible by the new/now executing process (modulo shmem etc.).
Also the 'external variable' is just a reference to the C specification, i.e. that's the way C says to the linker to find the variable defined elsewhere, not in this compilation unit/produced object code.
Which probably is what happens if you'd call the execv() kernel function, although that would need testing.
I can perhaps save someone's time, as there's no execv() kernel call. There's only execve() and that's why a POSIX compliant libc calls execve() with the current value of environ.
Thirdly, the 2 referenced pages clearly indicate that the whole environment handling is hairy at best in corner cases like this.
Perhaps, not relevant to us, IMO.
And lastly: We on purpose do not follow Libc; Otherwise we'd simply have built the whole RTL on top of it. So we are not under any obligation to mimic its behaviour.
No one said so. Actually that's just fine. The discussion went about various claims from various people that in POSIX the environment is either immutable at all, or the mutations are not visible in libraries, or not inherited on exec() - we (you and me) were not discussing FPC at all, IMO.
AFAICS, all the above claims were not true. Actually it's the first time ever I saw such claims, as mutating environment in a POSIX program, because of child process inherits that by default, is so common, that I have never even thought before of a possibility it could be otherwise, so I wanted to verify, to my own benefit, "how that stuff I never really looked into actually works" ;-)
-- jnml
PS: I think there's no reason why a SetEnv should not by available in sysutils (or system, or ...) on POSIX systems, and as other languages demonstrate, such call can work seamlessly on Windows too. And as FPC is a cross platform compiler.... Actually I think if there is GetEnv somewhere and its natural counterpart SetEnv is nowhere, then it's quite surprising - don't know about a similar example with some other language.
I think you'll find that the environment block is copied as soon as you add a new environment variable.
Since the original environment as passed by the kernel is not in the heap, so how could you add something to it, except by copying the array of pointers and enlarging it ?
What happens to it in a library, is currently open for speculation.
I agree a C person might interpret it like that.
I stand corrected on this front.
Yes. I was sloppy in my terminology.
I think the confusion came from the original posters request to modify the 'global environment', which - I hope you'll agree - is not possible on Posix, as the environment is passed on from process to process using execve.
So, my conclusions:
* The SetEnvironment() call on windows will do something totally different than what happens under Posix, and the Windows behaviour cannot be mimicked. Which is why it isn't in sysutils.
* A posixy SetEnv() could be implemented for the Unix layer, to mimic Libc. But I think it would not be usable for libraries, since the environment copy of the RTL would not be shareable with the library without pulling in the C memory manager.
At best it could be used to be passed on to a new process.
Michael.
I think you'll find that the environment block is copied as soon as you add a new environment variable.
Afaik BSD copies it in the startup code before main() executes.