프로세스의 환경 변수를 읽는 방법

프로세스의 환경 변수를 읽는 방법

Linux는 /proc/<pid>/environ프로세스 환경을 업데이트하지 않습니다. 내가 이해한 바로는 이 파일에는 프로세스의 초기 환경이 포함되어 있습니다.

프로세스를 어떻게 읽나요?현재의환경?

답변1

당신은 읽을 수있다초기의프로세스 환경은 /proc/<pid>/environ.

프로세스라면다양성환경을 읽으려면 프로세스의 기호 테이블이 있어야 하고 ptrace시스템 호출(예: 을 사용하여 )을 사용하여 gdb전역 변수에서 환경을 읽어야 합니다 char **__environ. 실행 중인 Linux 프로세스에서 변수 값을 얻는 다른 방법은 없습니다.

이것이 답입니다. 이제 메모해 보세요.

위의 내용은 프로세스가 POSIX를 준수한다고 가정합니다. 즉, 프로세스는 전역 변수를 사용하여 다음 char **__environ과 같은 환경을 관리합니다.참고사양.

프로세스의 초기 환경은 프로세스 스택의 고정 길이 버퍼를 통해 프로세스에 전달됩니다. (이를 수행하는 일반적인 메커니즘은 입니다 linux//fs/exec.c:do_execve_common(...).) 계산된 버퍼 크기는 초기 환경에 필요한 크기보다 크지 않으므로 기존 변수를 지우거나 스택을 파괴하지 않고는 새 변수를 추가할 수 없습니다. 따라서 프로세스 환경 변경을 허용하는 합리적인 방식은 임의 크기의 메모리를 할당하고 해제할 수 있는 힙을 사용하게 되는데, 이것이 바로 GNU libc( glibc)가 수행하는 작업입니다.

프로세스 가 Glibc에서 선언되고 프로세스 힙의 메모리에 대한 포인터로 초기화된 다음 초기 환경이 스택에서 해당 힙 영역으로 복사되면 glibcPOSIX 호환입니다 . __environ프로세스가 이 함수를 사용할 때마다 가리키는 영역의 크기가 새 값이나 변수에 맞게 조정됩니다. (glibc 소스 코드를 다운로드할 수 있습니다). 메커니즘을 실제로 이해하려면 Hurd 코드(git clone git://git.sv.gnu.org/hurd/hurd.git hurd)도 읽어야 합니다.glibc//posix/environ.c__environmallocsetenvglibcrealloc__environgit clone git://sourceware.org/git/glibc.git glibchurd//init/init.c:frob_kernel_process()

fork이제 이후에 exec스택을 덮어 쓰지 않고 단순히 새 프로세스가 생성되면 ()를 호출하여 새 프로세스의 스택을 할당하는 linux//kernel/fork.c:do_fork(...)루틴 copy_process호출 에서 인수 및 환경 복사 매직이 수행됩니다. 그러면 다음을 dup_task_struct사용하여 새 프로세스에 스택을 alloc_thread_info_node할당합니다 . 부르다 setup_thread_stack().linux//include/linux/sched.halloc_thread_info_node

마지막으로 POSIX __environ규칙은 다음과 같습니다.사용자 공간관습. 이는 Linux 커널의 어떤 것과도 관련이 없습니다. 전역 변수를 사용하지 않고 glibc사용자 공간 프로그램을 작성한 __environ다음 원하는 방식으로 환경 변수를 관리할 수 있습니다. 이렇게 한다고 해서 아무도 당신을 체포하지는 않을 것입니다. 그러나 당신은 당신 자신의 환경 관리 함수( setenv/ getenv)와 당신 자신의 래퍼를 작성해야 할 것이고, sys_exec아마도 당신이 환경 변경 사항을 어디에 두었는지 추측할 수 없을 것입니다.

답변2

프로세스가 환경 변수를 가져오거나 제거할 때 업데이트됩니다. environ/proc 파일 시스템 아래의 프로세스 디렉터리에 있는 프로세스에 대한 파일이 업데이트되지 않았음을 나타내는 참조가 있습니까 ?

xargs --null --max-args=1 echo < /proc/self/environ

또는

xargs --null --max-args=1 echo < /proc/<pid>/environ

또는

ps e -p <pid>

위의 내용은 프로세스의 환경 변수를 출력 형식으로 인쇄하는데 ps, 환경 변수를 목록 형식으로 보려면 텍스트 처리(파싱/필터링)가 필요합니다.

Solaris(묻지는 않았지만 참고용으로 여기에 게시하겠습니다):

/usr/ucb/ps -wwwe <pid>

또는

pargs -e <pid> 

편집하다:/proc/pid/environ이 업데이트되지 않았습니다! 나는 그것을 고쳤다. 확인 과정은 다음과 같습니다. 그러나 분기된 프로세스의 하위 프로세스는 프로세스 환경 변수를 상속하며 이는 해당 /proc/self/environ 파일에 표시됩니다. (문자열 사용)

셸에서: 여기서 xargs는 하위 프로세스이므로 환경 변수가 상속되어 해당 /proc/self/environ파일에 반영됩니다.

[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]$

터미널/세션이 환경 변수를 설정하는 쉘의 하위 프로세스가 아닌 다른 세션에서 확인하십시오.

동일한 호스트의 다른 터미널/세션에서 확인합니다.

터미널 1:: printenv는 분기되고 bash의 하위 프로세스이므로 자체 환경 파일을 읽습니다.

[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$ 

터미널 2:동일한 호스트에서 - 위의 변수를 설정한 동일한 쉘에서 시작하지 말고 터미널을 별도로 시작하십시오.

[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 ~]$ 

답변3

/proc/$pid/environ프로세스가 자체 환경을 변경하면 업데이트됩니다. 그러나 많은 프로그램은 자신의 환경을 변경하는 데 신경 쓰지 않습니다. 왜냐하면 그것은 약간 무의미하기 때문입니다. 프로그램의 환경은 일반 채널을 통해서는 볼 수 없으며 오직 /proc및 를 통해서만 볼 수 ps있으며 모든 유닉스 변형에도 이 기능이 있는 것은 아니므로 애플리케이션은 의존하지 마십시오. 그 위에.

커널에 관한 한 환경은 매개변수로만 나타납니다.execve프로그램을 시작하기 위한 시스템 호출입니다. Linux는 /proc일부 프로그램은 업데이트하고 다른 프로그램은 업데이트하지 않는 메모리 영역을 노출하여 작동합니다 . 특히 어떤 쉘도 이 영역을 업데이트하지 않을 것이라고 생각합니다. 영역의 크기는 고정되어 있으므로 새로운 변수를 추가하거나 값의 길이를 변경할 수 없습니다.

답변4

나는 일시적으로 gdb프로그램에 세션을 연결하고 getenv거기에서 호출하기로 결정했습니다. 에는 적용되지 않을 수도 있습니다모두절차이며 비용이 상당히 높지만 일반적으로 다음과 같이 작동합니다.

echo 'p (char *) getenv("PWD")' | \
     gdb --quiet -p $(pidof emacs) | \
     sed -n 's/.*"\(.*\)"$/\1/p'

관련 정보