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 o daemon systemd (executando como o
                PID 1) for vinculado à biblioteca atualizada, [então] você
                pode reiniciá-lo sem reinicializar executando systemctl daemon-reexec
                como o(a) usuário(a) root.
              
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 e /etc/ld.so.conf.
        
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”.