Product SiteDocumentation Site

5.2. Метаинформация пакета

Пакет 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)»). Операторы сравнения версий следующие:
  • <<: меньше;
  • <=: меньше или равна;
  • =: равна (однако «2.6.1» — не то же самое, что и «2.6.1-1»);
  • >=: больше или равна;
  • >>: больше.
В списке условий запятая играет роль разделителя. Её следует интерпретировать как логическое «и». Внутри условий вертикальная черта («|») означает логическое «или» (включающее «или», а не исключающее «строго одно из»). Поскольку оно имеет более высокий приоритет, чем «и», его можно использовать столько раз, сколько потребуется. Так, зависимость «(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 в его присутствии не осталось смысла.
Использование поля Provides для того, чтобы не нарушать зависимости

Рисунок 5.1. Использование поля Provides для того, чтобы не нарушать зависимости

Эта функция очень полезна, поскольку никогда нельзя предвидеть превратности процесса разработки, и важно иметь возможность подстроиться к переименованию устаревшего ПО или другим автоматическим заменам.
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 являются заполнителями для фактических (старых и новых) номеров версий пакета:
  1. Для обновления dpkg вызывает скрипт old-prerm и передаёт upgrade new-version в качестве аргументов.
  2. Также для обновления dpkg запускает скрипт new-preinst с аргументами upgrade old-version; для первоначальной установки он выполняет следующий скрипт new-preinst и передаёт install как аргумент. Он может добавить старую версию в последнем параметре, если пакет уже был установлен и удалён с тех пор (но не очищен, и, следовательно, файлы конфигурации были сохранены).
  3. После этого распаковываются файлы нового пакета. Если файл уже существует, он заменяется, но создаётся временная резервная копия.
  4. При обновлении dpkg вызывает скрипт old-postrm и передаёт upgrade new-versionкак аргумент.
  5. dpkg обновляет все внутренние данные (список файлов, сценарии настройки и т. п.) и удаляет резервные копии заменённых файлов. Теперь обратного пути нет: dpkg более недоступны все элементы, необходимые для отката к предыдущему состоянию.
  6. dpkg обновит все конфигурационные файлы, выводя запрос пользователю, если это невозможно сделать автоматически. Подробности этой процедуры рассмотрены в Раздел 5.2.3, «Контрольные суммы, список конфигурационных файлов.».
  7. Наконец, dpkg настраивает пакет, запуская скрипт new-postinst с аргументами configure last-version-configured.

5.2.2.2. Удаление пакета

Действия по удалению пакета аналогичны шагам установки. Основное отличие состоит в том, что скрипты удаления пакета называются:
  1. dpkg вызывает скрипт prerm и передаёт аргумент remove.
  2. dpkg удаляет все файлы пакета за исключением конфигурационных файлов и сценариев мейнтенера (сопровождающего).
  3. dpkg выполняет postrm и передаёт аргумент remove. Все сценарии настройки, за исключением скрипта postrm, удаляются. Если пользователь не использует опцию «purge», процесс удаления заканчивается на этом шаге.
  4. Для полного удаления пакета (в случае использования команды 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.