{"id":912,"date":"2026-06-01T14:53:38","date_gmt":"2026-06-01T12:53:38","guid":{"rendered":"https:\/\/www.blackhats.es\/wordpress\/?p=912"},"modified":"2026-06-01T15:02:00","modified_gmt":"2026-06-01T13:02:00","slug":"geos-v1-0-0-emacs-como-pid-1-con-soporte-completo-gnu-hurd","status":"publish","type":"post","link":"https:\/\/www.blackhats.es\/wordpress\/?p=912","title":{"rendered":"\u00a1GEOS v1.0.0: Emacs como PID 1, con soporte completo GNU\/Hurd!"},"content":{"rendered":"<p>Hace unos meses publiqu\u00e9 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 <strong>GNU\/Hurd<\/strong>: Emacs es PID 1 tambi\u00e9n ah\u00ed, con sesi\u00f3n multi-usuario EXWM de extremo a extremo sobre Debian GNU\/Hurd 0.9 can\u00f3nico.<\/p>\n<h2>T\u00e9sis<\/h2>\n<p>Emacs no es un editor que corre sobre un sistema operativo. Emacs ES el sistema operativo. El kernel da abstracci\u00f3n del hardware. Todo lo que hay por encima (supervisi\u00f3n de procesos, shell, gestor de ventanas, visor de logs, gestor de paquetes, configurador de red, asistente de instalaci\u00f3n) vive en buffers, escrito en Elisp, evaluable en caliente, introspectable con <code>C-h f<\/code>.<\/p>\n<p>El primer proceso de userspace que arranca el kernel es un binario en C diminuto que monta los pseudo-filesystems, recoge zombis, lee <code>\/etc\/hostname<\/code>, y hace <code>execve<\/code> a Emacs. El mismo c\u00f3digo C se compila una segunda vez como m\u00f3dulo din\u00e1mico de Emacs y se carga desde <code>early-init.el<\/code>, as\u00ed que el supervisor vive dentro del proceso supervisado. No hay Shepherd. No hay systemd. No hay <code>\/etc\/init.d<\/code>. Si esa frase incomoda, bien, deber\u00eda.<\/p>\n<h2>\u00bfPor qu\u00e9 GNU\/Hurd?<\/h2>\n<p>Porque la pieza que falta del puzzle GNU es la que tiene casi cuarenta a\u00f1os y la gente sigue asumiendo que no se puede usar en serio. Porque \u00abEmacs como PID 1 sobre Linux\u00bb tiene su gracia, pero \u00abEmacs como PID 1 sobre el Hurd\u00bb cierra el c\u00edrculo que Stallman dibuj\u00f3 en una nota al pie hace mucho tiempo. Y porque si funciona en los dos kernels, el c\u00f3digo est\u00e1 obligado a respetar una capa de abstracci\u00f3n honesta entre lo espec\u00edfico del kernel y lo que no, lo cual mejora la calidad de todo lo dem\u00e1s.<\/p>\n<h2>\u00bfQu\u00e9 funciona en Debian GNU\/Hurd 0.9?<\/h2>\n<ul>\n<li>pid1 arranca a Hurd, hace setup de los traductores correctos, ejecuta <code>execve<\/code> a emacs y carga el m\u00f3dulo din\u00e1mico que expone los primitives del supervisor.<\/li>\n<li>Sesi\u00f3n multi-usuario con login, audit, throttle, lockout y footer de \u00faltimo acceso. El handshake de peer-cred usa <code>auth_server_authenticate<\/code> sobre Hurd (en Linux es <code>SO_PEERCRED<\/code>).<\/li>\n<li>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.<\/li>\n<li>SSH de extremo a extremo: <code>ssh -p 2266 root@127.0.0.1<\/code> abre una sesi\u00f3n interactiva contra el emacs supervisado.<\/li>\n<li>Asistente de instalaci\u00f3n: el wizard <code>M-x install<\/code> formatea con <code>mkfs.ext4<\/code> e instala GRUB sobre un segundo disco, todo a trav\u00e9s de los wrappers Elisp.<\/li>\n<li><code>M-x geos-poweroff<\/code> y <code>M-x geos-reboot<\/code> usan <code>host_reboot<\/code> v\u00eda <code>get_privileged_ports<\/code> en Hurd, y <code>reboot(2)<\/code> en Linux. No hay <code>\/sbin\/poweroff<\/code> al que llamar; el supervisor ES Emacs y la respuesta a \u00abapaga\u00bb vive en Elisp.<\/li>\n<li>Buffers de sistema: <code>*processes*<\/code>, <code>*network*<\/code>, <code>*journal*<\/code>, <code>*services*<\/code>, <code>*disks*<\/code>, <code>*packages*<\/code>, <code>*users*<\/code>, <code>*audio*<\/code>, <code>*install*<\/code>. Todos vivos con timer de refresco.<\/li>\n<\/ul>\n<h2>Seam port_caps<\/h2>\n<p>Cada syscall espec\u00edfico de Linux dentro de <code>pid1\/<\/code> pasa por un struct de punteros a funci\u00f3n. La implementaci\u00f3n Linux vive en <code>port_linux.c<\/code> y la de Hurd en <code>port_hurd.c<\/code> (esta \u00faltima en la rama lateral <code>hurd<\/code>, rebase semanal sobre main). El Elisp por encima nunca sabe sobre qu\u00e9 kernel est\u00e1 corriendo; consulta <code>geos-kernel<\/code> s\u00f3lo si necesita decidir algo concreto.<\/p>\n<p>El build <code>STATIC=1<\/code> compila el binario <code>emacs-init<\/code> de Hurd como ejecutable est\u00e1tico puro: cero dependencias din\u00e1micas, alrededor de 1.5 MiB. Eso es lo que se hornea dentro de la imagen derivada cuando ejecuto <code>iso-build\/hurd-image-reroll.sh<\/code>.<\/p>\n<h2>Upstream gaps<\/h2>\n<p>Dos filas de la matriz de <code>docs\/HURD_PORT.md<\/code> siguen marcadas como \u00abdeferred-upstream\u00bb:<\/p>\n<ul>\n<li><strong>Audio en hardware real sobre Hurd.<\/strong> Debian GNU\/Hurd 0.9 can\u00f3nico no trae <code>\/hurd\/audio*<\/code> ni superficie ALSA\/OSS. El flavor <code>FLAVOR=apt-image<\/code> de la imagen derivada empaqueta el userland de PulseAudio para que el lado Elisp tenga con qu\u00e9 hablar; el sink real es trabajo upstream.<\/li>\n<li><strong>Contadores por interfaz de pfinet.<\/strong> El arm Elisp pinta ceros hasta que la superficie del traductor exponga los contadores.<\/li>\n<\/ul>\n<p>Hay ocho hilos abiertos en bug-hurd, debian-hurd y bug-gnu-emacs documentando estos y otros temas: entre ellos un assertion fail de <code>ext2fs file_pager_write_pages<\/code> bajo <code>apt-install<\/code>, un comportamiento sospechoso de <code>SO_RCVTIMEO<\/code> en pflocal, y la ausencia de la integraci\u00f3n evdev\/libinput en el Xorg de Hurd. Ninguno bloquea GEOS hoy.<\/p>\n<h2>\u00bfC\u00f3mo probarlo?<\/h2>\n<p>Camino f\u00e1cil, en un host Linux con KVM:<\/p>\n<pre><code>git clone https:\/\/github.com\/borjatarraso\/gnu-emacs-os.git\r\ncd gnu-emacs-os\r\n.\/iso-build\/dev-vm.sh<\/code><\/pre>\n<p>El primer build descarga unos 8 GiB en <code>\/gnu\/store<\/code>; los siguientes tardan segundos. El boot hasta un frame EXWM utilizable son unos once segundos.<\/p>\n<p>Para Hurd, partiendo de una instalaci\u00f3n limpia de Debian GNU\/Hurd 0.9, basta con ejecutar <code>install\/hurd-bootstrap.sh<\/code> como root y reiniciar. La receta completa (paquetes apt, build, formato de <code>init.args<\/code>, ruta de rollback) est\u00e1 en <code>docs\/HURD_BOOT.md<\/code>. La ruta alternativa es <code>iso-build\/hurd-image-reroll.sh<\/code>, que hornea una imagen derivada de la can\u00f3nica con pid1 est\u00e1tico, \u00e1rbol de supervisor, GRUB serial y <code>authorized_keys<\/code> ya dentro; se arranca bajo QEMU y se entra por SSH.<\/p>\n<p>Si alguien quiere comparar con la can\u00f3nica vainilla, <code>GEOS_BYPASS=1 .\/iso-build\/hurd-image-reroll.sh<\/code> produce una imagen con <code>\/sbin\/init<\/code> stock (bash, sysvinit, getty) en lugar del PID 1 de Emacs, manteniendo las conveniencias del bake (consola serial, claves SSH ya inyectadas).<\/p>\n<h2>Limitaciones aceptadas<\/h2>\n<p>Emacs es de un solo hilo. Un regex atascado bloquea el OS. Una llamada de red lenta bloquea el OS. Un <code>(while t)<\/code> bloquea el OS. El buffer <code>*panic*<\/code> mitiga el caso de los errores Elisp que pasan por <code>condition-case<\/code>, pero no salva del loop apretado en c\u00f3digo C ni de la llamada de red sin timeout. Es una restricci\u00f3n de dise\u00f1o asumida, no un bug. Pierdo aproximadamente una sesi\u00f3n 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\u00f3n leg\u00edtima para no usar este OS.<\/p>\n<h2>Demo<\/h2>\n<p><iframe loading=\"lazy\" title=\"GNU\/Emacs Operating System (GEOS) with GNU\/Hurd full support\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/h8oLu-voRGA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<h2>Enlaces<\/h2>\n<ul>\n<li>Repositorio: <a href=\"https:\/\/github.com\/borjatarraso\/gnu-emacs-os\">github.com\/borjatarraso\/gnu-emacs-os<\/a><\/li>\n<li>Release v1.0.0: <a href=\"https:\/\/github.com\/borjatarraso\/gnu-emacs-os\/releases\/tag\/v1.0.0\">github.com\/borjatarraso\/gnu-emacs-os\/releases\/tag\/v1.0.0<\/a><\/li>\n<li>Matriz Hurd: <a href=\"https:\/\/github.com\/borjatarraso\/gnu-emacs-os\/blob\/main\/docs\/HURD_PORT.md\">docs\/HURD_PORT.md<\/a><\/li>\n<li>Manual de arranque sobre Hurd: <a href=\"https:\/\/github.com\/borjatarraso\/gnu-emacs-os\/blob\/main\/docs\/HURD_BOOT.md\">docs\/HURD_BOOT.md<\/a><\/li>\n<li>Manifiesto: <a href=\"https:\/\/github.com\/borjatarraso\/gnu-emacs-os\/blob\/main\/docs\/MANIFESTO.md\">docs\/MANIFESTO.md<\/a><\/li>\n<\/ul>\n<p>Licencia: GPLv3-or-later. Maintainer: <a href=\"mailto:borja.tarraso@member.fsf.org\">borja.tarraso@member.fsf.org<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hace unos meses publiqu\u00e9 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\u00e9n ah\u00ed, con sesi\u00f3n multi-usuario EXWM de extremo [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[297,305],"tags":[67,8,379,375,115,381,376,377,66,378,380],"class_list":["post-912","post","type-post","status-publish","format-standard","hentry","category-advanced","category-internalshacking","tag-elisp","tag-emacs","tag-emacs-operating-system","tag-geos","tag-gnu","tag-gnu-geos","tag-gnu-hurd","tag-hurd","tag-lisp","tag-os","tag-sistema-operativo-emacs"],"_links":{"self":[{"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/912"}],"collection":[{"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=912"}],"version-history":[{"count":2,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/912\/revisions"}],"predecessor-version":[{"id":914,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/912\/revisions\/914"}],"wp:attachment":[{"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=912"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=912"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=912"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}