Пакет Debian - это не только архив файлов, предназначенных для установки. Это часть большего целого и описывает его взаимосвязь с другими пакетами Debian (реквизиты, зависимости, конфликты, предложения). Он также предоставляет сценарии, которые позволяют выполнять команды на различных этапах жизненного цикла пакета (установка, обновление, удаление). Эти данные используются инструментами управления пакетами, но не являются частью упакованного программного обеспечения; внутри пакета они представляют собой то, что называется его “метаинформацией” - информацией о другой информации.
5.2.1. Описание: файл control
Этот файл использует структуру, аналогичную заголовкам электронных писем (согласно определению
RFC 2822) и полностью описан в Политике Debian и на страницах руководства
deb-control(5) и
deb822(5).
Например, для apt файл control
выглядит следующим образом:
$
apt-cache show apt
Package: apt
Architecture: amd64
Version: 2.6.1
Priority: required
Section: admin
Maintainer: APT Development Team <deity@lists.debian.org>
Installed-Size: 4232
Provides: apt-transport-https (= 2.6.1)
Depends: adduser, gpgv | gpgv2 | gpgv1, libapt-pkg6.0 (>= 2.6.1), debian-archive-keyring, libc6 (>= 2.34), libgcc-s1 (>= 3.0), libgnutls30 (>= 3.7.5), libseccomp2 (>= 2.4.2), libstdc++6 (>= 11), libsystemd0
Recommends: ca-certificates
Suggests: apt-doc, aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), gnupg | gnupg2 | gnupg1, powermgmt-base
Breaks: apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~), aptitude (<< 0.8.10)
Replaces: apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~)
Filename: pool/main/a/apt/apt_2.6.1_amd64.deb
Size: 1372852
MD5sum: 2a077296b9b9f4f8b027f86d9500192b
SHA256: 6ea03cbbc7a7bfcee601c9fb08d4e026fd522ede5350561f06867ad9c0a0fa6b
Description-en: commandline package manager
This package provides commandline tools for searching and
managing as well as querying information about packages
as a low-level access to all features of the libapt-pkg library.
.
These include:
* apt-get for retrieval of packages and information about them
from authenticated sources and for installation, upgrade and
removal of packages together with their dependencies
* apt-cache for querying available information about installed
as well as installable packages
* apt-cdrom to use removable media as a source for packages
* apt-config as an interface to the configuration settings
* apt-key as an interface to manage authentication keys
Description-md5: 9fb97a88cb7383934ef963352b53b4a7
Tag: admin::package-management, devel::lang:ruby, hardware::storage,
hardware::storage:cd, implemented-in::c++, implemented-in::perl,
implemented-in::ruby, interface::commandline, network::client,
protocol::ftp, protocol::http, protocol::ipv6, role::program,
scope::application, scope::utility, suite::debian, use::downloading,
use::organizing, use::playing, use::searching, works-with-format::html,
works-with::audio, works-with::software:package, works-with::text
Давайте подробнее рассмотрим назначение некоторых полей, перечисленных в предыдущей команде.
5.2.1.1. Зависимости: поле Depends
Зависимости определяются в поле Depends
в заголовке пакета. Это список условий, выполнение которых необходимо для корректной работы пакета. Данная информация используется такими инструментами, как apt
, чтобы установить правильные версии необходимых библиотек, которые удовлетворяют зависимости устанавливаемого пакета. Для каждой зависимости диапазон версий, соответствующих этому условию, может быть ограничен. Другими словами, можно сказать, что нам требуется пакет libc6 версии не ниже чем «2.15» (пишется «libc6 (>= 2.15)
»). Операторы сравнения версий следующие:
В списке условий запятая играет роль разделителя. Её следует интерпретировать как логическое «и». Внутри условий вертикальная черта («|») означает логическое «или» (включающее «или», а не исключающее «строго одно из»). Поскольку оно имеет более высокий приоритет, чем «и», его можно использовать столько раз, сколько потребуется. Так, зависимость «(A или B) и C» записывается в виде
A | B, C
. Напротив, выражение «A или (B и C)» следует записывать как «(A или B) и (A или C)», поскольку поле
Depends
не допускает использования скобок, меняющих порядок приоритетов между логическими операторами «или» и «и». То есть должно писаться
A | B, A | C
.
Система зависимостей — хороший механизм для обеспечения работоспособности программ, но у него есть и другое применение — «метапакеты». Это пустые пакеты, в которых описаны только зависимости. Они обеспечивают установку группы взаимосвязанных программ, выбранных сопровождающим метапакета; соответственно, apt install метапакет
автоматически установит все эти программы, используя зависимости метапакета. Пакеты gnome, kde-full и linux-image-amd64 являются примерами метапакетов.
5.2.1.2. Конфликты: поле Conflicts
Поле Conflicts
указывает на то, что пакет не может быть установлен, если уже установлен другой пакет. Наиболее распространенными причинами для этого является включение обоими пакетами файлов с одинаковыми именами и путями, или предоставление сервисов на одном и том же порту TCP, либо мешающих работе друг друга.
dpkg
откажется установить пакет, если он вызовет конфликт с уже установленным пакетом, за исключением тех случаев, когда новый пакет указывает, что он будет «заменять» установленный пакет, — тогда dpkg
заменит старый пакет на новый. apt
всегда следует вашим указаниям: если вы выберете установку нового пакета, он автоматически предложит удалить проблемный пакет.
5.2.1.3. Несовместимость: поле Breaks
По своему действию поля Breaks
похоже на поле Conflicts
, но оно несёт особый смысл. Оно сообщает, что установка пакета «поломает» другой пакет (или конкретные его версии). Как правило, такая несовместимость между пакетами имеет временный характер, и Breaks
указывает на конкретные несовместимые версии.
dpkg
откажется установить пакет, который поломает уже установленный пакет, и apt
попытается решить проблему путём обновления пакета, который оказался бы сломанным, до более новой версии (которая, как предполагается, будет исправленной и, таким образом, снова совместимой).
Подобные ситуации могут возникнуть в случае обновления без обратной совместимости: это происходит, если новая версия работает не так, как старая, что приводит к сбою в другой программе, если не принять должных мер. Поле Breaks
помогает пользователю не сталкиваться с такими проблемами.
5.2.1.4. Предоставляемое пакетом: поле Provides
Это поле вводит очень интересную концепцию «виртуального пакета». Она имеет много применений, два из которых особенно важны. Первое состоит в использовании виртуального пакета, чтобы привязать к нему общее название сервиса (пакет «предоставляет» сервис). Вторая показывает, что пакет полностью заменяет другой, и что при этом он может удовлетворять зависимости, которые удовлетворил бы другой. Таким образом, можно создать замену пакета без необходимости использовать то же самое имя пакета.
5.2.1.4.1. Предоставление «сервиса»
Давайте рассмотрим первый случай более подробно на примере: все почтовые серверы, такие как postfix или sendmail, «предоставляют» виртуальный пакет mail-transport-agent. Поэтому в любом пакете, для работы которого нужен этот сервис (например менеджере списков рассылки вроде smartlist или sympa), просто указывается зависимость от mail-transport-agent вместо того, чтобы указывать большой, и при этом всё равно неполный список возможных решений (то есть postfix | sendmail | exim4 | …
). Кроме того, бесполезно устанавливать два почтовых сервера на одной машине, поэтому каждый из этих пакетов сообщит о конфликте с виртуальным пакетом mail-transport-agent. Конфликт пакета с самим собой игнорируется системой, но данная технология не допустит установки двух почтовых серверов одновременно.
5.2.1.4.2. Взаимозаменяемость другим пакетом
Поле Provides
также полезно в случаях, когда содержание пакета включается в состав другого, более крупного пакета. Например модуль Perl libdigest-md5-perl был необязательным в Perl 5.6, но стал стандартным в Perl 5.8 (и более поздних версиях, в частности 5.36, входящей в Bookworm). Поэтому в пакете perl, начиная с версии 5.8, указывается Provides: libdigest-md5-perl
, чтобы зависимости от этого пакета были удовлетворены при установке Perl версии 5.8 (или новее). Сам пакет libdigest-md5-perl в конечном итоге был удалён, поскольку после удаления старых версий Perl в его присутствии не осталось смысла.
Эта функция очень полезна, поскольку никогда нельзя предвидеть превратности процесса разработки, и важно иметь возможность подстроиться к переименованию устаревшего ПО или другим автоматическим заменам.
5.2.1.4.3. Прошлые ограничения
Виртуальные пакеты имеют некоторые ограничения, самым значительным из которых является отсутствие номера версии. Вернемся к предыдущему примеру: зависимость, такая как Depends: libdigest-md5-perl (>= 1.6)
, несмотря на наличие Perl 5.10, никогда не будет считаться удовлетворённой со стороны системы управления пакетами — в то время как на самом деле она, скорее всего, удовлетворена. Не зная этого, система управления пакетами выбирает наименее опасный путь, предполагая, что версии не соответствуют.
Это ограничение было снято в dpkg 1.17.11 и более не актуально. Пакеты вроде perl 5.36.0 могут назначать версию предоставляемым ими виртуальным пакетам при помощи зависимости, например: Provides: libdigest-md5-perl (= 2.58)
и, таким образом, позволяют другим пакетам использовать версионные зависимости.
5.2.1.5. Замена файлов: поле Replaces
Поле Replaces
указывает, что пакет содержит файлы, которые также присутствуют в другом пакете, но при этом пакет имеет право заменить их. Без этого поля dpkg
завершится с ошибкой, сообщив, что не может перезаписать файлы другого пакета (формально, можно заставить его сделать это с помощью опции --force-overwrite
, но это не является обоснованной стандартной операцией). Это позволяет выявить потенциальные проблемы и вынуждает сопровождающего изучить вопрос прежде чем добавлять такое поле.
Это поле используется при изменении имени пакета, или когда один пакет включается в состав другого. Это также происходит в случае, если сопровождающий решает распределить файлы по-другому между двоичными пакетами, полученными из одного и того же исходного: заменённый файл больше не принадлежит старому пакету, а только новому.
Если все файлы в установленном пакете были заменены, принимается решение об удалении пакета. Наконец, это поле также указывает dpkg
удалить заменённый пакет в случае конфликта.
5.2.2. Сценарии настройки
Кроме файла
control
файл
control.tar.gz
в каждом пакете Debian может содержать несколько сценариев, вызываемых
dpkg
на разных этапах обработки пакета. В Политике Debian подробно описаны все возможные случаи, в которых вызываются сценарии, и какие аргументы они при этом получают. Эти последовательности могут быть довольно сложными, поскольку если один из сценариев завершается с ошибкой,
dpkg
будет пытаться вернуться к нормальному состоянию (насколько это возможно) путём отмены текущей установки или удаления.
Если вкратце, сценарий preinst
вызывается перед установкой пакета, а postinst
после неё. Аналогично, prerm
запускается перед удалением пакета, а postrm
— после. Обновление пакета эквивалентно удалению предыдущей версии и установке более новой. Все возможные ситуации описать здесь не получится, но мы рассмотрим две, встречающиеся чаще всего: установку/обновление и удаление.
5.2.2.1. Установка и обновление
Во время первоначальной установки и при каждом обновлении пакета dpkg
вызывает так называемые maintainer scripts сценарии сопровождающего, такие как prerm
или preinst
. Эти сценарии могут выполнять дополнительные действия на разных этапах жизненного цикла пакета. Имена сценариев, которым предшествует new-
, представляют собой сценарии из новой версии пакета, который устанавливается или обновляется. Имена сценариев, которым предшествует old-
, — это сценарии из старой версии пакета, который обновляется.
During each invocation dpkg
will pass certain arguments to each script such as upgrade new-version
. The invoked script can then either handle the arguments and perform a particular action, or ignore the arguments and return with an exit code of 0
, if nothing needs to be done during that step. In practice many packages will not need to perform an action during every step in the life cycle. Thus a typical maintainer script will check for a particular argument and ignore all other ones, implicitly returning with exit code 0
.
Вот что происходит во время установки (или обновления). Аргументы old-version, new-version и last-version-configured являются заполнителями для фактических (старых и новых) номеров версий пакета:
Для обновления dpkg
вызывает скрипт old-prerm
и передаёт upgrade new-version
в качестве аргументов.
Также для обновления dpkg
запускает скрипт new-preinst
с аргументами upgrade old-version
; для первоначальной установки он выполняет следующий скрипт new-preinst
и передаёт install
как аргумент. Он может добавить старую версию в последнем параметре, если пакет уже был установлен и удалён с тех пор (но не очищен, и, следовательно, файлы конфигурации были сохранены).
После этого распаковываются файлы нового пакета. Если файл уже существует, он заменяется, но создаётся временная резервная копия.
При обновлении dpkg
вызывает скрипт old-postrm
и передаёт upgrade new-version
как аргумент.
dpkg
обновляет все внутренние данные (список файлов, сценарии настройки и т. п.) и удаляет резервные копии заменённых файлов. Теперь обратного пути нет: dpkg
более недоступны все элементы, необходимые для отката к предыдущему состоянию.
Наконец, dpkg
настраивает пакет, запуская скрипт new-postinst
с аргументами configure last-version-configured
.
Действия по удалению пакета аналогичны шагам установки. Основное отличие состоит в том, что скрипты удаления пакета называются:
dpkg
вызывает скрипт prerm
и передаёт аргумент remove
.
dpkg
удаляет все файлы пакета за исключением конфигурационных файлов и сценариев мейнтенера (сопровождающего).
dpkg
выполняет postrm
и передаёт аргумент remove
. Все сценарии настройки, за исключением скрипта postrm
, удаляются. Если пользователь не использует опцию «purge», процесс удаления заканчивается на этом шаге.
Для полного удаления пакета (в случае использования команды dpkg --purge
или dpkg -P
) также удаляются конфигурационные файлы и их копии (*.dpkg-tmp
, *.dpkg-old
, *.dpkg-new
) и временные файлы; после этого dpkg
запускает postrm
и передаёт аргумент purge
.
Четыре сценария, описанные выше, дополняются сценарием config
, предоставляемым пакетами, которые используют debconf
для запроса у пользователя информации для настройки. Этот сценарий определяет вопросы, которые будут заданы debconf
во время установки. Ответы заносятся в базу данных debconf
для дальнейшего использования. Эти сценарии обычно выполняются apt
до установки пакетов, последовательно, чтобы сгруппировать вопросы и задать их пользователю в начале процесса. Пред- и послеустановочные сценарии могут впоследствии использовать эту информацию, чтобы действовать в соответствии с пожеланиями пользователей.
5.2.3. Контрольные суммы, список конфигурационных файлов.
В дополнение к сценариям сопровождающего и управляющим данным, уже упомянутым в предыдущих разделах, архив control.tar.gz
пакета Debian может содержать и другие интересные файлы.
Первый,
md5sums
, содержит контрольные суммы MD5 для всех файлов пакета. Его главным преимуществом является то, что он позволяет
dpkg -verify
(который мы будем изучать в
Раздел 14.3.4.1, «Аудит пакетов с dpkg --verify
») и
debsums
(из одноимённого пакета; см.
Раздел 14.3.4.2, «Аудит пакетов: debsums
и его лимиты»), чтобы проверить, были ли эти файлы изменены с момента их установки. Обратите внимание, что когда этого файла не существует, что может быть в случае некоторых старых пакетов,
dpkg
будет генерировать его динамически во время установки (и хранить его в базе данных dpkg так же, как и другие файлы управления).
В conffiles
содержится список файлов, которые должны быть обработаны как конфигурационные файлы (см. deb-conffiles(5)). Конфигурационные файлы могут быть изменены администратором, и dpkg
постарается сохранить эти изменения во время обновления пакета.
Действительно, в этой ситуации dpkg
ведёт себя настолько интеллектуально, насколько это возможно: если стандартный конфигурационный файл не изменился между двумя версиями, она ничего не делает. Если, однако, файл был изменен, она будет пытаться обновить его. Возможны два варианта развития событий: если администратор не трогал конфигурационный файл, dpkg
автоматически установит новую версию; если же файл был изменен, dpkg
спросит администратора, какую версию он хочет использовать (старую с изменениями или новую из пакета). Для помощи в принятии решения dpkg
показывает «diff
», то есть различия между двумя версиями. Если пользователь предпочтёт оставить старую версию, новая будет храниться в том же месте, в файле с суффиксом .dpkg-dist
. Если же пользователь выбирает новую версию, старая сохраняется в файле с суффиксом .dpkg-old
. Другой вариант заключается в том, чтобы немедленно прервать dpkg
и отредактировать файл, попытавшись внести нужные изменения (ранее обнаруженные с помощью diff
).
Управляющий архив часто содержит и другие файлы, например triggers
, shlibs
, или symbols
. Эти файлы хорошо описаны в deb-triggers(5), deb-shlibs(5), и deb-symbols(5).
Триггеры были введены для уменьшения количества повторяющихся событий во время установки пакета, таких как регистрация файлов или задачи обновления каталога/базы данных. Пакеты могут определять свои собственные или активировать определённые триггеры. Более подробную документацию можно найти в
/usr/share/doc/dpkg/triggers.txt.gz
.
The shlibs
system is an older and simpler alternative to the symbols
system for declaring dependencies for shared libraries. It defines the package name and version in which to find a specific SONAME-version of a shared library. The newer symbols
system allows the definition of a dependency by tracking the symbols and their introduction or modification in the library instead.