При обновлении пакета, если в пакете раньше был файл "А", являющимся симлинком на файл "B", а в новой версии пакета "А" становится обычным файлом (т.е. перестаёт быть симлинком на файл "B"), а файл "B" больше не содержится в новой версии, то в зависимости от неопределённых условий можно получить 1 из следующих результатов: 1) В системе будет новый файл "A", но также останется файл "B", который должен был быть удалён. 2) В системе не будет файла "B", но файл "A" останется симлинком на файл "B". Учитывая, что файла "B" нет, симлинк будет "битым". Оба варианта неправильные, хоть первый обычно и менее вреден чем второй (и менее заметен). Ожидаемый вариант: Симлинк "А" будет заменён файлом "А", файл "B" будет удалён. Также не проверялось поведение при замене в новой версии симлинка "A", указывающего на файл "B", и файла "B" на симлинк "A", указывающий на файл "C", и, соответственно, файл "C". Думаю, аналогичные действия должны происходить при любой замене симлинков, в том числе на другие симлинки, регулярные файлы, директории или особые типы файлов.
Проблема известна давно.
Кажется, что замена файла на симлинк на файл и обратно должна работать. Надо воспроизвести на маленьких простых спеках и посмотреть, что же там не так. > Думаю, аналогичные действия должны происходить при любой замене симлинков, в > том числе на другие симлинки, регулярные файлы, директории или особые типы > файлов. Замена симлинков на каталоги и обратно -- особый случай, к которому есть особый интерес. В RPM явно запрещено заменять каталог на что-либо ещё, и заменять симлинк на каталог, поскольку "We can't correctly handle [that]": http://git.altlinux.org/gears/r/rpm.git?p=rpm.git;a=blob;f=lib/transaction.c;h=b55f11c0c2be5622887bdb1f06af3e8ff57812f7#l307 Нежелание иметь дело с такими обновлениями понятно: каталоги могут содержать файлы, в том числе файлы пользователя и файлы других пакетов; эти другие пакеты могут участвовать или не участвовать в текущей транзакции; наконец, ЕМНИП RPM "ходит по ссылкам" -- администратор может сам заменить какие-то каталоги на симлинки, и RPM (иногда) будет делать вид, что ничего не заметил. И на первый взгляд не очевидно, что можно специфицировать поведение RPM при замене симлинка на каталог или наоборот так, чтобы это поведение во всех случаях было понятным, очевидным и не приводило к нежелательным последствиям (вроде удаления файлов, которые на самом деле нужны, или "мусора" после удаления пакетов). Нужно постараться понять, какие возможны ситуации, и что мы хотим от RPM в каждой из них.
Чтобы вынести каталог и заменить его на что-то еще, rpm должен доказать, что транзакция полностью выносит каталог со всем его содержимым и всеми подкаталогами. Это не невозможно.
Задача замены каталогов на ссылки выглядит более сложной, чем замена ссылок на каталоги. Поэтому, а также потому, что все текущие баг-репорты именно про замену ссылок на каталоги, сперва решить задачу замены ссылок.
К сведению, сейчас в Сизифе 13 файлов, упакованных таким образом, что часть их пути является упакованной ссылкой на каталог: /etc/init.d/puppetserver /etc/init.d/xpra /etc/init.d/xtreemfs-dir /etc/init.d/xtreemfs-mrc /etc/init.d/xtreemfs-osd /usr/lib64/clip/etc/.macro /usr/lib64/clip/etc/.templ /usr/lib64/qt4/mkspecs/features/qcodeedit.prf /usr/lib64/qt4/translations/qscintilla_cs.qm /usr/lib64/qt4/translations/qscintilla_de.qm /usr/lib64/qt4/translations/qscintilla_es.qm /usr/lib64/qt4/translations/qscintilla_fr.qm /usr/lib64/qt4/translations/qscintilla_pt_br.qm
(In reply to comment #4) > Задача замены каталогов на ссылки выглядит более сложной, чем замена ссылок на > каталоги. > Поэтому, а также потому, что все текущие баг-репорты именно про замену ссылок > на каталоги, сперва решить задачу замены ссылок. Раньше, когда возникала задача замены ссылок каталогами, мы всегда создавали %pre-скрипты, в котором просто удаляли эти ссылки. Оказывается, в Федоре для замены ссылок каталогами теперь предлагают создавать %pretrans-скрипты, в котором просто удаляются эти ссылки: https://docs.fedoraproject.org/en-US/packaging-guidelines/Directory_Replacement/#_scriptlet_to_replace_a_symlink_to_a_directory_with_a_directory Поскольку все, не сговариваясь, до сих пор предлагают в качестве решения задачи замены ссылок каталогами простое удаление этих ссылкок, предлагаю не искать других вариантов и реализовать это поведение непосредственно в rpm по-умолчанию.
(В ответ на комментарий №6) > (In reply to comment #4) > > Задача замены каталогов на ссылки выглядит более сложной, чем замена ссылок на > > каталоги. > > Поэтому, а также потому, что все текущие баг-репорты именно про замену ссылок > > на каталоги, сперва решить задачу замены ссылок. > > Раньше, когда возникала задача замены ссылок каталогами, мы всегда создавали > %pre-скрипты, в котором просто удаляли эти ссылки. > > Оказывается, в Федоре для замены ссылок каталогами теперь предлагают создавать > %pretrans-скрипты, в котором просто удаляются эти ссылки: > https://docs.fedoraproject.org/en-US/packaging-guidelines/Directory_Replacement/#_scriptlet_to_replace_a_symlink_to_a_directory_with_a_directory > > Поскольку все, не сговариваясь, до сих пор предлагают в качестве решения задачи > замены ссылок каталогами простое удаление этих ссылкок, предлагаю не искать > других вариантов и реализовать это поведение непосредственно в rpm > по-умолчанию. Давайте. Кто? Иван, попробуете? Глеб сейчас в ppc64le по уши.
(In reply to comment #6) > (In reply to comment #4) > > Задача замены каталогов на ссылки выглядит более сложной, чем замена ссылок на > > каталоги. > > Поэтому, а также потому, что все текущие баг-репорты именно про замену ссылок > > на каталоги, сперва решить задачу замены ссылок. > > Раньше, когда возникала задача замены ссылок каталогами, мы всегда создавали > %pre-скрипты, в котором просто удаляли эти ссылки. > > Оказывается, в Федоре для замены ссылок каталогами теперь предлагают создавать > %pretrans-скрипты, в котором просто удаляются эти ссылки: > https://docs.fedoraproject.org/en-US/packaging-guidelines/Directory_Replacement/#_scriptlet_to_replace_a_symlink_to_a_directory_with_a_directory > > Поскольку все, не сговариваясь, до сих пор предлагают в качестве решения задачи > замены ссылок каталогами простое удаление этих ссылкок, предлагаю не искать > других вариантов и реализовать это поведение непосредственно в rpm > по-умолчанию. А пакеты, использующие механизм alternatives, не сломаются?
(In reply to comment #8) > (In reply to comment #6) > > (In reply to comment #4) > > > Задача замены каталогов на ссылки выглядит более сложной, чем замена ссылок на > > > каталоги. > > > Поэтому, а также потому, что все текущие баг-репорты именно про замену ссылок > > > на каталоги, сперва решить задачу замены ссылок. > > > > Раньше, когда возникала задача замены ссылок каталогами, мы всегда создавали > > %pre-скрипты, в котором просто удаляли эти ссылки. > > > > Оказывается, в Федоре для замены ссылок каталогами теперь предлагают создавать > > %pretrans-скрипты, в котором просто удаляются эти ссылки: > > https://docs.fedoraproject.org/en-US/packaging-guidelines/Directory_Replacement/#_scriptlet_to_replace_a_symlink_to_a_directory_with_a_directory > > > > Поскольку все, не сговариваясь, до сих пор предлагают в качестве решения задачи > > замены ссылок каталогами простое удаление этих ссылкок, предлагаю не искать > > других вариантов и реализовать это поведение непосредственно в rpm > > по-умолчанию. > > А пакеты, использующие механизм alternatives, не сломаются? Всё, что могло сломаться, уже сломано. Если не сделать новых ошибок, то дополнительно ничего не сломается, и замена ссылок каталогами будет исправлена.
(In reply to comment #0) > При обновлении пакета, если в пакете раньше был файл "А", являющимся симлинком > на файл "B", а в новой версии пакета "А" становится обычным файлом (т.е. > перестаёт быть симлинком на файл "B"), а файл "B" больше не содержится в новой > версии, то в зависимости от неопределённых условий можно получить 1 из > следующих результатов: > > 1) В системе будет новый файл "A", но также останется файл "B", который должен > был быть удалён. > 2) В системе не будет файла "B", но файл "A" останется симлинком на файл "B". > Учитывая, что файла "B" нет, симлинк будет "битым". Я решил начать с понятного и воспроизвести проблему с файлами. Для этого я накидал несколько маленьких спек-файлов, в которых реализуется этот и обратный сценарии: http://git.altlinux.org/people/iv/public/?p=rpm-update-tests.git;a=tree Оба варинта тестировал несколько раз, всё отработало штатно, проблема не воспроизвелась (Сизиф, rpm-4.13.0.1-alt6.x86_64).
(In reply to comment #10) > (In reply to comment #0) > > При обновлении пакета, если в пакете раньше был файл "А", являющимся симлинком > > на файл "B", а в новой версии пакета "А" становится обычным файлом (т.е. > > перестаёт быть симлинком на файл "B"), а файл "B" больше не содержится в новой > > версии, то в зависимости от неопределённых условий можно получить 1 из > > следующих результатов: > > > > 1) В системе будет новый файл "A", но также останется файл "B", который должен > > был быть удалён. > > 2) В системе не будет файла "B", но файл "A" останется симлинком на файл "B". > > Учитывая, что файла "B" нет, симлинк будет "битым". > > Я решил начать с понятного и воспроизвести проблему с файлами. Для этого я > накидал > несколько маленьких спек-файлов, в которых реализуется этот и обратный > сценарии: > > http://git.altlinux.org/people/iv/public/?p=rpm-update-tests.git;a=tree > > Оба варинта тестировал несколько раз, всё отработало штатно, проблема > не воспроизвелась (Сизиф, rpm-4.13.0.1-alt6.x86_64). Проблема возникает по крайней мере при обновлении систем p8 , содержащих lua5.1 и gdb Из письма cas@: "Попытка обновления 64-битного Альт Рабочая станция, Альт Образование и Альт Сервер (после успешной установки пакетов rpm apt): Совершаем изменения... Подготовка... ############################################################################# [100%] файл /usr/lib64/lua/5.1 из устанавливаемого пакета liblua5.1-5.1.5-alt15.x86_64 конфликтует с файлом из пакета lua5.1-alt-compat-1.0-alt1.x86_64 файл /usr/share/lua/5.1 из устанавливаемого пакета liblua5.1-5.1.5-alt15.x86_64 конфликтует с файлом из пакета lua5.1-alt-compat-1.0-alt1.x86_64 E: Ошибка во время исполнения транзакции (при этом говорит, что будет занято дополнительно 907 МБ). Для Альт Образование ещё конфликт: файл /usr/share/gdb/python/gdb из устанавливаемого пакета gdb-8.2.50.20180917-alt2.x86_64 конфликтует с файлом из пакета gdb-7.9-alt3.x86_64 Альт Образование 8 вообще рекордсмен по количеству удаляемых пакетов - 45: Следующие пакеты будут УДАЛЕНЫ: certmonger freeipa-client gimagereader-qt4 gst-plugins-bad i586-ICAClient-preinstall.32bit i586-libGLdispatch.32bit i586-libbrotlicommon0.32bit i586-libbrotlidec0.32bit i586-libcurl.32bit i586-nspluginwrapper.32bit i586-nvidia_glx_384.111.32bit i586-nvidia_glx_384.98.32bit kde5 kde5-mini kde5-network-manager-4-nm kde5-small kdenlive libcairo-devel libgtk+2-devel libopencv2.4 libpango-devel librrd4 lua5.1-alt-compat omsclient.32bit plasma5-desktop plasma5-kwin plasma5-nm-connect-openconnect plasma5-nm-maxi plasma5-workspace python-module-freeipa python-module-ipa_hbac python-module-ipaclient python-module-ipaclient-ntp python3-module-yieldfrom.requests syslogd task-auth-freeipa virtualbox-guest-additions vlc-plugin-a52 vlc-plugin-bonjour vlc-plugin-dca vlc-plugin-goom vlc-plugin-mad xfce4-mixer xorg-drv-openchrome xorg-drv-vboxvideo "
(In reply to comment #11) > (In reply to comment #10) > > (In reply to comment #0) > > > При обновлении пакета, если в пакете раньше был файл "А", являющимся симлинком > > > на файл "B", а в новой версии пакета "А" становится обычным файлом (т.е. > > > перестаёт быть симлинком на файл "B"), а файл "B" больше не содержится в новой > > > версии, то в зависимости от неопределённых условий можно получить 1 из > > > следующих результатов: > > > > > > 1) В системе будет новый файл "A", но также останется файл "B", который должен > > > был быть удалён. > > > 2) В системе не будет файла "B", но файл "A" останется симлинком на файл "B". > > > Учитывая, что файла "B" нет, симлинк будет "битым". [...] > > Оба варинта тестировал несколько раз, всё отработало штатно, проблема > > не воспроизвелась (Сизиф, rpm-4.13.0.1-alt6.x86_64). > > Проблема возникает по крайней мере при обновлении систем p8 , содержащих lua5.1 > и gdb Проблема с lua5.1 и gdb -- это проблема замены каталогов на симлинки и/или наоборот. Как я писал выше, такие замены намеренно заблокированы в коде RPM, и здесь мы должны поменять это поведение чтобы исправить проблему (ну то есть заменить её на другую, менее неприятную). Однако darktemplar@ в описании этого бага пишет про проблемы с симлинками на обычные файлы. Такая проблема мне не знакома. Если она действительно есть, то начинать разбираться надо именно с неё. Однако на простых примерах мне её не удалось воспроизвести. darktemplar@, а Вы на чём проверяли это?
(В ответ на комментарий №12) > (In reply to comment #11) > > (In reply to comment #10) > > > (In reply to comment #0) > > > > При обновлении пакета, если в пакете раньше был файл "А", являющимся симлинком > > > > на файл "B", а в новой версии пакета "А" становится обычным файлом (т.е. > > > > перестаёт быть симлинком на файл "B"), а файл "B" больше не содержится в новой > > > > версии, то в зависимости от неопределённых условий можно получить 1 из > > > > следующих результатов: > > > > > > > > 1) В системе будет новый файл "A", но также останется файл "B", который должен > > > > был быть удалён. > > > > 2) В системе не будет файла "B", но файл "A" останется симлинком на файл "B". > > > > Учитывая, что файла "B" нет, симлинк будет "битым". > [...] > > > Оба варинта тестировал несколько раз, всё отработало штатно, проблема > > > не воспроизвелась (Сизиф, rpm-4.13.0.1-alt6.x86_64). > > > > Проблема возникает по крайней мере при обновлении систем p8 , содержащих lua5.1 > > и gdb > > Проблема с lua5.1 и gdb -- это проблема замены каталогов на симлинки и/или > наоборот. Как я писал выше, такие замены намеренно заблокированы в коде RPM, и > здесь мы должны поменять это поведение чтобы исправить проблему (ну то есть > заменить её на другую, менее неприятную). > > Однако darktemplar@ в описании этого бага пишет про проблемы с симлинками на > обычные файлы. Такая проблема мне не знакома. Если она действительно есть, то > начинать разбираться надо именно с неё. Однако на простых примерах мне её не > удалось воспроизвести. > > darktemplar@, а Вы на чём проверяли это? Если я правильно помню, нарвался я на такую проблему когда работал над очередным пакетом. Пакет с такими проблемами в репозиторий я не отправлял, и похоже рабочего репозитория не сохранилось за ненадобностью. Возможно, описанная мной проблема не возникает на простых случаях или была уже исправлена.
> Поэтому, а также потому, что все текущие баг-репорты именно про замену ссылок > на каталоги, сперва решить задачу замены ссылок. Я вижу три способа решения проблемы: (1) удалить симлинк непосредственно перед созданием каталога, в процессе установки пакета; (2) сделать отдельный проход по всем пакетам, собрать все симлинки, которые нужно заменять на каталоги и удалить их перед началом транзакции -- такой захардкоженый pretrans trigger. (3) в каком-то виде вернуть предыдущее поведение, позволив пакетам исправлять праблему самим из %pre-скрипта Способ (1) кажется наиболее интересным, так как на первый взгляд меньше всего похож на грязный хак и больше всего на правильный шаг на пути к идеалу. Я попробовал его реализовать. Нужно учесть, что rpm "ходит по ссылкам", и это поведение нужно сохранить. Это значит, что при установке пакета необходимо различать два случая: когда симлинк будет удалён в той же транзакции (и тогда его нужно удалить заранее) и когда симлинк трогать не нужно (тогда достаточно проверить, что это симлинк на каталог). Чтобы разделить эти случаи, проще всего добавить новый action в rpmFileAction. Тогда можно выставить этот action для каталога из свежего пакета при анализе транзакции. В первом приближении получается следующее: http://git.altlinux.org/people/iv/packages/rpm.git?p=rpm.git;a=commitdiff;h=c33b836afae663c4bbef14d6f59945d7872cc24a Однако этого недостаточно. Рассмотрим простейший пример, когда вместе с исходным каталогом переехали файлы. http://git.altlinux.org/people/iv/public/?p=rpm-update-tests.git;a=commitdiff;h=b247c271ad7dd6641284631876db0065e8055bf1 Было: drwxr-xr-x 3 root root 4096 мая 13 17:27 /usr/share/rpm-test-symlink2dir drwxr-xr-x 2 root root 4096 мая 13 17:27 /usr/share/rpm-test-symlink2dir/a -rw-r--r-- 1 root root 46 мая 13 17:26 /usr/share/rpm-test-symlink2dir/a/x.txt lrwxrwxrwx 1 root root 1 мая 13 17:26 /usr/share/rpm-test-symlink2dir/b -> a Стало: drwxr-xr-x 4 root root 4096 мая 13 17:39 /usr/share/rpm-test-symlink2dir drwxr-xr-x 2 root root 4096 мая 13 17:39 /usr/share/rpm-test-symlink2dir/b -rw-r--r-- 1 root root 46 мая 13 17:26 /usr/share/rpm-test-symlink2dir/b/x.txt Здесь при анализе транзакции RPM увидит, что в новой версии пакета есть /usr/share/rpm-test-symlink2dir/b/x.txt; с точки зрения RPM он заменяет существующий /usr/share/rpm-test-symlink2dir/b/x.txt, а значит при удалении старой версии пакета этот файл не нужно трогать. В итоге, по результатам обновления остаётся "мусор": старый `x.txt` вместе со своим каталогом `a`. drwxr-xr-x 4 root root 4096 мая 13 18:30 /usr/share/rpm-test-symlink2dir/ drwxr-xr-x 2 root root 4096 мая 13 18:29 /usr/share/rpm-test-symlink2dir/a -rw-r--r-- 1 root root 46 мая 13 18:18 /usr/share/rpm-test-symlink2dir/a/x.txt drwxr-xr-x 2 root root 4096 мая 13 18:30 /usr/share/rpm-test-symlink2dir/b -rw-r--r-- 1 root root 46 мая 13 18:18 /usr/share/rpm-test-symlink2dir/b/x.txt Причина такого поведения понятна: fingerprint cache доверяет состоянию файловой системы на момент начала транзакции: http://git.altlinux.org/people/iv/packages/rpm.git?p=rpm.git;a=blob;f=lib/fprint.c;h=65eaeec66e2a0804648f3ce9bade8a34f99e8249#l194 Переделать fingerprint cache чтобы он правильно обрабатывал замену ссылки на каталог на каталог я пока не успел; похоже, для этого требуется достаточно серьёзно переписать doLookupId() из lib/fprint.c.
> (1) удалить симлинк непосредственно перед > созданием каталога, в процессе установки пакета; > > (2) сделать отдельный проход по всем пакетам, > собрать все симлинки, которые нужно заменять на > каталоги и удалить их перед началом транзакции > -- такой захардкоженый pretrans trigger. > > (3) в каком-то виде вернуть предыдущее поведение, > позволив пакетам исправлять праблему самим > из %pre-скрипта Учитывая вышесказанное, (2) кажется более простым способом получить решение прямо сейчас. Это означает, что нужно специально пройтись по всем пакетам, построить fingerPrintCache, вычислить с его помощью симлинки которые нужно удалить, удалить их и заново построить fingerPringCache. Имхо ужас, но работать будет.
(В ответ на комментарий №15) > > (1) удалить симлинк непосредственно перед > > созданием каталога, в процессе установки пакета; > > > > (2) сделать отдельный проход по всем пакетам, > > собрать все симлинки, которые нужно заменять на > > каталоги и удалить их перед началом транзакции > > -- такой захардкоженый pretrans trigger. > > > > (3) в каком-то виде вернуть предыдущее поведение, > > позволив пакетам исправлять праблему самим > > из %pre-скрипта > > Учитывая вышесказанное, (2) кажется более простым способом получить решение > прямо сейчас. Это означает, что нужно специально пройтись по всем пакетам, > построить fingerPrintCache, вычислить с его помощью симлинки которые нужно > удалить, удалить их и заново построить fingerPringCache. Имхо ужас, но работать > будет. Коллеги, согласны?
(In reply to comment #14) > Я вижу три способа решения проблемы: > > (1) удалить симлинк непосредственно перед > созданием каталога, в процессе установки пакета; > > (2) сделать отдельный проход по всем пакетам, > собрать все симлинки, которые нужно заменять на > каталоги и удалить их перед началом транзакции > -- такой захардкоженый pretrans trigger. > > (3) в каком-то виде вернуть предыдущее поведение, > позволив пакетам исправлять праблему самим > из %pre-скрипта Мы нацеливались на (2). При этом о таком и похожих примерах я беспокоился (попробую записать, что именно мне казалось важным): > Однако этого недостаточно. Рассмотрим простейший > пример, когда вместе с исходным каталогом переехали > файлы. > > http://git.altlinux.org/people/iv/public/?p=rpm-update-tests.git;a=commitdiff;h=b247c271ad7dd6641284631876db0065e8055bf1 > > Было: > > drwxr-xr-x 3 root root 4096 мая 13 17:27 /usr/share/rpm-test-symlink2dir > drwxr-xr-x 2 root root 4096 мая 13 17:27 /usr/share/rpm-test-symlink2dir/a > -rw-r--r-- 1 root root 46 мая 13 17:26 > /usr/share/rpm-test-symlink2dir/a/x.txt > lrwxrwxrwx 1 root root 1 мая 13 17:26 /usr/share/rpm-test-symlink2dir/b -> a > > Стало: > > drwxr-xr-x 4 root root 4096 мая 13 17:39 /usr/share/rpm-test-symlink2dir > drwxr-xr-x 2 root root 4096 мая 13 17:39 /usr/share/rpm-test-symlink2dir/b > -rw-r--r-- 1 root root 46 мая 13 17:26 > /usr/share/rpm-test-symlink2dir/b/x.txt > > Здесь при анализе транзакции RPM увидит, что в новой версии пакета > есть /usr/share/rpm-test-symlink2dir/b/x.txt; с точки зрения RPM > он заменяет существующий /usr/share/rpm-test-symlink2dir/b/x.txt, > а значит при удалении старой версии пакета этот файл не нужно трогать. > В итоге, по результатам обновления остаётся "мусор": старый > `x.txt` вместе со своим каталогом `a`. Было содержание пакета (повторяю, чтобы подчеркнуть, что путь файла пакета понимается как b/x.txt, т.е. использующий симлинк): %dir a b -> a b/x.txt Стало: %dir b b/x.txt На самом деле, раньше файл лежал по реальному пути a/x.txt и выполнял роль b/x.txt благодаря тому, что был симлинк b -> a (такая как бы зависимость от наличия такого симлинка). Старая версия пакета удаляется вместе с симлинком, должен удаляться и файл {b -> a}/x.txt, а создаваться b/x.txt. Сейчас насколкьо я понимаю, это плохо вписывается в процедуру erasing в конце, если не проводить различия между путями {b -> a}/x.txt и b/x.txt (придумал в голове такое обозначение чтобы их различать). Теперь ещё можно рассмотреть пример, когда было установлено два пакета (X, Y). X: b -> a Y: b/x.txt Файл из пакета Y реально лежит по пути a/x.txt. Если X обновляется на X: %dir b то Y потеряет свой файл. Можно это представить так, что X содержал симлинк b -> a, Y -- файл по пути {b -> a}/x.txt. Когда X исчезает с {b -> a}, нужно сообщать об ошибке (конфликтах в предпринятом действии): для пакета Y был нужен симлинк. То же самое (конфликт/ошибке) по моему представлению должно возникнуть, когда один симлинк заменяется на другой в таком случае: Y имеет файл {b -> a}/x.txt, а X при обновлении меняет {b -> a} на {b -> c}. В таких условиях Y не мог бы больше существовать, поэтому надо сообщить об ошибке при попытке так сделать.
А много ли проблемных пакетов? В банках описаны два: gdb и lua. Не проще ли уменьшить общность задачи?
(In reply to comment #17) > Было содержание пакета (повторяю, чтобы подчеркнуть, что путь файла пакета > понимается как b/x.txt, т.е. использующий симлинк): > > %dir a > b -> a > b/x.txt Есть гипотеза, что в Сизифе такого нет.
(In reply to comment #19) > (In reply to comment #17) > > Было содержание пакета (повторяю, чтобы подчеркнуть, что путь файла пакета > > понимается как b/x.txt, т.е. использующий симлинк): > > > > %dir a > > b -> a > > b/x.txt > > Есть гипотеза, что в Сизифе такого нет. Можно просто во всех случаях, когда среди установленных пакетов есть пути проходящие через удаляемый симлинк, сообщать об ошибке. (Т.е. упростить алгоритм тем, что не делать разницы, удаляются ли эти пути в той же транзакции или нет.) Возможно, так достаточно просто, чтобы реализовать поведение, достаточное для двух известных проблемных пакетов.
в apt'е есть обвязка для запуска скрипт до, во время и после транзации. Можем ли мы его использовать для решения проблемы с симлинками? pkgRPMPM::RunScriptsWithPkgs("RPM::Pre-Install-Pkgs") _lua->RunScripts("Scripts::PM::Pre"); _lua->RunScripts("Scripts::PM::Post"); Ret = RunScripts("RPM::Post-Invoke"); RunScripts("RPM::Post-Invoke");
(In reply to comment #21) > в apt'е есть обвязка для запуска скрипт до, во время и после транзации. > Можем ли мы его использовать для решения проблемы с симлинками? > > pkgRPMPM::RunScriptsWithPkgs("RPM::Pre-Install-Pkgs") > _lua->RunScripts("Scripts::PM::Pre"); > _lua->RunScripts("Scripts::PM::Post"); > Ret = RunScripts("RPM::Post-Invoke"); > RunScripts("RPM::Post-Invoke"); Как некий workaround можно было бы. Но я не уверен, что rpm в таком случае всё равно не будет жаловаться на замену как на конфликт исходя из свое базы.
Т.к. таких пакетов еденицы, то прежде чем перепахивать rpm можно попробовать реализовать такой workaround на apt'е и посмотреть к чему это приведёт.
(In reply to comment #22) > (In reply to comment #21) > > в apt'е есть обвязка для запуска скрипт до, во время и после транзации. > > Можем ли мы его использовать для решения проблемы с симлинками? > > > > pkgRPMPM::RunScriptsWithPkgs("RPM::Pre-Install-Pkgs") > > _lua->RunScripts("Scripts::PM::Pre"); > > _lua->RunScripts("Scripts::PM::Post"); > > Ret = RunScripts("RPM::Post-Invoke"); > > RunScripts("RPM::Post-Invoke"); > > Как некий workaround можно было бы. Но я не уверен, что rpm в таком случае всё > равно не будет жаловаться на замену как на конфликт исходя из свое базы. Да, похоже, rpm это переживёт, судя по коду: static int handleRemovalConflict(rpmfiles fi, int fx, rpmfiles ofi, int ofx) { int rConflicts = 0; /* Removed files don't conflict, normally */ rpmFileTypes ft = rpmfiWhatis(rpmfilesFMode(fi, fx)); rpmFileTypes oft = rpmfiWhatis(rpmfilesFMode(ofi, ofx)); struct stat sb; char *fn = NULL; if (oft == XDIR) { /* We can't handle directory changing to anything else */ if (ft != XDIR) rConflicts = 1; } else if (oft == LINK) { /* We can't correctly handle directory symlink changing to directory */ if (ft == XDIR) { Здесь проверяем, что это не просто симлинк по базе данных, а именно sym- или hardlink на директорию. fn = rpmfilesFN(fi, fx); if (stat(fn, &sb) == 0 && S_ISDIR(sb.st_mode)) rConflicts = 1; } } /* * ...but if the conflicting item is either not on disk, or has * already been changed to the new type, we should be ok afterall. */ if (rConflicts) { if (fn == NULL) fn = rpmfilesFN(fi, fx); Здесь отменяем конфликт, если, в частности, hardlink на директорию (т.е. симлинка нет уже) или если оно вообще отсутствует. (В общем случае -- если отсутствует или реальный тип совпадает с новым.) if (lstat(fn, &sb) || rpmfiWhatis(sb.st_mode) == ft) rConflicts = 0; } free(fn); return rConflicts; } Так что если apt перед транзакцией удалит симлинк у проблемных пакетов, то должно проскочить. Мои опасения были неверными. Нужно ещё подумать, как такой pretrans-скрипт для этих пакетов донести до apt.
Неужели скрипт для apt окажется проще? Не верится.
(In reply to comment #21) > в apt'е есть обвязка для запуска скрипт до, во время и после транзации. > Можем ли мы его использовать для решения проблемы с симлинками? > > pkgRPMPM::RunScriptsWithPkgs("RPM::Pre-Install-Pkgs") > _lua->RunScripts("Scripts::PM::Pre"); > _lua->RunScripts("Scripts::PM::Post"); > Ret = RunScripts("RPM::Post-Invoke"); > RunScripts("RPM::Post-Invoke"); Этот подход ничем не лучше %pretrans . Только хуже потому что * при установке пакетов rpm-ом ничего не произойдёт; * скрипты для apt-а нужно установить до обновления пакетов в которых лежат проблемные пути.
(In reply to comment #25) > Неужели скрипт для apt окажется проще? Не верится. Тут скорее речь об общности решения. Для apt скрипт -- просто для двух известных пакетов делает то, что известно, что для них можно сделать. (Аналог pretrans-скрипта, где ответственность лежит на мейнтейнере пакета, который написал такой скрипт.) А в rpm хардкодить надо более общее с дополнительной защитой от разрушения установленной системы.
А почему бы всё-таки не затащить %pretrans в наш rpm и не стать в этом плане ближе к остальным ?
Есть ли на сегодня варианты объезда (симлинк на директорию => директория)?
(Ответ для Anton Farygin на комментарий #28) > А почему бы всё-таки не затащить %pretrans в наш rpm и не стать в этом плане > ближе к остальным ? Других вариантов не просматривается. Инструмент для решения возникающих проблем нужен, даже, если мы сделаем невозможным попадание пакетов, ломающих обновление в будущем (проверка обновления версии в репозитории на ту, что собираем). Потому что зачастую каталоги в симлинки и наоборот превращает сам апстрим, так как у апстрима какой-нибудь Debian и проблемы rpm их не волнуют. Поддержка исправлений в коде потребует всё возрастающих затрат от мантейнера. Примером такого пакета, который к тому же собирается роботом - firmware-linux. Я добавил превентивную проверку на возникновения такой ситуации в cronbuild скрипте, но инструмента для решения таких проблем у меня просто нет. Придётся править апстримный код. В итоге может получиться, что в пакете не окажется нужного симлинка на firmware (в следствие моей ошибки при возникновении конфликта), а сам пакет всё чаще придётся собирать руками. Поэтому прошу дать мантейнерам такой инструмент.
есть шанс починки этой ошибки в p11 ?
(In reply to Anton Farygin from comment #31) > есть шанс починки этой ошибки в p11 ? На вики есть страница, на ней параграфы с рецептами миграции каталога на симлинк и симлинка на каталог. https://www.altlinux.org/RPM/pretrans Раз в Sisyphus это поддерживается, значит, будет и в p11.