Blog de Óscar

El Ingeniero de Sistemas Exóticos

Crear un USB multiboot

Hoy en día lo normal es que cuando queremos hacer un USB arrancable para instalar nuestra distribución preferida, terminemos tirando de dd para copiarnos la ISO tal cual. Este método es muy funcional porque con un comando simple tenemos nuestro dispositivo listo para arrancar, pero por norma general acabamos tirando espacio que podríamos aprovechar. Preparando un llavero multi-arranque podemos evitar esto y además tener un dispositivo que nos valga, no solo para instalar nuestra distribución preferida, sino también para instalar otras o incluso para arrancarlas en formato live.

Pese a que existen herramientas como MultiBootUSB que nos ayudan a crear este tipo de dispositivos multi-arrancables, en este artículo comentaré como realizar el proceso de manera manual y así evitarnos también algunos fallos que tienen estas herramientas.

Preparando el USB

Lo primero que tenemos que saber es que hoy en día conviven lo que llamaremos dos métodos de arranque distintos. Por un lado esta el clásico de los ordenadores mas antiguos conocido como BIOS y por otro el nuevo de máquinas mas modernas UEFI. Por lo que debemos preparar nuestro USB para que arranque en ambos sistemas.

Personalmente me he leído unas cuantas guías que hablan sobre este problema y muchas de ellas complican en exceso la solución. Dicen de hacer varias particiones en el dispositivo, formatear cada una con un sistema de ficheros distinto, etc. Yo considero que el método mas eficaz es simplemente tener una única partición FAT32 (que la va a poder leer hasta el apuntador) y luego utilizar las ISO de manera directa. De tal forma que luego cambiar una versión de una distribución por la siguiente sea tan sencillo como borrar la ISO anterior y copiar la nueva.

Particionando y formateando el USB

OJO, esto es completamente destructivo, por lo que asegúrate bien de que no tienes nada importante (como las fotos de tus vacaciones en pelotas en Tahití) en tu USB.

Suponiendo que nuestra unidad se encuentre en /dev/sdX haremos lo siguiente.

sudo fdisk /dev/sdX

Crearemos una nueva tabla de particiones DOS con el comando o. Luego una nueva partición con n y aceptamos los valores por defecto (partición 1, valores predeterminados para el primer y el último sector). En este paso nos podría indicar que ha encontrado una firma en el dispositivo, esto es normal si ya nos venía particionado de alguna manera anteriormente, le decimos que sí, que la elimine. Cambiamos el tipo de partición con el comando t y le indicamos c para el tipo W95 FAT32 (LBA). Usamos el comando a para activar la partición.

Para revisar que todo es correcto utilizamos el comando p donde nos tiene que indicar algo similar a lo siguiente.

Disco /dev/sdX: 7,22 GiB, 7746879488 bytes, 15130624 sectores
Modelo de disco: USB DISK 2.0
Unidades: sectores de 1 * 512 = 512 bytes
Tamaño de sector (lógico/físico): 512 bytes / 512 bytes
Tamaño de E/S (mínimo/óptimo): 512 bytes / 512 bytes
Tipo de etiqueta de disco: dos
Identificador del disco: 0xfe7d93cb

Disposit.  Inicio Comienzo    Final Sectores Tamaño Id Tipo
/dev/sdf1  *          2048 15130623 15128576   7,2G  c W95 FAT32 (LBA)

Evidentemente los valores de tamaño o el identificador va a variar dependiendo del dispositivo. Si todo es correcto usamos el comando w para guardar los cambios y salir.

Ahora formateamos la nueva partición en FAT32 y de paso le ponemos una etiqueta MULTIBOOT.

sudo mkfs.fat -F32 -n MULTIBOOT /dev/sdX1

Con esto ya tenemos listo el USB para instalar en él el gestor de arranque.

Instalando el gestor de arranque GRUB2 en el USB

Creamos un directorio de trabajo donde vamos a montar el USB y lo montamos.

sudo mkdir /usb
sudo mount /dev/sdX1 /usb

Creamos un directorio boot en el USB.

sudo mkdir /usb/boot

Instalamos GRUB2 para los sistemas BIOS.

sudo grub-install --target=i386-pc --recheck --boot-directory=/usb/boot /dev/sdX

Y GRUB2 para los sistemas UEFI.

sudo grub-install --target x86_64-efi --removable --boot-directory=/usb/boot --efi-directory=/usb

Podemos desmontar ahora el USB y borrar el directorio temporal ya que para incluir los ficheros ya podemos hacerlo como usuario normal.

sudo umount /usb
sudo rmdir /usb

Configurando las distribuciones en el USB

Ahora que ya tenemos la unidad preparada y GRUB2 instalado podemos decir que hemos finalizado con la parte mas delicada (al menos la mas destructiva al usar comandos como root). Nos quedaría ir añadiendo las distribuciones que nos interesen, tanto en la memoria como en el gestor de arranque. Aquí se presenta un dilema interesante y es que cada distribución se arranca de una manera distinta, por lo que tendremos que leer documentación si queremos agregar algo que no venga en esta guía.

Comenzaremos haciendo cd al directorio raíz de nuestro USB para editar el fichero boot/grub/grub.cfg donde introducimos lo siguiente.

insmod all_video
set gfxpayload=keep

Esto es para que no nos de el error no video mode set y es la configuración común. Si miramos manuales de GRUB2 veremos que tenemos muchas mas opciones para poner aquí como cambiar los colores o poner una imagen de fondo. Eso ya os lo dejo a vuestro criterio, en mi caso me he ido mas a que funcione que a hacerlo bonito.

Con esto tenemos la parte básica de la configuración creada. A partir de aquí se trata de meter elementos de menú para cada distribución que queramos arrancar.

Arch Linux

Para Arch, nos descargamos la ISO y la metemos en el USB en el directorio iso (se le puede poner otro nombre al directorio si se quiere, pero luego hay que cambiarlo en la configuración de GRUB2).

Suponiendo que la ISO que hayamos descargado sea la archlinux-2019.11.01-x86_64.iso, editamos boot/grub/grub.cfg e introducimos.

submenu "Arch Linux   --->" {
  set isover="2019.11.01"
  set isoarch="x86_64"
  set isofile="/iso/archlinux-${isover}-${isoarch}.iso"
  loopback loop ${isofile}
  menuentry "Arch Linux ${isover} ${isoarch}" {
    echo "Using ${isofile}..."
    probe -u ${root} --set=rootuuid
    linux  (loop)/arch/boot/x86_64/vmlinuz img_dev=/dev/disk/by-uuid/${rootuuid} img_loop=${isofile}
    initrd (loop)/arch/boot/intel_ucode.img (loop)/arch/boot/amd_ucode.img (loop)/arch/boot/x86_64/archiso.img
  }
  menuentry "Run Memtest86+ (RAM test)" {
    echo "Using ${isofile}..."
    linux16 (loop)/arch/boot/memtest
  }
}

Esto nos crea una sección de menú exclusiva para Arch donde tendremos dos opciones, la primera arranca la distribución en si misma y la segunda arranca el Memtest86+ incluido en la ISO.

Debian Mini

Debian tiene diferentes imágenes ISO, una de las mas interesantes por el poco tamaño que ocupa es la mini.iso, que contiene únicamente el instalador y requiere de conexión para poder instalar. Se puede descargar desde la web oficial en la sección de CD pequeños, memorias USB flexibles, etc, escogiendo arquitectura y yendo al directorio netboot.

Suponiendo que una vez descargada la ISO le ponemos de nombre debian-mini-10.1.0-amd64.iso, la metemos en el directorio iso del USB y editamos boot/grub/grub.cfg e introducimos.

submenu "Debian Mini  --->" {
  set isover="10.1.0"
  set isoarch="amd64"
  set isofile="/iso/debian-mini-${isover}-${isoarch}.iso"
  loopback loop ${isofile}
  menuentry "Debian ${isover} ${isoarch} mini install" {
    echo "Using ${isofile}..."
    linux  (loop)/linux
    initrd (loop)/initrd.gz
  }
  submenu "Debian ${isover} ${isoarch} Advanced options ..." {
    set isover="10.1.0"
    set isoarch="amd64"
    set isofile="/iso/debian-mini-${isover}-${isoarch}.iso"
    loopback loop ${isofile}
    menuentry "... Expert install" {
      echo "Using ${isofile}..."
      linux  (loop)/linux priority=low
      initrd (loop)/initrd.gz
    }
    menuentry "... Rescue mode" {
      echo "Using ${isofile}..."
      linux  (loop)/linux rescue/enable=true
      initrd (loop)/initrd.gz
    }
    menuentry "... Automated install" {
      echo "Using ${isofile}..."
      linux  (loop)/linux auto=true priority=critical
      initrd (loop)/initrd.gz
    }
  }
}

Esta configuración nos crea una serie de menús con los diferentes modos de arranque que tiene la mini.iso de Debian.

Debian Live

Aparte de las imágenes mínimas, Debian tiene todo un set de imágenes Live. La diferencia principal entre ellas es su tamaño dependiendo del entorno que queramos arrancar, ya sea solo una consola de texto hasta un GNOME o KDE completo.

En este ejemplo estoy usando la imagen debian-live-10.1.0-amd64-xfce.iso por ser la que menos ocupa con entorno gráfico, pero la configuración es similar para cualquiera de ellas. Editamos boot/grub/grub.cfg e introducimos.

submenu "Debian Live  --->" {
  set isover="10.1.0"
  set isoarch="amd64"
  set isofile="/iso/debian-live-${isover}-${isoarch}-xfce.iso"
  loopback loop ${isofile}
  menuentry "Debian ${isover} ${isoarch} live" {
    echo "Using ${isofile}..."
    linux  (loop)/live/vmlinuz-4.19.0-6-amd64 boot=live findiso=${isofile} components
    initrd (loop)/live/initrd.img-4.19.0-6-amd64
  }
}

La mayor dificultad que tiene esta ISO es que tanto el kernel como el initrd no tienen un nombre fijo sino que varía en cada versión. Como podemos ver en la configuración estos ficheros se encuentran en el directorio /live dentro de la imagen. Por lo que si estamos usando una versión distinta tendremos que montar la ISO para ver el nombre de los ficheros.

Ubuntu Mini

Al igual que Debian, Ubuntu tiene una mini.iso con la que podemos realizar una instalación en línea. Se puede descargar desde su web de cdimages.

Suponiendo que una vez descargada la ISO le ponemos de nombre ubuntu-19.10-mini-amd64.iso, la metemos en el directorio iso del USB y editamos boot/grub/grub.cfg e introducimos.

submenu "Ubuntu Mini  --->" {
  set isover="19.10"
  set isoarch="amd64"
  set isofile="/iso/ubuntu-${isover}-mini-${isoarch}.iso"
  loopback loop ${isofile}
  menuentry "Ubuntu ${isover} ${isoarch} mini install" {
    echo "Using ${isofile}..."
    linux  (loop)/linux
    initrd (loop)/initrd.gz
  }
  submenu "Ubuntu ${isover} ${isoarch} Advanced options ..." {
    set isover="19.10"
    set isoarch="amd64"
    set isofile="/iso/ubuntu-${isover}-mini-${isoarch}.iso"
    loopback loop ${isofile}
    menuentry "... Command-line install" {
      echo "Using ${isofile}..."
      linux	(loop)/linux tasks=standard pkgsel/language-pack-patterns= pkgsel/install-language-support=false
      initrd (loop)/initrd.gz
    }
    menuentry "... Expert install" {
      echo "Using ${isofile}..."
      linux	(loop)/linux priority=low
      initrd (loop)/initrd.gz
    }
    menuentry "... Command-line expert install" {
      echo "Using ${isofile}..."
      linux	(loop)/linux tasks=standard pkgsel/language-pack-patterns= pkgsel/install-language-support=false priority=low
      initrd (loop)/initrd.gz
    }
    menuentry "... Rescue mode" {
      echo "Using ${isofile}..."
      linux	(loop)/linux rescue/enable=true
      initrd (loop)/initrd.gz
    }
  }
}

De la misma manera que en la configuración de Debian, tenemos los diferentes modos de arranque para la mini.iso.

Ubuntu Live (o derivadas)

En el caso del Live de Ubuntu o cualquiera de sus derivadas la configuración es idéntica, solo cambia el nombre de la ISO. En este caso vamos a usar Lubuntu por ser mas ligera.

Suponiendo que nuestra imagen sea lubuntu-19.10-desktop-amd64.iso editamos boot/grub/grub.cfg e introducimos.

submenu "Lubuntu Live --->" {
  set isover="19.10"
  set isoarch="amd64"
  set isofile="/iso/lubuntu-${isover}-desktop-${isoarch}.iso"
  loopback loop ${isofile}
  menuentry "Lubuntu ${isover} ${isoarch} live" {
    echo "Using ${isofile}..."
    linux  (loop)/casper/vmlinuz boot=casper iso-scan/filename=${isofile} noprompt noeject
    initrd (loop)/casper/initrd
  }
  menuentry "Lubuntu ${isover} ${isoarch} live (safe graphics)" {
    echo "Using ${isofile}..."
    linux  (loop)/casper/vmlinuz boot=casper iso-scan/filename=${isofile} noprompt noeject nomodeset
    initrd (loop)/casper/initrd
  }
}

Puppy Linux

El caso de Puppy Linux es un poco especial. A diferencia de otras distribuciones esta no es capaz de finalizar el arranque directamente de la ISO. Esto es debido a que necesita acceder a unos ficheros squashfs que están en el raíz de la imagen, pero el kernel no tiene opción para ello.

Para arrancar Puppy necesitamos extraer los ficheros vmlinuz, initrd.gz y los que tienen la extensión sfs (para la última versión disponible de 64bit son puppy_xenialpup64_7.5.sfs y zdrv_xenialpup64_7.5.sfs) de la imagen ISO y los copiamos a nuestro USB en un directorio puppy que crearemos en la raíz del mismo. Editamos luego boot/grub/grub.cfg e introducimos.

submenu "Puppy Linux  --->" {
  set isover="8.0"
  set isoarch="amd64"
  menuentry "Puppy Linux ${isover} ${isoarch} live" {
    echo "Booting puppy from ${root}..."
    linux  /puppy/vmlinuz pmedia=usbflash psubdir=puppy
    initrd /puppy/initrd.gz
  }
  submenu "Puppy Linux ${isover} ${isoarch} Advanced options ..." {
    menuentry "... Command-line" {
      echo "Booting puppy from ${root}..."
      linux  /puppy/vmlinuz pmedia=usbflash psubdir=puppy pfix=nox
      initrd /puppy/initrd.gz
    }
    menuentry "... Ram disk shell" {
      echo "Booting puppy from ${root}..."
      linux  /puppy/vmlinuz pmedia=usbflash psubdir=puppy pfix=rdsh
      initrd /puppy/initrd.gz
    }
  }
}

Herramientas variadas

Aparte de tener distribuciones completas en nuestro USB podemos meter herramientas diversas. Realmente estas herramientas son similares a una distribución cualquiera, solo que vienen preparadas con lo necesario para arrancar dicha herramienta.

Cómo el método es exactamente el mismo, solo pondré las configuraciones necesarias.

Clonezilla

Descargar ISO de Clonezilla.

submenu "Clonezilla   --->" {
  set isover="2.6.4-10"
  set isoarch="amd64"
  set isofile="/iso/clonezilla-live-${isover}-${isoarch}.iso"
  loopback loop ${isofile}
  menuentry "Clonezilla ${isover} ${isoarch} live" {
    echo "Using ${isofile}..."
    linux  (loop)/live/vmlinuz boot=live findiso=${isofile} union=overlay components noeject toram=live,syslinux
    initrd (loop)/live/initrd.img
  }
}

GParted

Descargar ISO de GParted.

submenu "GParted      --->" {
  set isover="1.0.0-5"
  set isoarch="amd64"
  set isofile="/iso/gparted-live-${isover}-${isoarch}.iso"
  loopback loop ${isofile}
  menuentry "GParted ${isover} ${isoarch} live" {
    echo "Using ${isofile}..."
    linux  (loop)/live/vmlinuz boot=live username=user findiso=${isofile} union=overlay config components noswap noeject toram=filesystem.squashfs nosplash
    initrd (loop)/live/initrd.img
  }
  menuentry "GParted ${isover} ${isoarch} live (safe graphics)" {
    echo "Using ${isofile}..."
    set gfxpayload=text
    linux  (loop)/live/vmlinuz boot=live username=user findiso=${isofile} union=overlay config components noswap noeject toram=filesystem.squashfs nosplash nomodeset
    initrd (loop)/live/initrd.img
  }
  submenu "GParted ${isover} ${isoarch} live language options ..." {
    set isover="1.0.0-5"
    set isoarch="amd64"
    set isofile="/iso/gparted-live-${isover}-${isoarch}.iso"
    loopback loop ${isofile}
    menuentry "... English" {
      echo "Using ${isofile}..."
      linux  (loop)/live/vmlinuz boot=live username=user findiso=${isofile} union=overlay config components noswap noeject toram=filesystem.squashfs locales=en_US.UTF-8 keyboard-layouts=en_US nosplash
      initrd (loop)/live/initrd.img
    }
    menuentry "... English (safe graphics)" {
      echo "Using ${isofile}..."
      set gfxpayload=text
      linux  (loop)/live/vmlinuz boot=live username=user findiso=${isofile} union=overlay config components noswap noeject toram=filesystem.squashfs locales=en_US.UTF-8 keyboard-layouts=en_US nosplash nomodeset
      initrd (loop)/live/initrd.img
    }
    menuentry "... Spanish" {
      echo "Using ${isofile}..."
      linux  (loop)/live/vmlinuz boot=live username=user findiso=${isofile} union=overlay config components noswap noeject toram=filesystem.squashfs locales=es_ES.UTF-8 keyboard-layouts=es_ES nosplash
      initrd (loop)/live/initrd.img
    }
    menuentry "... Spanish (safe graphics)" {
      echo "Using ${isofile}..."
      set gfxpayload=text
      linux  (loop)/live/vmlinuz boot=live username=user findiso=${isofile} union=overlay config components noswap noeject toram=filesystem.squashfs locales=es_ES.UTF-8 keyboard-layouts=es_ES nosplash nomodeset
      initrd (loop)/live/initrd.img
    }
  }
  menuentry "Run Memtest86+ (RAM test)" {
    echo "Using ${isofile}..."
    linux16 (loop)/live/memtest
  }
}

Conclusión

Como podemos ver, aunque existen diferentes formas de montar un USB multi-arrancable con diversas herramientas, esta tal vez es la mas directa puesto que simplemente tenemos que copiar las ISO a la unidad y meter la entrada correspondiente en GRUB2 para arrancarla.

Las que he detallado aquí son las que a mi me parecen mas interesantes, pero hay muchas mas distribuciones y casi todas ellas se pueden utilizar con este método. En los proyectos MultiBoot USB y GRUB Live ISO Multiboot podemos sacar mas ideas de configuración para engrosar nuestra lista.

Por último comentar que al tener el USB formateado en VFAT lo podemos montar y utilizar desde cualquiera de las distribuciones que le hayamos metido, lo cual puede ser muy útil para almacenar lo que podamos haber generado con ellas.