Beinhaltet die PFAD-Suche Symlinks?

9

Der POSIX-Shell-Standard besagt dies auf dieser Site

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

Informationen darüber, wie Shells PATHzur Suche nach ausführbaren Dateien verwendet werden:

"Die Liste wird von Anfang bis Ende durchsucht, 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 es in einer echten POSIX-Implementierung nicht zu funktionieren:

man which sagt:

msgstr "" "gibt die Pfadnamen der Dateien (oder Links) zurück, die in der aktuellen Umgebung ausgeführt würden, wenn ihre Argumente als Befehle in einer streng POSIX - konformen Shell angegeben worden wären. Dies geschieht, indem der Pfad nach ausführbaren Dateien durchsucht wird, die mit den Namen der Dateien übereinstimmen Argumente. Es folgt keinen symbolischen Verknüpfungen. "

OK, schauen wir uns diese Situation an:

$ 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 gar nicht an, sondern interessiert sich nur dafür, worauf es hinweist.

Trotz der Tatsache, dass beide man whichausdrücklich besagen, dass sie keinen symbolischen Links folgen (und wir sehen, dass sie nicht folgen, weil which foobarsie nicht gedruckt werden foobar1) und dass in der oben zitierten POSIX-Shell-Dokumentation niemals erwähnt wird, dass Symlinks im PATHAlgorithmus folgen .

Ist whichund sind die vorhandenen Shells 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 die Dokumentation: Wo liegt mein Fehler bei der Befolgung der von mir zitierten Dokumentation? 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 Anforderung, dass das Wort des aktuellen POSIX-Standards GENAU befolgt werden MUSS (oder genauer gesagt, das Beste, weil der Standard selbst etwas fehlerhaft ist). Als ob es das Wort Gottes wäre.

Nun ist der Standardtext ziemlich klar - folgende Symlinks werden nicht erwähnt, an vielen anderen Stellen wird erwähnt, wo dies getan werden muss. Also in diesem Fall nicht.

Ich überprüfe jedoch immer genau, wie dashund wie ich mich bashverhalte, um sicherzugehen. Jetzt gibt es natürlich auch hier ein kleines Problem, dashobwohl es als POSIX berechnet wird und viele kleine Fehler in Übereinstimmung mit POSIX aufweist. bashIch habe noch keine Bugs mit POSIX gefunden, aber ... bash ist nicht wirklich POSIX, es ist viel mehr.

Da haben Sie es also. Deshalb ist es mir wichtig.

user322908
quelle
Du verstehst nicht: Was folgt nicht Symlinks auf Dateien . $PATHDose enthält Symlinks. Versuchen Sie es which sh.
Ipor Sircer
OK, aber in meinem Fall $PATHhat keine Symlinks.
User322908
In fast allen Situationen werden Symlinks transparent verfolgt. Die Fälle, in denen dies nicht der Fall ist, werden normalerweise explizit erwähnt (z. B. Systemaufrufe wie lstat(2)). Beispielsweise werden in der Beschreibung open(2)nur Symlinks erwähnt, wenn über das Verhalten von gesprochen wird O_CREAT | O_EXCL. Es muss nicht angegeben werden, dass die Zieldatei geöffnet wird.
Barmar

Antworten:

10

Die Berechtigungen des Symlinks selbst sind irrelevant. Sie könnten sie nicht einmal ändern, wenn Sie es versuchen würden.

Entscheidend sind die Berechtigungen der zugrunde liegenden Datei.

Es ist in Ordnung, dass Verzeichnisse in Ihrem PATH Symlinks zu ausführbaren Dateien enthalten. In der Tat 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 von symbolischen Links. Der chmod-Systemaufruf kann ihre Berechtigungen nicht ändern. Dies ist kein Problem, da die Berechtigungen von symbolischen Links niemals verwendet werden. Für jeden in der Befehlszeile aufgeführten symbolischen Link ändert chmod jedoch die Berechtigungen der Datei, auf die verwiesen wird. Im Gegensatz dazu ignoriert chmod symbolische Links, die bei rekursiven Verzeichnisdurchläufen auftreten. [Betonung hinzugefügt.]

Beispiel

Die Shell hat einen Test, -xum festzustellen, ob eine Datei ausführbar ist. Lass es uns versuchen:

$ 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 betrachtet whichdie Shell , wie Sie es bei festgestellt haben , eine ausführbare Softlink-Datei nur dann als ausführbar, wenn die zugrunde liegende Datei ausführbar ist.

Wie was funktioniert

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

 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, wird der -xTest verwendet, um festzustellen, ob eine Datei ausführbar ist.

POSIX spezifiziert den -xTest wie folgt:

-x Pfadname
True, wenn der 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, wenn es sich um ein Verzeichnis handelt) erteilt wird, wie in Datei lesen, schreiben und erstellen definiert. False, wenn der Pfadname nicht aufgelöst werden kann oder wenn der Pfadname in einen vorhandenen Verzeichniseintrag für eine Datei aufgelöst wird, für die die Berechtigung zum Ausführen (oder Durchsuchen) der Datei nicht erteilt wird. [Betonung hinzugefügt.]

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

POSIX-Exec-Funktion

Die POSIX-Exec-Funktion folgt symbolischen Links. Die POSIX-Spezifikation wird ausführlich beschrieben, um Fehlerzustände anzugeben, die möglicherweise gemeldet werden, wenn Symlinks zirkulär oder zu tief sind, z.

[ELOOP]
In symbolischen Links, die während der Auflösung des Pfad- oder Dateiarguments auftreten, ist eine Schleife vorhanden.

[ELOOP]
Bei der Auflösung des Pfad- oder Datei-Arguments wurden mehr als {SYMLOOP_MAX} symbolische Links gefunden.
[ENAMETOOLONG]
Infolge einer symbolischen Verknüpfung bei der Auflösung des Pfadarguments überschritt die Länge der ersetzten Pfadnamenzeichenfolge {PATH_MAX}.

John1024
quelle
Ich weiß alles, was Sie in Ihrer Antwort geschrieben haben. Ich weiß, wie Dinge "funktionieren". Das ist nicht meine frage Meine Frage betrifft die Dokumentation. Zeigen Sie mir, wo ich die Dokumentation nicht verstehe. Oder sag mir, dass die Dokumentation falsch ist.
User322908
@ user322908 Auf den meisten Systemen whichhandelt es sich um ein Shell-Skript. Daher ist es wahrscheinlich nur mit dem -xTest, den ich gezeigt habe. Prüft laut POSIX, -xob eine Datei in eine ausführbare Datei "aufgelöst" wird. Wenn Sie etwas anderes sehen, wo suchen Sie dann?
John1024
Vielen Dank und es tut mir leid, dass ich so weh getan habe. Mir ist klar, dass meine Frage sich von 99% der Fragen unterscheidet. Es ist daher schwer zu verstehen, wonach ich suche. Auch hier interessiert mich nicht, wie es whichfunktioniert oder ob es -xetwas anderes ist. Ich bin interessiert zu wissen, wo ich die von mir zitierte Dokumentation nicht richtig verfolge.
User322908
4
@ user322908 Die POSIX- execFunktion folgt symbolischen Links . Das scheint ziemlich deutlich zu machen, dass symbolisch verknüpfte Dateien unter POSIX ausführbar sein können.
John1024
2
Ich habe auch das Ubuntu 17.10 man which überprüft, in dem steht : "Pfadnamen werden nicht kanonisiert." Das heißt nicht, dass es den Links nicht folgt. Das bedeutet nur, wie Sie bemerkt haben, dass es die Namen nicht "kanonisiert".
John1024
3

In diesem Fall werden Symlinks transparent verfolgt, ohne den endgültigen Pfad zu kanonisieren. Mit anderen Worten, whiches ist egal, ob /home/mark/bines sich um einen Symlink handelt oder nicht. Was es interessiert, ist, ob die Datei /home/mark/bin/foobarexistiert oder nicht. Es ist nicht erforderlich , Symlinks entlang des Pfads manuell zu reduzieren - das Betriebssystem kann dies problemlos alleine tun.

Und tatsächlich, wenn whichnach Dateiinformationen gefragt wird /home/mark/bin/foobar, stellt das Betriebssystem fest, /home/mark/bindass es sich um einen Symlink handelt, folgt diesem und findet ihn erfolgreich foobarim Zielverzeichnis.

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

[Kommentare zusammengeführt in]

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 Verknüpfungen in allen Pfadkomponenten mit Ausnahme der letzten.)

Wenn in der Spezifikation nicht explizit angegeben ist, was mit Symlinks geschehen soll, wird das Standardverhalten verwendet. Das heißt, eine Shell, die dem Pfadalgorithmus folgt, löst Symlinks weder manuell auf, noch deaktiviert sie explizit das Betriebssystem, indem sie dasselbe tut. (Es verkettet einfach jede $ PATH-Komponente mit dem Namen der ausführbaren Datei.)

Wenn die what (1) -Handbuchseite besagt, dass sie keinen Symlinks folgt, kann das verschiedene Dinge bedeuten, aber die GNU-Coreutils-Version sagt es so aus:

Dabei werden zwei gleichwertige Verzeichnisse als unterschiedlich betrachtet, wenn eines einen Pfad mit einer symbolischen Verknüpfung enthält.

Das ist viel enger gefasst - es bedeutet nur, whichdass nicht versucht wird, alle Pfade zum Entfernen von Duplikaten manuell zu kanonisieren, aber dies bedeutet nicht, dass das Tool das Verfolgen von Symlinks 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.

Grawity
quelle
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 über Dokumentation. Wo verfolge ich die Dokumentation falsch. Oder ist die Dokumentation falsch.
User322908
2
Sie verstehen die Dokumentation falsch. Wenn die folgenden Symlinks nicht erwähnt werden, bedeutet dies, dass die Symlinks nicht manuell aufgelöst werden , das normale Verhalten des Betriebssystems jedoch weiterhin gilt. Auf der GNU- whichHandbuchseite heißt es anders: "Zwei gleichwertige Verzeichnisse werden als unterschiedlich betrachtet, wenn eines einen Pfad mit einem symbolischen Link enthält."
Grawity
OK, das ist besser, danke! Ich versuche zu verstehen ... Aber ... entschuldigen Sie, dass ich ein Nackenschmerz bin: "Das normale Verhalten des Betriebssystems" ist NICHT, immer implizit Symlinks zu folgen. Es gibt viele Dienstprogramme, die dies nicht tun. Es ist von Fall zu Fall.
User322908
1
Alle Kernel-Aufrufe - chdir, open, chmod, execve ... - folgen symbolischen Links sowohl im Pfad als auch im Tail, sofern Sie nicht AT_SYMLINK_NOFOLLOW oder ähnliches angeben. (lstat ist der einzige, der Symlinks am Ende nicht dereferenziert, dies jedoch für den verbleibenden Pfad.) Daher ist das Standardverhalten, Symlinks zu folgen. Wenn beispielsweise eine Shell aufruft execve("/home/mark/bin/foobar", …), werden alle Symlinks befolgt.
Grawity
OK, ich glaube, ich kaufe das execveArgument, tatsächlich ist es in meiner Implementierung execl()dasselbe. Bitte, wenn Sie dies in Ihre Antwort aufnehmen, werde ich akzeptieren.
User322908
1

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

Die Ausgabe von whichist der Dateiname und der Pfad des Links, nicht der Pfad, auf den der Symlink verweist. Dies ist in der Manpage angegeben.

Wenn ein Befehl ausgeführt wird, wird der Verknüpfung gemäß Abschnitt 4.13 Pfadnamenauflösung in derselben "gefolgt" . 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, mit der Ausnahme, dass, wenn der Inhalt des symbolischen Links eine leere Zeichenfolge ist, bei Funktionen, die ein [ENOENT] melden, eine der beiden Pfadnamenauflösungen fehlschlägt ] 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 und die kombinierte Länge {PATH_MAX} überschreitet und die Implementierung dies als Fehler ansieht, Die Auflösung von Pfadnamen schlägt fehl, wenn Funktionen einen [ENAMETOOLONG] -Fehler melden und Dienstprogramme eine entsprechende Diagnosemeldung schreiben. Andernfalls ist der aufgelöste Pfadname die Auflösung des gerade erstellten Pfadnamens. Wenn der resultierende Pfadname nicht mit einem beginnt, wird der Vorgänger des ersten Dateinamens des Pfadnamens als das Verzeichnis mit der symbolischen Verknüpfung angenommen.

Dave
quelle