Product SiteDocumentation Site

5.2. Metainformação do Pacote

O pacote Debian não é apenas um arquivamento de arquivos prontos para serem instalados. Ele é parte de um todo, e descreve sua relação com outros pacotes Debian (requisitos, dependências, conflitos, sugestões). Ele também fornece scripts que habilitam a execução de comandos em diferentes estágios do ciclo de vida do pacote (instalação, atualizações, remoção). Estes dados são usados pelas ferramentas de gerencia de pacotes mas não são parte do programa empacotado, eles são, junto com o pacote, o que chamamos de sua “meta-informação” - informação sobre outras informações.

5.2.1. Descrição: O arquivo control

Este arquivo usa uma estrutura similar aos cabeçalhos de email (como definido pela RFC 2822) e é completamente descrito na Política Debian e nas páginas man deb-control(5) e deb822(5).
Por exemplo, para o apt, o arquivo control parece com algo como:
$ apt-cache show apt
Package: apt
Version: 2.2.4
Installed-Size: 4337
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Replaces: apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~)
Provides: apt-transport-https (= 2.2.4)
Depends: adduser, gpgv | gpgv2 | gpgv1, libapt-pkg6.0 (>= 2.2.4), debian-archive-keyring, libc6 (>= 2.15), libgcc-s1 (>= 3.0), libgnutls30 (>= 3.7.0), libseccomp2 (>= 2.4.2), libstdc++6 (>= 9), 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)
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
Section: admin
Priority: required
Filename: pool/main/a/apt/apt_2.2.4_amd64.deb
Size: 1491328
MD5sum: 24d53e8dd75095640a167f40476c0442
SHA256: 75f07c4965ff0813f26623a1164e162538f5e94defba6961347527ed71bc4f3d
Vamos dar uma olhada mais de perto no objetivo de alguns campos listados pelos comandos anteriores.

5.2.1.1. Dependências: o campo Depends (depende de)

As dependências são definidas no campo Depends no cabeçalho do pacote. Esta é uma lista de condições a serem satisfeitas para o pacote funcionar corretamente. Esta informação é usada por ferramentas como o apt para instalar bibliotecas, ferramentas e drivers necessários nas versões corretas, preenchendo as dependências do pacote a ser instalado. Para cada dependência, é possível restringir o intervalo de versões que satisfazem esta condição. Em outras palavras, é possível expressar o fato de que nós precisamos do pacote libc6 em uma versão igual ou superior a “2.15” (escreve-se “libc6 (>= 2.15)”). Operadores de comparação de versão são os seguintes:
  • <<: menor que;
  • <=: menor ou igual que;
  • =: igual a (obs, este “2.6.1” não é igual a “2.6.1-1”);
  • >=: maior ou igual que;
  • >>: maior que.
Numa lista de condições para serem satisfeitas, a vírgula serve como um separador. Ela deve ser interpretada como um "e" lógico. Em condicionais, a barra vertical ("|") expressa um "ou" lógico (é um "ou" inclusivo, não um "ou isto ou aquilo"). Tem prioridade sobre o "e", pode ser usado tanto quanto necessário. Portanto, a dependência "(A ou B) e C" é escrita como A | B, C. Por outro lado, a expressão "A ou (B e C)" deve ser escrita como "(A ou B) e (A ou C)", uma vez que o campo Depends não aceita parêntesis que mudem a ordem de prioridades entre os operadores lógicos "ou" e "e". Ele poderia ser escrito, portanto, como A | B, A | C.
O sistema de dependências é um bom mecanismo para garantir a operação de um programa, mas ele tem outro uso com os "meta-pacotes". Estes são pacotes vazios que apenas descrevem dependências. Eles facilitam a instalação de um grupo consistente de programas pré-selecionados pelo mantenedor do meta-pacote; assim, apt install meta-package vai instalar automaticamente todos os programas nas dependências do meta-pacote. Os pacotes gnome, kde-full e linux-image-amd64 são exemplos de meta-pacotes.

5.2.1.2. Conflicts: o campo Conflicts

O campo Conflicts indica quando um pacote não pode ser instalado simultaneamente com outro. As razões mais comuns para isto é que ambos os pacotes incluem um arquivo de mesmo nome e caminho, ou fornecem o mesmo serviço na mesma porta TCP, ou vão atrapalhar a operação um do outro.
O dpkg vai se recusar a instalar um pacote se ele iniciar um conflito com um pacote já instalado, a menos que o novo pacote especifique que ele "substitui" o pacote instalado, e neste caso o dpkg vai escolher substituir o pacote antigo pelo novo. O apt sempre vai seguir suas instruções: se você escolher instalar um novo pacote, ele vai automaticamente se oferecer para desinstalar o pacote que apresentar um problema.

5.2.1.3. Incompatibilidades: o campo Breaks

O campo Breaks tem um efeito similar ao do campo Conflicts, mas com um significado especial. Ele assinala que a instalação de um pacote vai "quebrar" outro pacote (ou versões específicas dele). Em geral, esta incompatibilidade entre dois pacotes é transitória, e a relação Breaks se refere especificamente a estas versões incompatíveis.
O dpkg vai se recusar a instalar um pacote que quebra um pacote já instalado, e o apt vai tentar resolver o problema atualizando o pacote que vai ser quebrado para uma nova versão (que se espera que tenha sido corrigida, logo, voltou a ser compatível).
Este tipo de situação pode ocorrer no caso de atualizações sem retrocompatibilidade: este é o caso se a nova versão não funciona mais com a versão antiga, e causa um mal funcionamento em outro programa sem fazer "provisões especiais". O campo Breaks evita que o usuário se ponha nestes tipos de problemas.

5.2.1.4. Itens fornecidos: o campo Provides

Este campo introduz o interessante conceito de "pacote virtual". Ele tem muitos papéis, mas dois são de especial importância. O primeiro consiste em usar um pacote virtual para associar um serviço genérico com ele (o pacote "fornece" o serviço). O segundo indica que um pacote substitui completamente o outro, e que para este propósito ele também pode satisfazer as dependências que o outro satisfaz. É também possível criar um pacote de substituição sem ter que usar o mesmo nome de pacote.
5.2.1.4.1. Fornecendo um “Serviço”
Vamos discutir o primeiro caso em maiores detalhes com um exemplo: Dizemos que todos os servidores de e-mail, como o postfix ou o sendmail "fornecem" o pacote virtual mail-transport-agent. Então, qualquer pacote que precise deste serviço para ser funcional (e.g. um gerenciador de lista de e-mail, como o smartlist ou o sympa) simplesmente afirma nas suas dependências que ele precisa de um mail-transport-agent ao invés de especificar uma grande porém incompleta lista de possíveis soluções (e.g. postfix | sendmail | exim4 | …). Além disso, é inútil instalar dois servidores de e-mail na mesma máquina, sendo por isso que cada um destes pacotes declara um conflito com o pacote virtual mail-transport-agent. Um conflito entre um pacote e ele próprio é ignorado pelo sistema, mas esta técnica irá proibir a instalação de dois servidores de e-mail lado a lado.
5.2.1.4.2. "Interchangeability" com outro pacote
O campo Provides é também interessante quando o conteúdo de um pacote é incluído em um pacote maior. Por exemplo, o módulo Perl libdigest-md5-perl era um módulo opcional no Perl 5.6, e foi integrado como padrão no Perl 5.8 (e versões posteriores, como a 5.32.1 presente no Bullseye). Desta forma, o pacote perl tem, desde a versão 5.8, declarado Provides: libdigest-md5-perl de forma que as dependências neste pacote são satisfeitas se o usuário tem o Perl 5.8 (ou mais recentes). O pacote libdigest-md5-perl será eventualmente removido, uma vez que ele não terá utilidade quando versões antigas do Perl forem removidas.
Uso de um campo Provides para não quebrar dependências

Figura 5.1. Uso de um campo Provides para não quebrar dependências

Esta funcionalidade é muito útil, já que nunca é possível antecipar os caprichos do desenvolvimento, e é preciso poder se renomear, e fazer outras substituições automáticas, de software obsoleto.
5.2.1.4.3. Limitações Antigas
Pacotes virtuais costumavam sofrer de algumas limitações, sendo que a mais significante era a ausência de número de versão. Voltando ao exemplo anterior, uma dependência como Depends: libdigest-md5-perl (>= 1.6), independente da presença do Perl 5.10, nunca vai ser considerada como satisfeita pelo sistema de empacotamento — embora provavelmente esteja satisfeita. Sem perceber isto, o sistema de empacotamento escolhe a opção menos arriscada, assumindo que as versões não combinam.
Essa limitação foi superada no dpkg.1.17.11, e não é mais relevante. Pacotes, como perl 5.32.1, podem atribuir uma versão aos pacotes virtuais que eles fornecem, tal como Provides: libdigest-md5-perl (= 1.8), e assim possibilita outros pacotes usarem dependências versionadas.

5.2.1.5. Substituindo arquivos: o campo Replaces

O campo Replaces indica que o pacote contém arquivos que também estão presentes em outros pacotes, mas que o pacote foi designado legitimamente para substituí-los. Sem esta especificação, o dpkg falha, dizendo que não pode sobrescrever arquivos de outro pacote (tecnicamente, é possível forçá-lo a tal com a opção --force-overwrite, mas isso não é considerado uma operação padrão). Isto permite a identificação de problemas potenciais e requer que o mantenedor estude o assunto antes de escolher se adiciona tal campo.
O uso deste campo é justificado quando os nomes dos pacotes mudam ou quando um pacote é incluído em outro. Também acontece quando o mantenedor decide distribuir arquivos diferentes entre vários pacotes binários produzidos a partir do mesmo fonte: um arquivo substituído não pertence mais ao pacote antigo, mas apenas ao novo.
Se todos os arquivos num pacote instalado foram substituídos, o pacote é considerado "a ser removido". Finalmente, este campo também encoraja o dpkg a remover o pacote substituído onde existir conflito.

5.2.2. Scripts de Configuração

Além do arquivo control, o arquivamento control.tar.gz para cada pacote Debian pode conter vários scripts, chamados pelo dpkg em diferentes estágios do processamento de um pacote. A política Debian descreve os possíveis casos em detalhes, especificando os scripts e os argumentos que eles recebem. Estas sequências podem ser complicadas, já que se um dos scripts falha, o dpkg vai tentar retornar a um estado satisfatório cancelando a instalação ou a remoção em andamento (na medida do possível).
Em geral, o script preinst é executado antes da instalação do pacote, enquanto que o postinst é logo depois. Da mesma forma, o prerm é chamado antes da remoção de um pacote e o postrm depois. Uma atualização de um pacote é equivalente à remoção da versão anterior e a instalação do novo. Não é possível descrever em detalhes todos os cenários possíveis aqui, mas vamos discutir os dois mais comuns: uma instalação/atualização e uma remoção.

5.2.2.1. Instalação e upgrade (atualização)

Durante a instalação inicial e para cada atualização de pacote, o dpkg chama os maintainer scripts (scripts do mantenedor) como o prerm ou preinst. Estes scripts podem realizar ações adicionais durante os diferentes estágios do ciclo de vida de um pacote. Nomes de script iniciados por new- são os scripts da nova versão de um pacote sendo instalado ou atualizado. Nomes de script iniciados por old- são os scripts de uma versão antiga de um pacote que está sendo atualizado.
Durante cada invocação, o dpkg vai passar certos argumentos para cada script, como por exemplo upgrade new-version. O script invocado pode então tanto manipular os argumentos e realizar uma ação particular, ou ignorar os argumentos e retornar com um código de saída de 0, se nada precisar ser feito durante este passo. Na prática, muitos pacotes não vão precisar realizar nenhuma ação durante cada passo no ciclo de vida. Então um script de configuração típico vai verificar por um argumento em particular e ignorar todos os outros, implicitamente retornando código de saída 0.
Aqui está o que acontece durante uma instalação (ou um update). Os argumentos old-version (versão antiga), new-version (versão nova) e last-version-configured (última versão configurada) são substitutos para os números de versão reais (o velho e o novo) do pacote:
  1. Para uma atualização ("update"), o dpkg chama o script old-prerm e passa upgrade nova-versão como argumento.
  2. Ainda para uma atualização, o dpkg então executa o script new-preinst com os argumentos upgradeantiga-versão; para a instalação inicial, ele executa o script new-preinst e passa install como argumento. Ele pode adicionar a versão antiga no último parâmetro, se o pacote já foi instalado e removido desde então (mas não expurgado ("purged"), e então os arquivos de configuração ficam mantidos).
  3. Os arquivos do novo pacote são então desempacotados, se algum arquivo já existe, ele é substituído, mas uma cópia de backup é temporariamente feita.
  4. Para uma atualização, o dpkg executa o script old-postrm e passa upgrade nova-versão como argumento.
  5. dpkg atualiza todos os dados internos (lista de arquivos, scripts de configuração, etc.) e remove os backups dos arquivos substituídos. Este é o ponto sem volta: o dpkg não tem mais acesso a todos os elementos necessários para retornar ao estado anterior.
  6. O dpkg vai atualizar os arquivos de configuração, pedindo ao usuário para decidir se ele não for capaz de decidir tudo sozinho. Os detalhes deste procedimento são discutidos em Seção 5.2.3, “Checksums, Lista de arquivos de configuração, e outros.”.
  7. Finalmente, o dpkg configura o pacote executando o script new-postinst com os argumentos configure última-versão-configurada.

5.2.2.2. Remoção de pacote

Os passos para remover um pacote são análogos aos passos de instalação. A principal diferença é que os scripts de remoção do pacote são chamados:
  1. o dpkg chama o script prerm e passa remove como argumento.
  2. O dpkg remove todos os arquivos do pacote, com exceção dos arquivos de configuração e os scripts do mantenedor.
  3. O dpkg executa o script postrm e passa remove como argumento. Em seguida, todos os scripts do mantenedor, exceto o script postrm, são removidos. Se o usuário não utilizou a opção “purge”, o processo para aqui.
  4. Para um purge completo do pacote (comando lançado com dpkg --purge ou dpkg -P), os arquivos de configuração são também apagados, assim como uma certa quantidade de cópias (*.dpkg-tmp, *.dpkg-old, *.dpkg-new) e arquivos temporários; então o dpkg executa o script postrm e passa purge como argumento.
Os quatro scripts detalhados acima são complementados por um script config, fornecido por pacotes usando debconf para adquirir informações do usuário para a configuração. Durante a instalação, este script define em detalhes as perguntas feitas pelo debconf. As respostas são gravadas no banco de dados do debconf para futura referência. O script é geralmente executado pelo apt antes de instalar pacotes, um a um para agrupar todas as perguntas e fazê-las todas ao usuário no começo do processo. Os scripts de pre- e pos-instalação podem então usar esta informação para operar de acordo com o que o usuário espera.

5.2.3. Checksums, Lista de arquivos de configuração, e outros.

Adicionalmente aos scripts de manutenção e dados de controle já mencionados nas seções anteriores, o arquivamento control.tar.gz de um pacote Debian pode conter outros arquivos interessantes.
O primeiro, md5sums, contém as verificações (checksums) MD5 de todos os arquivos do pacote. Sua principal vantagem é que permite que o dpkg --verify (que vamos estudar em Seção 14.3.4.1, “Auditando Pacotes com o dpkg --verify) e debsums (do pacote de mesmo nome; veja Seção 14.3.4.2, “Auditando Pacotes: debsums e seus limites”) para verificar se estes arquivos foram modificados desde a instalação deles. Repare que quando este arquivo não existe, que pode ser o caso para alguns pacotes antigos, o dpkg vai gerar ele dinamicamente em tempo de instalação (e armazenar ele no banco de dados do dpkg assim como os outros arquivos de controle).
O arquivo conffiles lista arquivos do pacote que devem ser manipulados como arquivos de configuração (veja também deb-conffiles(5)). Arquivos de configuração podem ser modificados pelo administrador, e o dpkg tentará preservar estas mudanças durante uma atualização de pacote.
Com efeito, nesta situação, o dpkg se comporta o mais inteligente possível: se o arquivo de configuração padrão não mudou entre duas versões, ele não faz nada. Se, entretanto, o arquivo mudou, ele vai tentar atualizar o arquivo. Dos casos são possíveis: ou o administrador não tocou neste arquivo de configuração, e neste caso o dpkg automaticamente instala a nova versão; ou o arquivo foi modificado, e neste caso o dpkg pergunta ao administrador qual versão ele quer usar (a antiga com modificações ou a nova que o pacote fornece). Para auxiliar nesta decisão, o dpkg se oferece para mostrar um “diff” que mostra a diferença entre as duas versões. Se o usuário escolhe manter a versão antiga, a nova vai ser armazenada na mesma localização em um arquivo com o sufixo .dpkg-dist. Se o usuário escolhe a nova versão, a antiga é mentida num arquivo com o sufixo .dpkg-old. Outra ação disponível consiste em interromper momentaneamente o dpkg para editar o arquivo e tentar reinstalar as modificações relevantes (previamente identificadas com o diff).
O arquivo de controle frequentemente contém outros arquivos também, como triggers, shlibs, ou symbols. Estes arquivos são bem descritos em deb-triggers(5), deb-shlibs(5) e deb-symbols(5).
Gatilhos (triggers) foram introduzidos para reduzir a quantidade de eventos duplicados durante a instalação de pacotes, como tarefas de atualização de catalog/database ou registro de arquivos. Pacotes podem definir seus próprios gatilhos ou ativar outros. Uma documentação mais completa pode ser encontrada em /usr/share/doc/dpkg/triggers.txt.gz.
O sistema shlibs é uma alternativa mais antiga e simples ao sistema symbols para declarar dependências para bibliotecas compartilhadas. Ele define o nome e versão do pacote no qual encontrar um SONAME-version específico de uma biblioteca compartilhada. O novo sistema symbols permite, por outro lado, definir a dependência rastreando os símbolos e vendo quando eles são introduzidos ou alterados na biblioteca.