Archivo por años: 2016

Más Gentoo para MipsEL

Estoy actualizando la distribución de Gentoo para webtv y, como no podía ser de otra manera, hay problemillas. El último ha sido con busybox. Para poder compilarla hay que añadir, además de las opciones que indico en Generando Gentoo para WebTV, hay que añadir las siguientes:

busybox_config_option n NANDWRITE
busybox_config_option n NANDDUMP
busybox_config_option n FLASH_ERASEALL
busybox_config_option n FLASHCP
busybox_config_option n BLKDISCARD

Por otro lado, la variable USE debe contener:

USE="${ARCH} -pam -fortran -sanitize -X -iptables -hardened -seccomp -ipv6 -systemd -mdev internal-glib -caps -gtk -qt -t -boehm-gc -nls -filecaps"

Preparando Gentoo de nuevo

Estoy preparando una nueva versión de Transmission para el WebTV, y como perdí el sistema Gentoo que había construido hace tiempo he tenido que volver a generarlo, siguiendo mis propias notas.

Sin embargo esta vez me apareció un problema extra una vez finalizado todo. Para empezar, Python siguió dando problemas, así que compilé la versión 3.4 de manera cruzada y dejé para compilar en nativo la versión 3.5. Pero una vez compilado todo, y tras entrar con systemd-nspawn, me encuentro con que varios comandos, entre ellos el importantísimo emerge, devuelven un error rarísimo:

mipsel-unknown-linux-gnu / # env-update
Traceback (most recent call last):
  File "/usr/lib/python-exec/python3.4/env-update", line 31, in 
    import portage
ImportError: No module named 'portage'

Tras muchas pruebas, descubrí que el problema era que, como el sistema gentoo nativo era de 64 bits, metió muchas bibliotecas en /usr/lib64, directorio que el sistema Mipsel no encontraba porque es de 32 bits.

La solución fue tan sencilla como copiar recursivamente /usr/lib64 a /usr/lib.

El cubo III

Cuando actualicé mi PC hace unos años, opté por deshacerme del viejo Cubo II y utilizar una caja comercial cúbica. Luego volví a actualizar el ordenador y pasé a una caja clásica. Finalmente, hace unos meses, decidí que era hora de darle un poco a la carpintería, así que decidí construir una caja nueva.

Tras darle varias vueltas, sopesando posibles materiales, de pronto caí en la cuenta de que podía aprovechar la vieja caja cúbica. Esta caja era bastante grande, así que podía intentar reducirla a un tamaño más manejable (pulsar sobre las imágenes para verlas más grandes).

caja_pequena_2 caja_pequena_1

Esta es la caja original. No es realmente muy grande, pero aún así, dado que está pensada para contener placas MicroATX, dos unidades de 5 1/4 y una de 3 1/2 externas, y hasta dos discos duros internos, es obvio que sobra mucho espacio. Sobre todo cuando yo ya no uso el DVD para nada.

Lo primero que hice fue desmontarla completamente y dejar sólo el armazón.

caja_pequena_3

Vemos que hay dos piezas que van desde el frontal hasta la parte posterior y que, además de dar más solidez a la caja, permiten sostener las unidades externas; sobre una de ellas, además, se apoyan los discos duros y la fuente de alimentación. También hay una barra metálica en el otro lado. Las piezas están sujetas con remaches, que quité reventándolos con el taladro. La barra está atornillada, así que no tuvo ninguna dificultad.

caja_pequena_4

El siguiente paso consistió en cortar el chasis para acortarlo. Decidí reducirlo a lo mínimo que me permitiese la base donde se atornilla la placa madre (que es una pieza independiente). También recorté las dos mitades en altura, teniendo en cuenta el tamaño de la fuente de alimentación y la mínima altura a la que la podría poner.caja_pequena_5 caja_pequena_6

Una vez hecho esto, uní ambas mitades con remaches, consiguiendo así el chasis del tamaño que quería.

caja_pequena_7

A continuación, recorté la barra para ajustarla al tamaño, la limé bien para quitarle asperezas, y le hice un agujero en el lado recortado para poder fijarla con un tornillo en los mismos agujeros del chasis donde estaba originalmente.

caja_pequena_8 caja_pequena_9

Ahora tenía que añadir la pieza que va desde el frontal hasta la parte posterior, para poder apoyar la fuente de alimentación. Para ello eliminé primero los soportes de las unidades externas (usando el taladro, como en la primera foto), y la fijé boca arriba para poder recortar cómodamente los laterales con la dremel.

caja_pequena_11

Hecho esto, la fijé boca abajo sobre un listón y recorté la parte central, dejando unos dos centímetros extra de manera que dispusiese de una lengüeta, necesaria para fijar la pieza en el otro lado de la caja.

caja_pequena_12 caja_pequena_13

Doblé la lengüeta de manera que quedase perpendicular a la parte superior. Para que quedase lo mejor posible puse la pieza boca abajo de nuevo y la fijé con un listón, cuyo borde estaba situado justo en el punto de doblez. Luego sólo tuve que ir golpeando poco a poco con el martillo hasta conseguir dejarla exactamente como deseaba. El listón garantizó que sólo se doblará por donde me interesaba.

caja_pequena_14

Hecho esto, hice dos agujeros en los puntos adecuados y sujeté la pieza con unos remaches. Con esto terminé el chasis.

caja_pequena_15

Ahora le tocaba el turno a la fuente de alimentación. La coloqué sobre la pieza y recorté la zona de la rejilla de la parte posterior para dejar libres los conectores, además de hacer algún agujero extra para los tornillos.

caja_pequena_16

Llegó el turno de construir el frontal. Al principio había probado a recortar y recomponer el original, pero quedaba fatal, así que decidí hacer yo mismo uno nuevo. Y ya puestos, decidí darle algo de estilo, así que lo hice directamente en madera. Lo primero fue conseguir un trozo de tablero del tamaño deseado para el frontal y marcar en él qué zonas se van a recortar para colocar los conectores delanteros. En este caso dejé hueco para un lector de tarjetas, los conectores de audio, dos USB 2.0, dos USB 3.0 y dos eSATA.

caja_pequena_17

Procuré que la veta de la madera quedase en la misma dirección que los cortes más largos, pues simplifica el trabajo. A continuación fijé un listón de madera bien recto en cada una de las líneas a recortar, y usé un cincel de madera para recortar hasta una profundidad de unos cinco milímetros. El cincel lo iba apoyando en el listón para asegurarme de que el corte fuese lo más recto posible.

caja_pequena_18 caja_pequena_19

Una vez hechos todos los cortes, le di la vuelta a la tabla y usé una fresa para ir rebajando (poco a poco, unos milímetros de cada vez) por el lado opuesto las zonas de cada conector, hasta quedar a unos cuatro milímetros del frontal. Al hacerlo, los cortes que hice antes con el cincel hicieron que la pieza interna de los agujeros se soltase, quedando así libres.

caja_pequena_20

El siguiente paso fue lijar a conciencia la superficie, limar los bordes de los agujeros para dejarlos regulares y lisos, recortar los bordes del tablero con una fresa para darles un acabado redondeado, y barnizarla con tres capas de barniz. Este es el resultado definitivo, junto con los tres intentos fallidos anteriores.

caja_pequena_21

Luego ya sólo hubo que añadir el botón de encendido, los LEDs y los conectores por el lado trasero.

caja_pequena_22 caja_pequena_23

El siguiente paso fue el soporte del disco duro. Partí del mismo que tenía la caja vieja, pero lo recorté (el original tenía espacio para dos discos duros apilados, pero quedaba muy pegado a la tarjeta gráfica).

caja_pequena_28 caja_pequena_29

A continuación enderecé y volví a doblar la lengüeta superior para «colgar» el soporte de la barra que cruza la caja. Para ello utilicé un destornillador con el mismo diámetro que la barra, y el martillo. También recorté el lateral izquierdo para hacer una pestaña que encajase en la parte izquierda, para así sujetar el soporte a la caja con un remache (en la segunda foto, es la pestaña situada encima de las aberturas de las tarjetas de expansión, a la izquierda).

caja_pequena_30 caja_pequena_31

Por último, enderecé la pestaña de la derecha y le fijé un soporte para discos de 2 1/2 pulgadas, porque quería añadir un disco SSD a mi equipo.

caja_pequena_32

Y así quedaron ambos discos, ya montados y conectados.

caja_pequena_33

El último paso fue preparar la tapa y las paredes laterales. La tapa la recorté un centímetro más larga de lo necesario, y luego coloqué una tabla para doblarla en ángulo con el martillo. Esa zona quedó hacia atrás.

caja_pequena_24

Por último, las paredes. Comencé colocando las láminas originales en su sitio para marcar los dos cortes necesarios.

caja_pequena_25

Luego corté dejando un centímetro de más tanto por arriba como por detrás. La esquina común a ambos cortes la corté en chaflán. A continuación, usando una vez más un listón sujeto con dos sargentas y el martillo, procedí a doblar 180 grados el trozo que sobra. Al haber cortado en chaflán la esquina común, las dos lengüetas no se solaparon (como se puede ver en la tercera fotografía).

caja_pequena_26 caja_pequena_27

caja_pequena_35

Y este es el resultado final, una vez ensamblado todo y, por supuesto, darle una mano de pintura negra en spray: una caja que ocupa, aproximadamente, 2/3 del volumen de la caja original.

caja_pequena_34

Cargando fácilmente mis cascos

Hace tiempo acabé cansado de mis cascos con cable: se enredaban con todo, y a menudo me olvidaba que los llevaba puestos, con lo que, al levantarme, me daban un tirón. Es por esto que decidí comprar unos cascos inalámbricos. Además, para evitar interferencias o que los vecinos puedan escuchar desde otro equipo lo que estoy viendo en ese momento (cof, cof-porno-cof, cof), decidí usar unos cascos bluetooth. Compré unos bastante baratos, pero eran incómodos, así que trasplanté la circuitería a mis viejos cascos de cable.

Todo funcionaba bien, excepto por un detalle: cada dos por tres me encontraba sin batería porque me los quitaba y no los enchufaba al cargador, con lo que tenía que usarlos durante un buen rato con el cable enchufado, perdiendo así las ventajas. Ante esto empecé a pensar en maneras de recargar la batería de una manera más automática. La primera idea fue utilizar carga inalámbrica: montaría un soporte para los cascos con una bobina sobre él; a su vez, una segunda bobina montada en la diadema de los cascos estaría conectada a los pines de recarga. Así, al colocarlos en el soporte, ambas bobinas quedarían alineadas formando un transformador, igual que se hace en los sistemas de carga inalámbrica de los móviles. Por desgracia, aunque la teoría era muy sencilla, la práctica no lo era tanto: hacía falta un oscilador para alimentar la primera bobina, ajustar la impedancia del conjunto para que estuviese en resonancia… un cristo.

Decidí entonces probar una aproximación más pedestre: colocaría un par de contactos metálicos en la diadema que coincidiesen con otros situados en un soporte, de manera que cuando colgase los cascos éstos recibirían alimentación directamente. La primera idea fue colocar dos contactos en los laterales de la diadema para uno de los polos, y otro en el centro, por debajo, para el otro. De esta manera no habría riesgo de invertir la polaridad si colgaba los cascos al revés. Sin embargo, enseguida deseché esta opción por dos motivos: para empezar, no era sencillo construir un soporte con los tres contactos; y por otro, no me gustaba la idea de tener un contacto metálico apoyado en mi cuero cabelludo (con el sudor acabaría estropeándose). Tras darle varias vueltas, decidí que la mejor opción era usar sólo dos contactos, situados en cada lado de la diadema. Para evitar estropear los cascos por recibir la polaridad al revés si los colgaba mal, decidí añadir un puente de diodos entre los contactos y el circuito de carga. Por desgracia, a la salida tendría 1,4 voltios menos que en la entrada por culpa de las pérdidas de los diodos, y, por otro lado, no quería correr el riesgo de alimentar un dispositivo con una batería de Li-ion con una tensión excesiva(y menos si está situada junto a mi oreja) .

Dado que el diseño original estaba pensado para cargarse desde un USB y, por tanto, la tensión tenía que ser de 5V estabilizados, decidí añadir un regulador justo entre el puente de diodos y el circuito bluetooth. La primera idea que me vino a la cabeza fue el clásico 7805, pero dado que es un regulador lineal, podría tener problemas de sobrecalentamiento (y, una vez más, hay que recordar que eso va a ir pegado a nuestra oreja…), así que lo sustituí por un regulador conmutado, en concreto un TSRN 1-2450 de la marca TRACO. Gracias a él, podría usar cualquier tensión superior a 8 voltios en la entrada del circuito sin riesgo de quemar nada orgánico.

El sistema, finalmente, quedó así:

esquematico

Vemos que la tensión (que no es necesario que esté estabilizada) disponible en el soporte llega a los cascos mediante dos contactos metálicos situados a cada lado de la diadema. Esta tensión (que puede ir con cualquiera de las dos posibles polaridades) llega al puente de diodos, que nos garantiza tener el positivo y el negativo donde nos interesa, pero con una pérdida de 1,4 voltios (con lo que tendremos entre 7,6 y 10,6 voltios). A continuación viene el regulador de tensión, que nos proporciona los 5 voltios estabilizados que necesitamos para el circuito bluetooth.

Una vez diseñado llegó el momento de construirlo, y aquí fue donde empezaron los problemas, en concreto el problema de como hacer los contactos. La primera idea fue utilizar lámina de cobre, pero no fui capaz de encontrarla en ningún lugar. Decidí probar con papel de aluminio: supuse que, si iba bien pegado, no debería haber riesgo de rotura, y sería muy sencillo de fabricar al poder aplicar una capa de loctite primero, pegar encima el papel, y luego recortar con un cutter. Por desgracia el invento no aguantó ni dos días (no sólo el papel de aluminio es demasiado frágil, sino que el loctite no se adhiere nada bien a él). Empecé a buscar alternativas, llegando incluso a intentar hacer una especie de trenza con cable de cobre, pero no encontraba nada que fuese adecuado.

Y de pronto, la solución apareció por pura casualidad: malla de desoldar.

desoldar

Para los que no la conozcan, se trata de cable fino de cobre trenzado formando una tira plana, utilizado para desoldar componentes: básicamente se coloca encima del estaño que se quiere retirar y se calienta el conjunto con el soldador. Cuando el estaño se funde, la malla lo absorbe por capilaridad, quedando el punto completamente libre.

Probé a pegarlo con loctite y el resultado fue excelente… hasta que intenté alimentar el circuito: la malla había absorbido el loctite por capilaridad, por lo que había quedado completamente cubierta y ya no era conductora. Probé también con pistola de pegamento térmico, pero no agarraba en el cobre y se soltaba.

Entonces decidí hacer una prueba a la desesperada, así que fui a la papelería de enfrente de mi casa y compré cinta adhesiva de doble cara, la apliqué en ambos lados de la diadema, pegué la malla poco a poco pasando la uña fuertemente por encima para asegurarme de que quedase bien pegada, y recorté los trozos sobrantes con un cutter. El resultado fue perfecto, y es capaz de aguantar muy bien el rozamiento diario de colgarlo y quitarlo del soporte:

contactos

La cinta aislante negra colocada en los dos extremos es para evitar que la malla se suelte: aunque a lo largo queda muy bien fijada, en los extremos es muy fácil que se acabe levantando, lo que acaba en un «efecto cremallera». Es por esto que es fundamental protegerla de esta manera si queremos que nos dure mucho tiempo.

Para el soporte utilicé una alcayata grande en forma de L, y para los contactos aproveché las láminas de una pila de 4,5 voltios (la clásica «pila de petaca»):

pila_de_petaca

Con ellos hice dos contactos, uno en cada lado, y los conecté a un alimentador de 12 voltios:

soporte

El resultado no es muy elegante y puede mejorarse, lo reconozco, pero será cuando tenga algo de tiempo.

Y este es el resultado final: ahora sólo tengo que asegurarme de colgar los cascos en el soporte y siempre estarán cargados y listos para su uso.

completo

Multipackager más rápido

He lanzado una nueva versión de Multipackager con una interesante novedad: ahora es muchísimo más rápido. Para ello utilizo OverlayFS.

Para entender por qué es así, cabe explicar que cada vez que se utiliza por primera vez un sistema operativo concreto (por ejemplo: debian jessie i386), multipackager genera dos copias: una para construir paquetes, y otra para lanzar shells.

Hasta aquí nada especial. Sin embargo, la copia para construir paquetes no se utiliza nunca directamente. Cuando se va a construir uno, lo primero que se hace es sacar una copia de dicha copia, y sólo entonces se instalan los paquetes necesarios para crear el paquete. Si todo va bien se borra la copia vieja, y ya tenemos la máquina original con nuevos paquetes; si algo falla, se borra la copia nueva y se restaura la vieja. Así nunca se queda un sistema «a medias». Por último se hace una nueva copia para crear, esta vez sí, dentro de ella el nuevo paquete. Esta copia se destruye una vez que se ha terminado la generación.

Este sistema permite garantizar que las copias locales de cada sistema operativo están siempre «sanas», lo que evita tener que generar una nueva completa cada vez que queramos crear un paquete. El inconveniente es que sacar cada copia lleva MUCHO tiempo. Y lo que es peor: a medida que se instalan más y más paquetes, la copia tarda más y más.

La solución consistió en no hacer copias, sino utilizar OverlayFS para poder realizar las operaciones sin modificar la máquina original. Esta operativa es inmediata en el segundo caso, cuando queremos construir el paquete en una máquina que se borrará cuando se termine. Sin embargo, para el primer caso tuve que rascarme un poco la cabeza, pues si la operación de instalar paquetes termina correctamente es necesario «aplicar los cambios» sobre la máquina virtual original. Esta operación, afortunadamente, no es muy complicada.

El resultado es que los tiempos para generar los distintos paquetes se han reducido en un orden de magnitud, lo que no está nada mal, teniendo en cuenta que actualmente estoy generando entre seis y ocho paquetes por programa (debian, ubuntu, fedora y arch, cada una en 32 y 64 bits).

Más sobre Debian en Android

A raíz de la aparición de MaruOS, decidí intentar hacer algo similar en mi móvil Android, así que me puse a preparar una instalación de Debian para Android como ya había hecho otras veces. Por desgracia las cosas se torcieron ya al principio, así que voy a comentar los pasos que di para corregir los problemas que encontré, que no han sido pocos:

Para empezar, mi móvil tiene Android 6 (en concreto la distribución PureNexus para Nexus 4 que encontré en la página de El tendero digital). Parece que algunos cambios de seguridad hechos en él, junto con otros en APT fueron los que acabaron dando guerra. Pero no adelantemos acontecimientos…

Empecé creando el entorno básico con debootstrap, con el comando

sudo debootstrap --arch=armhf --variant=minbase --foreign sid  /home/raster/tmp  http://ftp.debian.org/debian

El resultado lo comprimí con TAR, lo pasé al móvil, y me conecté a través de USB con un shell ADB (para disponer de ADB hay que bajarse el SDK de Android):

sudo ./platform-tools/adb shell

Una vez hecho esto, lo primero es ejecutar el comando resize para ajustar el tamaño lógico de la ventana a la que tenemos físicamente, y que aplicaciones como los editores de texto y demás se vean correctamente.

Tras ello, fui hasta /data/media/0, que es donde se encuentra la zona de datos de usuario, y allí descomprimí el fichero .tar con el sistema Debian básico. Luego usé un sencillo script para entrar dentro de él para seguir la instalación:

resize
export SDCARD=/data
export ROOT=$SDCARD/media/0/debian
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
export HOME=/root
mount -o remount,exec,dev,suid $SDCARD
for f in dev dev/pts proc sys ; do mount -o bind /$f $ROOT/$f ; done
chroot $ROOT /bin/bash -l
for f in sys proc dev/pts dev ; do umount $ROOT/$f ; done

Tras lanzarlo, procedí a terminar la instalación del sistema, pero me encontré con que al ejecutar debootstrap/debootstrap –second-stage, fallaba y no continuaba la instalación. Tras varias pruebas, descubrí que el problema era que intentaba crear varias veces una serie de nodos en /dev.

Se me ocurrió probar a usar QEMU para realizar la operación en mi propio PC, así que instalé qemu-static, copié qemu-arm-static al directorio /usr/bin del sistema Debian sin configurar, y lancé una sesión de shell dentro de ella con CHROOT en mi propio PC. Ahí el comando debootstrap/debootstrap –second-stage sí funcionó, así que procedí a comprimir el sistema ya listo y subirlo al móvil.

Ahora ya tenía un sistema Debian. O casi, porque cualquier intento de usar APT para instalar paquetes o actualizar la lista de programas fallaba con un error muy raro: no era capaz de resolver la dirección del repositorio:

root@localhost:/# apt-get update
Err:1 http://ftp.debian.org/debian sid InRelease
  Temporary failure resolving 'ftp.debian.org'
Reading package lists... Done
W: Failed to fetch http://ftp.debian.org/debian/dists/sid/InRelease  Temporary failure resolving 'ftp.debian.org'
W: Some index files failed to download. They have been ignored, or old ones used instead.

Sin embargo, un PING o un WGET a dicha dirección sí funcionaba perfectamente, por lo que no parecía ser un problema de la red en sí. Probé a poner manualmente la IP en el fichero /etc/hosts y entonces el error pasó a ser otro:

root@localhost:/# apt-get update
Ign:1 http://ftp.debian.org/debian sid InRelease
Ign:2 http://ftp.debian.org/debian sid Release
Ign:3 http://ftp.debian.org/debian sid/main armhf Packages.diff/Index
Ign:4 http://ftp.debian.org/debian sid/main all Packages
Ign:5 http://ftp.debian.org/debian sid/main Translation-en.diff/Index
Ign:6 http://ftp.debian.org/debian sid/contrib armhf Packages.diff/Index
Ign:7 http://ftp.debian.org/debian sid/contrib all Packages
Ign:8 http://ftp.debian.org/debian sid/contrib Translation-en.diff/Index
Ign:9 http://ftp.debian.org/debian sid/non-free armhf Packages.diff/Index
Ign:10 http://ftp.debian.org/debian sid/non-free all Packages
Ign:11 http://ftp.debian.org/debian sid/non-free Translation-en.diff/Index
Ign:12 http://ftp.debian.org/debian sid/main armhf Packages
Ign:4 http://ftp.debian.org/debian sid/main all Packages
Ign:13 http://ftp.debian.org/debian sid/main Translation-en
Ign:14 http://ftp.debian.org/debian sid/contrib armhf Packages
Ign:7 http://ftp.debian.org/debian sid/contrib all Packages
Ign:15 http://ftp.debian.org/debian sid/contrib Translation-en
Ign:16 http://ftp.debian.org/debian sid/non-free armhf Packages
Ign:10 http://ftp.debian.org/debian sid/non-free all Packages
Ign:17 http://ftp.debian.org/debian sid/non-free Translation-en
Ign:12 http://ftp.debian.org/debian sid/main armhf Packages
Ign:4 http://ftp.debian.org/debian sid/main all Packages
Ign:13 http://ftp.debian.org/debian sid/main Translation-en
Ign:14 http://ftp.debian.org/debian sid/contrib armhf Packages
Ign:7 http://ftp.debian.org/debian sid/contrib all Packages
Ign:15 http://ftp.debian.org/debian sid/contrib Translation-en
Ign:16 http://ftp.debian.org/debian sid/non-free armhf Packages
Ign:10 http://ftp.debian.org/debian sid/non-free all Packages
Ign:17 http://ftp.debian.org/debian sid/non-free Translation-en
Ign:12 http://ftp.debian.org/debian sid/main armhf Packages
Ign:4 http://ftp.debian.org/debian sid/main all Packages
Ign:13 http://ftp.debian.org/debian sid/main Translation-en
Ign:14 http://ftp.debian.org/debian sid/contrib armhf Packages
Ign:7 http://ftp.debian.org/debian sid/contrib all Packages
Ign:15 http://ftp.debian.org/debian sid/contrib Translation-en
Ign:16 http://ftp.debian.org/debian sid/non-free armhf Packages
Ign:10 http://ftp.debian.org/debian sid/non-free all Packages
Ign:17 http://ftp.debian.org/debian sid/non-free Translation-en
Ign:12 http://ftp.debian.org/debian sid/main armhf Packages
Ign:4 http://ftp.debian.org/debian sid/main all Packages
Ign:13 http://ftp.debian.org/debian sid/main Translation-en
Ign:14 http://ftp.debian.org/debian sid/contrib armhf Packages
Ign:7 http://ftp.debian.org/debian sid/contrib all Packages
Ign:15 http://ftp.debian.org/debian sid/contrib Translation-en
Ign:16 http://ftp.debian.org/debian sid/non-free armhf Packages
Ign:10 http://ftp.debian.org/debian sid/non-free all Packages
Ign:17 http://ftp.debian.org/debian sid/non-free Translation-en
Ign:12 http://ftp.debian.org/debian sid/main armhf Packages
Ign:4 http://ftp.debian.org/debian sid/main all Packages
Ign:13 http://ftp.debian.org/debian sid/main Translation-en
Ign:14 http://ftp.debian.org/debian sid/contrib armhf Packages
Ign:7 http://ftp.debian.org/debian sid/contrib all Packages
Ign:15 http://ftp.debian.org/debian sid/contrib Translation-en
Ign:16 http://ftp.debian.org/debian sid/non-free armhf Packages
Ign:10 http://ftp.debian.org/debian sid/non-free all Packages
Ign:17 http://ftp.debian.org/debian sid/non-free Translation-en
Err:12 http://ftp.debian.org/debian sid/main armhf Packages
  Could not create a socket for 130.89.148.12 (f=2 t=1 p=6) - socket (13: Permission denied)
Ign:13 http://ftp.debian.org/debian sid/main Translation-en
Err:14 http://ftp.debian.org/debian sid/contrib armhf Packages
  Could not create a socket for 130.89.148.12 (f=2 t=1 p=6) - socket (13: Permission denied)
Ign:15 http://ftp.debian.org/debian sid/contrib Translation-en
Err:16 http://ftp.debian.org/debian sid/non-free armhf Packages
  Could not create a socket for 130.89.148.12 (f=2 t=1 p=6) - socket (13: Permission denied)
Ign:17 http://ftp.debian.org/debian sid/non-free Translation-en
Reading package lists... Done
W: The repository 'http://ftp.debian.org/debian sid Release' does not have a Release file.
N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
N: See apt-secure(8) manpage for repository creation and user configuration details.
W: Failed to fetch http://ftp.debian.org/debian/dists/sid/main/binary-armhf/Packages  Could not create a socket for 130.89.148.12 (f=2 t=1 p=6) - socket (13: Permission denied)
W: Failed to fetch http://ftp.debian.org/debian/dists/sid/contrib/binary-armhf/Packages  Could not create a socket for 130.89.148.12 (f=2 t=1 p=6) - socket (13: Permission denied)
W: Failed to fetch http://ftp.debian.org/debian/dists/sid/non-free/binary-armhf/Packages  Could not create a socket for 130.89.148.12 (f=2 t=1 p=6) - socket (13: Permission denied)
E: Some index files failed to download. They have been ignored, or old ones used instead.

Esto era otra cosa, claramente: por algún motivo, APT no conseguía permisos para acceder a la red. Parecía un problema de SELINUX, pero realmente estaba en modo permisivo, por lo que no debería estar fallando.

Tras rebuscar por todas partes, descubrí una entrada donde se comentaba el mismo problema para Kali-Rolling en Android: la clave parece estar en que el usuario _apt está en el grupo nogroup, y eso en Android supone no tener acceso a nada, ni siquiera a la red. Para solucionarlo, sólo tuve que editar el fichero /etc/passwd y cambiar el grupo de _apt de 65534 (nogroup) a 3004, que aunque es un grupo que no existe en mi sistema, es suficiente para que todo vuelva a funcionar como debe.