Why the contents of environ in the /proc file system differs from what extern environ pointed to?

2.9k views Asked by At

getenv() in my C++ apache/cgi gives me weird things, then I checked the environ inside /proc/${PID_OF_THE_RUNNING_PROCESS}, they did not match, which I think they should, I am wondering what was wrong with /proc or it was getenv()?

shell@kernel # xargs --null --max-args=1 echo < /proc/${PID_OF_THE_RUNNING_PROCESS}/environ 
PATH=/usr/bin:/bin:/usr/sbin:/sbin
LD_LIBRARY_PATH=/usr/local/httpd-2.2.19/lib:

Code of PID_OF_THE_RUNNING_PROCESS

#include<stdio.h>
extern char **environ;

void run()
{
    char* s = *environ;
    printf("declare -x  all env begin\n");    
    for (int i = 1; NULL != s; ++i) {
        printf("declare -x  %s\n", s);
        s = *(environ+i);
    }
    printf("declare -x  all env end\n");
}

Console log of PID_OF_THE_RUNNING_PROCESS

declare -x  all env begin
declare -x  FCGI_ROLE=RESPONDER
declare -x  UNIQUE_ID=Wvq-Cn8AAAEAAAkmJlsAAAmM
declare -x  HTTP_HOST=www.example.com
declare -x  HTTP_X_CLIENT_PROTO=https
declare -x  HTTP_X_CLIENT_PROTO_VER=HTTP/1.1
declare -x  HTTP_X_REAL_IP=112.96.194.222
declare -x  HTTP_X_FORWARDED_FOR=112.96.194.222
declare -x  CONTENT_LENGTH=177
declare -x  HTTP_CHARSET=utf-8
declare -x  HTTP_ACCEPT_ENCODING=gzip
declare -x  HTTP_REFERER=https://serviceexample.com/exbb58374cdce267a6/91/page-frame.html
declare -x  CONTENT_TYPE=application/x-www-form-urlencoded
declare -x  HTTP_USER_AGENT=Mozilla/5.0 (Linux; Android 5.1; vivo X6Plus D Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044030 Mobile Safari/537.36 MicroMessenger/6.6.6.1300(0x26060637) NetType/4G Language/zh_CN MicroMessenger/6.6.6.1300(0x26060637) NetType/4G Language/zh_CN
declare -x  PATH=/usr/bin:/bin:/usr/sbin:/sbin
declare -x  SERVER_SIGNATURE=
declare -x  SERVER_SOFTWARE=Apache/2.2.19 (Unix) mod_ssl/2.2.19 OpenSSL/1.0.1t DAV/2 mod_fcgid/2.3.9
declare -x  SERVER_NAME=www.example.com
declare -x  SERVER_ADDR=10.241.94.209
declare -x  SERVER_PORT=80
declare -x  REMOTE_ADDR=10.56.81.214
declare -x  DOCUMENT_ROOT=/data/doc/www.example.com/htdocs
declare -x  [email protected]
declare -x  SCRIPT_FILENAME=/data/doc/www.example.com/cgi-bin/ex/common/www_ex_time.cgi
declare -x  REMOTE_PORT=46151
declare -x  GATEWAY_INTERFACE=CGI/1.1
declare -x  SERVER_PROTOCOL=HTTP/1.1
declare -x  REQUEST_METHOD=POST
declare -x  QUERY_STRING=
declare -x  REQUEST_URI=/cgi-bin/ex/common/www_ex_time.cgi
declare -x  SCRIPT_NAME=/cgi-bin/ex/common/www_ex_time.cgi
declare -x  HTTP_CONNECTION=close
declare -x  all env end
declare -x  112.96.194.222
2

There are 2 answers

2
Kurtis Rader On BEST ANSWER

The /proc/$pid/environ data shows the state of the env vars when the process started. If the environment vars were subsequently modified (e.g., via putenv()) that will be reflected in the return value of getenv() but not /proc/$pid/environ. You can see this in action by compiling and running the following program in one terminal and looking at its proc/.../environ in another terminal.

#include <stdio.h>
#include <stdlib.h>

int main() {
    putenv("HOME=WTF");
    char *home = getenv("HOME");
    printf("pid %d  HOME=%s\n", getpid(), home);
    sleep(300);
}

P.S., Theoretically updates to the environ could be reflected in /proc/$pid/environ but in practice I'm not aware of any implementation which does so.

0
http8086 On

Yes, I found the answer, they are not the same in case of process changed env during run-time.
I found the official documentation here:

/proc/[pid]/environ
              This file contains the initial environment that was set when
              the currently executing program was started via execve(2).              
              ......
              If, after an execve(2), the process modifies its environment
              (e.g., by calling functions such as putenv(3) or modifying the
              environ(7) variable directly), this file will not reflect
              those changes.

Please notice initial environment when started
We changed the env by, say, setenv(), this will reflect on extern environ, we can walk through to verify it, but /proc/self/environ, they are static, will not be affected during run-time.