일부 쉘에서 `/proc/self/environ`의 이상한 동작, 무슨 일이 일어나고 있나요?

일부 쉘에서 `/proc/self/environ`의 이상한 동작, 무슨 일이 일어나고 있나요?

저는 Debian GNU/Linux 9를 사용하고 있습니다. 알아요/proc아주 특별한, 알아요무엇 /proc/self인가요.

이 명령

sh -c '/bin/cat /proc/self/comm - </proc/self/comm'

생산하다

cat
sh

dash대신 을 사용하면 패턴이 비슷해집니다 sh. 그러나 bash, ksh또는 zsh결과는 다음과 같습니다.

cat
cat

대신에 /proc/self/stat나는 둘 다 실제로 동일한 과정이라는 /proc/self/comm것을 확인할 수 있습니다 . cat분명히 후드 아래의 껍질은 다릅니다. 괜찮습니다. 이제 우리가 가져 가자

sh -c '/bin/cat /proc/self/environ - </proc/self/environ'

위의 내용을 관찰한 후, sh또는 dash내가 볼 것으로 예상한 내용은 cat나중에 쉘의 환경입니다. 작동하는 것 같습니다(어쨌든 두 환경은 동일할 가능성이 높으므로 여부를 말하기가 어렵습니다.모든 것예상대로 작동하지만 내 요점은 둘 다 environnull이 아니라는 것입니다.

bash, ksh또는 zsh두 번 볼 것으로 예상했던 환경이 있지만 cat인쇄만 됩니다.한 번. 두 가지 상황으로 나누어집니다.

  • bash -c '/bin/cat - </proc/self/environ'아무것도 인쇄하지 않고 environ마치 비어 있는 것처럼 작동합니다.
  • bash -c '/bin/cat /proc/self/environ'예상대로 무언가를 인쇄합니다.

무슨 일이야? comm아니면 그렇지 않습니다 stat. 왜 다른가요 environ?

$ uname -a
Linux barbaz 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1 (2018-04-29) x86_64 GNU/Linux

답변1

쉘 간의 차이는 프로세스 설정의 차이로 인해 발생합니다. dash분기하기 전에 리디렉션을 설정하여 /proc/self셸을 가리키 도록 bash하고 zsh분기 후에 이를 설정하여 /proc/self새 프로세스를 가리키도록 합니다. 이런 일이 일어나는 것을 볼 수 있습니다 strace -f:

  • strace -f dash -c '/bin/cat /proc/self/comm - </proc/self/comm'연기(그리고 다른 많은 것)

      open("/proc/self/comm", O_RDONLY)       = 3
      fcntl(0, F_DUPFD, 10)                   = 10
      close(0)                                = 0
      fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
      dup2(3, 0)                              = 0
      close(3)                                = 0
      clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f12581299d0) = 7743
      strace: Process 7743 attached
      [pid  7742] wait4(-1,  <unfinished ...>
      [pid  7743] execve("/bin/cat", ["/bin/cat", "/proc/self/comm", "-"], [/* 43 vars */]) = 0
    

    ( 시스템 호출 /proc/self/comm전에 열림 clone, 프로세스가 포크되는 곳입니다);

  • strace -f bash -c '/bin/cat /proc/self/comm - </proc/self/comm'프로그램

      clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fb506bdee10) = 8106
      strace: Process 8106 attached
      [... snip a ton of signal-handling setup ...]
      [pid  8106] open("/proc/self/comm", O_RDONLY) = 3
      [pid  8106] dup2(3, 0)                  = 0
      [pid  8106] close(3)                    = 0
      [pid  8106] execve("/bin/cat", ["/bin/cat", "/proc/self/comm", "-"], [/* 43 vars */]) = 0
    

    ( 자식 프로세스에서 /proc/self/comm호출 후 열림 clone, 8106).

비어 있는 것으로 나타나는 이유를 이해하려면 environ좀 더 설명이 필요합니다.언제 /proc/<pid>/environ열릴까?, 커널포인터 복사본을 작업에 저장mm_struct, 환경에 대한 포인터를 포함합니다. 하지만execve, cat프로세스를 시작하는 데 사용됩니다.mm_struct프로세스에 대한 새 프로세스 만들기. 따라서 리디렉션은 결국 오래된 정보를 가리키게 되며 cat입력을 읽을 때 실제 환경을 볼 수 없습니다. 환경을 조성하다하다see는 상위 환경의 복사본으로 간주되지만 execve새 환경을 분기하고 설정하기 전에 이를 정리하는 셸이 포함됩니다.

관련 정보