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

2

5

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
Frisian answered 15/5, 2018 at 11:33 Comment(2)
What output did you expect?Account
@Someprogrammerdude, I thought they are the same, A comes from /proc/${PID}/environ and B comes from extern environ, A and B, they are the same thing? am I right?Frisian
P
4

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.

Polysyllable answered 16/5, 2018 at 3:8 Comment(2)
Theoretically updates to the environ could be reflected in /proc/$pid/environ. -- Were you trying to say SHOULD BE?Frisian
@workplaylifecycle, No I did not mean to say "SHOULD BE". The only way for that to work is for the process to make a syscall to tell the OS the new virtual address of the environ block. That "could be" done by the libc functions such as setenv but I see no reason to always do so. Furthermore, there is nothing that would mandate the user-space code make that syscall. So even if the libc functions did so that wouldn't keep the process from moving the environ block using some other function that does not make the necessary syscall.Polysyllable
F
6

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.

Frisian answered 16/5, 2018 at 3:6 Comment(0)
P
4

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.

Polysyllable answered 16/5, 2018 at 3:8 Comment(2)
Theoretically updates to the environ could be reflected in /proc/$pid/environ. -- Were you trying to say SHOULD BE?Frisian
@workplaylifecycle, No I did not mean to say "SHOULD BE". The only way for that to work is for the process to make a syscall to tell the OS the new virtual address of the environ block. That "could be" done by the libc functions such as setenv but I see no reason to always do so. Furthermore, there is nothing that would mandate the user-space code make that syscall. So even if the libc functions did so that wouldn't keep the process from moving the environ block using some other function that does not make the necessary syscall.Polysyllable

© 2022 - 2024 — McMap. All rights reserved.