Encender el HDMI de la Raspberry PI aunque no esté conectada a una pantalla

Todo empezó de manera inocente con este mensaje que escribí en el foro OSMC:

Title: Audio related messages flooding the logs when no HDMI display present

For “reasons”, during the christmas holidays, I am using my regular OSMC Raspberry PI device abroad with no HDMI cable connected to a screen. No display at all. This is useful to me because this device does other functions beside OSMC.

I noticed these messages flooding /home/osmc/.kodi/temp/kodi.log:

2024-12-27 02:00:52.928 T:688      info <general>: CActiveAESink::OpenSink - initialize sink
2024-12-27 02:00:52.929 T:688      info <general>: CAESinkALSA::Initialize - Attempting to open device "default"
2024-12-27 02:00:52.931 T:688      info <general>: CAESinkALSA - Unable to open device "default" for playback
2024-12-27 02:00:52.931 T:688     error <general>: CAESinkALSA::Initialize - failed to initialize device "default"
2024-12-27 02:00:52.931 T:688     error <general>: CActiveAESink::OpenSink - no sink was returned
2024-12-27 02:00:52.931 T:687     error <general>: ActiveAE::InitSink - returned error
2024-12-27 02:00:52.935 T:674     error <general>: failed to duplicate EGL fence fd (EGL_SUCCESS)

The logfile grows fast, possibly filling soon the microSD and decreasing its lifetime.

Beside that, maybe unrelated, KODI is using all the file descriptors (1024 in my case) trying to do “something”. Maybe related to those logs or not:

root@osmcpi:/home/osmc/.kodi/temp# ls -la /proc/674/fd|tail
lr-x------ 1 root root 64 Dec 27 02:03 990 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 991 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 992 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 993 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 994 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 995 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 996 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 997 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 998 -> anon_inode:sync_file
lr-x------ 1 root root 64 Dec 27 02:03 999 -> anon_inode:sync_file

Checking /proc/674/fdinfo/ I see this (the same data for any file descriptor):

root@osmcpi:/home/osmc/.kodi/temp# cat /proc/674/fdinfo/999
pos:    0
flags:  02000000
mnt_id: 14
ino:    7559

I can not determine what mount id 14 filesystem is, even using findmnt.

All filedescriptors stuck prevent my kodi extensions to work correctly, for instance, to update IMDb ratings or screensavers. Not very important while this raspberry is headless during this trip, but I wonder if both issues are related and how to prevent them.

Interestingly, if I plug the HDMI wire to a display, everything works fine.

So, my questions:

  • How can I avoid flooding the log my Raspberry PI is running OSMC while headless?. This is an old issue of mine with some friends’ raspberries OSMC when they switch off their TV.
  • What is the reason for having all file descriptors (1024) stuck and how to solve it?

Happy Holidays and thanks for your time.

This is a Raspberry PI 3B+, OSMC fully updated.

La respuesta fue apropiada, pero decepcionante: En vez de diagnosticar el problema el consejo fue desactivar KODI cuando esté utilizando la Raspberry PI sin una pantalla conectada. Por ejemplo, usando el comando systemctl stop mediacenter.

Poco satisfecho, seguí investigando. El problema de fondo es que, por defecto, cuando la Raspberry PI se enciende sin una pantalla HDMI conectada, no activa la salida HDMI, y sin dicha salida tampoco se activa, por defecto, el sistema de audio. Los errores que se muestran más arriba son los intentos de KODI de conectarse a un sistema de audio que, sencillamente, está desactivado.

Un efecto secundario es que si enchufamos la pantalla HDMI a la Raspberry PI una vez que esta está funcionando, no tendremos salida de vídeo hasta el próximo reinicio de la Raspberry PI con la pantalla conectada.

¿Cómo activar la salida HDMI de la Raspberry PI aunque no esté conectada a una pantalla? En realidad se trata de un problema común bastante bien documentado. Ejemplos:

La lista de ejemplos es infinita, pero la solución es simple, aunque en algunos casos es necesario algo de experimentación: Hay que añadir al fichero /boot/config.txt la línea hdmi_force_hotplug=1. Para asegurar que hay sonido, podemos añadir hdmi_drive=2.

Como casi siempre, lo mejor es acudir a la fuente:

Advertencia

Si forzamos encender el HDMI aún sin monitor, si no forzamos un modo concreto o hemos grabado la información EDID del monitor, la Raspberry PI arrancará con una resolución reducida y compatible con casi cualquier cosa. Eso está bien, pero la imagen puede verse mal por la baja resolución. Habría que reiniciar la Raspberry PI con una pantalla HDMI conectada o bien fijar una configuraciòn manual o un volcado EDID previo. Lo segundo funcionaría hasta que enchufemos algún monitor incompatible con los modos que hemos puesto manualmente...

Python 3.13: zlib.error: Error -2 while flushing: inconsistent stream state

Tras actualizar a Python 3.13 y mod_wsgi, tal y como se describe en Problema actualizando mis servicios WSGI a Python 3.13, empecé a ver estos errores en el log:

Exception ignored in: <gzip on 0x7fd58e3c6fb0>
Traceback (most recent call last):
  File "/usr/local/lib/python3.13/gzip.py", line 373, in close
    fileobj.write(self.compress.flush())
zlib.error: Error -2 while flushing: inconsistent stream state

La excepción no parece tener ningún efecto práctico en el programa, pero muestra que hay un problema a resolver.

Lo primero que llama la atención es que el traceback no parece completo, no indica qué código está llamando a la función close(). Ese detalle junto al mensaje Exception ignored in: indica que se trata de una excepción asíncrona que ocurre en un destructor.

Para saber qué parte del código está generando esa excepción (de forma asíncrona), podemos modificar el código añadiendo esto al principio:

 import sys, inspect
 class GzipFile(gzip.GzipFile):
     def __init__(self, *args, **kwargs):
         creador = inspect.stack()[1]
         self._creador = (creador.filename, creador.function, creador.lineno)
         del creador
         return super().__init__(*args, **kwargs)

     def close(self):
         try:
             print("CLOSE", file=sys.stderr)
             return super().close()
         except Exception as exc:
             print(self._creador, file=sys.stderr)
             raise

 gzip.GzipFile = GzipFile

Leer más…

Compilamos un "Bind" personalizado en SmartOS a partir de PkgSrc

Este artículo fusiona los anteriores:

Adicionalmente queremos tener en cuenta:

Advertencia

No voy a repetir detalles de fondo y repasos de la configuración. Para ello debería leer los artículos anteriores.

Con todo lo anterior, queda algo así:

Leer más…

Thunderbird "habla demasiado" (respecto a tu configuración)

El otro día estaba mirando las cabeceras SMTP de mis correos electrónicos y me he llevado una sorpresa:

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
            Thunderbird/102.15.1

Mi cliente de correo, Thunderbird, filtra la versión que estoy utilizando y que estoy usando Linux sobre x86-64.

Y esto no lo hace solo en los correos electrónicos salientes sino también en las conexiones HTTP que se generen al visualizar mensajes en formato HTML.

Esto me parece algo innecesario y un peligro de privacidad y de seguridad.

Afortunadamente podemos irnos al editor de configuración de Thunderbird y editar (o crear, si no existe) la preferencia general.useragent.override. Ahí ponemos el texto que nos de la gana.

En versiones modernas de Thunderbird podemos indicarle directamente al programa que sólo envie Thunderbird como identificación, sin referencias de plataforma o versiones. Para ello hay que entrar en el editor de configuración y poner (o crear) la preferencia mailnews.headers.useMinimalUserAgent a True. Si no queremos enviar una identificación de usuario en absoluto, podemos poner a False la preferencia mailnews.headers.sendUserAgent.

Podeis ver los detalles por vosotros mismos en el código fuente de Thunderbird, en su servidor Mercurial.

Cómo ver los detalles de la CPU en Illumos (por ejemplo, SmartOS)

En una máquina con sistema operativo basado en Illumos, como un SmartOS, podemos ver los detalles de su CPU con el siguiente comando:

[root@X ~]# kstat -p cpu_info:0:cpu_info0:brand
cpu_info:0:cpu_info0:brand      Intel(r) Core(tm) i7-6700 CPU @ 3.40GHz

Una vez que conocemos el modelo, podemos investigar sus características en infinidad de páginas online. Si lo que queremos es saber cuántos núcleos tiene esa CPU, sin andar buscando online, podemos ir probando valores de núcleo:

[root@X ~]# kstat -p cpu_info:0:cpu_info0:brand
cpu_info:0:cpu_info0:brand      Intel(r) Core(tm) i7-6700 CPU @ 3.40GHz
[...]
[root@X ~]# kstat -p cpu_info:7:cpu_info7:brand
cpu_info:7:cpu_info7:brand      Intel(r) Core(tm) i7-6700 CPU @ 3.40GHz
[root@X ~]# kstat -p cpu_info:8:cpu_info8:brand
[root@X ~]#

La CPU de esta máquina tiene ocho núcleos. Recuerda que se empieza a contar desde cero.

Este comando es útil, por ejemplo, en máquinas en hospedaje en centros de datos ajenos, a las que no tenemos acceso físico.

Problema actualizando mis servicios WSGI a Python 3.13

Acaba de salir Python 3.13 y, como siempre, actualizo mi código y servicios a esta nueva versión. Actualizo rápido para aprovechar las mejoras de la nueva versión de Python y porque acumular actualizaciones pendientes supone que el coste de migrar va creciendo cada año.

Normalmente los cambios necesarios son mínimos, pero en esta ocasión tengo problemas con mis servicios WSGI a través del módulo mod_wsgi.

Los servicios en sí parecen funcionar correctamente, pero los logs se saturan de cientos de líneas por segundo con el siguiente error:

Exception ignored in: <_io.TextIOWrapper name='<wsgi.errors>' encoding='utf-8'>
RuntimeError: log object has expired

Viendo el código fuente de mod_wsgi y del propio intérprete de Python, esto ocurre cuando se escribe en el log (o se hace flush) una vez que ya se ha llamado a close. La parte de Exception ignored está dentro del intérprete de Python, cuando se intenta escribir en un fichero que no puede dar una excepción. Por ejemplo, cuando un destructor levanta una excepción o durante la recogida de basuras.

Aunque todo parece ir bien, de momento seguiré con Python 3.12, mientras investigo el problema en detalle. Ahora mismo estoy bastante ocupado...

20241015: Alguien se me ha adelantado informando del problema: RuntimeError: log object has expired in mod_wsgi 5.0.1 with Django 5.0.9 python 3.13.0 #912.

20241122: Se publica la versión 5.0.2 de mod_wsgi que, aparentemente, soluciona este problema.

20250125: Encuentro un rato para actualizar mis servicios WSGI a la nueva versión de mod_wsgi y confirmo que el problema se ha solucionado.

IPv6 en OSMC

Se puede activar IPv6 en una instalación OSMC moderna de forma simple, aunque hay que hacerlo interfaz de red a interfaz de red (tanto por cable ethernet como por wifi):

$ connmanctl
> services
[...]
> config ethernet_XXXXXXXXXX_cable --ipv6 auto
> quit

Esto es un problema porque, al aparecer la dirección MAC en la configuración, si metemos esta tarjeta en otra Raspberry PI el servicio IPv6 dejará de estar disponible hasta que lo volvamos a configurar.

También se pueden activar las privacy extensions de IPv6 en /var/lib/connman/*/settings, editando la línea IPv6.privacy. Los valores son: disabled, enabled (activado pero prefiere la IP pública) o preferred/prefered (activado y prefiere las privadas).

Para configurar la duración de las IPs privadas en IPv6, se configura en el directorio /proc/sys/net/ipv6/conf/INTERFAZ/, los ficheros temp_prefered_lft y temp_valid_lft. En las Raspberry PI que estoy modificando los valores son 24 horas y 7 días.

Espero que IPv6 esté mejor integrado en futuras versiones de OSMC, pero de momento podemos ir tirando.

Problema activando una característica opcional de ZFS y actualización urgente del módulo ZFS de este servidor Linux

Nota

Estas son notas rápidas durante la investigación y solución de un problema, no un artículo depurado y organizado.

He activado algunas características opcionales de uno de mis servidores con OpenZFS (una máquina con Linux) y me encuentro que la actividad del disco duro es muy baja y me salen errores de este estilo en dmesg:

[19937.978681] INFO: task z_upgrade:720856 blocked for more than 483 seconds.
[19938.004576]       Tainted: P           O      5.4.0-181-generic #201-Ubuntu
[19938.030512] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[19938.081727] z_upgrade       D    0 720856      2 0x80004000
[19938.081730] Call Trace:
[19938.081739]  __schedule+0x2e3/0x740
[19938.081744]  ? __wake_up_common_lock+0x8a/0xc0
[19938.081746]  schedule+0x42/0xb0
[19938.081747]  io_schedule+0x16/0x40
[19938.081757]  cv_wait_common+0xdc/0x180 [spl]
[19938.081759]  ? __wake_up_pollfree+0x40/0x40
[19938.081763]  __cv_wait_io+0x18/0x20 [spl]
[19938.081845]  txg_wait_synced_impl+0xd7/0x120 [zfs]
[19938.081903]  txg_wait_synced+0x10/0x40 [zfs]
[19938.081945]  dmu_objset_id_quota_upgrade_cb+0xba/0x170 [zfs]
[19938.081986]  dmu_objset_upgrade_task_cb+0xdf/0x100 [zfs]
[19938.081992]  taskq_thread+0x245/0x430 [spl]
[19938.081994]  ? wake_up_q+0xa0/0xa0
[19938.081998]  kthread+0x104/0x140
[19938.082003]  ? task_done+0x90/0x90 [spl]
[19938.082005]  ? kthread_park+0x90/0x90
[19938.082007]  ret_from_fork+0x35/0x40

Un top muestra una carga muy elevada en arc_prune, 99.4 de sys time.

El smartctl o leer el disco duro entero con ddrescue, no muestran ningún error. Esto parece un bug de OpenZFS.

Si importo el zpool en read only, funciona. Esto me permitiría recuperar los datos en caso necesario. No estoy en situación catastrófica aún, aunque no puedo hacer más copias de seguridad en este disco duro [1].

[1] Este servidor Linux es mi servidor de copias de seguridad. Si se perdiese ese zpool, se perdería la copia de los datos, no los datos originales. Además, ese zpool es un espejo y su otra mitad está desconectada y en otro domicilio, como procedimiento de seguridad. A las malas, tendría esa mitad actualizada hasta unas semanas antes.

Intento compilar OpenZFS 2.2.4, pero falla en construir los paquetes Debian.

Pruebo con OpenZFS 2.1.12. Toco configure para que use el Python3.8 del sistema operativo en vez del moderno 3.12.

Opto por usar el repositorio https://launchpad.net/~jonathonf/+archive/ubuntu/zfs?field.series_filter=focal , que me instalará OpenZFS 2.1.6.

Con esta versión, la cosa tiene buena pinta. Al importar el zpool, se empieza a actualizar, pero es un proceso que no se va de madre. Supongo que la actualización costosa es debido a la activación de project_quota.

La cuestión es no hacer más upgrades con esta versión de OpenZFS, de momento, para poder volver atrás si es necesario.

SmartOS: Stock "mkvtoolnix" crashes on 2023.4.0 with locale error

This post transcribes some emails I sent to the SmartOS mailing list some time ago. You can check the original thread:

Message-ID: <15dec164-940e-17d7-a7db-dcdf19f9ec2d@jcea.es>
Date: Tue, 12 Mar 2024 14:07:13 +0100
To: smartos-discuss <smartos-discuss@lists.smartos.org>
From: Jesus Cea <jcea@jcea.es>
List-Id: "smartos-discuss" <smartos-discuss.lists.smartos.org>
Subject: [smartos-discuss] Stock "mkvtoolnix" crashes on 2023.4.0 with locale
  error

Hi, there.

I install "pkgin install mkvtoolnix" with no issues (but a huge number
of dependencies, 1.6 Gigabytes total!).

Then, I run "mkvmerge" and it crashes:

"""
[jcea@test ~]$ mkvmerge
terminate called after throwing an instance of 'std::runtime_error'
what():  locale::facet::_S_create_c_locale name not valid
Abort (core dumped)
"""

This worked fine in 2022.4.0.

My environment variables are:

"""
MANPATH=/opt/local/man:/usr/share/man:/opt/local/lib/perl5/man:/opt/local/lib/perl5/vendor_perl/man
LC_MONETARY=es_ES.UTF-8
TERM=xterm
SHELL=/usr/bin/bash
SSH_CLIENT=***
LC_NUMERIC=es_ES.UTF-8
SSH_TTY=/dev/pts/26
USER=root
COLUMNS=80
PAGER=less
MAIL=/var/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/opt/local/sbin:/opt/local/bin:/usr/sbin:/usr/bin:/sbin
LC_COLLATE=es_ES.UTF-8
PWD=/home/jcea
LANG=en_US.UTF-8
TZ=Europe/Madrid
LINES=25
SHLVL=1
HOME=/home/jcea
TERMINFO=/opt/local/share/lib/terminfo
LOGNAME=jcea
SSH_CONNECTION=****
LC_TIME=es_ES.UTF-8
FTPMODE=auto
_=/opt/local/bin/env
"""

Jonathan Perkin replied:

Leer más…

Feed Slashdot: Modo "verboso" y peticiones HTTP incondicionales

Artículos previos sobre este proyecto para enviar por email las novedades diarias de un feed RSS:

Aunque el código va necesitando una refactorización y limpieza, sigo haciendo pequeñas modificaciones y mejoras:

  • Modo verboso: Normalmente cuando se invoca el programa hace su trabajo sin más. Pero a veces nos interesa saber qué ha hecho, si ha enviado un correo electrónico o no, por ejemplo, cuántas entradas nuevas hay en el feed RSS, etc.

  • Peticiones HTTP incondicionales: De vez en cuando el feed RSS de Slashdot da un error HTTP 50x, indicando un error interno. Cuando esto ocurre, el Sistema Operativo de mi servidor me envía un email indicando que el proceso ha fallado. Ejecutándolo manualmente compruebo que cuando ocurren esos errores el feed RSS de Slashdot no ha cambiado desde la petición anterior y que, de hecho, el problema se resuelve solo cuando aparece una entrada nueva.

    Esto tiene toda la pinta de ser un bug en el código de Slashdot y en realidad solo me afecta de forma cosmética (los correos electrónicos de errores que me llegan por ser administrador de la máquina que ejecuta este servicio), pero durante las pruebas comprobé que hacer una petición HTTP incondicional [1] no produce un error, así que añadí esa funcionalidad al programa.

    [1]

    Cuando mi programa detecta una actualización del feed RSS se queda con sus entradas y las siguientes peticiones no vuelven a pedir el feed RSS sin más, sino que envía al servidor HTTP de Slashdot lo que se llama una petición condicional que básicamente dice: "envíame el feed RSS solo si ha habido algún cambio desde la versión anterior. Si no no me mandes nada". Esto es ventajoso para todo el mundo, pero parece que Slashdot falla de vez en cuando cuando en realidad no ha habido un cambio en el feed RSS y simplemente tendría que haberme respondido con un código HTTP 304. Es así cómo debería ser y, de hecho, es lo que hace el 99.99% del tiempo. Pero falla ese 0.01%...

El parche es largo, pero fácil de entender:

Leer más…