поиск PATH включает в себя символические ссылки?

1139
user322908

Стандарт оболочки POSIX говорит на этом сайте

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

о том, как оболочки используют PATHдля поиска исполняемых файлов:

«Список следует искать от начала до конца, применяя имя файла к каждому префиксу, пока не будет найден исполняемый файл с указанным именем и соответствующими разрешениями на выполнение».

Ну, это не так, как это работает в реальной реализации POSIX:

man which говорит:

"возвращает пути к файлам (или ссылкам), которые были бы выполнены в текущей среде, если бы его аргументы были заданы в виде команд в строго POSIX-совместимой оболочке. Это делается путем поиска в PATH исполняемых файлов, соответствующих именам аргументы. Он не следует за символическими ссылками. "

Хорошо, давайте посмотрим на эту ситуацию:

$ 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 

Хорошо, вот символическая ссылка PATHс правильным именем, и она сообщается lsкак исполняемая.

which не смотрит на это вообще, а интересуется только тем, на что он указывает.

Это несмотря на тот факт, что оба man whichявно говорят о том, что они не следуют по символическим ссылкам (а мы действительно видим, что это не так, потому which foobarчто не печатает foobar1), а также о том, что приведенная выше документация оболочки POSIX никогда не упоминает следующие символические ссылки в PATHалгоритме.

Так, whichа существующие оболочки ошибочны или я не понимаю документацию?

УТОЧНИТЬ:

Я знаю и могу объяснить существующее поведение. Мой вопрос не "как это работает?" Что я знаю.

Мой вопрос касается документации: где моя ошибка в следовании документации, которую я цитировал. Или документация неверна?

МОТИВАЦИЯ: Почему меня это волнует?

Ну, я реализатор. У разных исполнителей разные требования. Для меня требование состоит в том, чтобы слово текущего стандарта POSIX ДОЛЖНО сопровождаться ТОЧНО (или, точнее, лучшим, каким оно может быть, потому что сам стандарт несколько глючит). Как будто это было слово Божие.

Теперь стандартная формулировка довольно ясна - следующие символические ссылки не упоминаются, где во многих других местах упоминается, где это необходимо сделать. Так что в этом случае нет.

Однако я всегда дважды проверяю, как dashи как bashсебя вести, просто чтобы убедиться. Теперь, конечно, здесь также есть небольшая проблема, dashдаже несмотря на то, что она называется POSIX, имеет много мелких ошибок, соответствующих POSIX. bashЯ еще не нашел никаких ошибок с POSIX, но ... bash на самом деле не POSIX, это намного больше, чем это.

Так что у вас есть это. Вот почему я забочусь

9
Вы не понимаете: что не следует по символическим ссылкам на ** файлы **. `$ PATH` может содержать символические ссылки. Попробуйте "который ш". Ipor Sircer 6 лет назад 0
Хорошо, но в моем случае `$ PATH` не имеет символических ссылок. user322908 6 лет назад 0
Практически во всех ситуациях символические ссылки следуют прозрачно. Случаи, когда они * не * обычно упоминаются в явном виде (например, системные вызовы типа `lstat (2)`), после них обычно не указывается. Например, описание `open (2)` упоминает только символические ссылки, когда говорит о поведении `O_CREAT | O_EXCL`. Не нужно указывать, что целевой файл будет открыт. Barmar 6 лет назад 0

3 ответа на вопрос

10
John1024

Разрешения самой символической ссылки не имеют значения. Вы даже не могли бы изменить их, если бы попытались.

Что важно, так это права доступа к базовому файлу.

Хорошо, чтобы в вашем PATH каталоги содержали символические ссылки на исполняемые файлы. На самом деле, вполне вероятно, что многие исполняемые файлы в вашем PATH являются символическими ссылками. Например, в системах, подобных debian / ubuntu:

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

Документация

От man chmod:

chmod никогда не меняет права доступа к символическим ссылкам; системный вызов chmod не может изменить их разрешения. Это не проблема, поскольку разрешения символических ссылок никогда не используются. Однако для каждой символической ссылки, указанной в командной строке, chmod изменяет права доступа к указанному файлу. Напротив, chmod игнорирует символические ссылки, встречающиеся во время рекурсивных обходов каталогов. [Акцент добавлен.]

пример

В оболочке есть тест, -xчтобы определить, является ли файл исполняемым. Давайте попробуем это:

$ 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 

Таким образом, как и в случае с whichоболочкой, оболочка не считает исполняемый файл программной ссылки, если базовый файл не является исполняемым.

Как работает

В системе Debian whichэто сценарий оболочки. Соответствующий раздел кода:

 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 

Как видите, он использует -xтест, чтобы определить, является ли файл исполняемым.

POSIX определяет -xтест следующим образом:

-x pathname
Истинно, если pathname разрешает существующую запись каталога для файла, для которого будет предоставлено разрешение на выполнение файла (или поиск в нем, если это каталог), как определено в File Read, Write и Creation. False, если путь не может быть разрешен, или если путь разрешается к существующей записи каталога для файла, для которого разрешение на выполнение (или поиск) файла не будет предоставлено. [Акцент добавлен.]

Так, POSIX проверяет, что путь решает к. Другими словами, он принимает символические ссылки.

POSIX exec функция

Функция POSIX exec следует символическим ссылкам. Спецификация POSIX продолжается, чтобы указать условия ошибки, о которых она может сообщить, если символические ссылки имеют круглую или слишком глубокую форму, например:

[ELOOP]
Цикл существует в символических ссылках, встречающихся во время разрешения пути или аргумента файла.

[ELOOP]
Более чем символических ссылок было найдено во время разрешения пути или аргумента файла.
[ENAMETOOLONG]
В результате обнаружения символической ссылки в разрешении аргумента пути длина замещенной строки имени пути превысила .

Я ЗНАЮ все, что вы написали в своем ответе. Я знаю, как все "работает". Это не мой вопрос. Мой вопрос о документации. Укажите мне, где я не понимаю документацию. Или скажите, что документация неверна. user322908 6 лет назад 0
@ user322908 В большинстве систем `which` является сценарием оболочки. Таким образом, это скорее всего просто использование теста `-x`, который я показал. Согласно POSIX, `-x` проверяет,« разрешает »ли файл исполняемый файл. Если вы видите что-то другое, куда вы смотрите? John1024 6 лет назад 0
Спасибо, и я прошу прощения за такую ​​боль ... Я понимаю, что мой вопрос отличается от 99% вопросов, поэтому трудно понять, что я хочу. Опять же, меня не интересует «как», «который» работает, или «-x», или что-то еще. Мне интересно знать, где я не следую правильно документации, которую я цитировал. user322908 6 лет назад 0
@ user322908 Ваша ссылка идет на титульную страницу. Я только что обновил свой ответ цитатами из внутренностей спецификации POSIX. Если вы видите что-то, что противоречит тому, что я вижу, пожалуйста, будьте более конкретны. John1024 6 лет назад 0
@ user322908 [POSIX `функция exec`] (http://pubs.opengroup.org/onlinepubs/009604599/functions/exec.html) следует за символическими ссылками. Кажется, это ясно показывает, что файлы с символическими ссылками могут быть исполняемыми файлами в POSIX. John1024 6 лет назад 4
@ user322908 _ "Это несмотря на то, что оба человека явно говорят, что не следуют по символическим ссылкам" _ Где ты это нашел? Мой "человек, который" говорит прямо противоположное. John1024 6 лет назад 0
ну, мой `человек, который` и это последняя версия Ubuntu, говорит, что это не так. user322908 6 лет назад 0
Да, функция `exec`. Я думаю, что я покупаю этот аргумент (наконец-то). Другой парень уже упомянул это в комментарии. Если вы положите это в свой ответ, я приму. И спасибо за ваши усилия, чтобы помочь мне. user322908 6 лет назад 0
@ user322908 ОК. Я добавил ссылку POSIX для exec. John1024 6 лет назад 0
Я также проверил [Ubuntu 17.10 `man which`] (http://manpages.ubuntu.com/manpages/artful/en/man1/which.1.html), который говорит:« Он не канонизирует имена путей ». Это не значит, что он не следует по ссылкам. Это означает только то, что, как вы заметили, это не «канонизирует» имена. John1024 6 лет назад 2
3
grawity

В этом случае символические ссылки следуют прозрачно, без канонизации окончательного пути. Другими словами, whichне имеет значения, /home/mark/binявляется ли символическая ссылка или нет. Что его волнует, так это то, /home/mark/bin/foobarсуществует файл или нет. Это не нужно вручную расплющить симлинка по пути - ОС может сделать это просто прекрасна сами по себе.

И действительно, когда whichзапрашивается информация о файле /home/mark/bin/foobar, ОС замечает, /home/mark/binчто является символической ссылкой, следует за ней и успешно находит foobarв целевом каталоге.

Это поведение по умолчанию, если программа не использует open(…, O_NOFOLLOW)или fstatat(…, AT_SYMLINK_NOFOLLOW)для доступа к файлу.

[комментарии объединены в]

В то время как вы говорите, что оболочка утилита сделать это на индивидуальной основе случая, это не то же самое с системными вызовами ядра: все вызовы связанных с файлами делать следуют символическим ссылкам по умолчанию, если «NOFOLLOW» флаг не даются. (Даже lstat следует за символическими ссылками во всех компонентах пути, кроме последнего.)

Если в спецификации явно не указано, что делать с символическими ссылками, это означает, что будет использоваться поведение по умолчанию. Таким образом, оболочка, следующая по алгоритму пути, не разрешает символические ссылки вручную и явно не отказывается от ОС, делая то же самое. (Он просто объединяет каждый компонент $ PATH с именем исполняемого файла.)

Когда на странице справки which (1) говорится, что она не следует символическим ссылкам, это может означать несколько вещей, но версия GNU coreutils утверждает это следующим образом:

При этом два эквивалентных каталога будут считаться разными, если один из них содержит путь с символической ссылкой.

Это намного уже по объему - это только означает, что whichон не будет пытаться вручную канонизировать все пути для удаления дубликатов, но это не означает, что инструмент откажется от символьных ссылок, следующих за ОС в целом. Например, если /binэто символическая ссылка /usr/bin, запуск which -a shвернет оба /bin/sh и /usr/bin/sh.

Да, спасибо, я все это знаю. Мой вопрос не в том, как все "работает". Я знаю, как они работают. Это не моя точка зрения. Моя точка зрения касается документации. Где я неправильно следую документации Или документация неверна. user322908 6 лет назад 0
Вы неправильно понимаете документацию - если в ней не упоминаются следующие символические ссылки, это означает, что она не разрешает символические ссылки вручную, но применяется обычное поведение ОС _still_. Страница руководства GNU `which` гласит это по-разному:« Который будет считать разные эквивалентные каталоги разными, когда один из них содержит путь с символической ссылкой ». grawity 6 лет назад 2
ОК, лучше, спасибо! Я пытаюсь понять ... Но ... простите за то, что у меня болит шея: "обычное поведение ОС" - это НЕ всегда неявно следовать символическим ссылкам. Есть множество утилит, которые этого не делают. Это на индивидуальной основе. user322908 6 лет назад 0
Все вызовы ядра - chdir, open, chmod, execve ... - будут следовать символическим ссылкам как в пути, так и в хвосте, _unless_ вы указываете AT_SYMLINK_NOFOLLOW или подобное. (lstat - единственный, который не разыменовывает символические ссылки в хвосте, но все же делает это для оставшегося пути.) Поэтому поведение по умолчанию состоит в том, чтобы следовать символическим ссылкам. Например, когда оболочка вызывает `execve (" / home / mark / bin / foobar ", ...)`, это приведет к тому, что будут следовать все символические ссылки. grawity 6 лет назад 1
ОК, я думаю, что я покупаю аргумент `execve`, на самом деле, в моей реализации это` execl () `, то же самое. Пожалуйста, если вы включите это в свой ответ, я приму. user322908 6 лет назад 0
1
Dave

Оболочка соответствует своей документации в том, что она следует правилам разрешения пути. whichсоответствует своей документации. Два делают немного разные вещи.

Выходные данные which- это имя файла и путь ссылки, а не путь, на который указывает символическая ссылка. Это прописано в справочной странице.

Когда команда выполняется, ссылка «следует» в соответствии с разделом 4.13 «Разрешение имени пути» в том же разделе . Соответствующее условие для выполнения файла:

Во всех других случаях система должна ставить префикс оставшегося имени пути, если таковое имеется, с содержимым символической ссылки, за исключением того, что если содержимое символической ссылки является пустой строкой, то любое разрешение пути не должно выполняться с функциями, сообщающими [ENOENT ] ошибки и утилиты, пишущие эквивалентное диагностическое сообщение, или путь к каталогу, содержащему символическую ссылку, должны использоваться вместо содержимого символической ссылки. Если содержимое символической ссылки состоит только из символов, то все итоговые символы оставшегося имени пути должны быть исключены из результирующего комбинированного имени пути, оставляя только начальные символы из содержимого символической ссылки. В тех случаях, когда происходит префикс, если объединенная длина превышает, и реализация считает это ошибкой, Разрешение пути не должно выполняться, если функции сообщают об ошибке [ENAMETOOLONG], а утилиты записывают эквивалентное диагностическое сообщение. В противном случае разрешенный путь должен быть разрешением только что созданного пути. Если результирующий путь не начинается с, предшественником первого имени файла пути считается каталог, содержащий символическую ссылку.

Похожие вопросы