Enthält die PATH-Suche Symlinks?

1275
user322908

Der POSIX-Shell-Standard sagt auf dieser Site

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

wie Shells PATHnach ausführbaren Dateien suchen:

"Die Liste soll von Anfang bis Ende durchsucht werden, wobei der Dateiname auf jedes Präfix angewendet wird, bis eine ausführbare Datei mit dem angegebenen Namen und den entsprechenden Ausführungsberechtigungen gefunden wird."

Nun, so scheint das in der realen POSIX-Implementierung nicht zu funktionieren:

man which sagt:

"gibt die Pfadnamen der Dateien (oder Verknüpfungen) zurück, die in der aktuellen Umgebung ausgeführt werden würden, wenn ihre Argumente als Befehle in einer streng POSIX - konformen Shell angegeben würden. Dazu sucht der PATH nach ausführbaren Dateien, die mit den Namen der Datei übereinstimmen Argumente. Es folgt nicht symbolischen Links. "

OK, lass uns diese Situation betrachten:

$ 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, hier ist ein symbolischer Link PATHmit dem richtigen Namen, und es wird gemeldet ls, dass er ausführbar ist.

which schaut es überhaupt nicht an, sondern interessiert nur, worauf es hinweist.

Trotz der Tatsache, dass beide man whichexplizit sagen, dass sie symbolischen Links nicht folgt (und in der Tat nicht, weil which foobarnicht gedruckt wird foobar1), und dass die oben zitierte POSIX-Shell-Dokumentation niemals folgende Symlinks im PATHAlgorithmus erwähnt.

Ist also whichund sind die vorhandenen Schalen falsch, oder verstehe ich die Dokumentation nicht?

ZU KLÄREN:

Ich kenne und kann das vorhandene Verhalten erklären. Meine Frage ist nicht "wie funktioniert das?". Dass ich weiß.

Meine Frage bezieht sich auf Dokumentation: Wo liegt mein Fehler darin, der von mir zitierten Dokumentation zu folgen. Oder ist die Dokumentation falsch?

MOTIVATION: Warum kümmert es mich?

Nun, ich bin ein Implementierer. Unterschiedliche Implementierer haben unterschiedliche Anforderungen. Für mich ist die Forderung, dass das Wort des aktuellen POSIX-Standards MÜSSEN GENAU MUSS (oder, genauer gesagt, das Beste, was es sein kann, weil der Standard selbst etwas fehlerhaft ist). Wie das Wort Gottes.

Nun ist der Standardwortlaut ziemlich klar - das Folgen von Symlinks wird nicht erwähnt, wo an vielen anderen Stellen erwähnt wird, wo es gemacht werden muss. Also in diesem Fall nicht.

Ich überprüfe jedoch immer wie dashund bashverhalte mich, nur um sicher zu gehen. Nun gibt es natürlich auch hier ein kleines Problem, dashobwohl es als POSIX in Rechnung gestellt wird und viele kleine Fehler mit der POSIX-Konformität aufweist. bash, Ich habe noch keine Fehler mit POSIX gefunden, aber ... bash ist nicht wirklich POSIX, es ist viel mehr als das.

Also da hast du es. Deshalb kümmere ich mich.

9
Sie verstehen nicht: was Symlinks in ** Dateien ** nicht folgt. `$ PATH` kann symbolische Links enthalten. Versuchen Sie "which sh". Ipor Sircer vor 6 Jahren 0
OK, aber in meinem Fall hat $ PATH keine Symlinks. user322908 vor 6 Jahren 0
In fast allen Situationen werden Symlinks transparent verfolgt. Die Fälle, in denen sie * nicht * sind, werden in der Regel explizit erwähnt (z. B. Systemaufrufe wie "lstat (2)"). Nach ihnen wird normalerweise nicht angegeben. Beispielsweise werden in der Beschreibung von `open (2)` nur Symlinks erwähnt, wenn Sie über das Verhalten von `O_CREAT | sprechen O_EXCL`. Es muss nicht angegeben werden, dass die Zieldatei geöffnet wird. Barmar vor 6 Jahren 0

3 Antworten auf die Frage

10
John1024

Die Berechtigungen des Symlinks selbst sind unerheblich. Sie konnten sie nicht einmal ändern, wenn Sie es versuchten.

Was zählt, sind die Berechtigungen der zugrunde liegenden Datei.

Es ist in Ordnung, dass Verzeichnisse in Ihrem PATH Symlinks zu ausführbaren Dateien enthalten. Tatsächlich ist es wahrscheinlich, dass viele ausführbare Dateien in Ihrem PATH Symlinks sind. Zum Beispiel auf Debian / Ubuntu-ähnlichen Systemen:

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

Dokumentation

Von man chmod:

chmod ändert niemals die Berechtigungen symbolischer Links. Der chmod-Systemaufruf kann seine Berechtigungen nicht ändern. Dies ist kein Problem, da die Berechtigungen symbolischer Links niemals verwendet werden. Für jeden in der Befehlszeile aufgelisteten symbolischen Link ändert chmod jedoch die Berechtigungen der Datei, auf die verwiesen wird. Im Gegensatz dazu ignoriert chmod symbolische Links, die während rekursiver Verzeichnisdurchquerungen gefunden wurden. [Betonung hinzugefügt.]

Beispiel

Die Shell hat einen Test, -xum festzustellen, ob eine Datei ausführbar ist. Versuchen wir das mal:

$ 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 

So wie Sie es mit gefunden haben which, betrachtet die Shell eine Softlink-Programmdatei nicht, es sei denn, die zugrunde liegende Datei ist ausführbar.

Wie das funktioniert

Auf einem Debian-System whichist ein Shell-Skript. Der relevante Abschnitt des Codes ist:

 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 

Wie Sie sehen, verwendet es den -xTest, um festzustellen, ob eine Datei ausführbar ist.

POSIX spezifiziert den -xTest wie folgt:

-x Pfadname
True, wenn Pfadname in einen vorhandenen Verzeichniseintrag für eine Datei aufgelöst wird, für die die Berechtigung zum Ausführen der Datei (oder zum Durchsuchen dieser Datei, wenn es sich um ein Verzeichnis handelt) erteilt wird, wie in Datei Lesen, Schreiben und Erstellen definiert. False, wenn Pfadname nicht aufgelöst werden kann oder wenn Pfadname in einen vorhandenen Verzeichniseintrag für eine Datei aufgelöst wird, für die die Berechtigung zum Ausführen (oder Suchen) der Datei nicht erteilt wird. [Betonung hinzugefügt.]

So prüft POSIX, was der Pfad löst zu. Mit anderen Worten, es akzeptiert symbolische Links.

POSIX-Exec-Funktion

Die POSIX-Exec-Funktion folgt Symlinks. Die POSIX-Spezifikation beschreibt ausführlich die Fehlerbedingungen, die gemeldet werden können, wenn Symlinks kreisförmig oder zu tief sind, z.

[ELOOP]
Eine Schleife existiert in symbolischen Links, die während der Auflösung des Pfad- oder Dateiarguments aufgetreten sind .

[ELOOP]
Bei der Auflösung des Pfad- oder Dateiarguments wurden mehr als symbolische Links gefunden.
[ENAMETOOLONG]
Durch das Auffinden eines symbolischen Links bei der Auflösung des Pfadarguments überschritt die Länge der ersetzten Pfadnamenzeichenfolge .

Ich weiß, was Sie in Ihrer Antwort geschrieben haben. Ich weiß, wie die Dinge funktionieren. Das ist nicht meine Frage. Meine Frage bezieht sich auf Dokumentation. Zeigen Sie mir, wo ich die Dokumentation nicht verstehe. Oder sagen Sie mir, dass die Dokumentation falsch ist. user322908 vor 6 Jahren 0
@ user322908 Auf den meisten Systemen ist "which" ein Shellskript. Daher ist es wahrscheinlich nur der `-x`-Test, den ich gezeigt habe. Laut POSIX prüft `-x ', ob eine Datei in eine ausführbare Datei aufgelöst wird. Wenn Sie etwas anderes sehen, wo suchen Sie? John1024 vor 6 Jahren 0
Vielen Dank und es tut mir leid, dass ich so ein Schmerz war ... Ich weiß, dass sich meine Frage von 99% der Fragen unterscheidet, daher ist es schwer zu verstehen, worauf ich hinaus will. Ich interessiere mich wiederum nicht für "wie", "was" funktioniert, oder ob es "-x" oder etwas anderes ist. Ich bin daran interessiert zu wissen, wo ich der zitierten Dokumentation nicht richtig folge. user322908 vor 6 Jahren 0
@ user322908 Ihr Link führt zur Titelseite. Ich habe gerade meine Antwort mit Zitaten aus dem Inneren der POSIX-Spezifikation aktualisiert. Wenn Sie etwas sehen, das dem widerspricht, was ich sehe, seien Sie bitte genauer. John1024 vor 6 Jahren 0
@ user322908 Die [POSIX-Funktion "exec" (http://pubs.opengroup.org/onlinepubs/009604599/functions/exec.html) folgt Symlinks. Das scheint ziemlich klar zu machen, dass symlinked Dateien unter POSIX ausführbar sein können. John1024 vor 6 Jahren 4
@ user322908 _ "Das trotz der Tatsache, dass beide Mann ausdrücklich sagen, dass sie symbolischen Links nicht folgt" _ Wo haben Sie das gefunden? Mein "Mann" sagt genau das Gegenteil. John1024 vor 6 Jahren 0
na ja, mein "mann welcher" und das ist das neueste Ubuntu, das sagt es nicht. user322908 vor 6 Jahren 0
Ja die `exec'-Funktion Ich glaube, ich kaufe dieses Argument (endlich). Das hat der andere schon erwähnt, auch im Kommentar. Wenn Sie dies in Ihre Antwort aufnehmen, werde ich akzeptieren. Und vielen Dank für Ihre Bemühungen, mir zu helfen. user322908 vor 6 Jahren 0
@ user322908 OK. Ich habe den POSIX-Link für exec hinzugefügt. John1024 vor 6 Jahren 0
Ich habe auch das [Ubuntu 17.10 `man which`] (http://manpages.ubuntu.com/manpages/artful/de/man1/which.1.html) überprüft, in dem es heißt:" Pfadnamen werden nicht kanonisiert. " Das bedeutet nicht, dass es nicht den Links folgt. Das bedeutet nur, wie Sie bemerkt haben, dass die Namen nicht "kanonisiert" werden. John1024 vor 6 Jahren 2
3
grawity

In diesem Fall werden Symlinks transparent verfolgt, ohne den endgültigen Pfad zu kanonisieren. Mit anderen Worten, whichkümmert sich nicht darum, ob /home/mark/bines sich um einen Symlink handelt oder nicht. Es geht darum, ob die Datei /home/mark/bin/foobarexistiert oder nicht. Es muss nicht notwendig sein, Symlinks entlang des Pfads manuell zu glätten. Das Betriebssystem kann dies problemlos selbst tun.

Und in der Tat, wenn das Betriebssystem nach Dateiinformationen whichfragt /home/mark/bin/foobar, bemerkt das Betriebssystem, /home/mark/bindass es ein Symlink ist, folgt ihm und findet erfolgreich foobarim Zielverzeichnis.

Dies ist das Standardverhalten, es sei denn, das Programm verwendet die open(…, O_NOFOLLOW)oder fstatat(…, AT_SYMLINK_NOFOLLOW)zum Zugriff auf die Datei.

[Kommentare zusammengeführt]

Während man sagt, dass Shell - Utilities es tut auf einer Fall-zu-Fall - Basis, ist es nicht das gleiche mit Kernel syscalls: alle dateibezogenen Anrufe tun standardmäßig Symlinks folgen, es sei denn, das „nofollow“ Flag gegeben wird. (Sogar lstat folgt symbolischen Links in allen Pfadkomponenten außer der letzten.)

Wenn in der Spezifikation nicht explizit erwähnt wird, was mit Symlinks zu tun ist, wird das Standardverhalten verwendet. Das heißt, eine Shell, die dem Pfadalgorithmus folgt, löst symbolische Links manuell auf und lehnt das Betriebssystem auch nicht explizit ab. (Es verkettet nur jede $ PATH-Komponente mit dem Namen der ausführbaren Datei.)

Wenn die which (1) -Manual-Seite sagt, dass sie nicht auf symbolische Links folgt, kann dies mehrere Dinge bedeuten, aber in der GNU-coreutils-Version heißt es:

Welches zwei äquivalente Verzeichnisse als unterschiedlich betrachtet, wenn eines von ihnen einen Pfad mit einem symbolischen Link enthält.

Das ist viel enger im Umfang - es bedeutet nur, whichdass Sie nicht versuchen werden, alle Pfade manuell zu kanonisieren, um Duplikate auszusondern. Dies bedeutet jedoch nicht, dass das Tool die Symlink-Verknüpfung durch das Betriebssystem im Allgemeinen ablehnt. Zum Beispiel, wenn /binein Link zu /usr/bin, läuft which -a shkehrt beide /bin/sh und /usr/bin/sh.

Ja danke, ich weiß das alles. Meine Frage ist nicht, wie die Dinge funktionieren. Ich weiß, wie sie funktionieren. Das ist nicht mein Punkt. Mein Punkt ist die Dokumentation. Wo folge ich der Dokumentation falsch? Oder ist die Dokumentation falsch? user322908 vor 6 Jahren 0
Sie verstehen die Dokumentation nicht richtig - wenn sie die folgenden Symbolverknüpfungen nicht erwähnt, werden die Symbolverknüpfungen nicht manuell _ aufgelöst, sondern das normale Verhalten des Betriebssystems _still_. Die GNU `which`-Manpage sagt es anders:" Welches zwei gleichwertige Verzeichnisse für unterschiedlich hält, wenn eines von ihnen einen Pfad mit einem symbolischen Link enthält. " grawity vor 6 Jahren 2
OK, das ist besser, danke! Ich versuche zu verstehen ... Aber ... Verzeihung, dass ich ein Schmerz im Nacken bin: "Das normale Verhalten des Betriebssystems" bedeutet NICHT, implizit immer auf symbolische Links zu folgen. Es gibt viele Dienstprogramme, die dies nicht tun. Es ist von Fall zu Fall. user322908 vor 6 Jahren 0
Alle Kernel-Aufrufe - chdir, open, chmod, execve ... - folgen sowohl im Pfad als auch im Tail den symbolischen Links. _Unless_ geben Sie AT_SYMLINK_NOFOLLOW oder ähnliches an. (lstat ist der einzige, der Symlinks am Ende nicht dereferenziert, jedoch immer noch für den verbleibenden Pfad.) Das Standardverhalten ist daher, Symlinks zu folgen. Wenn zum Beispiel eine Shell `execve '(" / home / mark / bin / foobar ", ...)` aufruft, werden alle Symlinks verfolgt. grawity vor 6 Jahren 1
OK, ich glaube, ich kaufe das Argument "execve". Eigentlich ist es in meiner Implementierung "execl ()", dieselbe Sache. Wenn Sie dies in Ihre Antwort aufnehmen, werde ich akzeptieren. user322908 vor 6 Jahren 0
1
Dave

Die Shell entspricht der Dokumentation, indem sie die Regeln für die Pfadnamenauflösung befolgt. whichentspricht seiner Dokumentation. Die beiden machen etwas unterschiedliche Dinge.

Die Ausgabe von whichist der Dateiname und der Pfad der Verknüpfung, nicht der Pfad, auf den der Symlink verweist. Dies ist in der Manpage beschrieben.

Wenn ein Befehl ausgeführt wird, wird der Link gemäß Abschnitt 4.13 "Pfadnamenauflösung" in derselben "verfolgt" . Die relevante Klausel zum Ausführen einer Datei lautet:

In allen anderen Fällen muss das System dem verbleibenden Pfadnamen, sofern vorhanden, den Inhalt des symbolischen Links voranstellen. Wenn der Inhalt des symbolischen Links jedoch der leere String ist, schlägt die Auflösung des Pfadnamens fehl, und die Funktionen melden ein [ENOENT ] Fehler und Dienstprogramme, die eine entsprechende Diagnosemeldung schreiben, oder der Pfadname des Verzeichnisses, das den symbolischen Link enthält, werden anstelle des Inhalts des symbolischen Links verwendet. Wenn der Inhalt des symbolischen Links nur aus Zeichen besteht, werden alle führenden Zeichen des verbleibenden Pfadnamens aus dem resultierenden kombinierten Pfadnamen weggelassen, wobei nur die führenden Zeichen aus dem Inhalt des symbolischen Links übrig bleiben. In den Fällen, in denen ein Präfix auftritt, wenn die kombinierte Länge überschreitet und die Implementierung dies für einen Fehler hält, Die Auflösung des Pfadnamens schlägt fehl, wenn Funktionen einen [ENAMETOOLONG] -Fehler melden und Dienstprogramme eine entsprechende Diagnosemeldung schreiben. Andernfalls muss der aufgelöste Pfadname die Auflösung des gerade erstellten Pfadnamens sein. Wenn der sich ergebende Pfadname nicht mit a beginnt, wird der Vorgänger des ersten Dateinamens des Pfadnamens als das Verzeichnis mit dem symbolischen Link angesehen.