Radiografía de paquetes instalados en Debian

Nota: Este artículo lo comencé a escribir hace mucho tiempo, pero al estar basado en los paquetes de la rama testing de Debian, la información aquí recogida cambiaba a la vez que cambiaban los paquetes y sus dependencias. Es por ello que he preferido esperar hasta la versión estable de Debian "Jessie" para publicarlo.

Utilizando los superpoderes que nos proporciona aptitude voy a realizar una pequeña radiografía de los paquetes que tengo instalados en mi actual Debian. El objetivo es usar más tarde dicha información para simplificar la instalación y limpiarla de paquetes innecesarios.

Para entender el origen de la instalación de un paquete cualquiera, lo más directo es echar un vistazo a su descripción1:

$ LANG=C aptitude show gzip
Package: gzip
Essential: yes
State: installed
Automatically installed: no
Version: 1.6-4
Priority: required
Section: utils
Maintainer: Bdale Garbee <bdale@gag.com>
Architecture: amd64
Uncompressed Size: 245 k
Depends: dpkg (>= 1.15.4) | install-info
PreDepends: libc6 (>= 2.17)
Suggests: less
Conflicts: gzip
Description: GNU compression utilities
 This package provides the standard GNU file compression utilities, which are
 also the default compression tools for Debian.  They typically operate on files
 with names ending in '.gz', but can also decompress files ending in '.Z'
 created with 'compress'.

Tags: implemented-in::c, interface::commandline, role::program, scope::utility,
      suite::gnu, use::compressing, works-with::archive, works-with::file

Los campos en los que fijarse son Essential:, Priority: y Automatically installed:. Los términos de búsqueda (search terms) de aptitude que usaremos relacionados con estos campos y otros adicionales son los siguientes:

  • ?essential selecciona los paquetes marcados como esenciales
  • ?priority(prioridad) selecciona los paquetes con determinada prioridad (required, important, standard, optional o extra)
  • ?automatic selecciona los paquetes que se han instalado automáticamente
  • ?installed selecciona los paquetes instalados (es lo mismo que ~i)
  • ?name(regex) selecciona los paquetes cuyo nombre case con la regex
  • ?section(sección) selecciona paquetes que pertenecen a la sección indicada (por ejemplo libs)
  • ?architecture selecciona los paquetes de determinada arquitectura (i386, amd64, all, native, ...)
  • ?not(term), ?and(term1,term2), ?or(term1,term2) negación, conjunción y disyunción lógicas de los terminos anteriores

Podéis encontrar más términos de búsqueda en la Search term reference de aptitude.

Es una buena práctica rodear siempre la expresión de búsqueda con "" para evitar que la shell interprete algunos caracteres especiales que usaremos.

Paquetes esenciales

Los paquetes marcados como Essential: yes son absolutamente necesarios para que el sistema funcione. Estarán siempre instalados en un sistema sano (no roto) y las herramientas de gestión de paquetes se negarán a desinstalarlos.

Averiguar cuáles son los paquetes marcados como esenciales es trivial:

aptitude search "?essential"

Pero, si se ha añadido una segunda arquitectura (como es mi caso con i386), aparecerán también los paquetes esenciales de esta otra arquitectura. Para evitar este "ruido" en la salida seleccionaré sólo los paquetes de la arquitectura nativa:

$ aptitude search "?essential ?architecture(native)"
i   apt                     - commandline package manager               
i   base-files              - Debian base system miscellaneous files    
i   base-passwd             - Debian base system master password and gro
i   bash                    - GNU Bourne Again SHell                    
i   bsdutils                - basic utilities from 4.4BSD-Lite          
i   coreutils               - GNU core utilities                        
i   dash                    - POSIX-compliant shell                     
i   debianutils             - Miscellaneous utilities specific to Debian
i   diffutils               - File comparison utilities                 
i   dpkg                    - Debian package management system          
i   e2fsprogs               - ext2/ext3/ext4 file system utilities      
i   findutils               - utilities for finding files--find, xargs  
i   grep                    - GNU grep, egrep and fgrep                 
i   gzip                    - GNU compression utilities                 
i   hostname                - utility to set/show the host name or domai
i A init                    - System-V-like init utilities - metapackage
i   libc-bin                - GNU C Library: Binaries                   
i   login                   - system login tools                        
i   mount                   - Tools for mounting and manipulating filesy
i   ncurses-base            - basic terminal type definitions           
i   ncurses-bin             - terminal-related programs and man pages   
i   perl-base               - minimal Perl system                       
i   sed                     - The GNU sed stream editor                 
i   sysvinit-utils          - System-V-like utilities                   
i   tar                     - GNU version of the tar archiving utility  
i   util-linux              - Miscellaneous system utilities

En Debian "Jessie" hay 26 paquetes esenciales, 25 de ellos específicos de la arquitectura (amd64 en mi caso) y uno (ncurses-base) común a todas las arquitecturas (all).

Observad por favor que todos los paquetes esenciales están instalados2 (indicador 'i'). Si no fuera así tenéis un problema muy serio en vuestra instalación. También observad que hay un paquete esencial con el indicador 'A' de automáticamente instalado (volveremos sobre esto).

Paquetes por prioridad

Las diferentes prioridades que puede tener un paquete en Debian las podéis consultar en la FAQ (y más detalladamente en la Debian Policy), pero sirva esta breve descripción a modo de resumen (de mayor a menor prioridad):

  • required: paquetes necesarios para el funcionamiento del sistema, incluyendo las herramientas básicas para repararlo. No deben borrarse.
  • important: paquetes (básicos) que uno espera encontrar en cualquier sistema Unix.
  • standard: paquetes estándar en cualquier sistema Linux, más herramientas para tener un sistema básico de consola.
  • optional: paquetes que posiblemente quieras instalar, aunque no sepas qué son, incluyendo el entorno gráfico y herramientas generales.
  • extra: paquetes que tienen conflictos con otros de más alta prioridad, o no caben en optional por diversas causas

Una instalación básica de Debian incluye normalmente los paquetes de prioridad standard o mayor.

Una regla importante de cara a qué prioridad debe tener un paquete es que un paquete no debe depender de otro con una prioridad menor. No debe haber paquetes de prioridad required cuyas dependencias tengan prioridad important, por ejemplo.

Paquetes required

Los paquetes de prioridad required y los paquetes esenciales parece que se solapan. ¿Por qué tener un campo separado cuando podríamos indicar lo mismo usando únicamente la prioridad? En realidad, no es así. Para entenderlo veamos cuáles son los paquetes required:

$ aptitude search "?priority(required) ?architecture(native)"
i   base-files              - Debian base system miscellaneous files    
i   base-passwd             - Debian base system master password and gro
i   bash                    - GNU Bourne Again SHell                    
i   bsdutils                - basic utilities from 4.4BSD-Lite          
i   coreutils               - GNU core utilities                        
i   dash                    - POSIX-compliant shell                     
i   debconf                 - Debian configuration management system    
i   debconf-i18n            - full internationalization support for debc
i   debianutils             - Miscellaneous utilities specific to Debian
i   diffutils               - File comparison utilities                 
i   dpkg                    - Debian package management system          
i   e2fslibs                - ext2/ext3/ext4 file system libraries      
i   e2fsprogs               - ext2/ext3/ext4 file system utilities      
i   findutils               - utilities for finding files--find, xargs  
p   gcc-4.8-base            - GCC, the GNU Compiler Collection (base pac
i A gcc-4.9-base            - GCC, the GNU Compiler Collection (base pac
i   grep                    - GNU grep, egrep and fgrep                 
i   gzip                    - GNU compression utilities                 
i   hostname                - utility to set/show the host name or domai
i A init                    - System-V-like init utilities - metapackage
i   initscripts             - scripts for initializing and shutting down
i   libacl1                 - Access control list shared library        
i   libattr1                - Extended attribute shared library         
i   libblkid1               - block device id library                   
i   libc-bin                - GNU C Library: Binaries                   
i   libc6                   - GNU C Library: Shared libraries           
i   libcomerr2              - common error description library          
i   libgcc1                 - GCC support library                       
i   liblocale-gettext-perl  - module using libc functions for internatio
i A liblzma5                - XZ-format compression library             
i A libmount1               - device mounting library                   
i   libncurses5             - shared libraries for terminal handling    
i   libpam-modules          - Pluggable Authentication Modules for PAM  
i A libpam-modules-bin      - Pluggable Authentication Modules for PAM -
i   libpam-runtime          - Runtime support for the PAM library       
i   libpam0g                - Pluggable Authentication Modules library  
i   libpcre3                - Perl 5 Compatible Regular Expression Libra
i   libselinux1             - SELinux runtime shared libraries          
i   libsepol1               - SELinux library for manipulating binary se
i A libsmartcols1           - smart column output alignment library     
i   libss2                  - command-line interface parsing library    
i   libtext-charwidth-perl  - get display widths of characters on the te
i   libtext-iconv-perl      - converts between character sets in Perl   
i   libtext-wrapi18n-perl   - internationalized substitute of Text::Wrap
i A libtinfo5               - shared low-level terminfo library for term
i   libuuid1                - Universally Unique ID library             
i   login                   - system login tools                        
i   lsb-base                - Linux Standard Base 4.1 init script functi
i   mawk                    - a pattern scanning and text processing lan
i   mount                   - Tools for mounting and manipulating filesy
i A multiarch-support       - Transitional package to ensure multiarch c
i   ncurses-base            - basic terminal type definitions           
i   ncurses-bin             - terminal-related programs and man pages   
i   passwd                  - change and administer password and group d
i   perl-base               - minimal Perl system                       
i   sed                     - The GNU sed stream editor                 
i   sensible-utils          - Utilities for sensible alternative selecti
i A startpar                - run processes in parallel and multiplex th
i   sysv-rc                 - System-V-like runlevel change mechanism   
i   sysvinit-utils          - System-V-like utilities                   
i   tar                     - GNU version of the tar archiving utility  
i   tzdata                  - time zone and daylight-saving time data   
i   util-linux              - Miscellaneous system utilities            
i   zlib1g                  - compression library - runtime

En Jessie hay 64 paquetes required, 55 específicos de la arquitectura más 9 independientes de la arquitectura (arquitectura all). De ellos, 25 son paquetes esenciales, y los otros 39 no. Es decir, hay paquetes required que no tienen el indicador de Essential: activado, y por lo tanto el gestor de paquetes no previene que se borren. De hecho, ¡tengo un paquete required no instalado!

$ aptitude search "?priority(required) ?architecture(native) ?not(?installed)"
p   gcc-4.8-base            - GCC, the GNU Compiler Collection (base pac

Tranquilos todos. Ese paquete no está instalado porque yo lo he borrado manualmente cuando me deshice de todos los paquetes de gcc 4.8, puesto que ya tenía los de gcc 4.93. Pero el caso es que me sirve para ilustrar con un ejemplo las razones de la distinción de Essential y required: los paquetes esenciales no se pueden borrar en ningún caso mientras que los required sí (por ejemplo porque se proporcione una alternativa). Otro motivo es que dos paquetes con conflictos (excluyentes) no pueden estar ambos marcados como esenciales (tendrían que estar ambos instalados, algo que es obviamente imposible) mientras que sí podrían pertenecer ambos a required, siempre que sólo uno de ellos esté instalado.

Así que los paquetes que forman parte de required son aquellos marcados como Essential más sus dependencias, con la particularidad de que estas dependencias deben poder ser sustituidas por otros paquetes diferentes, lo que les impide ser Essential ellas mismas. Estas dependencias cambiantes provienen de programas con alternativas (como mawk, que puedes sustituirlo por gawk o por cualquier otro awk) o de software del cual puedes tener instaladas varias versiones a la vez (gcc-4.8-base / gcc-4.9-base/ futuros gcc-X.Y-base). Así nos encontramos con cosas tan aparentemente contraintuitivas como que libc6, el paquete del cual dependen prácticamente todos los demás, no sea Essential. Esta "particularidad" es sin embargo la que permite instalar una biblioteca C estándar diferente (como las que usan otras arquitecturas Debian) o incluso una hipotética futura libc7, manteniendo abierta la posibilidad de que los que quieran sigan usando la libc6 actual.

En resumen, que un paquete tenga una prioridad required no obliga a que esté instalado (aunque sí es una fuerte indicación de que debería estarlo, salvo que realmente sepas lo que estás haciendo). Por otro lado, para indicar al gestor de paquetes que es obligatorio que cierto paquete esté instalado debemos construirlo con su indicador Essential a yes —y lidiar con las consecuencias y restricciones de tal decisión.

Paquetes important

Si habéis sido observadores os habréis fijado que hay un paquete Essential que no está entre los que tienen prioridad required (sólo había 25 de los 26 Essential en required):

$ aptitude search "?essential ?not(?priority(required)) ?architecture(native)"
i   apt                     - commandline package manager

$ aptitude show apt
Package: apt
Essential: yes
State: installed
Automatically installed: no
Version: 1.0.9.8
Priority: important
Section: admin
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Uncompressed Size: 3879 k
Depends: libapt-pkg4.12 (>= 1.0.9.8), libc6 (>= 2.15), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 4.9), debian-archive-keyring, gnupg
Suggests: aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), apt-doc, python-apt
...

No conozco la razón exacta por la que apt tiene prioridad important en vez de required, pero puedo apostar sin arriesgar mucho a que tiene que ver con sus dependencias. Concretamente, al hecho de depender de la biblioteca estándar de C++ (al estar apt escrita en ese lenguaje de programación), que hubiera obligado a mover la libstdc++ también a required (para disgusto de unos pocos), junto con gnupg y el resto de dependencias no required. Además, históricamente apt ha tenido la consideración de herramienta adicional para facilitar el uso de dpkg, que por entonces era el único y verdadero gestor de paquetes, y de hecho todavía se puede usar exclusivamente dpkg4 para instalar y desinstalar paquetes. Aunque ¿quién en su sano juicio querría hacer eso hoy en día?

Echemos un vistazo a la lista de paquetes de prioridad important:

$ aptitude search "?priority(important) ?architecture(native)"
i   adduser                 - add and remove users and groups           
i   apt                     - commandline package manager               
i   apt-utils               - package management related utility program
i   bsdmainutils            - collection of more utilities from FreeBSD 
i   cpio                    - GNU cpio -- a program to manage archives o
i   cron                    - process scheduling daemon                 
i   debian-archive-keyring  - GnuPG archive keys of the Debian archive  
i   dmidecode               - SMBIOS/DMI table decoder                  
i   gnupg                   - GNU privacy guard - a free PGP replacement
i   gpgv                    - GNU privacy guard - signature verification
i   groff-base              - GNU troff text-formatting system (base sys
i   ifupdown                - high level tools to configure network inte
i A init-system-helpers     - helper tools for all init systems         
i A iproute2                - networking and traffic control tools      
i   iptables                - administration tools for packet filtering 
i   iputils-ping            - Tools to test the reachability of network 
i   isc-dhcp-client         - DHCP client for automatically obtaining an
i   isc-dhcp-common         - common files used by all of the isc-dhcp p
i A kmod                    - tools for managing Linux kernel modules   
i   less                    - pager program similar to more             
i A libapt-inst1.5          - deb package format runtime library        
i A libapt-pkg4.12          - package management runtime library        
i A libboost-iostreams1.55.0- Boost.Iostreams Library                   
i   libbz2-1.0              - high-quality block-sorting file compressor
i A libestr0                - Helper functions for handling strings (lib
i   libgdbm3                - GNU dbm database routines (runtime version
i A libjson-c2              - JSON manipulation library - shared library
i A libkmod2                - libkmod shared library                    
i A liblogging-stdlog0      - easy to use and lightweight logging librar
i A liblognorm1             - Log normalizing library                   
i   libncursesw5            - shared libraries for terminal handling (wi
i   libnewt0.52             - Not Erik's Windowing Toolkit - text mode w
i A libpipeline1            - pipeline manipulation library             
i   libpopt0                - lib for parsing cmdline parameters        
i A libprocps3              - library for accessing process information 
i   libreadline6            - GNU readline and history libraries, run-ti
i   libsigc++-2.0-0c2a      - type-safe Signal Framework for C++ - runti
i   libslang2               - S-Lang programming library - runtime versi
i A libssl1.0.0             - Secure Sockets Layer toolkit - shared libr
i   libstdc++6              - GNU Standard C++ Library v3               
i A libudev1                - libudev shared library                    
i   libusb-0.1-4            - userspace USB programming library         
i A libxtables10            - netfilter xtables library                 
i   logrotate               - Log rotation utility                      
i   man-db                  - on-line manual pager                      
i   manpages                - Manual pages about using a GNU/Linux syste
i   nano                    - small, friendly text editor inspired by Pi
i   net-tools               - NET-3 networking toolkit                  
i   netbase                 - Basic TCP/IP networking system            
i   netcat-traditional      - TCP/IP swiss army knife                   
p   nfacct                  - netfilter accounting object tool          
i   procps                  - /proc file system utilities               
i   readline-common         - GNU readline and history libraries, common
i   rsyslog                 - reliable system and kernel logging daemon 
i A systemd                 - system and service manager                
i A systemd-sysv            - system and service manager - SysV links   
i   tasksel                 - tool for selecting tasks for installation 
i   tasksel-data            - official tasks used for installation of De
i   traceroute              - Traces the route taken by packets over an 
i   udev                    - /dev/ and hotplug management daemon       
i   vim-common              - Vi IMproved - Common files                
p   vim-tiny                - Vi IMproved - enhanced vi editor - compact
i   wget                    - retrieves files from the web              
i   whiptail                - Displays user-friendly dialog boxes from s

En Debian Jessie hay 64 paquetes important, 56 específicos de la arquitectura más 8 independientes de la arquitectura (all). Y, como he dicho, sólo apt es Essential, y por lo tanto obligatorio tenerlo instalado (más sus dependencias). El resto, aunque sea poco recomendable, el sistema de paquetes nos permite eliminarlos, y de hecho en mi caso podéis ver que tengo un un par de paquetes important desinstalados5.

Paquetes standard

Debian Jessie cuenta con 103 paquetes marcados con prioridad standard, divididos en 83 dependientes y 20 independientes de arquitectura. No voy a incluir la lista completa porque este artículo empieza a ser enormemente largo (y para estas alturas ya deberíais saber hacerlo vosotros mismos) pero sí diré que entre ellos se encuentran cosas que considero bastante básicas como at, file, info, time, telnet, ftp, el cliente de OpenSSH, patch, locales o bzip2, los intérpretes de perl y python (2.7), y luego cosas que me resulta más discutibles considerarlas básicas, como un servidor SMTP (exim4), un par de clientes de correo (mailx y mutt), m4, procmail, whois, el diccionario wamerican e incluso el propio aptitude. Además 45 de estos 103 paquetes son bibliotecas dinámicas que implementan funciones bastante básicas para el sistema: de seguridad, de red, de almacenamiento de datos, autenticación, criptografía, ... Otros paquetes de prioridad standard enlazan con estas bibliotecas, y por eso están aquí.

Tampoco tengo instalados la totalidad de los paquetes de prioridad standard. En concreto no tengo instalados 11 paquetes, de los cuales 8 son bibliotecas dinámicas (sobre todo relacionadas con el sistema de autenticación Kerberos), dos más son paquetes perl (?), y el último es un paquete "dummy" de transición que sólo existe para asegurarse que al actualizar la distribución el nuevo bind9-host se instala si teníamos instalado el antiguo host.

Paquetes optional y extra

Si bien los paquetes de alta prioridad (que sumados son 231 paquetes) son los que permiten tener la distribución Debian funcionando mínimamente, el grueso de la distribución la forman los paquetes con prioridad optional (31.102 paquetes) y extra (11.669 paquetes), hasta llegar a los 42.996 paquetes nativos que hay en total6. Son los paquetes con estas prioridades sobre los que voy a trabajar, ya que si algo fuera mal al menos tengo la certeza de que el sistema no va a quedar inusable (al menos no para los que estamos acostumbrados a manejarnos en la línea de comandos).

Paquetes automáticamente instalados

Previamente hemos visto en algunos de los listados de paquetes el indicador 'A', que significa que dicho paquete ha sido instalado automáticamente. Dicho indicador es una información que apt-get o aptitude añade a la base de datos de paquetes instalados cuando un paquete es instalado no porque sea solicitado por el usuario, sino porque la propia herramienta decide instalarlo para resolver una dependencia. El objeto de guardar esta información es desinstalar automáticamente estos paquetes 'A' cuando desinstalamos el paquete o los paquetes que provocaron la instalación por dependencia. De esta forma, mantenemos la distribución libre de paquetes innecesarios.

Desgraciadamente, esto es sólo la teoría. En la práctica, ha habido una serie de bugs que hacían que en algunas circunstancias esta información desapareciera, lo que significaba que cuando posteriormente desinstalábamos los paquetes, sus dependencias no se desinstalaran y permanecieran en el sistema a pesar de no ser requeridos por ningún otro paquete. Actualmente parece que todos esos bugs han sido corregidos, pero si lleváis como yo mucho tiempo con la misma distribución Debian, pasando de versión en versión, es muy posible que tengáis paquetes que en un momento dado hayan perdido su indicador 'A' y permanezcan innecesariamente instalados en vuestro sistema por esta causa. Esto se da especialmente con paquetes de bibliotecas dinámicas.

Hay varios motivos por lo que no es deseable tener paquetes instalados que en realidad no se usan. El principal motivo es que como todo software tiene bugs aún por descubrir, cuanto más software tenemos instalado más bugs tenemos en nuestro sistema, esperando el momento adecuado para fastidiarnos. Y esto es especialmente importante cuando un porcentaje de esos bugs son bugs de seguridad. Reducir la cantidad de sofware instalado significa reducir lo que se llama la "superficie de ataque", por lo que tener software en nuestro sistema cuando en realidad no lo necesitamos es siempre una mala idea. Además, siempre supone una ocupación de recursos adicional, que si bien la ocupación de disco hoy en día suele ser despreciable, no lo es tanto cuando tenemos en cuenta que esos paquetes también se actualizan por la red y por lo tanto consumen ancho de banda (tanto nuestro ancho de banda como el de los repositorios de Debian), y también se tienen que computar una y otra vez a la hora de resolver dependencias. Un montón de ciclos de procesador y de bits movidos por la red innecesario y que no aporta nada.

Entrando en faena

Todo esto ha sido una larga explicación para lo que luego van a ser unos pocos comandos, pero he creído que es importante conocer el contexto. No me gustan las "recetas" que sueltan los comandos sin más para que se ejecuten "mágicamente". Basta que algún detalle haya cambiado o el entorno donde se ejecuten los comandos no sea exactamente el mismo para que la "solución" se convierta en un problema aun mayor.

De todas formas, a pesar de que las operaciones que voy a utilizar no las considero peligrosas, voy a hacer el habitual disclaimer y a decir eso de úsalas bajo tu propia responsabilidad. Probablemente la gran mayoría de los que estéis leyendo esta enorme pared de texto sabéis perfectamente lo que hacéis y no necesitaba decirlo, pero uno nunca sabe quién va a terminar leyendo esto y qué tipo de FrankenDebian tendrá7.

Ya he dicho previamente que, para minimizar riesgos, sólo voy a jugar con paquetes con prioridades bajas optional o extra de forma que lo peor que pueda pasar es que desinstalemos algo de lo que dependa el sistema gráfico. Así que empezaré echando un vistazo a los paquetes NO automáticamente instalados que tenemos en esas dos prioridades:

aptitude search "?or(?priority(optional),?priority(extra)) ?installed ?not(?automatic)"

La lista obtenida os tiene que resultar muy familiar, porque son —o mejor dicho deberían ser— los paquetes que habéis ido instalando manualmente a lo largo del tiempo. Si en esa lista hay muchos nombres que no os suenan, sobre todo de bibliotecas dinámicas lib*, es que es muy posible que durante un tiempo hayáis sido victimas de los bugs que hacen desaparecer el indicador automatic de automáticamente instalado (aunque ya haya sido corregido).

Por fortuna, la pérdida del indicador automatic es fácilmente subsanable. Si estáis positivamente seguros que un paquete se instaló automáticamente por dependencias de otro, y queréis que recupere el indicador 'A' de automáticamente instalado, aptitude nos permite hacerlo mediante markauto:

aptitude markauto un-paquete otro-paquete mas-paquetes ...

Mucho cuidado con marcar como automático un paquete que no tenga otro que dependa de él, o en la próxima operación sobre paquetes aptitude (o apt-get) intentará borrarlo "porque ya no es necesario".

Sin embargo, revisar los paquetes uno a uno y marcarlos como automáticamente instalados no es algo práctico, salvo que la lista sea muy reducida. Necesitamos un método rápido para obtener qué paquetes nos interesa marcar como automáticamente instalados. Por ejemplo, si pudiéramos seleccionar todas esas bibliotecas dinámicas... Pues bien, sí que podemos, usando el término de selección ?section:

aptitude search "?or(?priority(optional),?priority(extra)) ?installed ?not(?automatic) ?section(libs)"

Este comando nos listará todas las bibliotecas dinámicas (paquetes de la sección libs) con prioridad optional o extra que estén instaladas, pero que no estén marcadas como instaladas automáticamente. Justo lo que estábamos buscando. Y lo realmente interesante es que aptitude nos permite usar la misma expresión para marcar todas como 'A' a la vez, sin tener que hacerlo paquete por paquete.

Pero como este marcado masivo es la operación peligrosa (si marcamos lo que no debemos), antes de hacerlo nos debemos preguntar: ¿es realmente seguro marcar todas las bibliotecas dinámicas como instaladas automáticamente? En general, sí: las bibliotecas dinámicas no tienen entidad por sí mismas, sólo funcionan cuando son enlazadas desde un ejecutable, lo que nos debería garantizar que existe una dependencia del paquete del ejecutable al de la biblioteca dinámica. Sin embargo, hay algunas excepciones a tener en cuenta. Si ejecuto el comando anterior en mi sistema (que ya ha pasado por este proceso), me devuelve:

$ aptitude search "?or(?priority(optional),?priority(extra)) ?installed ?not(?automatic) ?section(libs)"
i   gstreamer0.10-plugins-ugly  - Complementos de GStreamer del conjunto «ugly»                                
i   gstreamer1.0-libav          - libav plugin for GStreamer                                                   
i   libdvdcss2                  - library designed for accessing DVDs

Como veis, aún tengo tres bibliotecas dinámicas instaladas "manualmente", y las tengo así intencionadamente. Las dos primeras las instalé para solucionar mis problemas con tumbler, y la última es una biblioteca compilada a mano. El caso es que no quiero que ninguna de estas tres bibliotecas dinámicas se desinstalen automáticamente aunque en un momento dado no tengan aparentes dependencias. En el caso de las dos primeras, el problema es que hay una dependencia de funcionalidad no expresada en el grafo de dependencias de Debian (si están disponibles, tumbler usa estas bibliotecas para mostrar el icono de ciertos tipos de videos, si no usa un icono genérico), y en la tercera porque no está en los repositorios (así que, si me la borrara, la tendría que recrear a mano).

No es casualidad que las tres bibliotecas sean "problemáticas de distribuir" por asuntos legales (patentes, etc). Esto hace que programas que en otra situación tendrían una dependencia directa, las usen indirecta u opcionalmente, tratando de evitar dependencias de paquetes que pueden no estar disponibles.

El caso es que podéis encontraros con la misma situación que yo, que ciertas bibliotecas como las mencionadas no sea buena idea tenerlas como automáticamente instaladas para que el gestor de paquetes no trate de eliminarlas por su cuenta, pese a ser necesarias para que ciertas características (¡como la reproducción de videos MPEG4!) funcionen. Así que no nos queda otra línea de acción que primero marcar todas como 'A' e inmediatamente a continuación "desmarcar" la 'A' de las excepciones usando aptitude unmarkauto.

Así que, resumiendo:

  • marcar todas las bibliotecas dinámicas como automáticas con markauto
  • desmarcar con unmarkauto las bibliotecas "problemáticas" (como las -plugin-bad, -plugins-ugly, -libav y -ffmpeg de gstreamer).
  • invocar aptitude install para que aptitude haga lo que tenga que hacer y desinstale lo que ya no se use y esté marcado como automáticamente instalado

Lo que se traduce en los comandos:

$ aptitude markauto "?or(?priority(optional),?priority(extra)) ?installed ?not(?automatic) ?section(libs)"
$ aptitude unmarkauto gstreamer0.10-plugins-ugly gstreamer0.10-plugins-bad gstreamer1.0-libav ...
# aptitude install

Y ahora, si todo hay ido bien, aptitude querrá desinstalar un puñado de bibliotecas dinámicas innecesarias.

Problemas: si la lista de paquetes a eliminar resultara ser monstruosamente grande, y sobre todo si hay en ella paquetes que sabes que no deberían borrarse, aun te queda la posibilidad de abortar la operación. Por desgracia, no se puede volver a la situación anterior a la del markauto, por lo que deberás averiguar qué paquetes no deberías haber marcado como automáticos y hacerles un "unmarkauto". O, como solución de última instancia, hacer un unmarkauto masivo usando la misma expresión (pero perderías la 'A' de absolutamente todas las bibliotecas de las prioridades seleccionadas).

De todas formas, lo normal es que todo haya ido bien y las bibliotecas dinámicas habrán sido todas marcadas como automáticas y eliminadas las no usadas. Haciendo una nueva búsqueda con aptitude search no deberían aparecer más bibliotecas que aquellas que hayas preservado con unmarkauto.

Tras la limpieza de bibliotecas, la lista de paquetes instalados (excluyendo la sección de bibliotecas dinámicas que ya ha sido tratada) sin indicador 'A' debería aproximarse mucho a los paquetes que hemos ido instalando manualmente en el sistema durante su vida:

aptitude search "?or(?priority(optional),?priority(extra)) ?installed ?not(?automatic) ?not(?section(libs))"

Si no es así, lo que nos queda es trabajo manual: averiguar cuáles tienen pinta de haber sido instalados por otros paquetes (aptitude why puede ayudar aquí) y marcarlos con markauto. También podemos aprovechar y extender la limpieza a esos paquetes que instalamos manualmente y ya no usamos, o que ni nos acordábamos que estaban ahí.

¿Aplicar sobre prioridades altas?

Si habéis tenido éxito, tal vez estéis sopesando si no deberíais hacer lo mismo sobre los paquetes de prioridad más alta (required, important y standard). Mi respuesta es que, dado el pequeño número de paquetes en estas prioridades, y su importancia, en general no creo que merezca la pena. Personalmente, lo he aplicado sobre los paquetes de prioridad estandard, pero sólo despues de comprobar exhaustivamente que no iba a romper nada. Mucho trabajo para librarse de ¿7? paquetes.

Sin embargo, tampoco es algo a desestimar a la ligera: al ser paquetes muy frecuentemente instalados, son candidatos ideales para utilizar sus vulnerabilidades en exploits y ataques. Cada paquete desinstalado de este tipo ayuda a reducir significativamente la superficie de ataque del sistema, lo cual puede hacer merecer la pena el esfuerzo adicional de investigación.

¿Y deborphan?

Algunos os estaréis preguntando por que no he utilizado deborphan, que es precisamente una herramienta para buscar paquetes huérfanos sin dependencias, en vez de montar todo este tinglado. Primero, porque deborphan usa un heurístico8 muy similar al que hemos utilizado aquí mediante aptitude search, pero que opera sobre todos los paquetes sin importar su prioridad. Por defecto, deborphan también busca paquetes instalados de las secciones libs (y oldlibs) sin dependencias hacia ellos. De hecho, los paquetes devueltos por deborphan y los devueltos por la expresión de aptitude que hemos utilizado deberían ser los mismos, si exceptuamos que deborphan mostrará tambien los de prioridad required, important y standard (y la sección oldlibs), algo que ya he explicado que yo no quería por considerar que aumentaba las probabilidades de una pifia.

Segundo, porque deborphan en realidad sólo sugiere paquetes a borrar, pero no los borra ni marca ni nada. Usar aptitude nos ha permitido no sólo mostrar paquetes sino aplicar operaciones sobre ellos sin tener que ir uno a uno.

Y tercero, y lo más importante: porque aprendiendo a usar herramientas generales nos permite hacer muchas más cosas que las que nos permiten hacer herramientas específicas. ¿Que quisieramos por ejemplo marcar como automáticamente instalados todos los paquetes cuyo nombre termina en -common? Fácil, sólo tenemos que ampliar nuestro repertorio con el término de búsqueda ?name() y usar una sencilla expresión regular.

Por supuesto, así como todo gran poder conlleva una gran responsabilidad, toda herramienta potente conlleva una gran potencia de fuego contra nuestras extremidades inferiores. Lo que significa que es importante conocer el sistema y saber lo que se está haciendo, por si algo saliera mal.

:wq


  1. aunque no lo indique, todos los comandos los he prefijado con LANG=C para que la salida por pantalla sea siempre la misma independiementemente del idioma configurado 

  2. esta regla de los paquetes esenciales sólo se aplica a los paquetes de la arquitectura nativa, para el resto de arquitecturas los paquetes esenciales no tienen por qué estar instalados —y de hecho no lo están— 

  3. la razón de poder instalar varias versiones del mismo compilador da para su propio artículo 

  4. y lapiz y papel, para anotar qué paquetes —las dependencias— tenías que instalar antes que cuáles 

  5. tengo la versión completa de vim instalada, así que vim-tiny es superfluo; y en cuanto a nfacct no parece que me haya hecho falta hasta ahora 

  6. no os salen las cuentas por esto: aptitude search "?and(?priority(optional),?priority(extra)) ?architecture(native)" (es evidente que esos paquetes están mal construidos) 

  7. al fin y al cabo de lo único que podemos estar realmente seguros es de la muerte y de los impuestos 

  8. ese es el heurístico por defecto, pero tiene otros, ver man deborphan para más detalles 

blogroll

social