GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie verfolgt Unix das Arbeitsverzeichnis eines Benutzers beim Navigieren im Dateisystem?

Angenommen, ich logge mich in eine Shell auf einem Unix-System ein und fange an, Befehle abzutippen. Ich beginne zunächst im Home-Verzeichnis meines Benutzers ~ . Ich könnte von dort aus cd bis zum Verzeichnis Documents .

Der Befehl zum Wechseln des Arbeitsverzeichnisses ist hier intuitiv sehr einfach zu verstehen:Der übergeordnete Knoten hat eine Liste von untergeordneten Knoten, auf die er zugreifen kann, und verwendet vermutlich eine (optimierte) Variante einer Suche, um die Existenz eines untergeordneten Knotens mit dem zu lokalisieren Geben Sie den eingegebenen Benutzernamen ein, und das Arbeitsverzeichnis wird dann entsprechend „geändert“ – korrigieren Sie mich, wenn ich da falsch liege. Es kann sogar einfacher sein, dass die Shell einfach „naiv“ versucht, genau nach den Wünschen des Benutzers auf das Verzeichnis zuzugreifen, und wenn das Dateisystem einen Fehler zurückgibt, zeigt die Shell eine entsprechende Antwort an.

Was mich jedoch interessiert, ist, wie derselbe Prozess funktioniert, wenn ich in einem Verzeichnis nach oben navigiere, d. h. zu einem Elternteil oder einem Elternteil.

Angesichts meines unbekannten, vermutlich „blinden“ Standorts von Documents , eines von möglicherweise vielen Verzeichnissen im gesamten Dateisystembaum mit diesem Namen, wie bestimmt Unix, wo ich als nächstes platziert werden soll? Verweist es auf pwd und das untersuchen? Wenn ja, wie funktioniert pwd den aktuellen Navigationsstatus verfolgen?

Akzeptierte Antwort:

Die anderen Antworten sind zu starke Vereinfachungen, die jeweils nur Teile der Geschichte darstellen, und sind in einigen Punkten falsch.

Es gibt zwei Möglichkeiten, wie das Arbeitsverzeichnis verfolgt wird:

  • Für jeden Prozess speichert der Kernel in der Kernel-Space-Datenstruktur, die diesen Prozess darstellt, zwei vnode-Referenzen zu den vnodes des Arbeitsverzeichnisses und des Stammverzeichnisses für diesen Prozess. Die erstgenannte Referenz wird durch chdir() gesetzt und fchdir() Systemaufrufe, letztere durch chroot() . Man kann sie indirekt in /proc sehen auf Linux-Betriebssystemen oder über fstat Befehl unter FreeBSD und dergleichen:

    % fstat -p $$|head -n 5
    USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W
    JdeBP    zsh        92648 text /         24958 -r-xr-xr-x  702360  r
    JdeBP    zsh        92648 ctty /dev        148 crw--w----   pts/4 rw
    JdeBP    zsh        92648   wd /usr/home/JdeBP      4 drwxr-xr-x     124  r
    JdeBP    zsh        92648 root /             4 drwxr-xr-x      35  r
    % 

    Wenn die Pfadnamenauflösung funktioniert, beginnt sie bei dem einen oder anderen dieser referenzierten vnodes, je nachdem, ob der Pfad relativ oder absolut ist. (Es gibt eine Familie von …at() Systemaufrufe, die es als dritte Option ermöglichen, dass die Auflösung von Pfadnamen an dem vnode beginnt, auf den von einem offenen (Verzeichnis-)Dateideskriptor verwiesen wird.)

    In Mikrokernel-Unices befindet sich die Datenstruktur im Anwendungsbereich, aber das Prinzip, Verweise auf diese Verzeichnisse offen zu halten, bleibt dasselbe.

  • Intern, innerhalb von Shells wie der Z-, Korn-, Bourne Again-, C- und Almquist-Shell, die Shell zusätzlich verfolgt das Arbeitsverzeichnis durch String-Manipulation einer internen String-Variablen. Dies geschieht immer dann, wenn es Anlass zum Aufrufen von chdir() hat .

    Wenn man zu einem relativen Pfadnamen wechselt, manipuliert es die Zeichenfolge, um diesen Namen anzuhängen. Wenn man zu einem absoluten Pfadnamen wechselt, ersetzt er die Zeichenkette durch den neuen Namen. In beiden Fällen passt es die Zeichenfolge an, um . zu entfernen und .. Komponenten zu finden und symbolische Verknüpfungen aufzuspüren, indem sie durch ihre verknüpften Namen ersetzt werden. (Hier ist zum Beispiel der Code der Z-Shell dafür.)

    Der Name in der internen String-Variablen wird von einer Shell-Variablen verfolgt mit dem Namen PWD (oder cwd in den C-Schalen). Dies wird herkömmlicherweise als Umgebungsvariable (mit dem Namen PWD) exportiert ) zu Programmen, die von der Shell erzeugt werden.

Diese beiden Methoden zum Verfolgen von Dingen werden durch das -P offenbart und -L Optionen zum cd und pwd Shell-integrierte Befehle und durch die Unterschiede zwischen den in die Shell integrierten pwd Befehle und sowohl /bin/pwd Befehl und das eingebaute pwd Befehle von Dingen wie (unter anderem) VIM und NeoVIM.

% mkdir a ; ln -s a b
% (cd b; pwd; /bin/pwd; printenv PWD)
/usr/home/JdeBP/b
/usr/home/JdeBP/a
/usr/home/JdeBP/b
% (cd b; pwd -P; /bin/pwd -P)
/usr/home/JdeBP/a
/usr/home/JdeBP/a
% (cd b; pwd -L; /bin/pwd -L)
/usr/home/JdeBP/b
/usr/home/JdeBP/b
% (cd -P b; pwd; /bin/pwd; printenv PWD)
/usr/home/JdeBP/a
/usr/home/JdeBP/a
/usr/home/JdeBP/a
% (cd b; PWD=/hello/there /bin/pwd -L)
/usr/home/JdeBP/a
% 

Verwandte:Suchen Sie nach einem alternativen GUI-Dateieditor mit Unterstützung für große Dateien?

Wie Sie sehen:Um das „logische“ Arbeitsverzeichnis zu erhalten, müssen Sie sich das PWD ansehen Shell-Variable (oder Umgebungsvariable, wenn es sich nicht um das Shell-Programm handelt); während das Abrufen des „physischen“ Arbeitsverzeichnisses eine Frage des Aufrufs von getcwd() ist Bibliotheksfunktion.

Die Operation von /bin/pwd Programm, wenn das -L Option verwendet wird, ist etwas subtil. Es kann nicht vertrauen der Wert von PWD Umgebungsvariable, die sie geerbt hat. Schließlich muss es nicht von einer Shell aufgerufen worden sein, und dazwischenliegende Programme haben möglicherweise nicht den Shell-Mechanismus zum Erstellen des PWD implementiert Die Umgebungsvariable verfolgt immer den Namen des Arbeitsverzeichnisses. Oder jemand kann das tun, was ich gerade dort getan habe.

Was es also tut, ist (wie der POSIX-Standard sagt), zu überprüfen, ob der Name in PWD angegeben ist ergibt dasselbe wie der Name . , wie mit einem Systemaufruf-Trace zu sehen ist:

% ln -s a c
% (cd b;  truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/home/JdeBP/b",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
/usr/home/JdeBP/b
% (cd b; PWD=/usr/local/etc truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/local/etc",{ mode=drwxr-xr-x ,inode=14835,size=158,blksize=10240 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
__getcwd("/usr/home/JdeBP/a",1024)       = 0 (0x0)
/usr/home/JdeBP/a
% (cd b; PWD=/hello/there truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/hello/there",0x7fffffffe730)      ERR#2 'No such file or directory'
__getcwd("/usr/home/JdeBP/a",1024)       = 0 (0x0)
/usr/home/JdeBP/a
% (cd b; PWD=/usr/home/JdeBP/c truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/home/JdeBP/c",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
/usr/home/JdeBP/c
%

Wie Sie sehen:Es ruft nur getcwd() auf wenn es eine Nichtübereinstimmung erkennt; und es kann durch Setzen von PWD getäuscht werden zu einem String, der zwar dasselbe Verzeichnis benennt, aber auf einem anderen Weg.

Das getcwd() Bibliotheksfunktion ist ein eigenes Thema. Aber um es genau zu sagen:

  • Ursprünglich war es eine reine Bibliotheksfunktion, die einen Pfadnamen vom Arbeitsverzeichnis zurück bis zur Wurzel aufbaute, indem sie wiederholt versuchte, das Arbeitsverzeichnis in .. nachzuschlagen Verzeichnis. Es stoppte, als es eine Schleife erreichte, in der .. mit seinem Arbeitsverzeichnis identisch war oder beim Versuch, den nächsten .. zu öffnen, ein Fehler aufgetreten ist hoch. Das wären viele Systemaufrufe unter der Decke.
  • Heutzutage ist die Situation etwas komplexer. Unter FreeBSD zum Beispiel (das gilt auch für andere Betriebssysteme) ist es so ein echter Systemaufruf, wie Sie in der zuvor angegebenen Systemaufruf-Ablaufverfolgung sehen können. Die gesamte Traversierung vom vnode des Arbeitsverzeichnisses bis zur Wurzel erfolgt in einem einzigen Systemaufruf, der Dinge wie den direkten Zugriff des Codes im Kernelmodus auf den Cache für Verzeichniseinträge nutzt, um die Suche nach Pfadnamenkomponenten viel effizienter durchzuführen.

    Beachten Sie jedoch, dass selbst unter FreeBSD und diesen anderen Betriebssystemen der Kernel nicht Verfolgen Sie das Arbeitsverzeichnis mit einer Zeichenfolge.

Navigieren zu .. ist wieder ein Thema für sich. Noch ein Hinweis:Obwohl Verzeichnisse herkömmlicherweise (obwohl, wie bereits angedeutet, dies nicht ist erforderlich) enthalten einen tatsächlichen .. in der Verzeichnisdatenstruktur auf der Platte verfolgt der Kernel das übergeordnete Verzeichnis jedes Verzeichnis-Vnode selbst und kann somit zu .. navigieren vnode eines beliebigen Arbeitsverzeichnisses. Dies wird durch den Einhängepunkt und geänderte Root-Mechanismen etwas kompliziert, die den Rahmen dieser Antwort sprengen würden.

Beiseite

Windows NT macht tatsächlich etwas Ähnliches. Es gibt ein einzelnes Arbeitsverzeichnis pro Prozess, das durch SetCurrentDirectory() festgelegt wird API-Aufruf und Verfolgung pro Prozess durch den Kernel über ein (internes) offenes Datei-Handle zu diesem Verzeichnis; und es gibt eine Reihe von Umgebungsvariablen, die Win32 programmiert (nicht nur die Befehlsinterpreter, sondern alle Win32-Programme) verwenden, um die Namen mehrerer Arbeitsverzeichnisse (eines pro Laufwerk) zu verfolgen, an sie anzuhängen oder sie zu überschreiben, wenn sie das Verzeichnis wechseln.

Verwandte:Wie verwendet man $? und testen um funktion zu prüfen?

Herkömmlicherweise zeigen Win32-Programme, anders als bei Unix- und Linux-Betriebssystemen, diese Umgebungsvariablen Benutzern nicht an. Man kann sie jedoch manchmal in Unix-ähnlichen Subsystemen sehen, die auf Windows NT laufen, sowie durch die Verwendung des SET des Befehlsinterpreters Befehle auf eine bestimmte Weise.

Weiterführende Literatur

  • pwd “. Die Basisspezifikationen der Open Group Ausgabe 7. IEEE 1003.1:2008. Die Offene Gruppe. 2016.
  • „Pfadnamenauflösung“. Die Basisspezifikationen der Open Group Ausgabe 7. IEEE 1003.1:2008. Die Offene Gruppe. 2016.
  • https://askubuntu.com/a/636001/43344
  • Wie werden Dateien unter Unix geöffnet?
  • Wofür ist Inode in FreeBSD oder Solaris
  • Seltsame Umgebungsvariable !::=::in Cygwin
  • Warum funktioniert CDPATH nicht wie in den Handbüchern dokumentiert?
  • Wie kann ich zsh so einstellen, dass es physische Pfade verwendet?
  • In ein Verzeichnis gehen, das durch einen Link verlinkt ist

Linux
  1. Linux – Wie oft wird das Proc-Dateisystem unter Linux aktualisiert?

  2. Linux – Wie überprüft man die Verzeichnisstrukturinformationen einer Unix/Linux-Datei?

  3. Wie funktioniert der Exit-Befehl auf einem Unix-Terminal?

  4. Wie aktiviere ich die Indizierung von Apache-Dateien und -Verzeichnissen in Linux oder UNIX?

  5. UNIX / Linux:So verwenden Sie Sticky Bit für Verzeichnis und Datei

So bleiben Eigentums- und Dateiberechtigungen beim Kopieren von Dateien oder Verzeichnissen erhalten

So finden Sie die älteste Datei in einem Verzeichnisbaum in Linux

Wie drucke ich das Arbeitsverzeichnis mit dem Linux-Befehl pwd?

Wie kann man eine Datei komprimieren und die .gz-Datei behalten?

Verschieben einer Datei, während sie verwendet wird – Wie funktioniert das?

Was ist das Sticky Bit in UNIX-Dateisystemen? Wann wird es verwendet?