Un paquete Debian no es sólo un compendio de archivos a instalar. Es parte de un todo más grande y describe su relación con otros paquetes Debian (dependencias, conflictos, sugerencias). También provee scripts que permiten la ejecución de órdenes en diferentes etapas del ciclo de vida del paquete (instalación, eliminación, actualización). Estos datos utilizados por las herramientas de gestión de paquetes no son parte del software empaquetado, son lo que se denomina «metainformación» (información sobre otra información) dentro del paquete.
5.2.1. Descripción: el archivo control
Este archivo utiliza una estructura similar a las cabeceras de email (definidas en RFC 2822). Por ejemplo el archivo control
de apt se ve de la siguiente forma:
$
apt-cache show apt
Package: apt
Version: 1.4.8
Installed-Size: 3539
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Replaces: apt-utils (<< 1.3~exp2~)
Depends: adduser, gpgv | gpgv2 | gpgv1, debian-archive-keyring, init-system-helpers (>= 1.18~), libapt-pkg5.0 (>= 1.3~rc2), libc6 (>= 2.15), libgcc1 (>= 1:3.0), libstdc++6 (>= 5.2)
Recommends: gnupg | gnupg2 | gnupg1
Suggests: apt-doc, aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), powermgmt-base, python-apt
Breaks: apt-utils (<< 1.3~exp2~)
Description-en: commandline package manager
This package provides commandline tools for searching and
managing as well as querying information about packages
as a low-level access to all features of the libapt-pkg library.
.
These include:
* apt-get for retrieval of packages and information about them
from authenticated sources and for installation, upgrade and
removal of packages together with their dependencies
* apt-cache for querying available information about installed
as well as installable packages
* apt-cdrom to use removable media as a source for packages
* apt-config as an interface to the configuration settings
* apt-key as an interface to manage authentication keys
Description-md5: 9fb97a88cb7383934ef963352b53b4a7
Tag: admin::package-management, devel::lang:ruby, hardware::storage,
hardware::storage:cd, implemented-in::c++, implemented-in::perl,
implemented-in::ruby, interface::commandline, network::client,
protocol::ftp, protocol::http, protocol::ipv6, role::program,
scope::application, scope::utility, sound::player, suite::debian,
use::downloading, use::organizing, use::searching, works-with::audio,
works-with::software:package, works-with::text
Section: admin
Priority: important
Filename: pool/main/a/apt/apt_1.4.8_amd64.deb
Size: 1231676
MD5sum: 4963240f23156b2dda3affc9c0d416a3
SHA256: bc319a3abaf98d76e7e13ac97ab0ee7c238a48e2d4ab85524be8b10cfd23d50d
5.2.1.1. Dependencias: el campo Depends
Las dependencias están definidas en el campo Depends
en la cabecera del paquete. Esta es una lista de condiciones a cumplir para que el paquete funcione correctamente — las herramientas como apt
utilizan esta información para instalar las bibliotecas necesarias, las versiones apropiadas, para satisfacer las dependencias del paquete a instalar. Para cada dependencia es posible restringir el rango de versiones que cumplen dicha condición. En otras palabras, es posible expresar el hecho de que necesitamos el paquete libc6 en una versión igual o mayor a «2.15» (escrito como «libc6 (>= 2.15)
». Los operadores de comparación de versiones son los siguientes:
In a list of conditions to be met, the comma serves as a separator. It must be interpreted as a logical “and”. In conditions, the vertical bar (“|”) expresses a logical “or” (it is an inclusive “or”, not an exclusive “either/or”). Carrying greater priority than “and”, it can be used as many times as necessary. Thus, the dependency “(A or B) and C” is written
A | B, C
. In contrast, the expression “A or (B and C)” should be written as “(A or B) and (A or C)”, since the
Depends
field does not tolerate parentheses that change the order of priorities between the logical operators “or” and “and”. It would thus be written
A | B, A | C
.
El sistema de dependencias es un buen mecanismo para garantizar el funcionamiento de un programa, pero tiene otro uso con los «metapaquetes». Éstos son paquetes vacíos que sólo describen dependencias. Facilitan la instalación de un grupo consistente de programas preseleccionados por el desarrollador del metapaquete; como tal apt install metapaquete
instalará automáticamente todos estos programas utilizando las dependencias del metapaquete. Los paquetes gnome, kde-full y linux-image-amd64, por ejemplo, son metapaquetes.
5.2.1.2. Conflictos: el campo Conflicts
El campo Conflicts
indica que un paquete no puede instalarse simultáneamente con otro. La razón más común es que ambos paquetes contienen un archivo con el mismo nombre, proveen el mismo servicio en el mismo puerto TCP o estorban el funcionamiento del otro.
dpkg
se negará a instalar un paquete si genera un conflicto con un paquete ya instalado, excepto si el nuevo paquete especifica que «reemplazará» al paquete instalado en cuyo caso dpkg
elegirá reemplazar el paquete existente con el nuevo. apt
siempre seguirá sus instrucciones: si desea instalar un nuevo paquete ofrecerá automáticamente desinstalar el paquete que genera problemas.
5.2.1.3. Incompatibilidades: el campo Breaks
El campo Breaks
tiene un efecto similar al del campo Conflicts
pero con un significado especial. Indica que la instalación de un paquete «romperá» otro paquete (o versiones particulares del mismo). En general, esta incompatibilidad entre dos paquetes es temporal y la relación Breaks
se refiere específicamente a las versiones incompatibles.
dpkg
se negará a instalar un paquete que rompe un paquete ya instalado y apt
intentará resolver el problema actualizando a una nueva versión el paquete que se rompería (que se asume estaría arreglado y, por lo tanto, sería compatible nuevamente).
Este tipo de situaciones pueden ocurrir en casos de actualizaciones que no sean compatibles con versiones anteriores: este es el caso si una nueva versión ya no funciona con la versión anterior y causa un mal funcionamiento en otros programas si no se toman medidas especiales. El campo Breaks
previene que el usuario se tope con estos problemas.
5.2.1.4. Elementos provistos: el campo Provides
Este campo introduce el concepto interesante de un «paquete virtual». Tiene muchos roles pero hay dos particularmente importantes. El primero consiste en utilizar un paquete virtual para asociar un servicio genérico con él (el paquete «provee» el servicio). El segundo indica que un paquete reemplaza completamente a otro y, para esos propósitos, también puede satisfacer las dependencias que otros satisfacen. Es posible, entonces, crear un paquete substituto sin tener que utilizar el mismo nombre de paquete.
5.2.1.4.1. Proveyendo un «servicio»
Discutamos con más detalles el primer caso con un ejemplo: se dice que todos los servicios de correo, como postfix o sendmail «proveen» el paquete virtual mail-transport-agent. Por lo tanto, cualquier paquete que necesite este servicio para funcionar (por ejemplo, un gestor de listas de correo como smartlist o sympa) simplemente indican en sus dependencias que requieren de mail-transport-agent en lugar de especificar una lista larga y aún incompleta de posibles soluciones (por ejemplo postfix | sendmail | exim4 | ...
). Lo que es más, es inútil instalar dos servidores de correo en el mismo equipo, por lo que cada uno de estos paquetes declara un conflicto con el paquete virtual mail-transport-agent. Un conflicto de un paquete con sí mismo es ignorado por el sistema, pero esta técnica prohibirá la instalación de dos servidores de correo simultáneamente.
5.2.1.4.2. Intercambio con otro paquete
The Provides
field is also interesting when the content of a package is included in a larger package. For example, the libdigest-md5-perl Perl module was an optional module in Perl 5.6, and has been integrated as standard in Perl 5.8 (and later versions, such as 5.24 present in Stretch). As such, the package perl has since version 5.8 declared Provides: libdigest-md5-perl
so that the dependencies on this package are met if the user has Perl 5.8 (or newer). The libdigest-md5-perl package itself has eventually been deleted, since it no longer had any purpose when old Perl versions were removed.
Esta funcionalidad es muy útil ya que nunca es posible anticipar los caprichos del desarrollo y es necesario que sea posible adaptarse a cambios de nombre y otros reemplazos automáticos de software obsoleto.
5.2.1.4.3. Limitaciones anteriores
Los paquetes virtuales solían sufrir algunas limitaciones, la más importante de ellas era la ausencia de un número de versión. Volviendo al ejemplo anterior, una dependencia como Depends: libdigest-md5-perl (>= 1.6)
nunca será considerada como satisfecha aún en presencia de Perl 5.10 — cuando de hecho es altamente probable que esté satisfecha. Sin conocimientos de esto el sistema de paquetes selecciona la opción menos riesgosa y asume que las versiones no coinciden.
This limitation has been lifted in dpkg 1.17.11, and is no longer relevant in Stretch. Packages can assign a version to the virtual packages they provide with a dependency such as Provides: libdigest-md5-perl (= 1.8)
.
5.2.1.5. Reemplazo de archivos: el campo Replaces
El campo Replaces
indica que el paquete contiene archivos que también están presentes en otro paquete, pero que el paquete tiene el derecho legítimo de reemplazarlo. Sin esta especificación, dpkg
fallará indicando que no puede sobreescribir los archivos de otro paquete (técnicamente es posible forzar que lo haga con la opción --force-overwrite
, pero no se considera una operación estándar). Esto permite identificar problemas potenciales y requiere que el desarrollador estudie el hecho antes de decidir agregar dicho campo.
El uso de este campo está justificado cuando cambian los nombres de los paquetes o cuando un paquete está incluido en otro. Esto sucede cuando el desarrollador decide distribuir los archivos de otra forma entre los varios paquetes binarios producidos del mismo paquete fuente: un archivo reemplazado no le corresponde al paquete antiguo, sólo al nuevo.
Si todos los archivos de un paquete instalado fueron reemplazados, se considera que se eliminó el paquete. Finalmente, este campo incita que dpkg
elimie los paquetes reemplazados en casos de conflictos.
5.2.2. Scripts de configuración
Además del archivo control
, el compendio control.tar.gz
de cada paquete Debian puede contener una cantidad de scripts que serán ejecutados por dpkg
en diferentes etapas del procesamiento de un paquete. La Normativa Debian describe los casos posibles en detalle, especificando los scripts que serán llamados y los argumentos que recibirán. Estas secuencias pueden ser complicadas ya que si falla uno de los scripts dpkg
intentará volver a un estado satisfactorio cancelando la instalación o eliminación en curso (siempre que sea posible).
En general, se ejecuta el script preinst
antes de la instalación del paquete, y postinst
luego. De la misma forma, se invoca prerm
antes de la eliminación de un paquete y postrm
luego. Actualizar un paquete es equivalente a eliminar la versión anterior e instalar la nueva. No es posible describir en detalle todos los escenarios posibles aquí, pero discutiremos los dos más comunes: instalación/actualización y eliminación.
5.2.2.1. Instalación y actualización
Esto es lo que ocurre durante una instalación (o actualización):
En una actualización, dpkg
ejecuta old-prerm upgrade nueva-versión
.
En una actualización dpkg
ejecuta luego new-preinst upgrade antigua-versión
; para una primera instalación ejecuta new-preinst install
. También puede agregar la versión anterior en el último parámetro si el paquete ya ha sido instalada y eliminada desde entonces (pero no purgada, se mantuvieron los archivos de configuración).
Se descomprimen los archivos del nuevo paquete. Si un archivo ya existe, es reemplazado pero se guarda una copia de respaldo de forma temporal.
En una actualización, dpkg
ejecuta old-postrm upgrade nueva-versión
.
dpkg
actualiza toda su información interna (lista de archivos, scripts de configuración, etc.) y elimina los respaldos de los archivos reemplazados. Este es el punto sin retorno: dpkg
ya no tiene acceso a todos los elementos necesarios para volver al estado anterior.
Finalmente, dpkg
configura el paquete ejecutando new-postinst configure última-versión-configurada
.
5.2.2.2. Eliminación de un paquete
Esto es lo que sucede durante la eliminación de un paquete:
dpkg
ejecuta prerm remove
.
dpkg
elimina todos los archivos del paquete, con la excepción de los archivos de configuración y scripts de configuración.
dpkg
ejecuta postrm remove
. Se eliminan todos los scripts de configuración excepto postrm
. Si el usuario no utilizó la opción «purgar» («purge»), el proceso termina aquí.
Para eliminar completamente un paquete (con la orden dpkg --purge
o dpkg -P
), los archivos de configuración también son eliminados junto con una cantidad de copias (*.dpkg-tmp
, *.dpkg-old
, *.dpkg-new
) y archivos temporales; luego dpkg
ejecuta postrm purge
.
Los cuatro scripts que aparecen detallados anteriormente se complementan con un script config
provisto por los paquetes que utilizan debconf
para adquirir información de configuración del usuario. Durante la instalación este script define en detalle las preguntas realizadas por debconf
. Se graban las respuestas en la base de datos de debconf
para futuras referencias. Generalmente apt
ejecuta el script antes de instalar los paquetes uno por uno para agrupar las preguntas y realizarlas todas al usuario al comienzo del proceso. Los scripts de pre y postinstalación pueden utilizar esta información para operar según los deseos del usuario.
5.2.3. Sumas de verificación («checksum»), lista de archivos de configuración
Además de los scripts de gestión y los datos de control mencionados en las secciones anteriores, el compendio
control.tar.gz
en un paquete Debian puede contener otros archivos interesantes. El primero,
md5sums
contiene una lista sumas de verificación MD5 de todos los archivos del paquete. Su principal ventaja es que permite que
dpkg-verify
(que estudiaremos en la
Sección 14.3.3.1, “Auditoría de paquetes mediante dpkg --verify
”) chequee si estos archivos fueron modificados desde su instalación. Sepa que cuando este archivo no existe,
dpkg
lo generará dinámicamente en el momento de la instalación (y lo almacenará en la base de datos de dpkg al igual que cualquier otro archivo de control).
conffiles
enumera los archivos del paquete que tienen que administrarse como archivos de configuración. El administrador puede modificar los archivos de configuración y dpkg
intentará preservar estos cambios durante la actualización de un paquete.
De hecho, en esta situación, dpkg
se comporta tan inteligentemente como le es posible: si el archivo de configuración estándar no fue modificado entre dos versiones, no hace nada. Si, sin embargo, el archivo cambió intentará actualizar este archivo. Son posibles dos casos: o bien el administrador no modificó el archivo, en cuyo caso dpkg
automáticamente instalará la nueva versión; o el archivo fue modificado, en cuyo caso dpkg
le preguntará al administrador qué versión desea utilizar (la antigua con modificaciones o la nueva provista con el paquete). Para asistirlo en esta decisión dpkg
ofrece mostrar las diferencias entre las dos versiones («diff
»). Si el usuario decide mantener la versión anterior, la nueva será almacenada en la misma ubicación con el sufijo .dpkg-dist
. Si el usuario selecciona la nueva versión, se mantiene la versión anterior en la misma ubicación con el sufijo .dpkg-old
. Otra acción posible consiste en interrumpir momentáneamente dpkg
para editar el archivo e intentar rehacer las modificaciones relevantes (identificadas previamente con diff
).