czy wyszukiwanie PATH obejmuje dowiązania symboliczne?

9

Standard powłoki POSIX mówi na tej stronie

http://pubs.opengroup.org/onlinepubs/9699919799/

o tym, jak powłoki używają PATHdo wyszukiwania plików wykonywalnych:

„Listę należy przeszukiwać od początku do końca, stosując nazwę pliku do każdego prefiksu, aż do znalezienia pliku wykonywalnego o określonej nazwie i odpowiednich uprawnieniach do wykonywania.”

Cóż, nie tak to wygląda w rzeczywistej implementacji POSIX:

man which mówi:

"zwraca nazwy ścieżek plików (lub linków), które byłyby wykonane w bieżącym środowisku, gdyby ich argumenty zostały podane jako polecenia w ściśle zgodnej z POSIX powłoce. Robi to, przeszukując PATH w poszukiwaniu plików wykonywalnych pasujących do nazw argumenty. Nie podąża za dowiązaniami symbolicznymi. ”

OK, spójrzmy na tę sytuację:

$ pwd /home/mark

$ echo $PATH /home/mark/bin:...

$ ls -l bin/foobar
lrwxrwxrwx 1 mark mark 18 Dec 12 22:51 bin/foobar -> /home/mark/foobar1
$ touch foobar1
$ which foobar
$ chmod a+x foobar1
$ which foobar
/home/mark/bin/foobar

OK, tutaj jest dowiązanie symboliczne PATHz poprawną nazwą i jest zgłaszane przez program lsjako wykonywalny.

which wcale na to nie patrzy, ale interesuje go tylko to, na co wskazuje.

Że pomimo faktu, że oba man whichwyraźnie mówią, że nie podąża za dowiązaniami symbolicznymi (i rzeczywiście widzimy, że nie, ponieważ which foobarnie drukuje foobar1), a także, że cytowana powyżej dokumentacja powłoki POSIX nigdy nie wspomina o dowiązaniach symbolicznych w PATHalgorytmie.

Tak więc, whichczy istniejące powłoki są nieprawidłowe, czy też nie rozumiem dokumentacji?

WYJAŚNIĆ:

Znam i potrafię wyjaśnić istniejące zachowanie. Moje pytanie nie brzmi „jak to działa?”. To wiem.

Moje pytanie dotyczy dokumentacji: gdzie jest mój błąd w stosowaniu cytowanej przeze mnie dokumentacji. A może dokumentacja jest nieprawidłowa?

MOTYWACJA: Dlaczego mnie to obchodzi?

Jestem implementatorem. Różni realizatorzy mają różne wymagania. Dla mnie wymaganiem jest, aby słowo obecnego standardu POSIX MUSI BYĆ DOKŁADNIE WYKONANE (lub, dokładniej, najlepiej, jak może być, ponieważ sam standard jest nieco błędny). Jakby to było słowo Boże.

Teraz standardowe sformułowanie jest dość jasne - nie wymieniono następujących dowiązań symbolicznych, gdzie w wielu innych miejscach wspomniano, gdzie należy to zrobić. Więc w tym przypadku nie.

Ja jednak zawsze dokładnie sprawdzić, jak dashi bashzachowywać, żeby się upewnić. Oczywiście jest tu również mały problem, dashmimo że jest rozliczany jako POSIX, ma wiele małych błędów zgodnych z POSIX. bash, Jeszcze nie znalazłem żadnych błędów w POSIX, ale ... bash nie jest tak naprawdę POSIX, to o wiele więcej.

Więc masz to. Dlatego mnie to obchodzi.

użytkownik322908
źródło
Nie rozumiesz: co nie podąża za dowiązaniami symbolicznymi w plikach . $PATHmoże zawierać dowiązania symboliczne. Spróbować which sh.
Ipor Sircer,
OK, ale w moim przypadku $PATHnie ma żadnych dowiązań symbolicznych.
user322908,
W prawie wszystkich sytuacjach dowiązania symboliczne są stosowane w przejrzysty sposób. Przypadki, w których ich nie ma, są zwykle wyraźnie wymienione (np. Wywołania systemowe, takie jak lstat(2)), ich przestrzeganie zwykle nie jest określone. Na przykład, opis open(2)tylko wzmiankuje dowiązania symboliczne, gdy mówi się o zachowaniu O_CREAT | O_EXCL. Nie trzeba podawać, że plik docelowy zostanie otwarty.
Barmar

Odpowiedzi:

10

Uprawnienia do samego dowiązania symbolicznego są nieistotne. Nie możesz ich nawet zmienić, jeśli spróbujesz.

Liczy się uprawnienia do pliku bazowego.

W porządku jest, aby katalogi w PATH zawierały dowiązania symboliczne do plików wykonywalnych. W rzeczywistości jest prawdopodobne, że wiele plików wykonywalnych w zmiennej PATH to dowiązania symboliczne. Na przykład w systemach typu debian / ubuntu:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 23  2017 /bin/sh -> dash

Dokumentacja

Od man chmod:

chmod nigdy nie zmienia uprawnień do dowiązań symbolicznych; wywołanie systemowe chmod nie może zmienić swoich uprawnień. Nie stanowi to problemu, ponieważ uprawnienia dowiązań symbolicznych nigdy nie są używane. Jednak dla każdego dowiązania symbolicznego wymienionego w wierszu polecenia chmod zmienia uprawnienia do wskazanego pliku. Natomiast chmod ignoruje dowiązania symboliczne napotkane podczas przechodzenia przez rekurencyjne katalogi. [Podkreślenie dodane.]

Przykład

Powłoka ma test, -xaby ustalić, czy plik jest wykonywalny. Spróbujmy:

$ ls -l
total 0
lrwxrwxrwx 1 john1024 john1024 7 Dec 12 23:36 foo -> foobar1
-rw-rw---- 1 john1024 john1024 0 Dec 12 23:36 foobar1
$ [ -x foo ] && echo foo is executable
$ chmod +x foobar1
$ [ -x foo ] && echo foo is executable
foo is executable

Tak jak w whichprzypadku powłoki, powłoka nie uważa pliku wykonywalnego softlink, chyba że plik źródłowy jest wykonywalny.

Jak to działa

W systemie Debian whichjest skryptem powłoki. Odpowiednia sekcja kodu to:

 case $PROGRAM in
  */*)
   if [ -f "$PROGRAM" ] && [ -x "$PROGRAM" ]; then
    puts "$PROGRAM"
    RET=0
   fi
   ;;
  *)
   for ELEMENT in $PATH; do
    if [ -z "$ELEMENT" ]; then
     ELEMENT=.
    fi
    if [ -f "$ELEMENT/$PROGRAM" ] && [ -x "$ELEMENT/$PROGRAM" ]; then
     puts "$ELEMENT/$PROGRAM"
     RET=0
     [ "$ALLMATCHES" -eq 1 ] || break
    fi
   done
   ;;
 esac

Jak widać, wykorzystuje on -xtest do ustalenia, czy plik jest wykonywalny.

POSIX określa -xtest w następujący sposób:

-x nazwa ścieżki
Prawda, jeśli nazwa ścieżki rozwiązuje istniejącą pozycję katalogu dla pliku, dla którego udzielone zostanie zezwolenie na wykonanie pliku (lub przeszukanie go, jeśli jest to katalog), zgodnie z definicją w Odczyt pliku, Zapis i Tworzenie. Fałsz, jeśli nazwa ścieżki nie może zostać rozwiązana lub jeśli nazwa ścieżki rozwiązuje istniejący wpis katalogu dla pliku, dla którego uprawnienia do wykonania (lub wyszukiwania) pliku nie zostaną udzielone. [Podkreślenie dodane.]

POSIX sprawdza więc, do czego rozwiązuje się nazwa ścieżki . Innymi słowy, akceptuje dowiązania symboliczne.

Funkcja wykonująca POSIX

Funkcja wykonująca POSIX podąża za dowiązaniami symbolicznymi. Specyfikacja POSIX jest długa, aby określić warunki błędu, które może zgłosić, jeśli dowiązania symboliczne są okrągłe lub zbyt głębokie, takie jak:

[ELOOP]
Pętla występuje w dowiązaniach symbolicznych podczas rozwiązywania argumentu ścieżki lub pliku.

[ELOOP]
Podczas rozpoznawania argumentu ścieżki lub pliku napotkano więcej niż {SYMLOOP_MAX} dowiązań symbolicznych.
[ENAMETOOLONG]
W wyniku napotkania dowiązania symbolicznego w rozdzielczości argumentu path długość podstawionego ciągu nazwy ścieżki przekroczyła {PATH_MAX}.

John1024
źródło
WIEM wszystko, co napisałeś w swojej odpowiedzi. Wiem, jak rzeczy „działają”. To nie jest moje pytanie. Moje pytanie dotyczy dokumentacji. Wskaż mi, gdzie nie rozumiem dokumentacji. Lub powiedz mi, że dokumentacja jest niepoprawna.
user322908,
@ user322908 W większości systemów whichjest skryptem powłoki. Prawdopodobnie po prostu korzystam z -xtestu, który pokazałem. Według POSIX -xsprawdza, czy plik „rozpoznaje” plik wykonywalny. Jeśli widzisz coś innego, gdzie szukasz?
John1024,
Dziękuję i przepraszam za bycie takim bólem ... Zdaję sobie sprawę, że moje pytanie różni się od pytań w 99%, więc trudno zrozumieć, o co mi chodzi. Znów nie interesuje mnie „jak” whichdziała, czy to jest, -xczy coś innego. Chciałbym wiedzieć, gdzie nie przestrzegam poprawnie cytowanej przeze mnie dokumentacji.
user322908,
4
@ user322908 POSIX execfunkcji następuje dowiązania. Wydaje się to dość jasne, że pliki dowiązane symbolicznie mogą być plikami wykonywalnymi w systemie POSIX.
John1024,
2
Sprawdziłem również Ubuntu 17.10, man which który mówi: „Nie kanonizuje nazw ścieżek”. To nie znaczy, że nie podąża za linkami. Oznacza to tylko, jak zauważyłeś, że nie „kanonizuje” nazw.
John1024,
3

W tym przypadku dowiązania symboliczne są śledzone w sposób transparentny, bez kanonizacji końcowej ścieżki. Innymi słowy, whichnie dba o /home/mark/binto, czy jest dowiązaniem symbolicznym, czy nie. Ważne jest, czy plik /home/mark/bin/foobaristnieje, czy nie. Nie musi ręcznie spłaszczać dowiązań symbolicznych na ścieżce - system operacyjny może to zrobić samodzielnie.

I rzeczywiście, gdy whichpyta o informacje o pliku /home/mark/bin/foobar, system operacyjny zauważa, /home/mark/binże jest dowiązaniem symbolicznym, podąża za nim i z powodzeniem znajduje foobarw katalogu docelowym.

Jest to zachowanie domyślne, chyba że program używa open(…, O_NOFOLLOW)lub fstatat(…, AT_SYMLINK_NOFOLLOW)uzyskuje dostęp do pliku.

[komentarze zostały scalone]

Chociaż można powiedzieć, że media shell to zrobić na zasadzie case-by-case, to nie jest to samo z syscalli jądra: wszystkie połączenia związane z plikami zrobić śledzić dowiązania domyślnie, chyba że podano flagę „nofollow”. (Nawet lstat podąża za dowiązaniami symbolicznymi we wszystkich komponentach ścieżki oprócz ostatniego.)

Gdy specyfikacja nie mówi wprost o tym, co zrobić z dowiązaniami symbolicznymi, oznacza to, że zostanie użyte zachowanie domyślne. Oznacza to, że powłoka podążająca za algorytmem ścieżki nie rozpoznaje dowiązań symbolicznych ręcznie, ani też wyraźnie nie rezygnuje z tego, aby system operacyjny to robił. (Po prostu łączy każdy składnik $ PATH z nazwą pliku wykonywalnego.)

Kiedy strona podręcznika what (1) mówi, że nie podąża za dowiązaniami symbolicznymi, może to oznaczać kilka rzeczy, ale wersja GNU coreutils stwierdza to w ten sposób:

Który uzna, że ​​dwa równoważne katalogi są różne, gdy jeden z nich zawiera ścieżkę z dowiązaniem symbolicznym.

Jest to znacznie węższy zakres - oznacza to tylko, że whichnie będzie próbował ręcznie kanonizować wszystkich ścieżek, aby usunąć duplikaty, ale nie oznacza to, że narzędzie zrezygnuje z dowiązania symbolicznego stosowanego przez system operacyjny w ogóle. Na przykład, jeśli /binjest dowiązaniem symbolicznym /usr/bin, uruchomienie which -a shzwróci zarówno /bin/sh i /usr/bin/sh.

użytkownik1686
źródło
Tak, dziękuję, wiem o tym wszystkim. Moje pytanie nie dotyczy tego, jak rzeczy „działają”. Wiem jak działają. Nie o to mi chodzi. Chodzi mi o dokumentację. Gdzie niepoprawnie śledzę dokumentację. Lub dokumentacja jest nieprawidłowa.
user322908,
2
Dokumentacja jest źle rozumiana - jeśli nie wspomina o następujących dowiązaniach symbolicznych, oznacza to, że nie rozpoznaje ręcznie dowiązań symbolicznych, ale nadal obowiązuje normalne zachowanie systemu operacyjnego . Strona whichpodręcznika GNU stwierdza inaczej: „Które uznają dwa równoważne katalogi za różne, gdy jeden z nich zawiera ścieżkę z dowiązaniem symbolicznym”.
user1686,
OK, lepiej dziękuję! Próbuję zrozumieć ... Ale ... wybacz mi, że odczuwałem ból w szyi: „regularne zachowanie systemu operacyjnego” wcale NIE oznacza zawsze pośrednio podążać za symbolami. Istnieje wiele narzędzi, które tego nie robią. To zależy od przypadku.
user322908,
1
Wszystkie wywołania jądra - chdir, open, chmod, execve ... - będą podążać za dowiązaniami symbolicznymi zarówno na ścieżce, jak i na ogonie, chyba że podasz AT_SYMLINK_NOFOLLOW lub podobny. (lstat jest jedynym, który nie wyklucza dowiązań symbolicznych na ogonie, ale nadal robi to dla pozostałej ścieżki). Dlatego domyślnym zachowaniem jest podążanie za dowiązaniami symbolicznymi. Na przykład, gdy powłoka wywołuje execve("/home/mark/bin/foobar", …), spowoduje to, że wszystkie dowiązania symboliczne będą śledzone.
user1686,
OK, myślę, że kupuję execveargument, właściwie to w mojej implementacji jest to execl()samo. Jeśli uwzględnisz to w swojej odpowiedzi, zaakceptuję.
user322908,
1

Powłoka jest zgodna ze swoją dokumentacją, ponieważ przestrzega zasad rozpoznawania nazw ścieżek. whichjest zgodny z jego dokumentacją. Obaj robią nieco inne rzeczy.

Wynikiem whichjest nazwa pliku i ścieżka łącza, a nie ścieżka do tego, na co wskazuje dowiązanie symboliczne. Jest to zapisane na stronie podręcznika.

Po wykonaniu polecenia łącze jest „śledzone” zgodnie z rozdziałem 4.13 Rozpoznawanie nazw ścieżek w ten sam sposób . Odpowiednią klauzulą ​​dotyczącą wykonania pliku jest:

We wszystkich innych przypadkach system poprzedza pozostałą nazwę ścieżki, jeśli taka istnieje, zawartością dowiązania symbolicznego, z tym wyjątkiem, że jeśli treść dowiązania symbolicznego jest pustym łańcuchem, wówczas rozpoznawanie nazw ścieżek kończy się niepowodzeniem, a funkcje zgłaszają [ENOENT ] błąd i narzędzia piszące równoważny komunikat diagnostyczny lub nazwa ścieżki katalogu zawierającego dowiązanie symboliczne powinny być użyte zamiast zawartości dowiązania symbolicznego. Jeżeli zawartość dowiązania symbolicznego składa się wyłącznie ze znaków, wówczas wszystkie wiodące znaki pozostałej nazwy ścieżki należy pominąć w wynikowej połączonej nazwie ścieżki, pozostawiając tylko wiodące znaki z treści łącza symbolicznego. W przypadkach, w których występuje prefiks, jeśli łączna długość przekracza {PATH_MAX}, a implementacja uznaje to za błąd, rozpoznawanie nazwy ścieżki nie powiedzie się, gdy funkcje zgłaszają błąd [ENAMETOOLONG], a narzędzia zapisują równoważny komunikat diagnostyczny. W przeciwnym razie rozstrzygnięta nazwa ścieżki powinna być rozdzielczością właśnie utworzonej nazwy ścieżki. Jeśli wynikowa nazwa ścieżki nie zaczyna się od a, poprzednikiem pierwszej nazwy pliku ścieżki jest katalog zawierający łącze symboliczne.

Dave
źródło