W jaki sposób Unix śledzi katalog roboczy użytkownika podczas nawigacji w systemie plików?


29

Powiedzmy, że loguję się do powłoki w systemie uniksowym i zaczynam odsuwać polecenia. Początkowo zaczynam od katalogu domowego mojego użytkownika ~. Mógłbym stamtąd cdprzejść do katalogu Documents.

Polecenie zmiany katalogu roboczego jest bardzo proste intuicyjnie do zrozumienia: węzeł nadrzędny ma listę węzłów podrzędnych, do których może uzyskać dostęp, i prawdopodobnie używa (zoptymalizowanego) wariantu wyszukiwania w celu zlokalizowania istnienia węzła podrzędnego za pomocą wpisz nazwę użytkownika, a katalog roboczy zostanie „zmieniony”, aby dopasować to - popraw mnie, jeśli się mylę. Może być nawet prostsze, że powłoka po prostu „naiwnie” próbuje uzyskać dostęp do katalogu dokładnie zgodnie z życzeniem użytkownika, a gdy system plików zwraca pewien rodzaj błędu, powłoka odpowiednio wyświetla odpowiedź.

Interesuje mnie jednak to, jak działa ten sam proces, gdy przeglądam katalog, tzn. Do rodzica lub rodzica rodzica.

Biorąc pod uwagę moją nieznaną, prawdopodobnie „ślepą” lokalizację Documents, jednego z możliwie wielu katalogów w całym drzewie systemu plików o tej nazwie, w jaki sposób Unix określa, gdzie powinienem być umieszczony dalej? Czy zawiera odniesienie pwdi bada to? Jeśli tak, w jaki sposób pwdśledzi bieżący stan nawigacji?


1

Odpowiedzi:


76

Inne odpowiedzi są uproszczeniami, z których każda przedstawia tylko fragmenty historii i są błędne w kilku punktach.

Istnieją dwa sposoby śledzenia katalogu roboczego:

  • Dla każdego procesu w strukturze danych przestrzeni jądra, która reprezentuje ten proces, jądro przechowuje dwa odwołania vnode do vnodes katalogu roboczego i katalogu głównego dla tego procesu. Pierwsze odniesienie jest ustawione przez wywołania systemowe chdir()i fchdir(), drugie przez chroot(). Można je zobaczyć pośrednio w /procsystemach operacyjnych Linux lub za pomocą fstatpolecenia na FreeBSD i tym podobnych:

    % fstat -p $$ | head -n 5
    UŻYTKOWNIK 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
    % 

    Kiedy działa rozpoznawanie nazw ścieżek, zaczyna się od jednego lub drugiego z tych przywoływanych vnodes, w zależności od tego, czy ścieżka jest względna czy bezwzględna. (Istnieje rodzina …at()wywołań systemowych, które umożliwiają rozpoznawanie nazw ścieżek rozpoczynające się od vnode, do którego odwołuje się deskryptor pliku otwartego (katalogu) jako trzecia opcja).

    W mikrojądrach Unices struktura danych znajduje się w przestrzeni aplikacji, ale zasada utrzymywania otwartych odniesień do tych katalogów pozostaje taka sama.

  • Wewnętrznie, w powłokach takich jak powłoka Z, Korn, Bourne Again, C i Almquist, powłoka dodatkowo śledzi katalog roboczy za pomocą manipulacji ciągiem wewnętrznej zmiennej łańcuchowej. Robi to za każdym razem, gdy ma powód do połączenia chdir().

    Jeśli ktoś zmieni się na względną nazwę ścieżki, manipuluje ciągiem, aby dodać tę nazwę. Jeśli ktoś zmieni bezwzględną nazwę ścieżki, zastępuje ciąg nową nazwą. W obu przypadkach dostosowuje ciąg do usunięcia .i ..komponentów oraz do ścigania dowiązań symbolicznych, zastępując je nazwami połączonymi z nimi. ( Oto przykładowy kod powłoki Z. )

    Nazwa w wewnętrznej zmiennej łańcucha jest śledzona przez zmienną powłoki o nazwie PWD(lub cwdw powłokach C). Jest to konwencjonalnie eksportowane jako zmienna środowiskowa (o nazwie PWD) do programów spawnowanych przez powłokę.

Te dwie metody śledzenia rzeczy są ujawniane przez -Pi -Lopcje do cdi pwdpowłoki wbudowanych komend i różnicami między muszli wbudowanych pwdpoleceń i zarówno /bin/pwdpolecenia i wbudowanych pwdpoleceń rzeczy jak (między innymi) VIM i NeoVIM.

% mkdir a; ln -sab 
% (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
% 

Jak widać: uzyskanie „logicznego” katalogu roboczego polega na spojrzeniu na PWDzmienną powłoki (lub zmienną środowiskową, jeśli nie jest to program powłoki); podczas gdy uzyskanie „fizycznego” katalogu roboczego jest kwestią wywołania getcwd()funkcji biblioteki.

Działanie /bin/pwdprogramu, gdy -Lużywana jest opcja, jest nieco subtelne. Nie może ufać wartości PWDodziedziczonej zmiennej środowiskowej. W końcu nie musiała być wywoływana przez powłokę, a interweniujące programy mogły nie wdrożyć mechanizmu powłoki polegającego na tym, że PWDzmienna środowiskowa zawsze śledzi nazwę katalogu roboczego. Albo ktoś może zrobić to, co właśnie tam zrobiłem.

Więc to, co robi (jak mówi standard POSIX), sprawdza, czy nazwa podana w PWDdaje to samo co nazwa ., co można zobaczyć za pomocą śledzenia wywołania systemowego:

% ln -sac 
% (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, i-węzeł = 14835, rozmiar = 158, rozmiar blks = 10240}) = 0 (0x0) 
stat (".", {mode = drwxr-xr-x, i-węzeł = 120932, rozmiar = 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 „Brak takiego pliku lub katalogu” 
__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 , rozmiar = 2, rozmiar blks = 131072}) = 0 (0x0)
/ usr / home / JdeBP / c
%

Jak widać: wywołuje tylko getcwd()wtedy, gdy wykryje niezgodność; i można go oszukać, ustawiając PWDciąg znaków, który rzeczywiście nazywa ten sam katalog, ale inną drogą.

Funkcja getcwd()biblioteczna jest odrębnym przedmiotem. Ale aby to zrobić:

  • Pierwotnie była to funkcja czysto biblioteczna, która budowała nazwę ścieżki z katalogu roboczego z powrotem do katalogu głównego, wielokrotnie próbując wyszukać katalog roboczy w ..katalogu. Zatrzymał się, gdy osiągnął pętlę, w której ..był taki sam jak katalog roboczy, lub gdy wystąpił błąd podczas próby otwarcia następnego ... To byłoby dużo wywołań systemowych pod przykryciem.
  • Obecnie sytuacja jest nieco bardziej złożona. Na przykład we FreeBSD (dotyczy to również innych systemów operacyjnych) jest to prawdziwe wywołanie systemowe, jak widać w podanym wcześniej śladzie wywołania systemowego. Całe przejście od vnode katalogu roboczego do katalogu głównego odbywa się za pomocą pojedynczego wywołania systemowego, które wykorzystuje takie rzeczy, jak bezpośredni dostęp kodu trybu jądra do pamięci podręcznej wpisów katalogu, aby znacznie wydajniej wyszukiwać komponenty ścieżki.

    Zauważ jednak, że nawet w FreeBSD i innych systemach operacyjnych jądro nie śledzi łańcucha roboczego za pomocą łańcucha.

Nawigacja do ..jest znowu osobnym tematem. Kolejna zasada: chociaż katalogi konwencjonalnie (choć, jak już wspomniano, nie jest to wymagane) zawierają rzeczywistą ..strukturę danych katalogu na dysku, jądro śledzi katalog macierzysty każdego vnode katalogu i może w ten sposób nawigować do ..vnode dowolnego katalog roboczy. Jest to nieco skomplikowane przez punkt montowania i zmienione mechanizmy rootowania, które są poza zakresem tej odpowiedzi.

Na bok

Windows NT faktycznie robi podobne rzeczy. Istnieje jeden katalog roboczy na proces, ustawiony przez SetCurrentDirectory()wywołanie API i śledzony na proces przez jądro za pomocą (wewnętrznego) dojścia do otwartego pliku do tego katalogu; i istnieje zestaw zmiennych środowiskowych, które programy Win32 (nie tylko interpreter poleceń, ale wszystkie programy Win32) używają do śledzenia nazw wielu działających katalogów (jednego na dysk), dołączając je lub zastępując przy każdej zmianie katalogu.

Konwencjonalnie, w przeciwieństwie do systemów operacyjnych Unix i Linux, programy Win32 nie wyświetlają tych zmiennych środowiskowych użytkownikom. Czasem można je zobaczyć w podsystemach uniksopodobnych działających w systemie Windows NT, a także przy użyciu poleceń interpretera SETpoleceń w określony sposób.

Dalsza lektura


1
To o wiele więcej niż się spodziewałem. Dziękuję i dodatkowe podziękowania za dalszą lekturę!
ReactingToAngularVues

doc.cat-v.org/plan_9/4th_edition/papers/lexnames mówi o niektórych problemach ..w kontekście Plan9,
icarus

@JdeBP: Być może coś mi brakuje. Mówisz: „Wewnętrznie, w obrębie…, bash,… i…, powłoka dodatkowo śledzi katalog roboczy za pomocą manipulacji ciągiem wewnętrznej zmiennej ciągowej. … Dostosowuje ciąg do usunięcia .i ..komponentów oraz do ścigania dowiązań symbolicznych, zastępując je nazwami połączonymi z nimi. … Nazwa w wewnętrznej zmiennej łańcucha jest śledzona przez zmienną powłoki o nazwie PWD… ”(wyróżnienie dodane). … (Ciąg dalszy)
G-Man mówi „Przywróć Monikę”

(Ciąg dalszy)… Ale twój przykład pokazuje PWD= …/bpo cd bpoleceniu, mimo że bjest dowiązaniem symbolicznym do a- więc powłoka nie „ściga” a -> błącza. Czy popełniłeś błąd, czy też źle przeczytałem?
G-Man mówi „Przywróć Monikę”

Po prostu przelotnie przeleciałem nad punktem bocznym i wskazałem ci kod, aby uzyskać szczegółowe informacje. Zapoznaj się z podręcznikami różnych powłok, aby dowiedzieć się, kiedy i jak zdecydować się na ściganie dowiązań symbolicznych. The Z shell grzejniku nazywa swoją opcję powłoki, który jest jednym z elementów wzoru decyzyjnym CHASE_LINKS.
JdeBP,

1

Jądro nie śledzi nazw katalogów lub plików; plik lub katalog jest reprezentowany w jądrze przez parę węzłów i urządzeń. Wywołania systemowe, takie jak chdir(), open()itp wziąć ścieżkę jako parametr, który może być bezwzględne (np /etc/passwd) lub w stosunku do bieżącego katalogu (przykłady: Documents, ..). Po uruchomieniu procesu chdir("Documents")wyszukiwanie odbywa się Documentsw bieżącym katalogu roboczym, a katalog roboczy procesu jest aktualizowany w celu odniesienia do tego katalogu. Z punktu widzenia jądra w nazwie „..” nie ma nic specjalnego, to tylko konwencja w systemie plików, która ..odnosi się do katalogu nadrzędnego.

Ta getcwd()funkcja nie jest wywołaniem systemowym, ale funkcją biblioteki, która musi dotrzeć do katalogu głównego, rejestrując po drodze nazwy komponentów ścieżki.


0

Co ciekawe, tradycyjnie cd ..jest znacznie prostsze niż pwd. Nazwy katalogów ..są umieszczane jawnie w systemie plików. System śledzi urządzenie / i-węzeł bieżącego katalogu, cd ..a ściślej mówiąc, wywołanie systemowe wymaga chdir("..")jedynie wyszukania nazwy „..” w pliku należącym do i-węzła bieżącego katalogu i zmiany urządzenia / i-węzła bieżącego katalogu na wartość tam znaleziona.

pwd(dokładniej /bin/pwd) podąża ..kolejno za linkami i odczytuje odpowiednie katalogi, aż do znalezienia i-węzła, z którego pochodzi, zestawiając listę tych nazw w odwrotnej kolejności, aż dotrze do katalogu głównego (zwłaszcza nie zawierającego ..wpisu).

To jest pierwotne podstawowe zachowanie niskiego poziomu. Rzeczywiste polecenia powłoki pwdopierają się na różnych technikach buforowania bieżącej nazwy ścieżki. Ale w istocie znany jest tylko jego i-węzeł. Oznacza to, że po użyciu dowiązań symbolicznych do nawigacji w katalogach bieżące nazwy katalogów roboczych bieżącej powłoki i systemu /bin/pwdmogą się różnić.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.