Crie Seu Próprio Gerenciador de Pacotes do Zero - Parte 1

Eu sempre fui curioso em relação às coisas que me interessam, quando iniciei no mundo do GNU/Linux, eu fiquei admirado com a facilidade de instalar programas. No início, rodando entre as distribuições Linux, eu acabei conhecendo vários tipos de gerenciadores de pacotes e cada um com sua peculiaridade. Foi aí que me interessei em ler o código fonte de diversos gerenciadores e criar o meu próprio.

[ Hits: 10.234 ]

Por: Slackjeff em 19/02/2020 | Blog: https://slackjeff.com.br


pkgremove - Removendo um pacote



Até agora conseguimos criar um pacote e instalar, porém, uma das partes mais importantes não foi criada, a parte de remover o pacote e toda sua hierarquia no sistema.

Esta é a parte mais complexa, pois deverá ser feita com mais segurança! Já penso remover o que não pode na raiz do sistema? Precisamos criar algo com um pouco mais de segurança. Por isso, preste muita atenção nos detalhes.

Iniciamos nosso script como todos os outros dois que criamos, cabeçalho e o "set -e". Devemos iniciar uma função chamada REMOVE e um case com as opções: "-r|--remove|remove".

Na opção "-r|--remove|remove" devemos inserir um shift para rebaixar o parâmetro posicional e um teste verificando se o pacote está no sistema. Para isto usamos como base o arquivo de track localizado em /var/log/installed.

Vamos também entrar no diretório /var/log/installed para iniciar o processo de remoção:

#!/bin/sh
#=========================HEADER===============================|
#AUTOR:
# Jefferson Rocha
#
#VERSÃO:
# 0.1
#
#DESCRIÇÃO:
#removepkg - Remove pacote e hierarquia do sistema operacional.
#==============================================================|
# Erros? pare.
set -e

#==========================| FUNÇÕES
REMOVE()
{
}

#==========================| INICIO
case $1 in
   -r|--remove|remove)
      shift # Rebaixando um parâmetro posicional.

      # O usuário passou o nome de algum pacote?
      [ -z "$1" ] && { echo "Você deve fornecer o nome do pacote."; exit 1 ;}

      # Entrando no diretório /var lalala
      cd /var/log/installed

Vamos lançar um "loop for" com o "glob *" para verificar todos tracks que existem dentro do diretório /var/log/installed. Poderíamos usar um simples "ls", porém para ganhar um pouco de velocidade e economizar pipes, lançamos o "loop for", fazendo uma verificação com grep, se tem o padrão.

O padrão no caso, é o nome do pacote, se existir o padrão, lançamos em uma variável para fazer a captura e pausamos o for. Se tudo deu certo, no final a função é iniciada.

# Fazendo a listagem do diretório /var/log/installed e
# conferindo se o pacote está instalado no sistema.
for pack_exist in *; do
   if ! [ "$(grep "$1" < ${pack_exist})" ]; then
      echo "O pacote $1 não está instalado no sistema."
      exit 1
   else
      # Capturando o nome do track para lançar na função REMOVE.
      pkg_for_remove="$pack_exist"
      break
   fi
done

# Chamando a função REMOVE e passando como parâmetro o nome do pacote.
REMOVE "$pkg_for_remove"
;;
esac

Agora o trabalho "pesado" vai começar, vamos começar a elaborar a função REMOVE como normal, vamos lançar a variável "pkg_remove" no inicio para capturar o nome do track:
REMOVE()
{
   local pkg_remove="$1"

Vamos precisar lançar três "loops while" para percorrer todo o arquivo track. Começando com Arquivo comum, o mesmo será alimentado com o track para ler linha a linha todo o track, com isto vamos removendo tudo que é arquivo que foi instalado:

# Deletando arquivos.
while read the_file; do
   rm $the_file 2>/dev/null && echo " Delete: $the_file"
done < "$pkg_remove"

Outro "loop while" precisa ser chamado, desta vez removendo SE existir links simbólicos. Eles não podem ficar soltos no sistema do usuário:

# Removendo links simbólicos se existir..
while read the_link; do
   unlink $the_link &>/dev/null && echo "Delete Links: $the_link"
done < "$pkg_remove"

E por último, diretórios que ficaram vazios no sistema, por exemplo /usr/share/nano etc. Vamos fazer mais um "loop while", ainda sendo alimentado pelo track:

# Removendo diretórios nulos
while read the_dir; do
   rm -d $the_dir &>/dev/null && echo "Delete empty directories: $the_dir"
done < "$pkg_remove"

Por final, vamos apagar o arquivo "nano.track" para o gerenciador saber que ele foi removido:

echo "Deletando track ${pkg_remove}"
[ -e "${pkg_remove}" ] && rm -v ${pkg_remove}

Nosso programa "pkgremove" deve ficar assim no final:

#!/bin/sh
#=========================HEADER===============================|
#AUTOR:
# Jefferson Rocha
#
#VERSÃO:
# 0.1
#
#DESCRIÇÃO:
#removepkg - Remove pacote e hierarquia do sistema operacional.
#==============================================================|
# Erros? pare.
set -e

#==========================| FUNÇÕES
REMOVE()
{
   local pkg_remove="$1"

   # Deletando arquivos.
   while read the_file; do
      rm $the_file 2>/dev/null && echo " Delete: $the_file"
   done < "$pkg_remove"

   # Removendo links simbólicos se existir..
   while read the_link; do
      unlink $the_link &>/dev/null && echo "Delete Links: $the_link"
   done < "$pkg_remove"

   # Removendo diretórios nulos
   while read the_dir; do
      rm -d $the_dir &>/dev/null && echo "Delete empty directories: $the_dir"
   done < "$pkg_remove"

   echo "Deletando track ${pkg_remove}"
   [ -e "${pkg_remove}" ] && rm -v ${pkg_remove}
}

#==========================| INICIO
case $1 in
   -r|--remove|remove)
      shift # Rebaixando um parâmetro posicional.

      # O usuário passou o nome de algum pacote?
      [ -z "$1" ] && { echo "Você deve fornecer o nome do pacote."; exit 1 ;}

      # Entrando no diretório /var lalala
      cd /var/log/installed

      # Fazendo a listagem do diretório /var/log/installed e
      # conferindo se o pacote está instalado no sistema.
      for pack_exist in *; do
         if ! [ "$(grep "$1" < ${pack_exist})" ]; then
            echo "O pacote $1 não está instalado no sistema."
            exit 1
         else
            pkg_for_remove="$pack_exist"
            break
         fi
      done

      # Chamando a função REMOVE e passando como parâmetro o nome do pacote.
      REMOVE "$pkg_for_remove"
   ;;
esac

Dê permissão de execução e envie para /usr/sbin, em seguida execute "pkgremove -r" nano para fazer o teste:

# chmod -v +x pkgremove
mode of 'pkgremove' retained as 0755 (rwxr-xr-x)

# cp -v pkgremove /usr/sbin/
'pkgremove' -> '/usr/sbin/pkgremove'

# pkgremove -r nano
Delete: /usr/bin/rnano
Delete: /usr/bin/nano
Delete: /usr/share/info/nano.info
Delete: /usr/share/info/dir
Delete: /usr/share/locale/pl/LC_MESSAGES/nano.mo
Delete: /usr/share/nano/texinfo.nanorc
Delete: /usr/share/nano/nanorc.nanorc
Delete: /usr/man/man1/rnano.1
Delete: /usr/man/man5/nanorc.5
Delete empty directories: /usr/share/info/
Delete empty directories: /usr/share/doc/nano/
Delete empty directories: /usr/share/nano/
.........................

Deletando track nano-4.7.track
removed 'nano-4.7.track'


Perfeito! Funcionou tudo corretamente. Para não ficar a lista muito longa, o resultado foi cortado! Não temos mais o nano no sistema vamos ter que reinstalar ele, com o nosso gerenciador de pacotes, claro:

# which nano
which: no nano in (/usr/local/sbin:/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin)

# cd /tmp/build/
# ls
nano-4.7  nano-4.7.tar.xz

# pkginstall -i nano-4.7.tar.xz
========> Iniciando instalação do pacote nano-4.7.tar.xz

Removendo caracteres desnecessários do arquivo .track
Pacote: nano-4.7.tar.xz foi instalado com sucesso.


# which nano
/usr/bin/nano

Considerações finais do nível a1 - Parte 1

NOTA: se você quiser dar uma olhada em todos os programas que criamos "createpkg", "pkginstall" e "pkgremove", eles estão disponíveis em:
Vimos que nosso gerenciador de pacotes está funcional, criando pacotes, instando e removendo! Mas não com perfeição. Há muito a ser feito ainda e muitas funcionalidades precisam ser inseridas.

Por exemplo, nosso gerenciador não instala vários pacotes de uma só vez, não instala pacotes de um diretório diferente, somente quando você está no mesmo diretório que o pacote. Também temos a questão de instalar em outro lugar "raiz" utilizado para fazer um "jailroot".

Outra questão, é de por "comandos" em um script de pré e pós instalação do pacote! Tudo é muito estático. No nível a2, vamos fazer estas e mais algumas melhorias. Assim você pode utilizar no seu dia a dia.

Outro detalhe, o código está muito simples e foi feito proposicionalmente. Poderíamos ter feito código mais complexos para agilizar muita coisa, porém, a abordagem é direcionado para aprendizagem, o programador menos experiente precisa entender bloco a bloco o que está acontecendo e com comentários para complementar.

A abordagem continuará assim nesta pegada em outros níveis.

Este artigo foi retirado do meu site: Bem vindo | DIY PACKAGE MANAGER

Obrigado pela leitura e bom divertimento!

Página anterior    

Páginas do artigo
   1. Introdução
   2. Iniciando
   3. createpkg - Criando um pacote
   4. pkginstall - Instalando um pacote
   5. pkgremove - Removendo um pacote
Outros artigos deste autor

Compilação do Kernel Linux para máquinas locais Debian

Software Manivela VS Software Modinha

Slackware x Debian

Compilação Kernel Linux no Slackware

Howto de Compilação com Slackbuilds

Leitura recomendada

Introdução ao Linux: Instalação do OpenSuSE

Arredondando o Ubuntu em seu desktop

DebEX - Debian 10 com o Budgie Desktop 10.5 e Linux Kernel 5.7

Leia, grave e execute!

O Sistema Debian Alternatives

  
Comentários
[1] Comentário enviado por Tio_do_Toldo em 23/02/2020 - 11:06h

Legal.

[2] Comentário enviado por cizordj em 29/02/2020 - 15:23h

Caramba hein, que massa! Nunca entendi como o dpkg do Debian removia os pacotes do sistema e vendo agora o seu shell script dá para entender a lógica disso. E é uma coisa perigosa, o comando rm se for passado o argumento errado já era.

Outra coisa que aprendi também é que #!/bin/sh também interpreta funções.
________________________________________________
O programador tem a mania de achar que tudo é objeto


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts