Jun 01

¡GEOS v1.0.0: Emacs como PID 1, con soporte completo GNU/Hurd!

Tag: advanced,internals/hackingadmin @ 2:53 pm

Hace unos meses publiqué la v0.1 de GEOS (GNU/Emacs Operating System), un sistema operativo donde Emacs es a la vez el userland y el PID 1. Hoy etiqueto la v1.0.0. La novedad es que ya no hace falta hablar en condicional sobre GNU/Hurd: Emacs es PID 1 también ahí, con sesión multi-usuario EXWM de extremo a extremo sobre Debian GNU/Hurd 0.9 canónico.

Tésis

Emacs no es un editor que corre sobre un sistema operativo. Emacs ES el sistema operativo. El kernel da abstracción del hardware. Todo lo que hay por encima (supervisión de procesos, shell, gestor de ventanas, visor de logs, gestor de paquetes, configurador de red, asistente de instalación) vive en buffers, escrito en Elisp, evaluable en caliente, introspectable con C-h f.

El primer proceso de userspace que arranca el kernel es un binario en C diminuto que monta los pseudo-filesystems, recoge zombis, lee /etc/hostname, y hace execve a Emacs. El mismo código C se compila una segunda vez como módulo dinámico de Emacs y se carga desde early-init.el, así que el supervisor vive dentro del proceso supervisado. No hay Shepherd. No hay systemd. No hay /etc/init.d. Si esa frase incomoda, bien, debería.

¿Por qué GNU/Hurd?

Porque la pieza que falta del puzzle GNU es la que tiene casi cuarenta años y la gente sigue asumiendo que no se puede usar en serio. Porque «Emacs como PID 1 sobre Linux» tiene su gracia, pero «Emacs como PID 1 sobre el Hurd» cierra el círculo que Stallman dibujó en una nota al pie hace mucho tiempo. Y porque si funciona en los dos kernels, el código está obligado a respetar una capa de abstracción honesta entre lo específico del kernel y lo que no, lo cual mejora la calidad de todo lo demás.

¿Qué funciona en Debian GNU/Hurd 0.9?

  • pid1 arranca a Hurd, hace setup de los traductores correctos, ejecuta execve a emacs y carga el módulo dinámico que expone los primitives del supervisor.
  • Sesión multi-usuario con login, audit, throttle, lockout y footer de último acceso. El handshake de peer-cred usa auth_server_authenticate sobre Hurd (en Linux es SO_PEERCRED).
  • EXWM 0.33 sobre Xvfb. Las ventanas X11 son buffers de Emacs igual que en Linux. Xorg nativo con DRM sobre Hurd queda como trabajo upstream.
  • SSH de extremo a extremo: ssh -p 2266 root@127.0.0.1 abre una sesión interactiva contra el emacs supervisado.
  • Asistente de instalación: el wizard M-x install formatea con mkfs.ext4 e instala GRUB sobre un segundo disco, todo a través de los wrappers Elisp.
  • M-x geos-poweroff y M-x geos-reboot usan host_reboot vía get_privileged_ports en Hurd, y reboot(2) en Linux. No hay /sbin/poweroff al que llamar; el supervisor ES Emacs y la respuesta a «apaga» vive en Elisp.
  • Buffers de sistema: *processes*, *network*, *journal*, *services*, *disks*, *packages*, *users*, *audio*, *install*. Todos vivos con timer de refresco.

Seam port_caps

Cada syscall específico de Linux dentro de pid1/ pasa por un struct de punteros a función. La implementación Linux vive en port_linux.c y la de Hurd en port_hurd.c (esta última en la rama lateral hurd, rebase semanal sobre main). El Elisp por encima nunca sabe sobre qué kernel está corriendo; consulta geos-kernel sólo si necesita decidir algo concreto.

El build STATIC=1 compila el binario emacs-init de Hurd como ejecutable estático puro: cero dependencias dinámicas, alrededor de 1.5 MiB. Eso es lo que se hornea dentro de la imagen derivada cuando ejecuto iso-build/hurd-image-reroll.sh.

Upstream gaps

Dos filas de la matriz de docs/HURD_PORT.md siguen marcadas como «deferred-upstream»:

  • Audio en hardware real sobre Hurd. Debian GNU/Hurd 0.9 canónico no trae /hurd/audio* ni superficie ALSA/OSS. El flavor FLAVOR=apt-image de la imagen derivada empaqueta el userland de PulseAudio para que el lado Elisp tenga con qué hablar; el sink real es trabajo upstream.
  • Contadores por interfaz de pfinet. El arm Elisp pinta ceros hasta que la superficie del traductor exponga los contadores.

Hay ocho hilos abiertos en bug-hurd, debian-hurd y bug-gnu-emacs documentando estos y otros temas: entre ellos un assertion fail de ext2fs file_pager_write_pages bajo apt-install, un comportamiento sospechoso de SO_RCVTIMEO en pflocal, y la ausencia de la integración evdev/libinput en el Xorg de Hurd. Ninguno bloquea GEOS hoy.

¿Cómo probarlo?

Camino fácil, en un host Linux con KVM:

git clone https://github.com/borjatarraso/gnu-emacs-os.git
cd gnu-emacs-os
./iso-build/dev-vm.sh

El primer build descarga unos 8 GiB en /gnu/store; los siguientes tardan segundos. El boot hasta un frame EXWM utilizable son unos once segundos.

Para Hurd, partiendo de una instalación limpia de Debian GNU/Hurd 0.9, basta con ejecutar install/hurd-bootstrap.sh como root y reiniciar. La receta completa (paquetes apt, build, formato de init.args, ruta de rollback) está en docs/HURD_BOOT.md. La ruta alternativa es iso-build/hurd-image-reroll.sh, que hornea una imagen derivada de la canónica con pid1 estático, árbol de supervisor, GRUB serial y authorized_keys ya dentro; se arranca bajo QEMU y se entra por SSH.

Si alguien quiere comparar con la canónica vainilla, GEOS_BYPASS=1 ./iso-build/hurd-image-reroll.sh produce una imagen con /sbin/init stock (bash, sysvinit, getty) en lugar del PID 1 de Emacs, manteniendo las conveniencias del bake (consola serial, claves SSH ya inyectadas).

Limitaciones aceptadas

Emacs es de un solo hilo. Un regex atascado bloquea el OS. Una llamada de red lenta bloquea el OS. Un (while t) bloquea el OS. El buffer *panic* mitiga el caso de los errores Elisp que pasan por condition-case, pero no salva del loop apretado en código C ni de la llamada de red sin timeout. Es una restricción de diseño asumida, no un bug. Pierdo aproximadamente una sesión a la semana por un freeze que tengo que recuperar desde QEMU. Me parece un ratio aceptable. Puede que a ti no, y esa es una razón legítima para no usar este OS.

Demo

Enlaces

Licencia: GPLv3-or-later. Maintainer: borja.tarraso@member.fsf.org.

Leave a Reply

You must be logged in to post a comment.