9

Стандарт оболочки 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, это гораздо больше.

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

3 ответа3

10

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

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

Хорошо, чтобы в вашем 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 путь
Истинно, если путь разрешается к существующей записи каталога для файла, для которого будет предоставлено разрешение на выполнение файла (или поиск в нем, если это каталог), как определено в разделе «Чтение, запись и создание файла». False, если путь не может быть разрешен, или если путь разрешается к существующей записи каталога для файла, для которого разрешение на выполнение (или поиск) файла не будет предоставлено. [Акцент добавлен.]

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

POSIX exec функция

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

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

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

3

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

И действительно, когда , which спрашивает об информации файла /home/mark/bin/foobar извещений OS /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 .

1

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

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

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .