Linux From Scratch XI: Gestión de paquetes

En mi anterior post (siempre empiezo igual todos los artículos 🙂 ) he dejado todo listo para instalar los headers del kernel. Eso es lo siguiente que voy a hacer, pero antes de meterme con ello, he querido investigar cómo puedo crear paquetes binarios con el resultado de la compilación de cada uno de los paquetes de código fuente que voy a instalar.

En principio, el libro no usa ningún tipo de gestión de paquetes, aunque sí que dedica un capítulo a hablar sobre la problemática de la gestión de paquetes y posibles opciones. Además, en Hints Project hay una serie de artículos sobre el uso de gestores de paquetes existentes y otros desarrollados específicamente para Linux From Scratch.

Técnicas triviales de gestión de paquetes

Algunas técnicas de gestión de paquetes que propone el libro son lo suficientemente triviales como para no necesitar ningún gestor de paquetes en absoluto. Todas ellas tienen inconvenientes importantes, claro. Vamos a ver algunas.

Llevarlo todo en la cabeza

El nombre lo dice todo. Esta técnica de gestión de paquetes es tan trivial que consiste en no hacer ningún tipo de gestión de paquetes. 🙂 Esto sólo es viable si sabes exactamente lo que tienes instalado y conoces los paquetes con tanto detalle que sabes exactamente lo que hay que hacer para instalar, actualizar o desinstalar cada uno de ellos …o si tienes intención de recompilar todo cada vez que hagas cualquier cambio. 🙂 No es la que más me gusta. No hacía falta decirlo, ¿verdad? 🙂

Instalar en directorios separados

La idea es instalar cada versión de cada paquete en un directorio diferente. Pondré el mismo ejemplo que el libro: El paquete foo-1.1 se instalaría en /usr/pkg/foo-1.1 y se crearía un enlace de /usr/pkg/foo a /usr/pkg/foo-1.1. Al instalar una nueva versión, se instalaría en /usr/pkg/foo-1.2 y se actualizaría el enlace para apuntar a él. De esa manera se pueden tener instaladas varias versiones del mismo paquete y el enlace sirve para seleccionar la versión activa actualmente.

La idea parece buena, pero requiere añadir a las variables PATH, LD_LIBRARY_PATH, MANPATH, INFOPATH y CPPFLAGS la ruta de cada uno de los paquetes y mantenerlas actualizadas cada vez que se instala o desinstala un paquete nuevo, lo que puede ser inmanejable cuando haya muchos paquetes. Además, no siempre es fácil instalar un paquete en una ruta alternativa. Algunos paquetes no dan facilidades para ello y hay que modificarlos.

Gestión de paquetes mediante enlaces simbólicos

Esta técnica es parecida a la anterior. La diferencia es que en lugar de crear un sólo enlace y actualizar tantas variables, se crea en /usr un enlace por cada fichero del paquete. De esta manera, los enlaces quedan en los directorios normales del sistema de ficheros y no es necesario modificar ninguna variable. GoboLinux utiliza esta técnica para los paquetes instalados.

Lo malo es que el número de enlaces aumenta enormemente y hay que actualizarlos todos cada vez que se actualiza el paquete. Esto sería factible si se hace de forma automática mediante algún script. De hecho, hay gestores de paquetes basados en esta idea, como Stow, Epkg, Graft o Depot, pero todavía es necesario modificar algunos paquetes para conseguir instalarlos así.

Detección de ficheros modificados

Dejando a un lado las técnicas que acabamos de ver, cualquier gestor de paquetes decente necesita ser capaz de detectar cuáles son los ficheros instalados para ser capaz de desinstalarlos correctamente o para generar un paquete binario con ellos. Vamos a ver algunas de las técnicas que se pueden usar para eso.

Comparar timestamps

En esta técnica se crea un fichero con la fecha actual antes de instalar un paquete (por ejemplo, con touch). Una vez instalado, se buscan con find los ficheros cuya fecha es mayor que la del fichero. Esos serán los ficheros instalados o modificados, así que se puede crear un log para desinstalarlos o empaquetarlos para crear un binario. Install-log usa esta técnica.

El problema de esta técnica es que algunos paquetes pueden crear ficheros con fechas anteriores a la fecha actual y no serían detectados. Además, no se pueden instalar dos paquetes a la vez desde dos terminales distintas, ya que no sería posible diferenciar los ficheros de uno y otro. También habría problemas si algún otro proceso está escribiendo en otros ficheros durante la instalación, porque esos ficheros parecerían modificados por el instalador.

Trazar los scripts de instalación

Esta técnica consiste en vigilar, de alguna forma automática, las operaciones que hace el script de instalación en el sistema de ficheros. Esto se puede hacer de varias maneras. Una de ellas es utilizar LD_PRELOAD para cargar una librería que vigile las llamadas al sistema que hacen los programas que lanza el instalador. Checkinstall funciona así. Por lo visto esto puede provocar efectos laterales que habría que vigilar para asegurarnos de que todos los ficheros quedan bien y se logean correctamente.

Otra forma de hacerlo es usando strace, que logea las llamadas al sistema que hace un proceso. Algunas herramientas hacen esto, pero el problema es que a veces las llamadas al sistema cambian de un kernel a otro, así que hay que mantener actualizados los scripts que usemos para esto. Además de asegurarnos de que no se nos olvida ninguna llamada. A veces hay varias maneras de hacer lo mismo y no sabemos cuál va a usar el instalador.

Una forma más que he visto mirando los hints, es reemplazar los comandos cp, mv, install y los demás comandos que el instalador pueda usar, por versiones nuestras que logean las operaciones antes de llamar a los originales. El problema que tiene es que el instalador puede utilizar técnicas poco ortodoxas para crear los ficheros y no podemos estar seguros de haber incluido todos los comandos posibles.

Instalar en un directorio separado

Sí, la idea es hacer lo mismo que en las técnicas triviales de las que he hablado antes: instalar los ficheros en un directorio separado, sólo que esta vez se compilan como si fueran a instalarse en / en vez de en ese directorio. De esta manera tenemos todos los ficheros separados para empaquetarlos o logearlos y luego podemos moverlos a / para instalarlos definitivamente.

El primer problema que tiene es el mismo que las técnicas en las que se basa: A veces hay que modificar los paquetes de código fuente para poder instalarlos así. Y en este caso es más grave todavía, porque estamos instalando en un directorio distinto del directorio en el que va a funcionar el paquete. La mayoría de los gestores de paquetes de las distribuciones importantes utilizan esta técnica para generar los paquetes binarios. Incluyendo rpm y dpkg.

Gestión de ficheros basada en usuarios

Este sistema crea un usuario y un grupo por cada paquete y los ficheros de cada paquete se instalan con su usuario y su grupo. De esta manera se puede identificar fácilmente a qué paquete pertenece cada fichero y con un simple find se pueden encontrar los ficheros correspondientes a un paquete. Esta técnica es una genialidad. No es necesario ningún gestor de paquetes. Toda la gestión se puede hacer mediante comandos del propio sistema operativo. Voy a enumerar las ventajas que tiene:

  • Como los usuarios no tienen permiso de administrador es más dificil que el instalador haga cosas que no debe. Por lo tanto este sistema mejora la seguridad.
  • Un paquete no puede modificar los ficheros de otro paquete. Si ocurre esto, el instalador dará un error, dándonos la oportunidad de decidir qué queremos hacer. Por ejemplo, podemos renombrar uno de los ficheros y quedarnos con los dos.
  • Si un paquete intenta instalar un binario como suid root también dará error y podemos elegir si realmente queremos instalarlo como suid root o no. Muchas veces no es necesario y los suid root presentan problemas de seguridad, o sea que instalándolos como binarios normales tendremos un sistema más seguro.
  • Normalmente las cuentas de usuario de cada paquete no tienen contraseña, por lo que sólo el root puede entrar en ellas para administrar, pero se puede poner contraseña a varias cuentas para permitir que otro administrador se encargue de gestionar un grupo de paquetes sin darle permisos para tocar los demás. Otra mejora en la seguridad.
  • Se puede hacer que las cuentas de usuario de los paquetes pertenezcan al grupo install. De esta manera se puede ver la lista de paquetes instalados simplemente con el comando grep install /etc/group.
  • Se puede usar el directorio home de cada usuario para tener información sobre el paquete. Por ejemplo, se podría poner en él el código fuente, parches, scripts de compilación, etc. Así se tendría todo clasificado por paquete.
  • Si se escribe información sobre el paquete en el fichero .project del usuario, se podría ver esta información con finger o pinky. Aquí se pueden poner cosas como la descripción, el nombre, la versión, la URL del upstream, información de dependencias… lo que se quiera.

Por supuesto, no todo es de color rosa. También tiene inconvenientes. El principal es que los cambios que requiere hacer en el script de instalación para que funcione todo esto son muy grandes. El proceso típico suele ser lanzar la instalación, ver que da un error, buscar el error y modificar el script hasta corregirlo, volver a lanzar la instalación, ver que da otro error y así hasta haber corregido todos los problemas. Interesante pero bastante engorroso.

Usar una unión de varios directorios

Esta es una técnica muy interesante que he encontrado leyendo el Hints Project. La idea es, de nuevo, instalar los paquetes en directorios separados, pero esta vez se usa el sistema de ficheros unionfs (o su sucesor, aufs) para montar todos esos directorios a la vez en /. De esa manera cada paquete está separado, pero se puede usar como si estuviera instalado en /.

La principal ventaja de este método es que se puede cargar y descargar cada paquete sin necesidad de instalarlo y desinstalarlo. También se pueden unir o separar paquetes fácilmente moviendo los ficheros de un directorio a otro sin que afecte a la instalación. Además, se pueden tener instaladas varias versiones del mismo paquete y cargar la que nos interese.

Lo malo es que, de nuevo, requiere modificar los paquetes para poder instalarlos así. Otra desventaja es que aumenta el tiempo que tarda el sistema en arrancar y requiere modificar los scripts de arranque para cargar todos los paquetes necesarios.

Uso de un gestor de paquetes existente

En el Hints Project hay instrucciones para usar con Linux From Scratch gestores de paquetes típicos de otras distros, como RPM o dpkg. Estas instrucciones están pensadas para instalar el gestor de paquetes compilándolo desde el código fuente después de haber instalado Linux From Scratch entero. No están pensados para gestionar los paquetes de Linux From Scrath sino para permitir instalar paquetes de otras distros.

Se podrían empaquetar paquetes deb o rpm para Linux From Scratch, pero tal y como lo hacen estas instrucciones no sirven para los paquetes que se instalan a lo largo del capítulo 6 del libro. Sin embargo, puede ser una opción a considerar en el futuro. Hay que tener en cuenta que estos gestores utilizan la técnica de instalar en un directorio separado y, por lo tanto, requieren modificar el código fuente de los paquetes que den problemas con esa técnica.

Gestores de paquetes específicos

También existen gestores de paquetes hechos específicamente para Linux From Scratch. Cada uno usa alguna de las técnicas que he descrito más arriba, como la de unionfs o la de gestión basada en usuarios, que son únicas de Linux From Scratch. Aparte de estos que ya he comentado antes, voy a hablar brevemente de los que he encontrado en el Hints Project.

TRIP

Este gestor de paquetes se basa en usar unionfs para detectar los ficheros que crea y modifica el instalador. Hace toda la gestión de paquetes mediante un script bastante sencillo y está pensado para poder usarlo durante el capítulo 6 del libro. Lo malo que tiene es que modifica las instrucciones del libro.

Paco

Paco usa LD_PRELOAD para detectar los ficheros instalados y viene con un GUI opcional hecho en GTK+. Tiene buena pinta, pero hereda los problemas de detectar cambios mediante LD_PRELOAD. Además, en las instrucciones no queda claro si puede usarse durante el capítulo 6 del libro. Más bien parece que no.

LPM

Este sí se puede usar durante el capítulo 6. Las instrucciones no dicen qué técnica utiliza, pero el uso parece muy sencillo. Al igual que las dos herramientas anteriores no genera paquetes, sino que guarda un log de los ficheros instalados para borrarlos al desinstalar.

Otras consideraciones sobre la gestión de paquetes

Para hacer una verdadera gestión de paquetes quedan todavía dos cuestiones en las que no me he metido por ahora. Una de ellas es la gestión de dependencias. Hay distros que no gestionan dependencias y lo dejan todo en manos del administrador, como slackware, pero lo normal, puestos a usar un gestor de paquetes, es que resuelva las dependencias e instale automáticamente los paquetes dependientes. Linux From Scratch no se mete en este tema y yo no lo he hecho tampoco. Quizás mas adelante habría que mirarlo.

Otra cosa que hay que tener en cuenta son los scripts de instalación y desinstalación. Muchas veces instalar o desinstalar un paquete no es tan sencillo como copiar los ficheros o borrarlos. A veces hay que hacer cosas como lanzar o detener demonios, actualizar la caché de fuentes, cargar módulos en el kernel, actualizar el gestor de arranque, etc. Para esto lo normal es introducir uno o varios scripts en el paquete binario de manera que el gestor de paquetes lo ejecute al hacer la instalación o desinstalación.

Lo típico suele ser tener cuatro scripts: Preinstalación, postinstalación, predesinstalación y postdesinstalación. Estos scripts dependen del paquete, así que hay que conocer cada paquete y crear los scripts de forma personalizada para cada uno de ellos. No es tan difícil como suena, pero no se pueden dar instrucciones generales para hacer esto. Es un tema que tendremos que tener en cuenta si decidimos crear paquetes binarios.

Conclusión

Me ha quedado un post muy largo. Ni me imaginaba que fuera para tanto. 🙂 Creo que es buena idea dejarlo aquí. En mi siguiente post contaré la solución que he decidido adoptar para tener cierta gestión de paquetes de forma sencilla sin que sea necesario modificar las instrucciones del libro. Será un artículo más práctico y espero poder llegar a compilar algo por fin.

EOF

Anuncios