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!