Обновление в Arch Linux выглядит обманчиво просто. Одна строка pacman -Syu, пара минут скачивания, и система снова свежая. За этой сценой стоит слой инфраструктуры: базы данных в /var/lib/pacman, журнал транзакций, связка ключей и кеш пакетов, который однажды спасает всю систему. Фоновой службы у pacman нет, всё, что он знает о системе, лежит на диске в виде обычных файлов, их можно раскрыть tar-ом и полистать в редакторе. Дальше разберём устройство баз, механизм зависимостей, ловушку частичных обновлений и рабочие способы вернуть пакет к прошлой версии.

Где Pacman хранит всё, что знает о системе

Pacman собран вокруг библиотеки libalpm, Arch Linux Package Management. Консольная команда лишь надстройка, поэтому графические менеджеры пакетов и хелперы для AUR читают те же базы и не заводят собственных. Между запусками pacman ничего не делает в фоне и не держит процессов.

Поведение задаёт файл /etc/pacman.conf. В стандартной поставке там раскомментированы HoldPkg = pacman glibc, pacman спросит подтверждение, если транзакция затронет менеджер или glibc, CheckSpace для проверки свободного места и ParallelDownloads = 5, пять одновременных загрузок. Строка SigLevel закомментирована, но умолчание жёсткое, подписи баз и пакетов обязательны.

Каталоги распределены так: базы в /var/lib/pacman (DBPath), архивы пакетов в /var/cache/pacman/pkg (CacheDir), журнал в /var/log/pacman.log (LogFile), ключи в /etc/pacman.d/gnupg (GPGDir), хуки в /etc/pacman.d/hooks (HookDir). Внутри /var/lib/pacman два подкаталога, local и sync, и разница между ними объясняет всю дальнейшую кухню:

ls /var/lib/pacman
local
sync

Синхронная база репозитория оказывается обычным сжатым архивом tar

В /var/lib/pacman/sync лежат core.db, extra.db и multilib.db, по файлу на каждый репозиторий из /etc/pacman.conf. Название обманчиво, это не базы в привычном смысле, а gzip-сжатые tar-архивы, первые байты core.db дают фирменную подпись 1f 8b. Раскрыть базу можно под обычным пользователем:

tar -tzf /var/lib/pacman/sync/core.db | head -8

Реальный вывод свежей базы:

acl-2.4.0-1/
amd-ucode-20261019-1/
archlinux-keyring-20260909-1/
attr-2.6.0-1/
...

Каждая строка это каталог в архиве, имя собирается из версии пакета и номера сборки, внутри текстовый файл desc. На момент проверки в core.db было 299 записей, в extra.db свыше 15 тысяч, плюс отдельная multilib. Формат стабилен годами, в репозиториях сейчас pacman ветки 7.1.

Фрагмент desc для bash версии 5.3.20-1:

%NAME%
bash
%VERSION%
5.3.20-1
%CSIZE%
2001850
%ISIZE%
10055840
%SHA256SUM%
73a67dc509ed4a6dd64e4c7eca2895643f48083940f49431782ce78c4d4619e1
%PGPSIG%
iQEzBAABCgAdFiEEW34/txt/EDKaHAOrdx32Yn7faB8F...
%DEPENDS%
readline
libreadline.so=8-64
glibc
ncurses
%OPTDEPENDS%
bash-completion: for tab completion

CSIZE это размер сжатого архива, около 1,9 МБ, ISIZE распакованного, 9,6 МБ. SHA256SUM сверяется после загрузки, PGPSIG это отсоединённая подпись в base64, обрезанная в листинге, BUILDDATE хранится как unix-время. Вытащить desc любого пакета можно на лету:

E=$(tar -tzf /var/lib/pacman/sync/extra.db | grep -m1 ^gimp)
tar -xzOf /var/lib/pacman/sync/extra.db "${E}desc" | less

Есть и штатный способ. pacman -Fy скачивает базы списков файлов, после чего pacman -Fl gimp печатает состав пакета, а pacman -F /путь/к/файлу подсказывает, в каком ещё не установленном пакете лежит нужный файл.

Каталог local с личным делом каждого установленного пакета

На каждый установленный пакет в /var/lib/pacman/local заведён каталог вида bash-5.3.20-1. Файл desc повторяет метаданные репозитория и добавляет локальные факты: %INSTALLDATE% с датой установки, %SIZE% с фактическим занятым местом, %VALIDATION% со способом проверки. Главная метка, %REASON%, ноль значит поставлен вручную, единица приехал как зависимость.

Файл files перечисляет все пути пакета, плюс раздел %BACKUP% с конфигурационными файлами, которые pacman защищает от затирания. install хранит текст установочных сценариев. Самый занимательный файл, mtree, это gz-манифест с контрольной суммой каждого файла на момент установки:

gzip -dc /var/lib/pacman/local/bash-5.3.20-1/mtree | head -6

Каждая строка начинается с пути и несёт параметры size, time и sha256digest. Сверяя диск с этим слепком, pacman замечает изменённые и пропавшие файлы, команда pacman -Qkk прогоняет проверку по всей системе, медленно, но честно.

Повседневные запросы идут без прав root. pacman -Ql bash печатает список файлов пакета, pacman -Qo /usr/bin/pacman называет владельца файла, pacman -Qi bash показывает выжимку из desc. Метку причины можно переключать без переустановки, pacman -D --asdeps и pacman -D --asexplicit. Уборка мусора растёт отсюда же: pacman -Qet перечисляет явные пакеты, pacman -Qdt находит осиротевшие зависимости, а pacman -Rns $(pacman -Qdtq) удаляет сирот разом, список перед запуском стоит глянуть глазами.

Цена базы высока, /var/lib/pacman/local единственное место, где записано, что вообще установлено. Потеряете каталог, pacman ослепнет, и список придётся восстанавливать по журналу.

Откуда Pacman берёт зависимости и зачем метка "установлен как зависимость"

Зависимости в desc не появляются сами, упаковщик описывает их в PKGBUILD, и после сборки они застывают в базе. Формат допускает три уровня строгости: простое имя, например ncurses, имя с условием вроде readline>=8.0 и soname-зависимости вида libreadline.so=8-64, где пакет требует конкретную версию разделяемого объекта .so.

Soname-механизм связывает всю экосистему. Библиотека объявляет в поле %PROVIDES%, какие объекты .so поставляет, bash в примере выше даёт sh. Когда выходит новая мажорная версия с другим суффиксом, репозиторий пересобирает все зависящие пакеты, и штатное pacman -Syu привозит систему целиком, а не кусками. Если поставщиков у требования несколько, pacman не угадывает, а выводит список и спрашивает, какой выбрать.

Отдельная графа optdepends, необязательные дополнения вроде bash-completion: for tab completion, это подсказка, а не зависимость.

Версии сравниваются по правилам pacman, где 5.3.20 старше 5.3.2, числовые части сопоставляются целиком:

vercmp 5.3.20 5.3.2

Вывод 1 значит, что левое значение новее. Префикс 1:2.0-1 это эпоха, она старше любой версии без неё, страховка на случай откатов нумерации.

Счётчики причин говорят о масштабе: pacman -Qet | wc -l выдаёт на порядок меньше строк, чем pacman -Q | wc -l, явных пакетов десятки, зависимостей сотни. Достаточно раз в месяц запускать pacman -Qdt и решать, что из сирот ещё пригодится.

Чем грозит pacman -Sy без u и как разваливается частично обновлённая система

Репозитории Arch хранят только текущую версию каждого пакета, старая исчезает с зеркал. Команда pacman -Sy обновляет прайс-лист, pacman -Su сами пакеты, и опасна их комбинация с установкой: pacman -Sy пакет ставит программу по свежим метаданным, оставляя остальную систему вчерашней.

Первая поломка бьёт по библиотекам. Новое приложение требует libfoo.so=2-64, pacman ставит библиотеку 2.x, версии 1.x в репозитории уже нет, а программы под объект .so=1 остаются без поставщика. Полное обновление привезло бы и их, репозиторий пересобрал зависимые пакеты, частичное об этом не знает. Итог, старый плеер не запускается с сообщением error while loading shared libraries, и сходу непонятно, что сломалось.

Вторая поломка бьёт по ядру. linux обновился, модули или заголовки остались, модуль не проходит проверку vermagic, и драйвер видеокарты не поднимается. Третья история с интерпретаторами: модуль python встал в каталог версии 3.14, сам python остался 3.13, скрипты падают с ModuleNotFoundError.

Откатить такое состояние средствами репозиториев нельзя, прошлых версий там нет. Arch официально поддерживает только полное обновление, любая другая схема считается частичной. Даже легальный IgnorePkg создаёт похожий риск, замороженный пакет не поспевает за зависящими по soname пакетами. Строка HoldPkg = pacman glibc подстраховывает, pacman остановится и спросит, если транзакция затронет эти два пакета.

Правило короткое. Обновление системы делается одной командой pacman -Syu, точка. Всё, что обновляет базы без пакетов или пакеты без баз, накапливает рассинхрон, который аукнется, когда уже не вспомнишь, с чего началось.

Откат пакета на прошлую версию через кеш и архив репозиториев

Кеш в /var/cache/pacman/pkg устроен как антресоль, pacman складывает туда каждый скачанный архив .pkg.tar.zst и сам ничего не удаляет:

ls -1 /var/cache/pacman/pkg/ | grep ^linux-
linux-6.16.1.arch1-1-x86_64.pkg.tar.zst
linux-6.16.2.arch1-1-x86_64.pkg.tar.zst

Откат выполняется от root, префикс file:// указывает на локальный файл:

pacman -U file:///var/cache/pacman/pkg/linux-6.16.1.arch1-1-x86_64.pkg.tar.zst

Ядро откатывают комплектом, вместе с linux-headers и пакетами модулей вроде virtualbox-host-modules-arch, иначе модули не совпадут с версией ядра, а initramfs пересоберёт хук сам.

За кешем нужен уход, помогает скрипт paccache из пакета pacman-contrib. По умолчанию paccache -r оставляет три последние версии каждого пакета, paccache -rk1 держит только одну, paccache -ruk0 вычищает архивы того, чего в системе уже нет. Еженедельная уборка включается командой systemctl enable paccache.timer, аргументы правятся в /etc/conf.d/pacman-contrib строкой вида PACCACHE_ARGS='-k1'. Опасен pacman -Sc, он стирает из кеша всё, чего нет в текущих базах, включая прошлые версии установленных пакетов, то есть уничтожает саму полку для отката.

Порядок действий при откате ядра после неудачного обновления выглядит так:

  1. Если система не стартует, в меню загрузчика выбрать предыдущую запись с прошлым ядром и загрузиться в неё;
  2. Найти прошлую версию в кеше командой ls -1 /var/cache/pacman/pkg/ | grep ^linux-;
  3. Откатить ядро, заголовки и модули одной транзакцией pacman -U с префиксом file://;
  4. Зафиксировать версию строкой IgnorePkg = linux в секции [options] файла /etc/pacman.conf и снять фиксацию, когда причина сбоя будет найдена.

Фиксация нужна потому, что ближайшее же pacman -Syu накатит сломанную версию обратно:

[options]
HoldPkg = pacman glibc
ParallelDownloads = 5
IgnorePkg = linux

Если кеш уже вычищен, выручает архив репозиториев по адресу archive.archlinux.org. Прошлые версии лежат по схеме /packages/первая буква/имя пакета/, снимки репозиториев на дату по пути вида /repos/2026/03/15/, ссылка repos/last указывает на свежий. Схема та же, скачать и поставить:

curl -O https://archive.archlinux.org/packages/l/linux/linux-6.16.1.arch1-1-x86_64.pkg.tar.zst
pacman -U linux-6.16.1.arch1-1-x86_64.pkg.tar.zst

Архив вместе с pacman -Suu, где удвоенная буква u разрешает понижение версий, приводит всю систему к состоянию на выбранную дату.

Журнал транзакций, подписи пакетов и страховочная копия базы local

Все транзакции фиксируются в /var/log/pacman.log без ротации. Формат читается легко:

[PACMAN] Running 'pacman -Syu'
[ALPM] upgraded linux (6.16.2.arch1-1 -> 6.16.3.arch1-1)
[ALPM-SCRIPTLET] :: Mkinitcpio image generation successful

Метка [PACMAN] фиксирует запущенную команду, [ALPM] изменения версий, [ALPM-SCRIPTLET] вывод установочных сценариев. По журналу находятся старые версии, даже если кеш давно очищен:

grep "upgraded linux" /var/log/pacman.log | tail -5

Вторая линия защиты, подписи. Умолчание SigLevel = Required DatabaseOptional означает, что базы и пакеты обязаны иметь действительную подпись доверенного ключа. Ключи лежат в /etc/pacman.d/gnupg и обновляются обычным пакетом archlinux-keyring. Если система долго стояла без обновлений и pacman выдаёт invalid or corrupted package (PGP signature), первым делом обновляют archlinux-keyring, при упорстве выполняют pacman-key --populate archlinux.

Страховку базы local делает хук транзакции. Файл /etc/pacman.d/hooks/backup-local-db.hook перед каждой транзакцией складывает копию базы в /root:

[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *

[Action]
When = PreTransaction
Exec = /usr/bin/tar -czf /root/pacman-local-db.tar.gz -C / var/lib/pacman/local

Имя копии фиксированное, каждая транзакция перезаписывает её заново, зато база всегда подстрахована.

В сухом остатке четыре предмета: прайс-лист репозиториев в /var/lib/pacman/sync, личное дело пакетов в /var/lib/pacman/local, антресоль в /var/cache/pacman/pkg и протокол в /var/log/pacman.log. Когда обновление ломает систему, вопрос "что изменилось" решается чтением журнала, а откат возвращается одной командой pacman -U. Один раз распакованный core.db с полистанным desc переводит аварию из разряда непонятной в разряд рутинной работы на десять минут.