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 (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, remoção, atualizações). Estes dados usados pelas ferramentas de gerencia de pacotes não são parte do programa empacotado, mas 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 a cabeçalhos de email (como foi definido pela RFC 2822). Por exemplo, para apt, o arquivo control
parece com algo como:
$
apt-cache show apt
Package: apt
Version: 0.9.7.9
Installed-Size: 3271
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Replaces: manpages-pl (<< 20060617-3~)
Depends: libapt-pkg4.12 (>= 0.9.7.9), libc6 (>= 2.4), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 4.6), debian-archive-keyring, gnupg
Suggests: aptitude | synaptic | wajig, dpkg-dev, apt-doc, xz-utils, python-apt
Conflicts: python-apt (<< 0.7.93.2~)
Description-pt_BR: gerenciador de pacotes em linha de comando
Este pacote fornece ferramentas em linha de comando para busca e
gerenciamento assim como consultas de informações sobre pacotes como um
acesso de baixo nível a todas as funcionalidades da biblioteca libapt-pkg.
.
Inclui:
* apt-get para obter pacotes e informações sobre os mesmos de fontes
autenticadas e para instalação, atualização e remoção de pacotes e
dependências
* apt-cache para consultar informações disponíveis sobre pacotes
instalados e instaláveis
* apt-cdrom para usar mídias removíveis como fontes de pacotes
* apt-config como uma interface para as configurações
* apt-key para uma interface para as chaves de autenticação
Description-md5: 9fb97a88cb7383934ef963352b53b4a7
Tag: admin::package-management, hardware::storage, hardware::storage:cd,
implemented-in::c++, interface::commandline, network::client,
protocol::ftp, protocol::http, protocol::ipv6, role::program,
suite::debian, use::downloading, use::searching,
works-with::software:package
Section: admin
Priority: important
Filename: pool/main/a/apt/apt_0.9.7.9_amd64.deb
Size: 1253524
MD5sum: 00a128b2eb2b08f4ecee7fe0d7e3c1c4
SHA1: 6a271487ceee6f6d7bc4c47a8a16f49c26e4ca04
SHA256: 3bba3b15fb5ace96df052935d7069e0d21ff1f5b496510ec9d2dc939eefad104
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. Este campo é uma lista de condições a serem satisfeitas para o pacote funcionar corretamente — Esta informação é usada por ferramentas como o apt
para instalar as biblitecas necessárias, nas versões corretas, que o pacote a ser instalado depende. 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.3.4” (escreve-se “libc6 (>= 2.3.4)
”). Operadores de comparação de versão são os seguintes:
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-get 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, 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-get
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-get
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. O conflito com 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
é novamente 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.14 presente no Wheezy). 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.
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 atuais
Pacotes virtuais sofrem de algumas limitações, sendo a mais significante 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 considerado como satisfeito pelo sistema de empacotamento — embora provavelmente esteja satisfeito. "Unaware" disto, o sistema de empacotamento escolhe a opção menos arriscada, assumindo que as versões não combinam.
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 sobreescrever arquivos de outro pacote (na verdade, é possível força-lo a tal com a opção --force-overwrite
). 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 substituido 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 se 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)
Aqui está o que acontece durante uma instalação (ou uma atualização):
Para uma atualização ("update"), o dpkg
chama o old-prerm upgrade new-version
.
Ainda para uma atualização, o dpkg
então executa new-preinst upgrade old-version
; para uma primeira instalação, ele executa new-preinst install
. Ele pode adicionar a versão antiga no último parâmetro, se o pacote já foi instalado e removido "since" (mas não "purged", os arquivos de configuração foram "retained").
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.
Para uma atualização, o dpkg
executa old-postrm upgrade new-version
.
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.
Finalmente, o dpkg
configura o pacote executando new-postinst configure last-version-configured
.
5.2.2.2. Remoção de pacote
Aqui temos o que acontece durante uma remoção de pacote:
o dpkg
chama prerm remove
.
O dpkg
remove todos os arquivos do pacote, exceto os arquivos de configuração e os scripts de configuração.
O dpkg
executa postrm remove
. Todos os scripts de configuração, exceto postrm
, são removidos. Se o usuário não usou a opção “purge", os processos param aqui.
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 um postrm purge
.
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
além dos scripts de mantenedor e dados de controle mencionados nas seções anteriores, o arquivo
control.tar.gz
de um pacote Debian pode conter outros arquivos interessantes. O primeiro,
md5sums
, contém as somas de verificação (checksums) de todos os arquivos do pacote. Sua principal vantagem é que permite que uma ferramenta como o
debsums
(que vamos estudar em
Seção 14.3.3.1, “Auditando Pacotes: debsums
e seus limites”) verifique se estes arquivos foram modificados desde a instalação deles. Repare que quando este arquivo não existe, o
dpkg
vai gerar ele dinamicamente em tempo de instalação (e armazenar ele num banco de dados do dpkg assim como os outros arquivos de controle).
conffiles
lista arquivos do pacote que devem ser manipulados como arquivos de configuração. 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
).