la recherche PATH inclut-elle des liens symboliques?

9

La norme shell POSIX dit sur ce site

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

sur la façon dont les shells utilisent PATHpour rechercher les exécutables:

"La liste doit être recherchée du début à la fin, en appliquant le nom de fichier à chaque préfixe, jusqu'à ce qu'un fichier exécutable avec le nom spécifié et les autorisations d'exécution appropriées soit trouvé."

Eh bien, ce n'est pas ainsi que cela semble fonctionner dans une implémentation POSIX réelle:

man which dit:

"renvoie les chemins d'accès des fichiers (ou liens) qui seraient exécutés dans l'environnement actuel, si ses arguments avaient été donnés sous forme de commandes dans un shell strictement conforme à POSIX. Il le fait en recherchant dans le PATH des fichiers exécutables correspondant aux noms des arguments. Il ne suit pas les liens symboliques. "

OK, regardons cette situation:

$ 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, voici un lien symbolique PATHavec le nom correct, et il est signalé par lsêtre exécutable.

which ne le regarde pas du tout, mais ne s'intéresse qu'à ce qu'il pointe.

Cela malgré le fait que les deux man whichdisent explicitement qu'il ne suit pas les liens symboliques (et en effet nous le voyons pas, car which foobarne s'imprime pas foobar1), et aussi que la documentation du shell POSIX citée ci-dessus, ne mentionne jamais de suivre les liens symboliques dans l' PATHalgorithme.

Alors, est which-ce que les obus existants sont faux, ou est-ce que je ne comprends pas la documentation?

CLARIFIER:

Je connais et peux expliquer le comportement existant. Ma question n'est pas "comment ça marche?". Ce que je sais.

Ma question concerne la documentation: où est mon erreur en suivant la documentation que j'ai citée. Ou la documentation est-elle erronée?

MOTIVATION: Pourquoi je m'en soucie?

Eh bien, je suis un réalisateur. Les différents implémenteurs ont des exigences différentes. Pour moi, l'exigence est que le mot de la norme POSIX actuelle DOIT être suivi EXACTEMENT (ou, plus précisément, le meilleur possible, car la norme elle-même est quelque peu boguée). Comme si c'était la parole de Dieu.

Maintenant, le libellé standard est assez clair - les liens symboliques suivants ne sont pas mentionnés, alors que dans de nombreux autres endroits, il est mentionné où cela doit être fait. Donc, dans ce cas, ne le faites pas.

Cependant, je vérifie toujours comment dashet je me bashcomporte, juste pour m'assurer. Maintenant, bien sûr, il y a un petit problème ici aussi, dashmême s'il est facturé comme POSIX, il y a beaucoup de petits bogues conformes à POSIX. bash, Je n'ai pas encore trouvé de bugs avec POSIX, mais ... bash n'est pas réellement POSIX, c'est bien plus que cela.

Alors voilà. Voilà pourquoi je m'en soucie.

user322908
la source
Vous ne comprenez pas: qui ne suit pas les liens symboliques sur les fichiers . $PATHpeut contenir des liens symboliques. Essayez which sh.
Ipor Sircer
OK mais, dans mon cas, $PATHn'a pas de liens symboliques.
user322908
Dans presque toutes les situations, les liens symboliques sont suivis de manière transparente. Les cas où ils ne le sont pas sont généralement mentionnés explicitement (par exemple, les appels système comme lstat(2)), les suivre n'est généralement pas indiqué. Par exemple, la description de open(2)ne mentionne que les liens symboliques lorsque l'on parle du comportement de O_CREAT | O_EXCL. Il n'est pas nécessaire d'indiquer que le fichier cible sera ouvert.
Barmar

Réponses:

10

Les autorisations du lien symbolique lui-même ne sont pas pertinentes. Vous ne pourriez même pas les changer si vous essayiez.

Ce qui importe, ce sont les autorisations du fichier sous-jacent.

C'est bien d'avoir des répertoires dans votre PATH qui incluent des liens symboliques vers des exécutables. En fait, il est probable que de nombreux exécutables de votre PATH soient des liens symboliques. Par exemple, sur des systèmes de type Debian / Ubuntu:

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

Documentation

De man chmod:

chmod ne modifie jamais les autorisations des liens symboliques; l'appel système chmod ne peut pas modifier leurs autorisations. Ce n'est pas un problème car les autorisations des liens symboliques ne sont jamais utilisées. Cependant, pour chaque lien symbolique répertorié sur la ligne de commande, chmod modifie les autorisations du fichier pointé. En revanche, chmod ignore les liens symboliques rencontrés lors des traversées récursives de répertoires. [Je souligne.]

Exemple

Le shell a un test, -xpour déterminer si un fichier est exécutable. Essayons cela:

$ 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

Ainsi, tout comme vous l'avez trouvé avec which, le shell ne considère pas un exécutable de lien logiciel sauf si le fichier sous-jacent est exécutable.

Comment ça marche

Sur un système Debian, whichest un script shell. La section pertinente du code est:

 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

Comme vous pouvez le voir, il utilise le -xtest pour déterminer si un fichier est exécutable.

POSIX spécifie le -xtest comme suit:

-x chemin d'accès
Vrai si le chemin d'accès se résout en une entrée de répertoire existante pour un fichier pour lequel l'autorisation d'exécuter le fichier (ou de le rechercher, s'il s'agit d'un répertoire) sera accordée, comme défini dans Lecture, écriture et création de fichiers. False si le chemin d'accès ne peut pas être résolu, ou si le chemin d'accès se résout en une entrée de répertoire existante pour un fichier pour lequel l'autorisation d'exécuter (ou de rechercher) le fichier ne sera pas accordée. [Je souligne.]

Ainsi, POSIX vérifie la résolution du nom de chemin . En d'autres termes, il accepte les liens symboliques.

Fonction d'exécution POSIX

La fonction exec POSIX suit les liens symboliques. La spécification POSIX continue longuement pour spécifier les conditions d'erreur qu'elle peut signaler si les liens symboliques sont circulaires ou trop profonds, tels que:

[ELOOP]
Une boucle existe dans les liens symboliques rencontrés lors de la résolution du chemin ou de l'argument de fichier.

[ELOOP]
Plus de {SYMLOOP_MAX} liens symboliques ont été rencontrés lors de la résolution du chemin ou de l'argument de fichier.
[ENAMETOOLONG]
Suite à la rencontre d'un lien symbolique dans la résolution de l'argument path, la longueur de la chaîne de chemin d'accès substituée a dépassé {PATH_MAX}.

John1024
la source
JE SAIS tout ce que vous avez écrit dans votre réponse. Je sais comment les choses "fonctionnent". Ce n'est pas ma question. Ma question concerne la documentation. Indiquez-moi où je ne comprends pas la documentation. Ou dites-moi que la documentation est incorrecte.
user322908
@ user322908 Sur la plupart des systèmes, whichest un script shell. Ainsi, il est probable qu'il utilise simplement le -xtest que j'ai montré. Selon POSIX, -xteste si un fichier "se résout" en un exécutable. Si vous voyez quelque chose de différent, où cherchez-vous?
John1024
Merci et je suis désolé d'être une telle douleur ... Je me rends compte que ma question est différente de 99% des questions, donc il est difficile de comprendre ce que je recherche. Encore une fois, je ne suis pas intéressé par "comment" whichfonctionne, ou si c'est -xou autre chose. Je suis intéressé de savoir où ne suis-je pas en train de suivre correctement la documentation que j'ai citée.
user322908
4
@ user322908 La fonction POSIXexec suit les liens symboliques. Cela semble indiquer assez clairement que les fichiers liés par des liens symboliques peuvent être des exécutables sous POSIX.
John1024
2
J'ai également vérifié l' Ubuntu 17.10 man which qui dit "Il ne canonise pas les noms de chemin". Cela ne signifie pas qu'il ne suit pas les liens. Cela signifie seulement, comme vous l'avez observé, qu'il ne "canonise" pas les noms.
John1024
3

Dans ce cas, les liens symboliques sont suivis de manière transparente, sans canoniser le chemin final. En d'autres termes, whichpeu importe s'il /home/mark/bins'agit d'un lien symbolique ou non. Ce qui importe c'est de savoir si le fichier /home/mark/bin/foobarexiste ou non. Il n'a pas besoin d'aplatir manuellement les liens symboliques le long du chemin - le système d'exploitation peut le faire très bien par lui-même.

Et en effet, lorsque vous whichdemandez des informations sur le fichier /home/mark/bin/foobar, le système d'exploitation remarque /home/mark/binqu'il s'agit d'un lien symbolique, le suit et le trouve avec succès foobardans le répertoire cible.

Il s'agit du comportement par défaut, sauf si le programme utilise open(…, O_NOFOLLOW)ou fstatat(…, AT_SYMLINK_NOFOLLOW)pour accéder au fichier.

[commentaires fusionnés]

Alors que vous dites que les utilitaires shell font au cas par cas, ce n'est pas la même chose avec syscalls du noyau: tous les appels liés à fichiers font suivre les liens symboliques par défaut, à moins que le drapeau « nofollow » est donnée. (Même lstat suit les liens symboliques dans tous les composants de chemin sauf le dernier.)

Lorsque la spécification ne mentionne pas explicitement quoi faire avec les liens symboliques, cela implique que le comportement par défaut sera utilisé. C'est-à-dire qu'un shell suivant l'algorithme de chemin ne résout pas les liens symboliques manuellement et ne désactive pas explicitement le système d'exploitation en faisant de même. (Il concatène simplement chaque composant $ PATH avec le nom de l'exécutable.)

Lorsque la page de manuel which (1) indique qu'elle ne suit pas les liens symboliques, cela peut signifier plusieurs choses, mais la version de GNU coreutils l'indique de cette façon:

Ce qui considérera deux répertoires équivalents comme différents lorsque l'un d'eux contient un chemin d'accès avec un lien symbolique.

La portée est beaucoup plus étroite - cela signifie seulement que whichvous n'essaierez pas de canoniser manuellement tous les chemins pour éliminer les doublons, mais cela n'implique pas que l'outil désactive le lien symbolique suivi par le système d'exploitation en général. Par exemple, si /binest un lien symbolique vers /usr/bin, l'exécution which -a shrenverra à la fois /bin/sh et /usr/bin/sh.

user1686
la source
Oui merci, je sais tout ça. Ma question n'est pas de savoir comment les choses "fonctionnent". Je sais comment ça marche. Ce n'est pas mon point. Mon point concerne la documentation. Où suis-je mal suivre la documentation. Ou la documentation est-elle incorrecte.
user322908
2
Vous comprenez mal la documentation - si elle ne mentionne pas les liens symboliques suivants, cela signifie qu'elle ne résout pas manuellement les liens symboliques, mais le comportement normal du système d'exploitation s'applique toujours . La whichpage de manuel GNU le dit différemment: "Ce qui considérera deux répertoires équivalents comme différents lorsque l'un d'eux contient un chemin avec un lien symbolique."
user1686
OK, c'est mieux merci! J'essaie de comprendre ... Mais ... pardonnez-moi d'être une douleur dans le cou: "le comportement normal du système d'exploitation" n'est PAS de toujours suivre implicitement les liens symboliques. Il existe de nombreux utilitaires qui ne le font pas. C'est au cas par cas.
user322908
1
Tous les appels du noyau - chdir, open, chmod, execve ... - suivront les liens symboliques à la fois dans le chemin et la queue, sauf si vous spécifiez AT_SYMLINK_NOFOLLOW ou similaire. (lstat est le seul qui ne déréférence pas les liens symboliques à la queue, mais le fait toujours pour le chemin restant.) Par conséquent, le comportement par défaut est de suivre les liens symboliques. Par exemple, lorsqu'un shell appelle, execve("/home/mark/bin/foobar", …)tous les liens symboliques seront suivis.
user1686
OK, je pense que j'achète l' execveargument, en fait, dans ma mise en œuvre, c'est la execl()même chose. S'il vous plaît, si vous incluez ceci dans votre réponse, j'accepterai.
user322908
1

Le shell est conforme à sa documentation en ce qu'il suit les règles de résolution des noms de chemin. whichest conforme à sa documentation. Les deux font des choses légèrement différentes.

La sortie de whichest le nom et le chemin du fichier du lien, pas le chemin vers lequel pointe le lien symbolique. Ceci est expliqué dans la page de manuel.

Lorsqu'une commande est exécutée, le lien est "suivi" conformément à la section 4.13 Résolution de chemin d'accès de la même manière . La clause pertinente pour exécuter un fichier est:

Dans tous les autres cas, le système doit préfixer le nom de chemin restant, le cas échéant, avec le contenu du lien symbolique, sauf que si le contenu du lien symbolique est la chaîne vide, alors la résolution du nom de chemin échouera avec les fonctions signalant un [ENOENT ] erreur et utilitaires écrivant un message de diagnostic équivalent, ou le chemin d'accès au répertoire contenant le lien symbolique doit être utilisé à la place du contenu du lien symbolique. Si le contenu du lien symbolique se compose uniquement de caractères, tous les caractères de tête du nom de chemin restant doivent être omis du nom de chemin combiné résultant, ne laissant que les caractères de tête du contenu du lien symbolique. Dans les cas où le préfixe se produit, si la longueur combinée dépasse {PATH_MAX} et que l'implémentation considère qu'il s'agit d'une erreur, la résolution des noms de chemin échouera avec les fonctions signalant une erreur [ENAMETOOLONG] et les utilitaires écrivant un message de diagnostic équivalent. Sinon, le chemin d'accès résolu sera la résolution du chemin d'accès qui vient d'être créé. Si le nom de chemin résultant ne commence pas par a, le prédécesseur du premier nom de fichier du nom de chemin est considéré comme le répertoire contenant le lien symbolique.

Dave
la source