Gerenciamento de Pacote é uma adição frequentemente solicitada ao Livro LFS. Um Gerenciador de Pacote rastreia a instalação de arquivos, tornando mais fácil remover e atualizar pacotes. Um bom gerenciador de pacote também lidará com os arquivos de configuração, especialmente para manter a configuração do(a) usuário(a) quando o pacote for reinstalado ou atualizado. Antes que você comece a questionar, NÃO—esta seção não falará nem recomendará qualquer gerenciador de pacote em particular. O que ela fornece é um resumo acerca das técnicas mais populares e como elas funcionam. O gerenciador de pacote perfeito para você possivelmente esteja entre essas técnicas ou possivelmente seja uma combinação de duas ou mais dessas técnicas. Esta seção menciona brevemente problemas que possivelmente surjam quando da atualização de pacotes.
Algumas razões porque nenhum gerenciador de pacote é mencionado no LFS ou no BLFS incluem:
Lidar com gerenciamento de pacote retira o foco das finalidades desses livros—ensinar como um sistema Linux é construído.
Existem múltiplas soluções para gerenciamento de pacote, cada uma tendo seus pontos fortes e fracos. Encontrar uma solução que satisfaça todas as audiências é difícil.
Existem algumas dicas escritas no tópico do gerenciamento de pacote. Visite o Hints Project e veja se uma delas se adéqua às suas necessidades.
Um Gerenciador de Pacote torna fácil atualizar para versões mais novas quando elas são liberadas. Geralmente as instruções nos livros LFS e BLFS podem ser usadas para atualizar para as versões mais novas. Aqui estão alguns pontos que você deveria estar ciente quando da atualização de pacotes, especialmente em um sistema em execução.
Se o núcleo Linux precisar ser atualizado (por exemplo, de 5.10.17 para 5.10.18 ou 5.11.1), [então] nada mais precisa ser reconstruído. O sistema seguirá funcionando bem graças à interface bem definida entre o núcleo e o espaço de usuária(o). Especificamente, os cabeçalhos da API do Linux não precisam ser atualizados juntamente com o núcleo. Você meramente precisará reiniciar o teu sistema para usar o núcleo atualizado.
Se a Glibc precisar ser atualizada para uma versão mais recente (por exemplo, da Glibc-2.36 para a Glibc-2.40), [então] algumas etapas extras serão necessárias para evitar quebrar o sistema. Leia-se Seção 8.5, “Glibc-2.40” para detalhes.
Se um pacote contendo uma biblioteca compartilhada for
atualizado e se o nome da biblioteca mudar, então quaisquer
pacotes dinamicamente vinculados à biblioteca precisam ser
recompilados, para vincular contra a biblioteca mais nova.
(Observe que não existe correlação entre a versão de pacote e
o nome da biblioteca). Por exemplo, considere um pacote
foo-1.2.3 que instala uma biblioteca compartilhada com o nome
libfoo.so.1
. Suponha que você
atualize o pacote para uma versão mais nova foo-1.2.4 que
instala uma biblioteca compartilhada com o nome libfoo.so.2
. Nesse caso, quaisquer pacotes
que estiverem dinamicamente vinculados à libfoo.so.1
precisam ser recompilados para
vincular contra libfoo.so.2
com
a finalidade de usar a nova versão da biblioteca. Você não
deveria remover as bibliotecas antigas até que todos os
pacotes dependentes tenham sido recompilados.
Se um pacote estiver (direta ou indiretamente) vinculado aos
nomes antigo e novo de uma biblioteca compartilhada (por
exemplo, o pacote aponta para libfoo.so.2
e libbar.so.1
, enquanto o último se vincula a
libfoo.so.3
), [então] o pacote
possivelmente funcione mal, pois as diferentes revisões da
biblioteca compartilhada apresentam definições incompatíveis
para alguns nomes de símbolo. Isso pode ser causado pela
recompilação de alguns, mas não todos, dos pacotes vinculados
à antiga biblioteca compartilhada depois que o pacote que
fornece a biblioteca compartilhada for atualizado. Para
evitar o problema, os(as) usuários(as) precisarão reconstruir
cada pacote vinculado a uma biblioteca compartilhada com uma
revisão atualizada (por exemplo, libfoo.so.2 para
libfoo.so.3) o mais rápido possível.
Se um pacote contendo uma biblioteca compartilhada for
atualizado e o nome da biblioteca não mudar, porém o número
de versão do arquivo da biblioteca
decrescer (por exemplo, a biblioteca ainda é chamada de
libfoo.so.1
, porém o nome do
arquivo da biblioteca for mudado de libfoo.so.1.25
para libfoo.so.1.24
), [então] você deveria
remover o arquivo da biblioteca originário da versão
previamente instalada (libfoo.so.1.25
nesse caso). Do contrário,
um comando ldconfig (invocado por você
mesmo(a) a partir da linha de comando ou pela instalação de
algum pacote) reconfigurará o link simbólico libfoo.so.1
para apontar para o antigo
arquivo da biblioteca, pois ele aparenta ser uma versão
“mais
nova”; o número de versão dele é mais largo.
Essa situação possivelmente surge se você tiver que
desatualizar um pacote ou se os(as) autores(as) mudarem o
esquema de versionamento para arquivos de biblioteca.
Se um pacote contendo uma biblioteca compartilhada for
atualizado e o nome da biblioteca não mudar, porém um
problema severo (especialmente, uma vulnerabilidade de
segurança) for corrigido, [então] todos os aplicativos em
execução vinculados à biblioteca compartilhada deveriam ser
reiniciados. O seguinte comando, executado como root
depois que a atualização estiver
completa, listará quais processos estão usando as versões
antigas daquelas bibliotecas (substitua libfoo
pelo nome da
biblioteca):
grep -l 'libfoo
.*deleted' /proc/*/maps | tr -cd 0-9\\n | xargs -r ps u
Se o OpenSSH estiver sendo usado para acessar o sistema e ele estiver vinculado à biblioteca atualizada, [então] você precisa reiniciar o serviço sshd, então deslogar-se, logar-se novamente e executar o comando precedente novamente para confirmar se nada ainda está usando as bibliotecas deletadas.
Se um aplicativo executável ou uma biblioteca compartilhada for sobrescrito, [então] os processos usando o código ou os dados naquele aplicativo ou biblioteca possivelmente quebrem. A maneira correta para atualizar um aplicativo ou uma biblioteca compartilhada sem causar quebra ao processo é a de removê-lo primeiro, então instalar a versão nova. O comando install fornecido por coreutils já implementou isso e a maioria dos pacotes usa esse comando para instalar arquivos binários e bibliotecas. Isso significa que você não estaria encrencada(o) por esse problema a maior parte do tempo. Entretanto, o processo de instalação de alguns pacotes (notadamente "SpiderMonkey" no BLFS) apenas sobrescreve o arquivo se ele existir; isso causa uma quebra. Assim, é mais seguro salvar seu trabalho e fechar processos em execução desnecessários antes de atualizar um pacote.
As seguintes são algumas técnicas comuns de gerenciamento de pacote. Antes de se decidir acerca de um gerenciador de pacote, pesquise sobre as várias técnicas, particularmente os pontos fracos de cada esquema em particular.
Sim, essa é uma técnica de gerenciamento de pacote. Algumas pessoas não necessitam de um gerenciador de pacote, pois elas conhecem os pacotes intimamente e sabem quais arquivos estão instalados por cada pacote. Alguns(mas) usuários(as) também não precisam de qualquer gerenciamento de pacote, pois eles(as) planejam reconstruir o sistema inteiro sempre que um pacote for mudado.
Essa é uma técnica simplista de gerenciamento de pacotes que não
precisa de um aplicativo especial para gerenciar os pacotes. Cada
pacote é instalado em um diretório separado. Por exemplo, o
pacote "foo-1.1" é instalado em "/opt/foo-1.1
" e um link simbólico é feito de
"/opt/foo
" para "/opt/foo-1.1
". Quando uma nova versão "foo-1.2"
surge, ela é instalada em "/opt/foo-1.2
" e o link simbólico anterior é
substituído por um link simbólico para a nova versão.
Variáveis de ambiente, como "PATH
",
"MANPATH
", "INFOPATH
", "PKG_CONFIG_PATH
", "CPPFLAGS
", "LDFLAGS
", e
o arquivo de configuração "/etc/ld.so.conf
", possivelmente precisem ser
expandidas para incluir os subdiretórios correspondentes em
"/opt/foo -x.y
".
Esse esquema é usado pelo livro BLFS para instalar alguns pacotes muito grandes para facilitar a atualização deles. Se você instalar mais que alguns pacotes, [então] esse esquema se tornará ingerenciável. E alguns pacotes (por exemplo, os cabeçalhos de "API" do "Linux" e "Glibc") possivelmente não funcionem bem com esse esquema. Nunca use esse esquema em todo o sistema.
Essa é uma variação da técnica de gerenciamento de pacote
anterior. Cada pacote é instalado como no esquema anterior. Mas,
em vez de fazer o link simbólico via um nome genérico de pacote,
cada arquivo é simbolicamente vinculado à hierarquia /usr
. Isso remove a necessidade de expandir as
variáveis de ambiente. Ainda que os links simbólicos possam ser
criados pelo(a) usuário(a), muitos gerenciadores de pacote usam
essa abordagem e automatizam a criação dos links simbólicos.
Alguns dos populares inclui Stow, Epkg, Graft, e Depot.
O script de instalação precisa ser falseado, de modo que o pacote
pense que está instalado em /usr
,
ainda que, na realidade, ele esteja instalado na hierarquia
/usr/pkg
. Instalar dessa maneira
geralmente não é uma tarefa trivial. Por exemplo, suponha que
você está instalando um pacote libfoo-1.1. As seguintes
instruções possivelmente não instalem adequadamente o pacote:
./configure --prefix=/usr/pkg/libfoo/1.1 make make install
A instalação funcionará, mas os pacotes dependentes possivelmente
não se vinculem à libfoo conforme você esperaria. Se você
compilar um pacote que se vincula contra a libfoo, [então] você
possivelmente perceba que ele está vinculado a /usr/pkg/libfoo/1.1/lib/libfoo.so.1
em vez de
/usr/lib/libfoo.so.1
como você
esperaria. A abordagem correta é a de usar a variável
DESTDIR
para direcionar a instalação.
Essa abordagem funciona como se segue:
./configure --prefix=/usr make make DESTDIR=/usr/pkg/libfoo/1.1 install
A maioria dos pacotes suporta essa abordagem, mas existem alguns
que não. Para os pacotes não conformes, você possivelmente ou
precise instalar manualmente o pacote, ou você possivelmente ache
que é mais fácil instalar alguns pacotes problemáticos em
/opt
.
Nessa técnica, um arquivo é carimbado temporalmente antes da instalação do pacote. Depois da instalação, um simples uso do comando find com as opções apropriadas consegue gerar um registro de todos os arquivos instalados após o arquivo de carimbo de tempo ser criado. Um gerenciador de pacote que use essa abordagem é instalação-registro.
Ainda que esse esquema tenha a vantagem de ser simples, ele tem duas desvantagens. Se, durante a instalação, os arquivos forem instalados com algum outro carimbo de tempo que não a hora atual, [então] aqueles arquivos não serão rastreados pelo gerenciador de pacote. Além disso, esse esquema pode ser usado apenas quando um pacote for instalado de cada vez. Os registros não são confiáveis se dois pacotes forem instalados simultaneamente a partir de dois consoles.
Nessa abordagem, os comandos que os scripts de instalação realizam são gravados. Existem duas técnicas que se pode usar:
A variável de ambiente LD_PRELOAD
pode
ser configurada para apontar para uma biblioteca a ser
pré-carregada antes da instalação. Durante a instalação, essa
biblioteca rastreia os pacotes que estão sendo instalados
anexando-se a vários executáveis, tais como o cp, o installe o mv, e rastreando as chamadas de
sistema que modificam o sistema de arquivos. Para essa abordagem
funcionar, todos os executáveis precisam ser dinamicamente
vinculados sem o bit suid ou sgid. Pré-carregar a biblioteca
possivelmente cause alguns efeitos colaterais indesejados durante
a instalação. Portanto, é uma boa ideia realizar alguns testes
para garantir que o gerenciador de pacote não quebre nada e que
ele registre todos os arquivos adequados.
Outra técnica é a de usar o strace, que registra todas as chamadas de sistema feitas durante a execução dos scripts de instalação.
Nesse esquema, a instalação do pacote é falseada em uma árvore separada como descrito previamente na seção do gerenciamento de pacote estilo Link Simbólico. Depois da instalação, um arquivamento de pacote é criado usando os arquivos instalados. Esse arquivamento é então usado para instalar o pacote na máquina local ou até mesmo em outras máquinas.
Essa abordagem é a usada pela maioria dos gerenciadores de pacote encontrados nas distribuições comerciais. Exemplos de gerenciadores de pacote que seguem essa abordagem são RPM (o qual, incidentalmente, é exigido pela Linux Standard Base Specification), pkg-utils, apt do Debian, e sistema Portage do Gentoo. Uma dica descrevendo como adotar esse estilo de gerenciamento de pacote para sistemas LFS está localizada em https://www.linuxfromscratch.org/hints/downloads/files/fakeroot.txt.
A criação de arquivos de pacote que incluem informação de dependência é complexa e além do escopo do LFS.
O Slackware usa um sistema baseado em tar para arquivamentos de pacote. Esse sistema intencionalmente não manuseia dependências de pacote como gerenciadores de pacote mais complexos fazem. Para detalhes de gerenciamento de pacote do Slackware, veja-se http://www.slackbook.org/html/package-management.html.
Esse esquema, único para LFS, foi concebido por Matthias Benkmann e está disponível a partir do Hints Project. Nesse esquema, cada pacote é instalado como uma(m) usuária(o) separada(o) nos locais padrão. Arquivos pertencentes a um pacote são facilmente identificados checando o ID de usuária(o). As características e deficiências dessa abordagem são muito complexas para serem descritas nesta seção. Para os detalhes, por favor veja-se a dica em https://www.linuxfromscratch.org/hints/downloads/files/more_control_and_pkg_man.txt.
Uma das vantagens de um sistema LFS é a de que não existem arquivos
que dependam da posição de arquivos em um sistema de disco. Clonar
uma construção do LFS para outro computador com a mesma arquitetura
que a do sistema base é tão simples quanto usar tar na partição do LFS que contém
o diretório raiz (cerca de 900MB descomprimido para uma construção
básica do LFS), copiando aquele arquivo via transferência de rede
ou CD-ROM/stick USB para o novo sistema e expandindo-o. Depois
disso, uns poucos arquivos de configuração terão que ser mudados.
Arquivos de configuração que possivelmente precisem ser atualizados
incluem: /etc/hosts
, /etc/fstab
, /etc/passwd
, /etc/group
, /etc/shadow
, /etc/ld.so.conf
, /etc/sysconfig/rc.site
, /etc/sysconfig/network
e /etc/sysconfig/ifconfig.eth0
.
Um núcleo personalizado possivelmente seja necessário para o novo sistema, dependendo das diferenças no hardware do sistema e a configuração original do núcleo.
Tem havido alguns relatos de problemas quando da cópia entre arquiteturas similares, porém não idênticas. Por exemplo, o conjunto de instruções para um sistema Intel não é idêntico às instruções do processador AMD, e versões posteriores de alguns processadores possivelmente forneçam instruções que estão indisponíveis em versões anteriores.
Finalmente, o novo sistema tem de ser tornado inicializável via Seção 10.4, “Usando o GRUB para Configurar o Processo de Inicialização”.