Скрипты пакета, reinstall и конфигурационные файлы
Зачем пакету скрипты
Установка — не только распаковка файлов. Многим программам нужны действия, которые нельзя выразить списком файлов. Для этого пакет содержит скрипты сопровождающего (maintainer scripts), которые менеджер запускает в определённые моменты.
| Debian (dpkg) | RPM | Когда выполняется |
|---|---|---|
preinst |
%pre |
до распаковки файлов (при установке и обновлении) |
postinst |
%post |
после распаковки (настройка — configure) |
prerm |
%preun |
до удаления файлов (при удалении и обновлении — у старой версии) |
postrm |
%postun |
после удаления файлов (в том числе purge) |
Скрипт получает аргумент-контекст: install, upgrade <старая версия>, configure <версия>, remove, purge (в RPM — число установленных экземпляров), и может вести себя по-разному.
Типичные задачи pre-install
- Проверить условия и прервать установку (ненулевой код выхода): несовместимая версия, нет нужного ресурса.
- Остановить старую версию службы перед заменой исполняемых файлов.
- Создать пользователя/группу, если распаковываемые файлы должны сразу им принадлежать.
- Подготовить миграцию: сохранить данные старой версии, переименовать устаревший конфиг.
Типичные задачи post-install
- Создать системного пользователя (
adduser --system nginx), каталоги с нужными владельцами и правами (/var/lib/app). - Сгенерировать то, что нельзя положить в пакет: ключи SSH-сервера (
openssh-serverсоздаёт/etc/ssh/ssh_host_*), сертификаты, уникальные идентификаторы. - Зарегистрировать и запустить службу:
systemctl enable --now, перезапустить после обновления. - Обновить системные кеши и базы:
ldconfigпосле установки библиотек (вспомните урок оldd), базы man, кеш шрифтов и иконок,update-alternatives,depmodдля модулей ядра. Сейчас многое из этого делают триггеры пакетного менеджера — один раз на всю транзакцию. - Мигрировать данные и конфигурацию со старой версии.
#!/bin/sh
# postinst
set -e
case "$1" in
configure)
adduser --system --group --no-create-home myapp || true
install -d -o myapp -g myapp /var/lib/myapp
systemctl daemon-reload
systemctl enable --now myapp.service
;;
esac
exit 0
Скрипты выполняются от root
Поэтому пакеты принимают только из доверенных подписанных репозиториев: скрипт пакета может сделать в системе что угодно.
Конфигурационные файлы
Файлы в /etc пользователь правит под себя. При обновлении нельзя просто затереть их новой версией. Поэтому пакет помечает конфигурационные файлы:
- dpkg: список
conffiles(все файлы пакета в/etcобычно попадают туда автоматически); - RPM:
%configи%config(noreplace)в спецификации.
dpkg: три контрольные суммы
При установке новой версии dpkg сравнивает: файл на диске (текущий), файл из старого пакета (сумма запомнена при прошлой установке) и файл из нового пакета.
| Пользователь менял? | В пакете изменился? | Действие dpkg |
|---|---|---|
| нет | нет | ничего не делать |
| нет | да | тихо поставить новую версию |
| да | нет | оставить версию пользователя |
| да | да | спросить пользователя (или по опциям --force-confold / --force-confnew); новая версия — .dpkg-dist, старая — .dpkg-old |
| удалил | — | считать удаление намеренным, не восстанавливать (кроме --force-confmiss) |
apt remove оставляет конфиги (пакет в состоянии rc), apt purge удаляет и их.
RPM
| Пометка | Пользователь изменил файл | Результат |
|---|---|---|
%config(noreplace) |
да | файл пользователя остаётся, новый — рядом как .rpmnew |
%config |
да | ставится новый, файл пользователя сохраняется как .rpmsave |
| любая | нет | тихо заменяется |
Reinstall
Переустановка той же версии: apt install --reinstall pkg, dnf reinstall pkg, rpm -Uvh --replacepkgs.
Когда это осмысленно
- Повреждены или удалены файлы пакета: случайно удалили бинарник или библиотеку, сбой диска;
debsums pkg/rpm -V pkgпоказывают расхождения. - Файлы перезаписаны вручную:
make installповерх пакетной версии, ручная замена библиотеки. - Нужно снова выполнить скрипты пакета: служба не зарегистрирована, удалён системный пользователь, не обновлён кеш.
Reinstall не нужен для обновления версии и не сбрасывает изменённые конфиги.
Что происходит
dpkg выполняет полный цикл как при обновлении на ту же версию: prerm upgrade старой копии → preinst upgrade → распаковка всех файлов заново (повреждённые и удалённые обычные файлы восстанавливаются) → postrm upgrade → postinst configure.
С конфигурационными файлами — по правилам выше:
- изменённые пользователем — сохраняются (пакетная версия та же, вопросов нет);
- неизменённые — остаются равными пакетным;
- удалённые conffiles не восстанавливаются — dpkg считает удаление волей пользователя. Восстановить:
apt install --reinstall -o Dpkg::Options::="--force-confmiss" pkg.
В RPM при reinstall изменённый %config(noreplace) остаётся, а пакетная версия кладётся как .rpmnew; изменённый %config заменяется, а старый сохраняется как .rpmsave.
Ответ на задачу 6 коротко
Скрипты pre/post-install нужны для действий, которых нет в списке файлов: проверить условия и прервать установку, остановить старую службу; после распаковки — создать пользователей и каталоги, сгенерировать ключи, зарегистрировать и запустить службу, обновить кеши (ldconfig, man), мигрировать данные. Reinstall осмыслен, когда файлы пакета повреждены, удалены или перезаписаны вручную, либо нужно заново выполнить скрипты. При этом все файлы пакета распаковываются заново и скрипты выполняются снова, а конфигурационные файлы, изменённые администратором, сохраняются; удалённые конфиги dpkg не восстанавливает без --force-confmiss; RPM кладёт новую версию рядом (.rpmnew) или сохраняет старую (.rpmsave).
Итог
- preinst/postinst/prerm/postrm (
%pre/%post/%preun/%postun) — действия до и после распаковки и удаления. - Конфиги помечаются (
conffiles,%config); изменения пользователя не затираются. - Reinstall восстанавливает файлы пакета и перезапускает скрипты, но изменённые конфиги оставляет.
Практика решено 0 из 5
В каком скрипте пакета уместно каждое действие?
| preinst (до распаковки) | postinst (после распаковки) | prerm (до удаления файлов) | postrm (после удаления) | |
|---|---|---|---|---|
| Создать системного пользователя nginx для службы | ||||
| Остановить работающую старую версию службы перед обновлением | ||||
| Включить и запустить службу, обновить кеш ldconfig | ||||
| Проверить, что на диске хватает места / несовместимая версия — и прервать установку | ||||
| Остановить службу перед удалением пакета | ||||
| При purge удалить данные и пользователя, созданных пакетом |
Зачем в метаинформации пакета нужны скрипты pre-install и post-install?
Что произойдёт с конфигурационным файлом при apt install --reinstall pkg (dpkg)?
| Заменится версией из пакета | Останется как есть | Будет вопрос пользователю | |
|---|---|---|---|
| Файл не менялся пользователем | |||
| Пользователь изменил файл, версия в пакете та же | |||
| Пользователь удалил conffile | |||
| Пользователь изменил файл, а в новой версии пакета (обновление) файл тоже изменился |
В каких случаях осмысленно выполнить reinstall пакета?
RPM-пакет помечает конфиг как %config(noreplace). Пользователь изменил файл. Что сделает dnf reinstall?
Войдите, чтобы отмечать пройденные уроки.