3

This question relates to this answer.

Is it possible to get the current (not initial) environmental variables of a process by making a child process and checking its initial environmental variables?

The idea is that the initial environment of a child process is inherited from the current environment of the parent.

2 Answers2

4

The environment is a list of strings passed along the execve system call, just like the list of arguments. Period. What the applications do with that list of strings it receives is up to the application.

Now, by convention, that list is generally used differently from the list of arguments. Programs generally remember the list of environment variables they receive and reuse the same when executing another command.

They've got C library functions to help them doing that: the environment is made available as a environ variable, and you can retrieve and modify that list (the copy of the list of environment variables it received) with getenv, setenv, putenv, and functions like execvp, execl, system, popen... use that environ variable when executing commands (call execve with the environ they're keeping track of).

Now applications don't have to use that API. They can use their own way to manage the list of environment variables. Shells for instance, map environment variables to shell variables and are likely not to use putenv/setenv libc functions. perl has its %ENV associative array and so on.

You can always use gdb to attach to a process and make it call system("env > /tmp/some-file") (assuming they are dynamically linked to the libc), but you've got no guarantee that env will get the same environment than another command would get if the command you're attaching to was executing it in its own way (think of shells for instance). (also note that system() starts a shell (to interpret the command line) and shells may alter their environment on start up (try for instance env -i sh -c env).

$ sleep 100 &
[1] 17098
$ gdb --pid=$! /bin/sleep
[...]
(gdb) p environ[0]
$1 = 0x7fffd722d227 "STY=7498.pts-0.hostname"
(gdb) p environ[1]
$2 = 0x7fffd722d245 "TERM=screen-bce"
(gdb) call system("env > /tmp/some-file")
$4 = 0
(gdb) detach
Detaching from program: /bin/sleep, process 17098
(gdb) quit
$ cat /tmp/some-file
GNOME_KEYRING_PID=6850
SSH_AGENT_PID=6844
SHLVL=1
[...]
-2

If you are running Linux, or one of the Unixes that has a /proc filesystem, a process' environment is in one of the per-process files under /proc. I don't have access to a Solaris machine right now, but for Linux this worked:

$ tr  '\0' '\n' < /proc/$$/environ

That prints the environment variables of the current shell, but $$ can be any process ID your user ID has access to.

There was a way to do this under Solaris, but it was a lot more complicated. I think the BSDs have a /proc more similar to Linux.

maxschlepzig
  • 57,532
  • 1
    On Solaris it is: pargs -e $$ | cut -d' ' -f2- – maxschlepzig Jul 17 '13 at 06:18
  • 1
    Reread the question - /proc/.../environ only includes the initial environment, the OP asks for the current environment ... As a side note - on Solaris, pargs (and ucb/ps) actually lookup the current environment in the address space (/proc/.../as) of the process. – maxschlepzig Sep 17 '13 at 09:58