Внутреннее устройство dpkg
dpkg — низкоуровневый движок под apt. Файл .deb — это двухархивный пакет: control.tar с метаданными и скриптами мейнтейнера, data.tar с реальными файлами. dpkg -i/-l/-L/-S запрашивает и управляет локальной базой пакетов в /var/lib/dpkg.
На середине sudo apt install сеть упала. Теперь dpkg говорит, что пакет «half-configured», и каждая последующая команда apt завершается ошибкой: «dpkg was interrupted, you must manually run ‘sudo dpkg —configure -a’». Или ты нашёл файл в файловой системе и хочешь узнать, какой пакет его владелец. Или вендор поставляет .deb без apt-репозитория. В трёх случаях ты работаешь с dpkg напрямую — apt вне игры. Понимание dpkg — это разница между «застрял» и «две команды до исправления».
После этого урока ты сможешь запрашивать базу dpkg с помощью -l, -L и -S, устанавливать отдельный .deb через -i, понимать содержимое .deb-архива на бинарном уровне, объяснять что такое half-configured и как восстановиться, а также объяснять, почему apt вызывает dpkg, а не заменяет его.
dpkg — движок; apt — front-end. dpkg управляет локальной базой пакетов и устанавливает/удаляет файлы. Он ничего не знает о репозиториях, зеркалах или разрешении зависимостей через ещё не скачанные пакеты. apt добавляет эти слои сверху: получает индексы, разрешает полный граф зависимостей, скачивает .deb-файлы и затем передаёт их dpkg в правильном порядке.
# Установка без apt — только dpkg
# (все зависимости уже должны быть установлены; dpkg откажет, если нет)
sudo dpkg -i ./mypackage_1.2.3_amd64.deb
# Ошибка dpkg -i при отсутствии зависимости:
# dpkg: dependency problems prevent configuration of mypackage:
# mypackage depends on libfoo3 (>= 3.1); libfoo3 is not installed.
# Используй apt для разрешения: sudo apt -f installapt -f install («fix broken») говорит apt просмотреть текущее состояние dpkg, найти недостающие зависимости, скачать их из репозитория и снова передать всё dpkg для завершения конфигурации. Это правильный путь восстановления после частичной установки.
База dpkg находится в /var/lib/dpkg/ и хранится в виде обычного текста. Самые важные файлы:
# Файл статуса — одна запись на каждый установленный/известный пакет
cat /var/lib/dpkg/status | head -40
# Директория info/ — метаданные и скрипты мейнтейнера для каждого пакета
ls /var/lib/dpkg/info/nginx.list # список всех файлов, установленных nginx
cat /var/lib/dpkg/info/nginx.postinst # post-install скрипт (запускается после распаковки)
# Запросить базу: список установленных пакетов
dpkg -l # все установленные пакеты
dpkg -l 'nginx*' # фильтрация по шаблону
dpkg -l | grep '^ii' # только полностью установленные (ii = installed)Префикс статуса в выводе dpkg -l — две буквы: первая — желаемое состояние (i=install, r=remove, p=purge), вторая — текущее состояние (i=installed, c=config-files only, H=half-installed). Строка, начинающаяся с iH, означает: dpkg пытался установить, но был прерван до завершения конфигурации.
Архив .deb — это ar-архив, содержащий три элемента. Можно изучить без установки:
# Изучить .deb без установки
ar t nginx_1.18.0-6ubuntu14_amd64.deb
# Вывод:
# debian-binary ← "2.0\n" — маркер версии формата
# control.tar.xz ← метаданные, зависимости, скрипты мейнтейнера
# data.tar.xz ← реальное дерево файловой системы для распаковки
# Извлечь и изучить control.tar
ar x nginx_1.18.0-6ubuntu14_amd64.deb control.tar.xz
tar --list -f control.tar.xz
# ./control ← имя пакета, версия, архитектура, зависимости
# ./conffiles ← список конфиг-файлов, переживающих purge
# ./preinst ← запускается ДО распаковки
# ./postinst ← запускается ПОСЛЕ распаковки (обычно запускает сервис)
# ./prerm ← запускается ДО удаления
# ./postrm ← запускается ПОСЛЕ удаленияСкрипты мейнтейнера (pre/post install/remove) — shell-скрипты, выполняемые от root. Именно поэтому важна подлинность пакетов (подпись GPG) — вредоносный postinst в подделанном пакете выполняет произвольный код с правами root во время установки.
dpkg -L и dpkg -S позволяют ориентироваться в графе владельцев. Это два наиболее полезных запроса dpkg при расследовании инцидентов:
# Список всех файлов, установленных пакетом
dpkg -L nginx
# /usr/sbin/nginx
# /etc/nginx/nginx.conf
# /lib/systemd/system/nginx.service
# ...
# Найти пакет-владелец файла
dpkg -S /usr/sbin/nginx
# nginx: /usr/sbin/nginx
# Проверить, принадлежит ли файл какому-либо пакету
dpkg -S /etc/nginx/nginx.conf.bak
# dpkg-query: no path found matching pattern /etc/nginx/nginx.conf.bak
# (создан оператором, не пакетом — безопасно редактировать или удалять)
# Проверить целостность пакета: сравнить файлы с ожидаемыми контрольными суммами
dpkg -V nginx
# (нет вывода = все файлы совпадают; отличия выводятся по каждому файлу)dpkg -V вычисляет md5-суммы каждого файла из манифеста пакета и сравнивает с тем, что на диске. Изменённый конфиг-файл будет обнаружен — полезно для выявления несанкционированных изменений системных файлов.
Состояние half-configured — самая распространённая аварийная ситуация с dpkg. Возникает, когда установка прервана после распаковки, но до завершения скрипта postinst. Пакет на диске есть, но dpkg не зарегистрировал его как полностью настроенный.
# Симптомы — любая команда apt завершается ошибкой:
# E: dpkg was interrupted, you must manually run:
# sudo dpkg --configure -a
# Исправление: сказать dpkg завершить конфигурацию всего прерванного
sudo dpkg --configure -a
# Если сам postinst завершается с ошибкой (например, сервис не запускается):
sudo dpkg --configure -a --force-confdef --force-confnew
# Крайняя мера: удалить наполовину установленный пакет и начать заново
sudo dpkg --remove --force-remove-reinstreq badpackage
sudo apt install badpackage # заново скачать и установитьФлаг --force-remove-reinstreq удаляет пакет, даже если dpkg считает его в состоянии reinstreq (требуется переустановка). Используй его только когда --configure -a не помогает — он может оставить файлы на диске, которые нужно убирать вручную.
Диагностика сломанного состояния пакета после обрыва сети во время apt install.
Джуниор-инженер запустил sudo apt install postgresql-15, и в середине установки сеть упала. Теперь каждая команда apt или dpkg завершается ошибкой.
# Шаг 1: посмотреть, в каком состоянии dpkg считает пакеты
dpkg -l 'postgresql*'
# ii postgresql-client-15 ... ok installed
# iH postgresql-15 ... half-installed ← проблемный пакет
# Шаг 2: изучить ошибку в файле статуса
grep -A5 'Package: postgresql-15' /var/lib/dpkg/status
# Status: install half-configured
# ...
# Шаг 3: попытаться завершить конфигурацию (ничего не скачивает, только запускает postinst)
sudo dpkg --configure -a
# Если postinst запускает кластер postgres и он падает из-за проблем с data dir:
# dpkg: error processing package postgresql-15 (--configure):
# subprocess installed post-installation script returned error exit status 1
# Шаг 4: проверить ошибку postinst
journalctl -u postgresql@15-main.service --since "5 minutes ago"
# Убедиться, что это проблема запуска, а не сломанный пакет
# Шаг 5: исправить проблему запуска (например, права на data dir)
sudo chown -R postgres:postgres /var/lib/postgresql/15/
sudo dpkg --configure -a # повторить — теперь успешно
dpkg -l 'postgresql-15' # ii = полностью установленКлючевое понимание: dpkg --configure -a ничего не переcкачивает. Он только запускает скрипт postinst пакетов, застрявших в состоянии half-configured. Реальная ошибка почти всегда в самом скрипте postinst, а исправление — в решении проблемы запуска сервиса.
▸Частая ошибка
Никогда не редактируй файлы в /var/lib/dpkg/ вручную, чтобы «исправить» плохое состояние пакета. Формат выглядит простым, но поля взаимозависимы — файл статуса с неверной записью приведёт к сбою всех команд dpkg и apt, и встроенного инструмента восстановления повреждённой базы dpkg не существует. Если действительно нужно удалить устаревшую запись, используй dpkg --remove --force-remove-reinstreq <package> — это хотя бы проходит через правильный автомат состояний. Ручное редактирование статус-файла — крайняя мера для оффлайн-восстановления из резервной копии.
▸Почему это работает
Почему скрипты мейнтейнера выполняются от root? dpkg разрабатывался в 1990-х для общесистемной установки. postinst часто создаёт системных пользователей (useradd --system), устанавливает права на файлы (chmod 700 /etc/postgresql) или запускает сервисы (systemctl enable postgresql). Всё это требует root. Вот почему подпись пакетов не обсуждается: postinst имеет те же полномочия, что и sudo rm -rf /. Поверхность атаки вредоносного .deb — вся корневая файловая система.
Ты находишь бинарный файл /usr/bin/pg_dump и хочешь узнать, какой пакет его установил и не был ли он подделан. Какая пара команд даст тебе эту информацию?
dpkg — низкоуровневый движок; apt строится поверх него. Файл .deb — ar-архив с control.tar (метаданные + скрипты мейнтейнера preinst/postinst/prerm/postrm) и data.tar (дерево файловой системы). База dpkg в /var/lib/dpkg/ отслеживает состояние каждого установленного пакета. Ключевые запросы: -l — список пакетов (префикс iH = half-configured), -L — файлы пакета, -S — пакет-владелец файла, -V — проверка контрольных сумм. Состояние half-configured (прерванная установка) исправляется командой dpkg --configure -a. Никогда не редактируй /var/lib/dpkg/status вручную.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.