чи включає PATH пошук символьних посилань?


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, це набагато більше, ніж це.

Так ось у вас це є. Ось чому я дбаю.


Ви не розумієте: що не слідує за посиланнями на файли . $PATHможе містити посилання. Спробуйте which sh.
Іпор Сірсер

Гаразд, але в моєму випадку $PATHнемає ніяких символьних посилань.
user322908

Практично у всіх ситуаціях символьні посилання дотримуються прозоро. Випадки, коли вони зазвичай не згадуються явно (наприклад, системні дзвінки, як-от lstat(2)), наступні за ними зазвичай не зазначаються. Наприклад, опис open(2)лише згадок символізує, коли йдеться про поведінку O_CREAT | O_EXCL. Не потрібно вказувати, що цільовий файл буде відкрито.
Вармар

Відповіді:


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 ім'я шляху
Істинно, якщо ім'я шляху доходить до існуючої записи в каталозі для файлу, для якого буде надано дозвіл на виконання файлу (або пошук у ньому, якщо це каталог), як визначено у розділі «Читання файлів, запис та створення». Неправильно, якщо ім'я шляху не вдалося вирішити або якщо ім'я шляху доріже до існуючої записи каталогу для файлу, для якого дозвіл на виконання (або пошук) файл не буде наданий. [Наголос додано.]

Отже, POSIX перевіряє, на що вирішує ім'я шляху . Іншими словами, він приймає символьні посилання.

Функція POSIX exec

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

[ELOOP]
У символічних посиланнях, що виникають під час вирішення шляху або аргументу файлу, існує цикл.

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


Я ЗНАЮ все, що ви написали у своїй відповіді. Я знаю, як все "працює". Це не моє питання. Моє запитання щодо документації. Наведіть мене, де я не розумію документацію. Або скажіть, що документація невірна.
user322908

@ user322908 У більшості систем which- це сценарій оболонки. Таким чином, ймовірно, якраз використовую -xтест, який я показав. Згідно з POSIX, -xперевіряється, чи файл "вирішує" виконуваний файл. Якщо ви бачите щось інше, куди ви дивитесь?
John1024

Дякую і мені дуже шкода, що я такий біль ... Я розумію, що моє запитання відрізняється від 99% запитань, тому важко зрозуміти, що я хочу. Знову ж таки, мене не цікавить "як" whichпрацює, чи це, -xчи щось інше. Мені цікаво дізнатися, де я не дотримуюся належно цитованої документації.
користувач322908

4
@ User322908 POSIX execфункції наступним чином символічні посилання. Це, мабуть, дає зрозуміти, що файли, що мають посилання, можуть виконуватися під POSIX.
John1024

2
Я також перевірив Ubuntu 17.10, в man which якому сказано: "Він не канонізує назви шляхів". Це не означає, що він не переходить за посиланнями. Це означає лише, як ви зауважили, що воно не "канонізує" імена.
John1024

3

У цьому випадку посилання слідують прозоро, без канонізації остаточного шляху. Іншими словами, 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 з ім'ям, що виконується.)

Коли на сторінці (1) інструкції сказано, що вона не відповідає посиланням, це може означати декілька речей, але версія coreutils GNU констатує це так:

Що вважатиме два еквівалентні каталоги різними, коли один з них містить шлях із символічним посиланням.

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


Так, дякую, я все це знаю. Моє питання не в тому, як все "працює". Я знаю, як вони працюють. Це не моя суть. Моя думка стосується документації. Де я невірно слідкую за документацією. Або документація неправильна.
user322908

2
Ви неправильно розумієте документацію - якщо в ній не вказано наступні посилання, це означає, що вона не вручну розв’язує символьні посилання, але звичайна поведінка ОС все одно застосовується. На whichсторінці посібника GNU зазначено це інакше: "Що буде вважати два еквівалентні каталоги різними, коли один з них містить шлях із символічним посиланням."
користувач1686

Гаразд, краще дякую! Я намагаюся зрозуміти ... Але ... вибачте, що я болю в шиї: "регулярна поведінка ОС" НЕ завжди неявно слідувати символічним посиланням. Є багато комунальних служб, яких немає. Це в кожному конкретному випадку.
user322908

1
Усі дзвінки ядра - chdir, open, chmod, execve ... - будуть слідувати посиланнями як у шляху, так і в хвіст, якщо ви не вказали AT_SYMLINK_NOFOLLOW або подібне. (lstat - це єдиний, який не переносить символи, що посилаються в хвіст, але все ж робить це для решти шляху.) Тому поведінка за замовчуванням - це слідування символьним посиланням. Наприклад, коли оболонка викликає execve("/home/mark/bin/foobar", …)її, це призведе до дотримання всіх посилань.
user1686

Гаразд, я думаю, що я купую execveаргумент, насправді, в моїй реалізації це execl()одне і те ж. Будь ласка, якщо ви включите це у свою відповідь, я прийму.
user322908

1

Оболонка відповідає своїй документації тим, що вона дотримується правил дозволу назви шляху. whichвідповідає його документації. Вони роблять трохи різні речі.

Результатом whichє ім'я та шлях файлу посилання, а не шлях до того, на що вказує символьне посилання. Про це написано на сторінці man.

Коли команда виконується, посилання "дотримується" відповідно до розділу 4.13 Роздільна здатність Pathname у тому ж самому . Відповідним пунктом для виконання файлу є:

У всіх інших випадках система повинна префіксувати залишкову назву шляху, якщо така є, до вмісту символічного посилання, за винятком випадків, якщо вміст символьної посилання є порожнім рядком, то будь-яке дозвіл імені шляху не може виконувати функції, що повідомляють про [ENOENT ] помилка та утиліти, що записують еквівалентне діагностичне повідомлення, або ім'я шляху до каталогу, що містить символічне посилання, використовуються замість вмісту символічного посилання. Якщо вміст символьної посилання складається виключно з символів, то всі провідні символи залишкового імені шляху опускаються з отриманого комбінованого імені шляху, залишаючи лише провідні символи зі вмісту символічного посилання. У випадках, коли відбувається префіксація, якщо комбінована довжина перевищує {PATH_MAX}, і реалізація вважає це помилкою, Розв’язання імені шляху не може працювати з функціями, що повідомляють про помилку [ENAMETOOLONG], і утиліти записують рівнозначне діагностичне повідомлення. В іншому випадку вирішеною назвою шляху є дозвіл щойно створеного імені шляху. Якщо отримане ім'я шляху не починається з a, попередником першого імені файлу буде вказано каталог, що містить символічне посилання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.