Linux From Scratch XXXII: Arrancando desde USB con un kernel alternativo

En el artículo anterior, hemos compilado un kernel y llegado a arrancar desde disco duro. En este vamos a arrancar desde USB, aunque todavía no vamos a hacerlo de forma definitiva, pero nos servirá para probar cosas y hacer unos últimos ajustes en la configuración.

Hay dos razones por las que lo que hemos hecho anteriormente no nos ha servido para arrancar desde USB. La primera es que el kernel necesita colaboración por parte de algún proceso para poder reconocer los USB, lo que significa que hay que crear un initrd para ello. La segunda es que los nombres de los dispositivos pueden cambiar, así que hay que localizar la partición root usando su UUID. El problema es que el kernel tampoco puede leer los UUID de las particiones sin ayuda por parte de algún proceso externo, o sea que tenemos una doble razón por la cual necesitamos un initrd.

Copiando el kernel de otra distro

Para comprobar que el problema es del kernel y/o del initrd y que el resto de nuestro sistema LFS funciona correctamente, una cosa que podemos hacer es usar un kernel de otra distro, con su correspondiente initrd, para arrancar nuestro LFS. Así de paso nos sirve como kernel alternativo en caso de que el nuestro nos dé algún problema. No está de más tener algo así.

Para esto voy a recurrir a un LiveUSB de Debian que tengo por ahí. Lo que voy a hacer es extraerle el kernel con su initrd, módulos y todo lo que dependa de él y meterlo en el LFS que estamos creando. En realidad no es un LiveUSB, es un Debian testing completo instalado en un USB. Es lo que uso como disco de rescate. 🙂

En vuestro caso, no necesitáis una Debian para hacer esto. Debería serviros cualquier distro. Eso sí: la forma de hacerlo es ligeramente distinta en cada distro, así que deberíais fijaros bien en cómo son los ficheros que necesitáis y extraer esos. La principal diferencia será el número de versión del kernel.

Tampoco hace falta que esté instalada en un USB. Yo he usado esta para estar completamente seguro de que funciona en un USB, pero otras también deberían arrancar desde USB aunque estén instaladas en el disco duro. Más abajo hago lo mismo con el kernel de mi ArchLinux que está instalada en un SSD.

Hay dos formas de hacer esto. Una es arrancar con el USB, disco duro o dispositivo en el que está el kernel que queréis extraer. La otra es montar la partición correspondiente en algún punto de sistema de ficheros de la distro que estáis usando para crear LFS. En el primer caso necesitáis algún otro USB, carpeta de red, o cualquier otro medio que os permita pasar el kernel extraído a vuestra máquina. En el segundo caso es necesario tener acceso a boot y a root, así que si usáis una partición boot aparte, tenéis que montarla también.

En mi caso he optado por la primera forma. Más que nada porque he usado otra máquina, así que la segunda no era factible. Lo primero que he hecho ha sido arrancar con el USB de Debian y enchufar el que estoy usando para instalar LFS. Habréis notado que la swap está en sdc2 y la partición raíz en sdc3. Eso es porque en sdc1 tengo una partición vfat que uso para intercambiar ficheros incluso con equipos Windows, así que me sirve para pasar el kernel a la otra máquina. Curiosamente, al enchufar el USB le ha asignado el nombre de dispositivo sdc. No tendría por qué ser así. Es casualidad.

Lo que he hecho a continuación es montar la partición vfat de mi USB y crear en ella un archivo comprimido con el kernel de Debian y todos los ficheros que necesita para arrancar. Estos ficheros son los que cambian de una distro a otra. En primer lugar, para saber con qué kernel estáis arrancando, en caso de que haya más de uno, podéis mirar los ficheros de configuración del gestor de arranque que uséis. Estarán en un directorio dentro de /boot. En ese mismo fichero de configuración aparece también el initrd que usa. Tenéis que añadir los ficheros de esa misma versión del kernel que estén en /boot, además de los módulos, que estarán en /lib/modules. Todo esto hay que hacerlo desde el directorio raíz para que el fichero que estamos generando se descomprima después correctamente.

Otro directorio que hay que tener en cuenta es el del firmware. Normalmente es /lib/firmware y no lleva número de versión porque suele ser siempre igual. Se trata de drivers privativos que se distribuyen en binario porque el fabricante no proporciona el código fuente. Si nuestro equipo funciona bien sin software privativo podríamos omitirlo.

linux@debian:~$ sudo mkdir /mnt/sdc1
linux@debian:~$ sudo mount /dev/sdc1 /mnt/sdc1
linux@debian:~$ cd / 
linux@debian:/$ tar cvJf /mnt/sdc1/linux-3.2.0-2-debian.txz \
> boot/vmlinuz-3.2.0-2-amd64 \ 
> boot/initrd.img-3.2.0-2-amd64 \ 
> boot/System.map-3.2.0-2-amd64 \ 
> lib/firmware/ \ 
> lib/modules/3.2.0-2-amd64/ 
linux@debian:/$ sudo umount /dev/sdc1
linux@debian:/$ exit

Ahora ya puedo apagar el equipo Debian (siempre de forma controlada, por supuesto) y enchufar el USB con el kernel extraído en mi máquina. En esta máquina, la partición vfat del USB se monta en /media/USBDATA. El siguiente paso es instalarlo en LFS usando el script que tenemos para ello. El fichero txz que hemos generado es compatible con él, si hemos puesto las opciones de tar correctas y hemos comprimido desde el raíz.

[~]$ sudo lfsinst /media/USBDATA/linux-3.2.0-2-debian.txz

Voy a hacer lo mismo con el kernel de Arch. No tengo la misma garantía que con el de Debian, pero intuyo que va a funcionar y además sirve como ejemplo de cómo hacer lo mismo con otra distro, ya que es parecido pero diferente. En este caso estoy lanzando los comandos en mi máquina principal, así que no tengo que montar nada. Es la misma máquina en la que estoy instalando LFS.

[~]$ cd /
[/]$ tar cvJf ~/lfs/linux-3.8.4-1-ARCH.txz \
> boot/vmlinuz-linux \
> boot/initramfs-linux.img \
> lib/firmware \
> lib/modules/3.8.4-1-ARCH \
> lib/modules/extramodules-3.8-ARCH/ \
> lib/modprobe.d/
[/]$ cd ~/lfs
[~/lfs]$ sudo lfsinst ~/lfs/linux-3.8.4-1-ARCH.txz

Ya tengo nada menos que dos kernels alternativos en mi LFS. Con uno sería suficiente, pero así confirmo que es factible arrancar desde nuestro sistema. Esos kernels tienen sus propios initrd en los que estarán las herramientas que el kernel necesita para detectar el USB y luego localizar y montar la partición raíz.

Con esto podemos solucionar el primer problema que teníamos: usar un initrd que soporte USB. Falta el segundo: localizar la partición por UUID. Para ello, en primer lugar, hay que averiguar el UUID de la partición raíz de nuestro LFS. Esto se puede hacer examinando el directorio /dev/disk/bu-uuid, donde el kernel deja todos los dispositivos que detecta organizados por UUID.

[~/lfs]$ ls -l /dev/disk/by-uuid/ | grep sdc3
lrwxrwxrwx 1 root root 10 Apr  2 18:55 dd02b529-840e-4ffa-9433-e2709dffd81c -> ../../sdc3

O sea que el UUID de mi partición raíz de LFS es dd02b529-840e-4ffa-9433-e2709dffd81c. Este UUID no cambia nunca lo enchufemos donde lo enchufemos mientras no formateemos la partición, así que es seguro localizarla por este UUID.

Ya tenemos todo lo que necesitamos para arrancar desde USB. Ahora sólo falta actualizar los ficheros de configuración de los gestores de arranque. Sigo teniendo instalados tanto grub como Syslinux, así que voy a probar con los dos. Hay que añadir los dos nuevos kernels (o los que hayáis extraido vosotros) teniendo cuidado de especificar el initrd. Además hay que cambiar el nombre de la partición raíz por el UUID. Esto lo voy a hacer también con el kernel de LFS, aunque de momento no va a funcionar desde USB.

Primero mi gestor de arranque favorito: Syslinux.

[~/lfs]$ sudo lfs
root:/# cat > /boot/extlinux/extlinux.conf << "EOF"
> PROMPT 1
> TIMEOUT 50
> DEFAULT lfs
> 
> LABEL lfs
>     LINUX ../vmlinuz-3.5.2-lfs-7.2
>     APPEND root=UUID=dd02b529-840e-4ffa-9433-e2709dffd81c ro
>
> LABEL lfsdebian
>     LINUX ../vmlinuz-3.2.0-2-amd64
>     APPEND root=UUID=dd02b529-840e-4ffa-9433-e2709dffd81c ro
>     INITRD ../initrd.img-3.2.0-2-amd64
>
> LABEL lfsarch
>     LINUX ../vmlinuz-linux
>     APPEND root=UUID=dd02b529-840e-4ffa-9433-e2709dffd81c ro
>     INITRD ../initramfs-linux.img
> EOF

Ahora hacemos lo mismo con el grub.

root:/# cat > /boot/grub/grub.cfg << "EOF"
> # Begin /boot/grub/grub.cfg
> set default=0
> set timeout=5
>
> insmod ext2
> set root=(hd0,3)
>
> menuentry "GNU/Linux, Linux 3.5.2-lfs-7.2" {
>         linux   /boot/vmlinuz-3.5.2-lfs-7.2 root=UUID=dd02b529-840e-4ffa-9433-e2709dffd81c ro
> }
>
> menuentry "GNU/Linux, Linux 3.2.0-2-amd64 debian" {
>         linux   /boot/vmlinuz-3.2.0-2-amd64 root=UUID=dd02b529-840e-4ffa-9433-e2709dffd81c ro
>         initrd  /boot/initrd.img-3.2.0-2-amd64
> }
>
> menuentry "GNU/Linux, Linux 3.8.4-1 arch" {
>         linux   /boot/vmlinuz-linux root=UUID=dd02b529-840e-4ffa-9433-e2709dffd81c ro
>         initrd  /boot/initramfs-linux.img
> }
> EOF

Ahora podemos probar a arrancar con los dos gestores de arranque para ver si funciona. Claro, el detalle que nos falta es que no se puede arrancar con dos gestores de arranque a la vez, así que sólo puede haber uno configurado para arrancar el USB. Cuando instalemos uno en el MBR quitará al otro y viceversa, así que para cambiar de uno a otro hay que usar el comando que instala en el MBR el gestor de arranque que queremos probar.

Para arrancar con Syslinux:

root:/# cat /usr/share/syslinux/mbr.bin > /dev/sdc

Ojo: Syslinux necesita que la partición esté marcada como arrancable en la tabla de particiones. Esto ya lo hemos hecho en el post anterior, así que no debería haber problema, pero no está de más verificarlo con fdisk.

Para arrancar con grub:

root:/# grub-install /dev/sdc

Así que lanzamos uno de los dos comandos anteriores, probamos los dos kernels, lanzamos el otro y volvemos a probar. Y el resultado es…

…¡Que ha funcionado tanto con grub como con Syslinux y con los dos kernels!! 🙂

Por ahora eso es todo. Por supuesto, tenemos que crear nuestro propio initrd. No vamos a ser menos. 🙂 Pero eso para más adelante. En el siguiente post lo que vamos a crear es un usuario para no tener que trabajar con la cuenta de root.

EOF

Anuncios