Lo hice y lo entendí

El blog de Vicente Navarro
23 nov

Tres formas de instalar GRUB

En la mayoría de los casos, un usuario de Linux rara vez necesitará enfrentarse a la instalación manual de GRUB, el gestor de arranque más común para Linux, ya que en el momento de la instalación de su distribución favorita, ésta lo hará por él. En muchos casos, puede ser suficiente para el usuario medio saber cómo editar el fichero /boot/grub/menu.lst para modificar las entradas del menú de arranque de acuerdo a sus necesidades. Sin embargo, sigue habiendo casos en los que necesitaremos hacer esta instalación manualmente.

Por ejemplo, en entradas anteriores vimos cómo instalar manualmente GRUB en una memoria USB para poder arrancar múltiples sistemas operativos desde ella:

También vimos cómo, en caso de estar trabajando sobre un fakeRAID, el instalador de la distribución no es capaz de instalar GRUB con éxito, teniendo que hacerlo nosotros mismos manualmente:

Esta entrada pretende resumir las diferentes técnicas que ya habíamos visto previamente en un único documento que sirva de referencia, así como dar algunos detalles adicionales sobre el funcionamiento interno de GRUB. Por supuesto, toda esta información ya existe, como no podía ser de otra forma, en el manual de GRUB.

Para empezar, convendría recordar los componentes que conforman GRUB. Los ficheros implicados en la instalación de GRUB en el sector de arranque los encontraremos en /boot/grub/, pero éstos realmente provienen de /usr/lib/grub/i386-pc/ o /usr/lib/grub/x86_64-pc/, según la arquitectura:

-rw-r--r-- 1 root root   7552 2008-04-12 00:44 e2fs_stage1_5
-rw-r--r-- 1 root root   7424 2008-04-12 00:44 fat_stage1_5
-rw-r--r-- 1 root root   8192 2008-04-12 00:44 jfs_stage1_5
-rw-r--r-- 1 root root   6848 2008-04-12 00:44 minix_stage1_5
-rw-r--r-- 1 root root   9248 2008-04-12 00:44 reiserfs_stage1_5
-rw-r--r-- 1 root root    512 2008-04-12 00:44 stage1
-rw-r--r-- 1 root root 108328 2008-04-12 00:44 stage2
-rw-r--r-- 1 root root   8872 2008-04-12 00:44 xfs_stage1_5

En primer lugar, tenemos el stage1, un fichero de apenas 512 bytes, lo justo para que quepa en el Master Boot Record (MBR) o en el sector de arranque de alguna de las particiones primarias. En éstos 512 bytes apenas hay espacio para un poco de código de inicialización del sistema y para cargar el stage2, que es donde está todo el código de GRUB. Como el stage1 no tiene capacidad, en tan poco código, para buscar en un sistema de ficheros dónde está el stage2, hay que escribir un stage1 modificado que lleve la posición exacta del fichero stage2 en disco para que pueda leerlo directamente. El problema de ese procedimiento es que si movemos el stage2 de sitio (un movimiento físico dentro del disco, aunque realmente no cambie de sitio en la jerarquía de directorios), el stage1 no sabrá encontrar al stage2.

Por eso GRUB también lleva varios ficheros sistemadeficheros_stage1_5. Cuando instalamos GRUB en el MBR, el stage1_5 se escribe en el hueco que hay entre el sector de arranque, de 512 bytes, y la primera partición, que empieza tras los primeros 32 KiB del disco (ver Montar una imagen raw de Qemu. Los primeros 32 Kbytes de un disco.). El stage1_5, que ya puede contener algo más de código, sí que es capaz de entender un tipo de sistema de ficheros (ext2/3, JFS, ReiserFS, XFS, FAT) lo suficiente para poder localizar en él el stage2 sin problemas, aunque éste haya cambiado de sitio físicamente en el disco.

Por tanto, al arrancar un sistema con GRUB instalado en el MBR, donde los ficheros de /boot/grub/ están en un sistema de ficheros ext2/3, lo que ocurrirá es que el procesador cargará el código de stage1 del primer sector. Este código a su vez arrancará el e2fs_stage1_5, que estará en el segundo sector del disco. Y éste, a su vez, con capacidad de moverse por el sistema de ficheros, localizará el stage2 y lo cargará. Ahora ya tendremos el GRUB completamente cargado y listo para gestionar todos los sistemas de ficheros soportados. En este punto ya podremos usar comandos de la shell de GRUB de manejo de ficheros como find, cat, cmp o el autocompletado de los nombres de ficheros/directorios con la tecla TAB.

GRUB usa una nomenclatura propia para discos duros y particiones. Los discos duros son (hd0), (hd1), (hd2), (hd3), etc. Las particiones del disco (hdX) son (hdX,0), (hdX,1), (hdX,2), etc. La cuenta siempre empieza por cero (0), y es importante tenerlo siempre presente porque en los ficheros de dispositivo de partición (p.e. /dev/sda1) la cuenta empieza por uno (1).

Y es precisamente ese el meollo de GRUB y la fuente más importante de problemas, que qué disco es (hd0) y qué disco es (hd3) según la BIOS. Hace unos años, cuando los PCs sólo sabían arrancar de CD/DVD, de disquete, y los discos siempre eran IDE, saber esto era extremadamente fácil. El disco maestro del canal IDE primario siempre iba a ser (hd0), y por detrás se ordenarían el disco esclavo del canal IDE primario y los discos del canal IDE secundario. Hoy en día, esto se ha complicado muchísimo: En nuestro PC conviven discos IDE, discos SATA (en ocasiones incluso tenemos varias controladoras), discos externos USB y otras extravagancias como discos en fakeRAID. ¿Cuál de ellos es el primero y cuál el segundo? El orden de arranque que establecemos en la BIOS es el factor que lo determina, pero ese orden lo alteraremos si durante el arranque pulsamos la tecla que, en nuestra placa base, saque el menú de selección del dispositivo de arranque (típicamente el Boot menu).

El asunto se complica porque dentro de Linux, los dispositivos que se asignen al disco, no tendrán, en la mayoría de los casos, nada que ver con ese orden. Ya dentro del sistema operativo, tendremos cosas como /dev/hda, /dev/hdb, /dev/sda, /dev/sdi y /dev/mapper/dispositivo_fakeraid, nada que nos dé una pista sobre quién es (hd0) y quién es (hd3). Al menos, algo sabemos seguro, y es que (hd0) es el disco del que la BIOS va a arrancar.

Así, para instalar GRUB en un disco (por ejemplo, en uno USB externo) desde nuestra distribución actual de Linux, podríamos, simplemente, usar el grub-install, al que le tenemos que indicar dónde está montada la partición donde tiene copiar los ficheros *stage* dentro de /boot/grub/, y el dispositivo donde escribir el GRUB. Puede ser un dispositivo de disco (p.e. /dev/sdi) y el GRUB se escribirá en el MBR; o puede ser un dispositivo de partición (p.e. /dev/sdi1) y el GRUB se escribirá en el sector de arranque de la partición:

$ sudo grub-install --no-floppy --root-directory=/media/disk /dev/sdi
Probing devices to guess BIOS drives. This may take a long time.
Installing GRUB to /dev/sdi as (hd4)...
Unknown partition table signature
Installation finished. No error reported.
This is the contents of the device map /media/disk/boot/grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-run the script `grub-install'.

(hd0)	/dev/sda
(hd1)	/dev/sdb
(hd2)	/dev/sdc
(hd3)	/dev/sdh
(hd4)	/dev/sdi

Vemos que grub-install intenta emparejar los ficheros de dispositivo de los discos con los números de disco que la BIOS le ha asignado al disco. Esto es una potencial fuente de problemas, porque hemos instalado GRUB en sdi especificando que es el cuarto disco (hd4), pero cuando vayamos a arrancar de este disco, para la BIOS será el primer disco (hd0).

Por eso, es mucho mejor, antes de ejecutar grub-install, especificar claramente en el fichero device.map del directorio /boot/grub/ del disco en el que queremos instalar GRUB, que el dispositivo en el que estamos instalando GRUB será (hd0) cuando vayamos a arrancar de él:

$ cd /media/disk

$ sudo mkdir -p boot/grub

$ sudo vi boot/grub/device.map

$ cat boot/grub/device.map
(hd0) /dev/sdi

$ sudo grub-install --no-floppy --root-directory=/media/disk/ /dev/sdi
Installing GRUB to /dev/sdi as (hd0)...
Installation finished. No error reported.
This is the contents of the device map /media/disk//boot/grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-run the script `grub-install'.

(hd0)	/dev/sdi

Fijémonos en que el propio fichero de dispositivo también es muy variable. En el caso de memorias USB, sólo depende del orden en el que las conectemos al ordenador. Por eso, es importante revisar el fichero device.map cada vez que necesitemos reinstalar GRUB.

Desafortunadamente, con según que tipos de ficheros de dispositivo, el comando grub-install se lía, porque no puede obtener el número de disco de la BIOS, incluso aunque se lo especifiquemos en el device.map. Es el caso, por ejemplo, de los fakeRAID:

$ cat /boot/grub/device.map 
/dev/mapper/nvidia_bdehcbaa (hd0)

$ sudo grub-install --no-floppy '(hd0)'
/dev/mapper/nvidia_bdehcbaa3 does not have any corresponding BIOS drive.

En estos casos, podemos usar la shell de GRUB que tenemos a nuestra disposición, que supone nuestro segundo método de instalación de GRUB. Esta shell es similar a la línea de comandos a la que podemos acceder desde el GRUB real que tenemos al arrancar, pero con sus peculiaridades, dado que se ejecuta dentro de un sistema operativo y no bajo la BIOS. La shell de GRUB dispone del comando device, que nos permite asociar a mano ficheros de dispositivo con discos y particiones de la BIOS:

 $ sudo grub  --device-map=/dev/null

       [ Minimal BASH-like line editing is supported.   For
         the   first   word,  TAB  lists  possible  command
         completions.  Anywhere else TAB lists the possible
         completions of a device/filename. ]
grub> device (hd0,2) /dev/mapper/nvidia_bdehcbaa3
device (hd0,2) /dev/mapper/nvidia_bdehcbaa3
grub> device (hd0) /dev/mapper/nvidia_bdehcbaa
device (hd0) /dev/mapper/nvidia_bdehcbaa
grub> root (hd0,2)
root (hd0,2)
grub> setup (hd0)
setup (hd0)
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/e2fs_stage1_5" exists... yes
 Running "embed /boot/grub/e2fs_stage1_5 (hd0)"...  16 sectors are embedded.
succeeded
 Running "install /boot/grub/stage1 (hd0) (hd0)1+16 p (hd0,2)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded
Done.

La tercera forma de instalar GRUB es por medio de la línea de comandos del GRUB real, el que tenemos en el momento del arranque. Desde un GRUB instalado en un disco/partición, instalamos otro GRUB en otro disco/partición. Este procedimiento escribirá el stage1 en el sector de arranque, y el stage1_5 en el hueco disponible si procede, pero no copiará los ficheros *stage* al directorio /boot/grub/ de la partición destino. Eso lo tenemos que hacer de forma manual previamente:

$ mkdir -p /media/disk/boot/grub

$ cp -p /usr/lib/grub/i386-pc/* /media/disk/boot/grub/

Una vez que el disco/partición destino ya tiene los ficheros *stage*, rearrancaremos el sistema y en el propio menú de GRUB:

pulsaremos la tecla “C” para entrar en su línea de comandos. En ella, buscamos en qué discos tenemos los ficheros *stage* con el comando find. Tenemos que encontrarlos en al menos dos sitios, en el disco/partición desde el que hemos arrancado GRUB, y en el disco/partición en el que vamos a instalar GRUB:

grub> find /boot/grub/stage2
 (hd0,0)
 (hd1,0)

Y finalmente, usamos el comando setup indicando el dispositivo donde escribiremos el stage1 (puede ser un disco o una partición) y la partición donde ha de buscar los ficheros *stage*:

grub> setup (hd1) (hd1,0)

La gran ventaja de este sistema es que ahora GRUB no se fía en ningún momento de lo que le diga el sistema operativo, y usará los números de unidades que le pase directamente la BIOS, una garantía para no equivocarnos.

Por cierto, si en algún caso necesitamos deshacernos del GRUB que tenemos instalado en el MBR, podemos usar el ms-sys (Ubuntu y Debian eliminan ms-sys de sus repositorios) en Linux y el MBRFix en Windows (Instalar Windows XP desde una memoria USB que arranque BartPE) para instalar el MBR típico de los sistemas operativos de Microsoft, que lo único que hace es cargar el sector de arranque de la partición que esté activa (que, por supuesto, podría dar la casualidad de que contuviera un stage1 de GRUB, claro).

:wq

Entradas relacionadas

4 Comentarios a “Tres formas de instalar GRUB”

Tema LHYLE09, creado por Vicente Navarro