/proc/<pid>/environ does not update (as I understand it, the file contain the initial environment of the process).
How can I read a process's current environment?
/proc/$pid/environ does update if the process changes its own environment. But many programs don't bother changing their own environment, because it's a bit pointless: a program's environment is not visible through normal channels, only through
ps, and even not every unix variant has this kind of feature, so applications don't rely on it.
As far as the kernel is concerned, the environment only appears as the argument of the
execve system call that starts the program. Linux exposes an area in memory through
/proc, and some programs update this area while others don't. In particular, I don't think any shell updates this area. As the area has a fixed size, it would be impossible to add new variables or change the length of a value.
You can read the initial environment of a process from
If a process changes its environment, then in order to read the environment you must have the symbol table for the process and use the
ptrace system call (for example by using
gdb) to read the environment from the global
char **__environ variable. There isn't any other way to get the value of any variable from a running Linux process.
That's the answer. Now for some notes.
The above assumes that the process is POSIX compliant, meaning that the process manages its environment using a global variable
char **__environ as specified in the Ref Spec.
The initial environment for a process is passed to the process in a fixed-length buffer on the process's stack. (The usual mechanism that does this is
linux//fs/exec.c:do_execve_common(...).) Since the size of the buffer is calculated to be no more than the size required for the initial environment, you can't add new variables without erasing existing variables or smashing the stack. So, any reasonable scheme to allow changes in a process's environment would use the heap, where memory in arbitrary sizes can be allocated and freed, which is exactly what GNU
glibc) does for you.
If the process uses
glibc, then it is POSIX compliant, with
__environ being declared in
glibc//posix/environ.c Glibc initializes
__environ with a pointer to memory that it
mallocs from the process's heap, then copies the initial environment from the stack into this heap area. Each time the process uses the
glibc does a
realloc to adjust the size of the area that
__environ points to to accommodate the new value or variable. (You can download the glibc source code with
git clone git://sourceware.org/git/glibc.git glibc). To really understand the mechanism you will also have to read the Hurd code in
hurd//init/init.c:frob_kernel_process() (git clone git://git.sv.gnu.org/hurd/hurd.git hurd).
Now if the new process is only
forked, without a subsequent
exec overwriting the stack, then the argument and environment copying magic is done in
linux//kernel/fork.c:do_fork(...), where the
copy_process routine calls
dup_task_struct that allocates the new process's stack by calling
linux//include/linux/sched.h) for the new process using
Finally, the POSIX
__environ convention is a user-space convention. It has no connection with anything in the Linux kernel. You can write a userspace program without using
glibc and without the
__environ global and then manage the environment variables however you like. No one will arrest you for doing this but you will have to write your own environment management functions (
getenv) and your own wrappers for
sys_exec and it is likely that no one will be able to guess where you put the changes to your environment.
It is updated as and when the process acquires/deletes its environment variables. Do you have a reference which states the
environ file is not updated for the process in its process directory under /proc filesystem?
xargs --null --max-args=1 echo < /proc/self/environ
xargs --null --max-args=1 echo < /proc/<pid>/environ
ps e -p <pid>
The above will print the environment variables of the process in the
ps output format, text-processing (parsing/filtering) is required to see the environment variables as a list.
Solaris (not asked, but for reference I will post here):
/usr/ucb/ps -wwwe <pid>
pargs -e <pid>
EDIT: /proc/pid/environ is not updated! I stand corrected. Verification process is below. However, the children from which the process are fork'd inherit the process environment variable and it is visible in their respective /proc/self/environ file. (Use strings)
With in the shell: here xargs is a child process and hence inherits the environment variable and also reflects in its
[centos@centos t]$ printenv | grep MASK [centos@centos t]$ export MASK=NIKHIL [centos@centos t]$ printenv | grep MASK MASK=NIKHIL [centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK MASK=NIKHIL [centos@centos t]$ unset MASK [centos@centos t]$ printenv | grep MASK [centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK [centos@centos t]$
Checking it from other session, where the terminal/session is not the child process of the shell where the environment variable is set.
Verifying from another terminal/session on the same host:
terminal1: : Note that printenv is fork'd and is a child process of bash and hence it reads its own environ file.
[centos@centos t]$ echo $$ 2610 [centos@centos t]$ export SPIDEY=NIKHIL [centos@centos t]$ printenv | grep SPIDEY SPIDEY=NIKHIL [centos@centos t]$
terminal2: on the same host -- do not launch it with in the same shell where the above variable was set, launch the terminal separately.
[centos@centos ~]$ echo $$ 4436 [centos@centos ~]$ xargs --null --max-args=1 echo < /proc/self/environ | grep -i spidey [centos@centos ~]$ strings -f /proc/2610/environ | grep -i spidey [centos@centos ~]$ xargs --null --max-args=1 echo < /proc/2610/environ | grep -i spidey [centos@centos ~]$
Well the following is not related with author's real intentions, but if you really want to "READ" the
/proc/<pid>/environ, you may try
which is better than