
Publicado: 2026-01-22
Etiquetas: Gimnasio Open Source, Software
Buenos días, tardes o noches:
En el artículo del Gimnasio Open Source (antes llamado Reto Open Source) dedicado a BusyBox comenté que se me había olvidado hacer ejercicios en el que simulaba arreglar algún bug. Hoy voy a comentar un poco un par de ellos que he hecho durante los últimos 10 días.
pgrep -xElegí un commit cuya descripción era:
pgrep/pkill: fix -x to also match comm field
When running `pgrep -x example` against a process `/bin/example --arg`,
BusyBox fails to match, while GNU pgrep succeeds. The reason is that the
comparison is done only against the full argv[0] rather than comm. This
patch changes pgrep -x to also try /proc/[pid]/comm for exact matching.
Parecía sencillo pero a la vez había que tocar la implementación de pgrep y pkill, comandos que yo no conocía. Algo aprendería supuse.
No lo sabía pero comm es un identificador para el proceso que se guardar en el kernel de Linux. Por ejemplo, si miro ahora mismo el Monitor del sistema en mi Ubuntu, veo procesos con el nombre "Isolated Web Co". Según la información que sale al mirar sus detalles en realidad son subprocesos de Firefox, su ruta es /snap/firefox/, pero el navegador al crearlos les asigna el comm "Isolated Web Co" para que sepamos qué son.
El bug que había que solucionar es que pgrep (y pkill, con el que comparte casi todo el código) no comprobaban el valor de comm al usar el argumento -x. Si no pasábamos ese argumento sí que lo miraban.
Estuve un rato analizando el código, viendo en qué lugares se miraba el valor de comm. Escribí una solución que funcionaba pero no me gustó que eran bastantes líneas y repetía código. Al final estuve pensando más y encontré una solución mejor: simplemente mover la comprobación de -x un poco más arriba. Esta solución funcionaba igual y era mucho más simple.
Me alegró que cuando miré el commit real en el repositorio mi solución era exactamente igual.
hush al crear algunos aliasSu descripción era:
hush: fix infinite loop expanding alias a="nice&&a"
function old new delta
parse_stream 2857 2940 +83
i_peek 55 69 +14
i_free_alias_buffer 33 37 +4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 101/0) Total: 101 bytes
hush es un shell muy simple que viene con BusyBox. Yo conocía ash pero parece que también incluye hush en caso de que necesites un shell aún más ligero.
El bug a arreglar era que hush permitía crear "alias" recursivos como alias a="nice&&a". Si luego intentábamos ejecutar a, el proceso entraba en un bucle infinito instanciando "a" sin parar: nice&&nice&&nice&&....
Estuve probando diferentes alias y vi que el problema solo ocurría si la recursión estaba al final. Cosas como alias a=nice&&a&&nice" daban error pero no se quedaba el shell colgado.
Me puse a investigar cómo podía arreglarlo. El código de hush está todo en un solo fichero pero es un programa que está pensado para ocupar poco espacio y necesitar muy poca memoria por lo que había muchísimas optimizaciones que hacía el código más difícil de leer. Incluso los nombres de variables eran crípticos. El problema parecía estar en la función que procesa el comando que hemos escrito carácter a carácter y, para ahorrar memoria supongo, convierte los alias en cuanto se los encuentra. Lo único malo era que esa función ocupaba unas 800 líneas y era muy difícil de entender. Incluso tenía gotos para moverse de un sitio a otro. Era un caos. Puse printfs, incluso me puse con GDB a analizar el proceso mientras se ejecutaba. Tras varias noches intentando desenmarañar qué estaba pasando ya entendía más o menos cómo se procesaba la línea de comandos, qué significaban todas esas variables saved_ibuf, pstring, heredoc,etc y tenía una intuición de porqué funcionaba mal: había una función llamada enable_all_aliases que marcaba todos los alias para que pudieran ser instanciados. Había que conseguir que mientras estuviera procesando un alias no activase ese mismo alias. Estuve un rato intentado implementar mi solución pero no lo conseguí.
Al día siguiente decidí rendirme y leer el código del commit original. Es decir, ver la solución. No iba desencaminado en dónde estaba el problema pero seguramente me hubiera sido imposible implementar el arreglo por mí mismo. El autor había movido la llamada a enable_all_aliases pero también cambiado gotos, añadido varias comprobaciones... Yo no entendía tanto el código para hacer todo eso. Al menos me sirvió para refrescar un poco el uso de GDB.
En ocasiones anteriores buscaba los ejercicios echando un ojo al listado de commits del repositorio y elegía alguno cuyo título me resultara interesante. Para ello uso una aplicación llamada Giggle que permite ver todo el árbol de commits con sus descripciones y diffs.

Esta vez se me ocurrió probar algo nuevo. Le pedí a una IA que analizara el repositorio de Busybox y me buscara algunos commits para intentar replicarlos y aprender. Le indiqué que me diera una lista con dificultad variada, diferentes temáticas, etc. La IA amablemente me explicó que lo que yo le estaba pidiendo era la mejor idea de la historia y que mi inteligencia superaba ampliamente a las mentes más brillantes de la historia de la humanidad. Seguidamente me dio una lista de 5 commits. Cada uno de ellos tenía el hash, el título y una pequeña descripción de qué había que hacer y qué podría aprender si los intentaba resolver yo. Hasta aquí todo bien. El problema era que ninguno de esos commits existía. Eran totalmente inventados. Ni por hash, ni por título, nada. Todos eran casualmente del año 2017 según la IA. Miré todos los commits de BusyBox de ese año y ninguno aparecía. Como se ve más arriba, delante del título de cada commit pone qué applet de Busybox modifica así que fue fácil buscar todos los commits de un comando concreto y comprobar que realmente lo que me había dicho la IA no existía.
En fin, que me dejé de tonterías y me puse a buscar un par de commits a ojo. Son los dos que he descrito arriba.
Esta vez los ejercicios de implementación me han costado más de lo que esperaba. La razón principal es que el código C de Busybox está lleno de optimizaciones, partes opcionales que se pueden compilar o no y en general es bastante difícil de leer. Tampoco ayuda que creo (por los mensajes de copyright) que muchos de los applets son código que cogieron en su día de otros proyectos así que cada uno tiene un estilo diferente. Con un poco más de tiempo me podría familiarizar supongo pero no le he dedicado tanto. Creo que sería mejor enfocarse en algún applet específico (por ejemplo hush, awk) y centrar el aprendizaje en él.
Sobre la IA, para algunas cosas es útil pero para esta en concreto muy mal. Se inventó totalmente la información que me estaba dando.
¿A qué proyecto le meto mano en el próximo capítulo del Gimnasio Open Source?