Sometimes its useful to be able see the values of environment variables in running processes. We can use the following test program to see how well we can accomplish this:

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
        int n;
        char *envstr;
        while((n = scanf("%as", &envstr)) != EOF) {
                putenv(envstr);
        }
        return 0;
}

This program just reads strings from stdin and then basically passes them on to putenv(3) so we have any easy way to modify our environment.

Now, lets run it with env -i to reset the environment to something pretty sparse:

[cperl@localhost ~]$ gcc -Wall t.c -o t
[cperl@localhost ~]$ env -i FOO=bar ./t

First, lets see what we can get out of /proc/{pid}/environ, as googling for this problem will undoubtedly point you in this direction (including ps eww which reads /proc/{pid}/environ):

[cperl@localhost ~]$ cat /proc/$(pgrep -x t)/environ | xargs -r0 -n1 echo
FOO=bar

Great, so that looks like its our answer!

Unfortunately, /proc/{pid}/environ only reflects the environment of the process when it started and does not reflect any calls that process might have made to putenv(3) or setenv(3) (you can experiment with the above program substituting in setenv(3) for putenv(3) and playing with overwrite to see what you get).

We can see that if we feed some data into our program, causing calls to putenv(3):

[cperl@localhost ~]$ env -i FOO=bar ./t
BAR=baz

And then check /proc/{pid}/environ again:

[cperl@localhost ~]$ cat /proc/$(pgrep -x t)/environ | xargs -r0 -n1 echo
FOO=bar

However, we can verify the data is really there if we attach with gdb and iterate over the environ(7) array directly:

[cperl@localhost ~]$ gdb ./t $(pgrep -x t)
...
(gdb) set $i = 0
(gdb) while (environ[$i] != 0)
 >print environ[$i++]
 >end
$1 = 0x7fffc8e42fec "FOO=bar"
$2 = 0x12d4080 "BAR=baz"

Unfortunately, I’m not aware of any other way to get this “dynamic environment info” (except for other ptrace based solutions). Obviously attaching to production processes with gdb (or ptrace in general) isn’t a great idea. Most of the time you’ll probably be fine inspecting /proc/{pid}/environ and verifying (via source code inspection) that that process you care about doesn’t make any calls to putenv(3) or setenv(3) for the variables whose values you are interested in.

If you have any better ideas about how to get this information, please share in the comments!