Una Distribución Linux desde Cero
Creo que, como mucha gente, uso Linux a diario. Personalmente uso NixOS. Pero al final no sé realmente cómo funciona todo bajo el capó.
Me encontré varias veces con videos de un estadounidense, creo que Nir Lichtman, que se divierte creando diferentes distribuciones Linux desde cero para diferentes casos de uso.
Un ejemplo de video:
El concepto es realmente genial y lo hace muy accesible, así que gracias a él por estos videos.
IMPORTANTLa distribución final no está destinada a ser utilizada en producción, sino solo con fines educativos.
Así que en este post voy a mostrarles lo que hice para crear una distribución Linux mínima from scratch.
Requisitos técnicos previos
En mi caso voy a hacer esto en un contenedor docker ubuntu. Y para lanzar la VM uso QEMU, que pueden instalar fácilmente.
En NixOS simplemente lancé: nix-shell -p qemu
Para las otras distribuciones pueden ver la doc oficial de QEMU. La documentación de docker. Y de paso la documentación oficial de Linux From Scratch que está muy bien hecha.
División
Necesitaremos tres bloques para hacer funcionar nuestra distribución:
kernel(el núcleo Linux)User Space(BusyBox)bootloader(Syslinux)
El Núcleo Linux
Como les dije al principio, voy a usar un contenedor docker ubuntu para hacer todo esto. Así que mi primer paso es lanzarlo.
docker run —privileged -it ubuntu

Nos encontramos en la shell del contenedor, el primer paso es actualizar e instalar las dependencias necesarias.
apt update && apt upgrade -y apt install bzip2 git vim make gcc libncurses-dev flex bison bc cpio libelf-dev libssl-dev -y

Tenemos nuestras dependencias instaladas, ahora podemos clonar el repositorio del núcleo linux.
NOTEPrefiero clonarlo en el directorio del usuario pero eso es como ustedes prefieran (/home/ubuntu).
git clone —depth 1 https://github.com/torvalds/linux.git
*—depth 1 - para no tener todo el historial git del núcleo sino solo el último commit

Ya que vamos con una instalación x86_64 vamos a configurar el núcleo para esta arquitectura. Usamos una configuración ya hecha por los desarrolladores del núcleo.
make x86_64_defconfig

Una vez hecho podemos lanzar la compilación del núcleo, podemos usar make o make -j N donde N es el número de núcleos de su procesador para acelerar la compilación.
Yo voy a usar todos los núcleos disponibles para ir más rápido.
make -j $(nproc)


Kernel: arch/x86/boot/bzImage is ready (#1)
Una vez terminada la compilación podemos ver la imagen del núcleo en el directorio arch/x86/boot/bzImage.
Creamos un directorio boot-files en la raíz y copiamos la imagen del núcleo dentro.
mkdir /boot-files mv arch/x86/boot/bzImage /boot-files
Terminado con el núcleo, pasamos al espacio de usuario.
Espacio de Usuario - BusyBox
La documentación oficial de BusyBox.
Volvemos al espacio de usuario /home/ubuntu y clonamos el repositorio de busybox.
cd /home/ubuntu git clone —depth 1 https://git.busybox.net/busybox cd busybox
Es el mismo principio que para el núcleo, configuramos y compilamos.
Para inicializar la configuración por defecto usamos make defconfig.
make defconfig
Nosotros queremos la versión de busybox en modo static para que todo esté en un solo binario. Así que modificamos la configuración en settings, hay que desmarcar la sección Build static binary (no shared libs) para eso hay que lanzar el comando:
make menuconfig
Una vez en el menú, vamos a Settings (enter).

Una vez desmarcado no ha terminado porque con las versiones recientes de ubuntu hay que desactivar tc, para hacer esto vamos a Networking Utilities y desmarcamos tc (8.3 kb) (puede ser otro valor Xkb).

Una vez hecho hacemos exit y guardamos la configuración. Luego construimos busybox de la misma manera que el núcleo.
make -j $(nproc)

En el directorio que creamos anteriormente /boot-files creamos un directorio initramfs y copiamos el binario de busybox dentro (mkdir /boot-files/initramfs).
Instalamos busybox en este directorio usando el comando make install con la variable CONFIG_PREFIX que apunta al directorio de instalación.
make CONFIG_PREFIX=/boot-files/initramfs install

Nuestro sistema aún no tiene shell, vamos a crear un script init que será el primer proceso lanzado por el núcleo. Lo gracioso en el archivo init es que le decimos que se use a sí mismo como shell.
NOTEHay que crear bien el archivo
initen el directorio/boot-files/initramfsy darle los derechos de ejecución con el comandochmod +x init.
Antes creamos las carpetas importantes en el directorio initramfs.
mkdir /boot-files/initramfs/{proc,sys,dev}
#!/bin/sh
mount -t proc proc /procmount -t sysfs sysfs /sysmount -t devtmpfs devtmpfs /dev
echo "Bienvenido a mi distribución"
exec /bin/shTodavía en el directorio /boot-files/initramfs creamos un archivo cpio comprimido que será utilizado por el núcleo al inicio.
cd /boot-files/initramfs find . | cpio -o -H newc > ../init.cpio
Es todo para el espacio de usuario, pasamos al bootloader.
Bootloader - Syslinux
Aquí vamos a usar Syslinux como bootloader, la doc oficial está aquí.
Lo instalamos ya que no está instalado por defecto.
cd /boot-files # volvemos al directorio boot-files apt install syslinux -y
Entonces una vez instalado, vamos a crear un archivo de 50Mo que servirá de disco duro virtual para nuestra distribución.
dd if=/dev/zero of=boot bs=1M count=50

Necesitamos dosfstools para formatear el archivo en FAT32.
apt install dosfstools -y mkfs -t fat boot syslinux boot
Aquí montamos el disco duro virtual, lo formateamos e instalamos syslinux en él.
Listo, ahora tenemos un archivo boot que contiene nuestra distribución linux mínima. El objetivo es lanzarla en una máquina virtual.
Dado que estamos en un contenedor docker hay que transferir el archivo boot al host. Para hacer esto usamos el comando docker cp.
En otro terminal en el host.
docker cp <container_id>:/boot-files/boot .

Ahora hay que lanzar la máquina virtual con QEMU usando el archivo boot como disco duro.
qemu-system-x86_64 boot

Pero tenemos un problema, nos dice No configuration file found. No hay problema, vamos a darle manualmente el archivo de configuración que creamos anteriormente.
así que en boot escribimos:
WARNINGEl teclado está en QWERTY
/bzImage -initrd=/init.cpio
Presionamos enter y ya está, tenemos nuestra distribución linux mínima.

NOTEVemos bien nuestro mensaje personalizado “Bienvenido a mi distribución”
Ahora pueden jugar con su distribución linux mínima. Pueden escribir comandos como ls, cd, pwd, etc.
Así es a grandes rasgos cómo funciona, por supuesto existen otros bootloaders, otros espacios de usuario, y muchas otras cosas que agregar para hacer la distribución más completa pero para empezar no está mal.
Gracias a Nir Lichtman por la inspiración.
¡Gracias por leerme! Si tienen preguntas no duden en hacérmelas en X.