Seltsames Verhalten von `/ proc / self / environ` in einigen Shells; Was ist los?

7

Ich bin auf Debian GNU / Linux 9. Ich weiß, /procist etwas Besonderes , ich weiß, was /proc/selfist .

Dieser Befehl

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

ergibt

cat
sh

Das Muster wird ähnlich sein, wenn ich dashanstelle von verwende sh. Aber mit bash, kshoder zshdas Ergebnis

cat
cat

Nehmen /proc/self/statstatt /proc/self/commich kann bestätigen, dass die zwei cat-s in der Tat der gleiche einzelne Prozess sind. Anscheinend unterscheiden sich die Muscheln unter der Haube, es ist in Ordnung. Jetzt nehmen wir

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

Nachdem ich das Obige beobachtet habe, mit shoder dashich erwarte, die Umgebung der catersten, die Umgebung der Shell später zu sehen. Es scheint zu funktionieren (beide Umgebungen sind höchstwahrscheinlich sowieso identisch, daher ist es schwer zu sagen, ob alles wie erwartet funktioniert, aber mein Punkt ist: Keine environist leer).

Mit bash, kshoder zshich erwarte, die Umgebung catzweimal zu sehen, aber es wird nur einmal gedruckt . Aufteilung in zwei getrennte Fälle:

  • bash -c '/bin/cat - </proc/self/environ'druckt nichts, als wäre environes leer;
  • bash -c '/bin/cat /proc/self/environ' druckt etwas wie erwartet.

Was ist los? Dies ist bei commoder nicht der Fall stat. Warum ist environanders?

$ uname -a
Linux barbaz 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1 (2018-04-29) x86_64 GNU/Linux
Kamil Maciorowski
quelle
Ich denke, subtile Unterschiede beim Parsen, Öffnen von Subshells und Timings. Zu müde, um das zu verdauen. +1
Rui F Ribeiro

Antworten:

3

Die Unterschiede zwischen den Schalen sind auf Unterschiede im Prozessaufbau zurückzuführen. dashRichtet Umleitungen vor dem Gabeln ein und /proc/selfzeigt auf die Schale. bashund zshrichten Sie sie nach dem Gabeln ein, damit Sie /proc/selfauf den neuen Prozess hinweisen . Sie können dies sehen mit strace -f:

  • strace -f dash -c '/bin/cat /proc/self/comm - </proc/self/comm' Shows (unter anderem)

    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/commwird vor dem cloneSystemaufruf geöffnet , in dem sich der Prozess teilt);

  • strace -f bash -c '/ bin / cat / 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/commwird nach dem cloneAufruf im untergeordneten Prozess 8106 geöffnet ).

Um zu verstehen, warum environleer angezeigt wird, ist etwas mehr Erklärung erforderlich. Beim /proc/<pid>/environÖffnen speichertmm_struct der Kernel eine Kopie des Zeigers auf die Aufgabe , die Zeiger auf die Umgebung enthält. Mit execvedem zum Starten des catProzesses wird jedoch ein neuer mm_structProzess erstellt . Somit zeigt die Umleitung auf veraltete Informationen und wenn sie catihre Eingabe liest, sieht sie ihre reale Umgebung nicht. Die Umgebung, die es sieht , sollte eine Kopie der übergeordneten Umgebung sein, aber die beteiligten Shells bereinigen sie, bevor die neue Umgebung (die von eingerichtet wird execve) gegabelt und eingerichtet wird .

Stephen Kitt
quelle