"Después del juego es antes del juego"
Sepp Herberger

viernes, 10 de mayo de 2024

tty-share: permitir acceso remoto por terminal de forma inmediata y sencilla.

A veces sucede que necesitamos permitir la conexión remota, mediante terminal, de un tercero a una de nuestras máquinas para hacer alguna tarea de mantenimiento. Lo normal es habilitar la conexión por ssh, pero eso implica dar las credenciales, habilitar ssh en la máquina si no está habilitado y lidiar con problemas de puertos y redirecciones si estamos en redes distintas.

Una solución rápida y sencilla es usar tty-share. Es un único programa ejecutable que descargamos desde aquí.

El funcionamiento es sencillo: ejecutamos el programa en un terminal y se genera una URL que permite, desde otra máquina y abriéndola en un navegador web, iniciar una sesión remota de shell en la máquina y usuario donde hemos lanzado tty-share. Por tanto, pasamos la URL a otra persona y con su navegador podrá entrar y trastear sin contraseñas. Cuando queramos acabar cerramos tty-share y se cortará la conexión. Por ejemplo:
# ./tty-share_linux-amd64 -listen 172.X.Y.Z:8123 -headless
local session: http://172.X.Y.Z:8123/s/local/
Siendo 172.X.Y.Z la dirección IP de la máquina donde ejecutamos tty-share (sirve para decir en que tarjeta de red se escuchará) y 8123 el puerto donde se escuchará.

Cualguier colega a quien pasemos la URL http://172.X.Y.Z:8123/s/local/ y la ponga en un navegador abrirá una sesión de shell remota en nuestra máquina como si hubiera hecho un ssh. El único requisito es que la IP esté accesible desde red (es decir, que pueda desde su máquina hacer ping 172.X.Y.Z). Cuando cerremos tty-share (pulsando ctrl-c) la puerta que hemos abierto se cerrará. Fácil.

Una variante que podemos usar en casa es añadiendo el parámetro -public:
# ./tty-share_linux-amd64 -public -listen 172.X.Y.Z:8123 -headless
public session: https://on.tty-share.com/s/0-0ozhPF7pbykkpo-nSVvI378o6xR4KdcIg6ow46_NlXd-70ku-9eL4Gj5ujM18YPzs/
local session: http://172.X.Y.Z:8123/s/local/
En este caso se crea una URL adicional https://on.tty-share.com/s/..... que permite acceder a nuestra máquina a través de Internet aunque las redes sean distintas. Está posibilidad no funciona en la red educativa porque el firewall corta el acceso a tty-share por motivos de seguridad, pero para uso doméstico o en otras redes menos estrictas es también una buena solución de acceso temporal.

Out!

martes, 7 de mayo de 2024

Ampliar una partición ext3/4 después de clonarla.

Ya he comentado otras veces que es muy conveniente hacer las imágenes Clonezilla de las particiones con un tamaño muy pequeño con vistas a poder clonarlas luego en cualquier disco, ya que si no es un fastidio hacerlas encajar tal como vimos aquí. Yo suelo hacerlas con particiones de menos de 30GB siempre que sea posible y luego mas tarde redimensiono.

Antes redimensionaba usando gparted pero ahora quería redimensionar usando herramientas de consola, justo después de clonar con clonezilla y antes de reiniciar. Los comandos serían:
# parted /dev/sda resizepart 1 60GB
# e2fsck -f /dev/sda1
# resize2fs /dev/sda1
Lo que hacemos es ampliar la partición sda1 hasta la posición 60GB (es una posición absoluta en el disco, no un tamaño), luego chequeamos el sistema de ficheros para ver confirmar que está bien y por último expandimos el sistema de fichero para que se ajuste a la partición que ha crecido.

Ojo: esto no quiere decir que la partición pase a tener 60GB, sino que la partición crezca hasta llegar al sector 60GB del disco. Es decir, si la partición está entre las posiciones 5GB y 40GB y la ampliamos para poner el final en la posición 60GB, pasa de tener un tamaño de 35GB a tener un tamaño de 55GB. Por supuesto, si la posición 60GB está dentro de otra partición no nos dejará ampliar sda1.

De esta manera lo hacemos todo de un tirón: clonar, ampliar y reiniciar. Sencillo, ¿no?.

viernes, 3 de mayo de 2024

Disco usb/pendrive autoarrancable con Clonezilla, otra vez.

Esta entrada complementa a esta otra del pasado. En esta ocasión haremos un pendrive/disco externo USB con clonezilla que tiene solo una partición con todo lo necesario y arrancará mediante Legacy usando syslinux.cfg. Pasos a seguir:
  • Formatea el dispositivo a FAT32 con gparted o manualmente.
  • Descarga el clonezilla.zip que mas te guste: https://clonezilla.org/downloads/download.php?branch=stable
  • Descomprime el ZIP dentro de la raiz del dispositivo (pista: la carpeta GPL debe quedar en la raíz)
  • Ejecutamos makeboot para hacer bootable el pendrive:
    cd util/linux
    bash makeboot.sh /deb/sdXX   # por ejemplo: sda1
  • Metemos en home/partimag las imágenes deseadas (cada una en un subdirectorio, como siempre)

Al fichero syslinux/syslinux.cfg añadimos la parte en negrita de lo siguiente:
# Created by generate-pxe-menu! Do NOT edit unless you know what you are doing! 
# Keep those comment "MENU DEFAULT" and "MENU HIDE"! Do NOT remove them.
# Note!!! If "serial" directive exists, it must be the first directive
default vesamenu.c32
timeout 300
prompt 0
noescape 1
MENU MARGIN 5
 MENU BACKGROUND ocswp.png
# Set the color for unselected menu item and timout message
 MENU COLOR UNSEL 7;32;41 #c0000090 #00000000
 MENU COLOR TIMEOUT_MSG 7;32;41 #c0000090 #00000000
 MENU COLOR TIMEOUT 7;32;41 #c0000090 #00000000
 MENU COLOR HELP 7;32;41 #c0000090 #00000000

# MENU MASTER PASSWD

say **********************************************************************
say Clonezilla, the OpenSource Clone System.
say NCHC Free Software Labs, Taiwan.
say clonezilla.org, clonezilla.nchc.org.tw
say THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!
say **********************************************************************

# Allow client to edit the parameters
ALLOWOPTIONS 1

# simple menu title
MENU TITLE clonezilla.org, clonezilla.nchc.org.tw

# Since no network setting in the squashfs image, therefore if ip=, the network is disabled. That's what we want.
label Clonezilla Live
  MENU DEFAULT
  # MENU HIDE
  MENU LABEL Clonezilla live
  # MENU PASSWD
  kernel /live/vmlinuz
  append initrd=/live/initrd.img boot=live union=overlay username=user config components quiet noswap edd=on nomodeset noeject locales=es_ES.UTF-8 keyboard-layouts=es ocs_live_run="ocs-live-general" ocs_live_extra_param="" ocs_live_batch="no" vga=788 ip= net.ifnames=0  splash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1
  TEXT HELP
  * Boot menu for BIOS machine
  * Clonezilla live version: 2.5.5-38-amd64. (C) 2003-2018, NCHC, Taiwan
  * Disclaimer: Clonezilla comes with ABSOLUTELY NO WARRANTY
  ENDTEXT

label Clonezilla Live Auto
  # MENU HIDE
  MENU LABEL Clonezilla live - Install xubuntu22 to sda1
  # MENU PASSWD
  kernel /live/vmlinuz
  append initrd=/live/initrd.img boot=live union=overlay username=user config components quiet noswap edd=on nomodeset noeject locales=es_ES.UTF-8 keyboard-layouts=es ocs_prerun="sudo ln -s /lib/live/mount/medium/home/partimag/* /home/partimag/" ocs_live_run="/usr/sbin/ocs-sr -g auto -e1 auto -e2 -c -r -icds -j2 -scr -p choose restoredisk xubuntu22-universal sda" ocs_live_extra_param="" ocs_live_batch="no" vga=788 ip= net.ifnames=0  splash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1  TEXT HELP
  * Boot menu for BIOS machine
  * Clonezilla live version: 2.5.5-38-amd64. (C) 2003-2018, NCHC, Taiwan
  * Disclaimer: Clonezilla comes with ABSOLUTELY NO WARRANTY
  ENDTEXT

# Since no network setting in the squashfs image, therefore if ip=, the network is disabled. That's what we want.
label Clonezilla Live SSH
  #MENU DEFAULT
  # MENU HIDE
  MENU LABEL Clonezilla live SSH 
  # MENU PASSWD
  kernel /live/vmlinuz
  append initrd=/live/initrd.img boot=live union=overlay username=user config components quiet noswap edd=on nomodeset noeject locales=es_ES.UTF-8 keyboard-layouts=es ocs_live_run="ocs-live-general" ocs_live_extra_param="" ocs_live_batch="no" vga=788 ocsnet.ifnames=0  ocs_repository="ssh://root@172.19.X.Y/home/partimag/"  splash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1
  TEXT HELP
  * Boot menu for BIOS machine
  * Clonezilla live version: 2.5.5-38-amd64. (C) 2003-2018, NCHC, Taiwan
  * Disclaimer: Clonezilla comes with ABSOLUTELY NO WARRANTY
  ENDTEXT

MENU BEGIN Other modes of Clonezilla live

... Esta parte no la tocamos ...

MENU END
Lo añadido a la configuración estándar es:
  • La primera opción "Clonezilla live - Install xubuntu22 to sda1" arranca clonezilla y de forma automática restaura la imagen llamada xubuntu22-universal (el nombre del directorio en /home/partimag) sobre sda1.
  • La segunda opción "Clonezilla live SSH" arranca clonezilla, lo conecta a la red y monta /home/partimag por ssh sobre "ssh://root@172.19.X.Y/home/partimag", para que usemos las imágenes que allí haya.
Solo quedaría ajustarlo a nuestras circunstancias personales.

再见! Hasta la próxima.

miércoles, 24 de abril de 2024

Chequear mediante javascript si está instalada una extensión de Google Chrome

Que complicadas son a veces las cosas. Necesitaba asegurarme en la parte javascript de una página web de que Google Chrome tenía instalada una extensión determinada y me encuentro que no hay ninguna función en el API de Chrome que permita averiguarlo. La única manera es mediante métodos indirectos y cutres: intentar hacer algo con la extensión y capturar el error que salta si no está presente.

Hay varías maneras de hacerlo, esta es simplemente una de ellas. Necesitamos saber:
  1. La ID de la extensión, que es como su DNI que la identifica de forma universal. La instalamos desde https://chromewebstore.google.com/ y luego vamos a Gestionar Extensiones de nuestro Chrome.
  2. Elegimos la extensión en cuestión en "Gestionar Extensiones" y le damos a "Detalles". En la barra de la URL aparece el ID, por ejemplo: chrome://extensions/?id=pmlcjncilaaaemknfefmegedhcgelmee.
  3. Visualizamos al manifiesto de la extensión para ver la parte pública de la misma, esto se hace accediendo con la URL: chrome-extension://pmlcjncilaaaemknfefmegedhcgelmee/manifest.json (cambiar la parte en negrita por el ID de tu extensión).
  4. En el manifiesto, que es una estructura .json localizamos el atributo "web_accessible_resources.resources". Alli se enumeran los recursos de la extensión que son públicos.
  5. Elegimos uno de esos recursos públicos. Por ejemplo, dado el manifiesto:
     {
       "action": {
          "chrome_url_overrides": {
             "newtab": "popup.html"
          },
          "default_title": "__MSG_extName__"
       },
       "background": {
          "service_worker": "js/background.js"
       },
       "content_scripts": [ {
          "all_frames": false,
          "js": [ "js/content.js" ],
          "match_about_blank": false,
          "matches": [ "\u003Call_urls>" ],
          "run_at": "document_start"
       } ],
       "default_locale": "en",
       "description": "__MSG_extShortDesc__",
       "host_permissions": [ "\u003Call_urls>" ],
       "icons": {
          "128": "icons/icon-128.png",
          "16": "icons/icon-16.png",
          "300": "icons/icon-300.png",
          "48": "icons/icon-48.png"
       },
       "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxAT6Z9x4SMUH91sYicM+8qwroIqnrZoMYW4zd+0IX3DGnEtzUX6bNusmBjiwKydV9LvASRM5o12bmc+XuWsYr/G/YwzoKuVfmLHgr8JVfJDwS67XlYKHc1YeSLDI1r7mVrP2nr6W6MBfxRuxWz4QoAZxnaQkw9Dw+SNQksGQq2BIDt12uqSFavzEILGcURMM1+YdILVAEHLSiGVwiLveZfcZzPhS91tJNgawW/nagxxe7iuRE0ea0h+m4I9b3cHCW1oc22nUR9FIliXsslM1F6BZNQDxJoHBJM01+Jq5VDpInXTykeHvL2+v9JRhRrizeLsdRcPBKyIFZDROXQnR+wIDAQAB",
       "manifest_version": 3,
       "minimum_chrome_version": "88.0",
       "name": "__MSG_extName__",
       "offline_enabled": true,
       "permissions": [ "storage", "scripting", "alarms" ],
       "update_url": "https://clients2.google.com/service/update2/crx",
       "version": "1.0.5",
       "web_accessible_resources": [ {
          "matches": [ "\u003Call_urls>" ],
          "resources": [ "icons/*" ],
          "use_dynamic_url": false
       } ]
    }
    
    Podríamos escoger el recurso icons/icon-16.png. La URL para acceder a él sería: chrome-extension://pmlcjncilaaaemknfefmegedhcgelmee/icons/icon-16.png. Si abrimos esa URL en el navegador debería cargarse dicho icono. Ojo: igual que hemos elegido un .png podríamos haber elegido un .html o un .txt, no importa el tipo de recurso.
  6. La URL elegida anteriormente será la que usemos para chequear si existe la extensión desde JavaScript. Intentaremos acceder a dicha URL y si obtenemos HTTP 200 OK es que la extensión está instalada y activa, en caso contrario la extensión no está disponible. Es feo, pero funciona.


La función quedaría:
function extensionInstalada() {

	 var url = 'chrome-extension://pmlcjncilaaaemknfefmegedhcgelmee/icons/icon-16.png';
	 var hasExtension=null;

	 var xhr = new XMLHttpRequest();
	 xhr.onreadystatechange = function() {
		 if (xhr.readyState != 4) return;
		 if (xhr.status === 200) {
			   hasExtension=true;
		 }
	 };
	 xhr.open("GET", url, false);
	 try {
		  xhr.send();
	 } catch (error) {
		 hasExtension=false;
	 }
	 return hasExtension;

}  
El código JavasCript que comprobaría la extensión sería:
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
if (is_chrome == false) {
	 alert("Esto solo funciona con Google Chrome");
	 return;
}
resultado=extensionInstalada();
if (!resultado) {
	 alert("No tienes instalada la extensión XXX.");
	 return;
}
Y ya está. No me digan que Google no podría currarselo un poquito para hacerlo más sencillo.

Puppet: regla para instalar el paquete linux-headers del kernel actual.

Tras migrar a Xubuntu 22, quería instalar mediante puppet en los infolab el driver "nvidia-driver-390" y "nvidia-dkms-390". Estos paquetes necesitan que se haya instalado previamente el paquete linux-headers-xxx correspondiente al kernel que corre actualmente el sistema operativo.

El problema es que ninguno ambos paquetes instala linux-headers y, para mas inri, si no lo encuentran lo que sucede es que falla lo instalación. Tenemos que instalar nosotros a mano previamente el linux-headers-xxx y luego los nvidia-tal-390. Como odio hacer a mano cosas que son automatizables he encontrado la manera de instalarlo todo de un tirón usando puppet. Las reglas serían:
...
   # Facter $kernelrelease => 5.15.0-105-generic
  $kernel=regsubst($kernelrelease,'-generic', '', 'G') # Quitamos -generic y queda "5.15.0-105"
  
  package {"linux-headers-$kernel" : ensure =>installed }
  package {"nvidia-driver-390" : ensure =>installed }
  package {"nvidia-dkms-390" : ensure => installed }
  ....
Explicación: el problema es saber desde puppet que versión de los linux-headers tenemos que instalar. El truco está en usar el facter $kernelrelease, que nos devuelve el kernel instalado en la forma "xxx-generic". Si quitamos la parte "-generic" (con la función de puppet "regsubst") nos quedará la versión del kernel, que unida a "linux-headers-" nos permitirá instalar el paquete correcto. Voilà!

Puppet: regla para instalar VirtualBox completo en Ubuntu 22

Si queremos instalar VirtualBox al completo (VirtualBox, Guest Additions y Extension Pack) de forma automatizada mediante puppet en los equipos de nuestra red las reglas serían:
   ...
   package {"virtualbox": ensure => installed }
   ->
   package {"virtualbox-guest-additions-iso": ensure => installed }
   ->
   exec { "accept-virtualbox-license":
            command => "/bin/sh -c \"echo virtualbox-ext-pack virtualbox-ext-pack/license select true | sudo debconf-set-selections\""
   }
   ->
   package {"virtualbox-ext-pack" : ensure => installed }
   ....
La parte mas exótica es el "accept-virtualbox-license", que permite instalar luego el paquete virtualbox-ext-pack de forma automática sin preguntas al usuario. Si no se pone la instalación es interactiva (pregunta si aceptamos la licencia) y la regla puppet falla. De esta manera preparamos la respuesta a la pregunta antes de instalar el paquete.

Es de agradecer que ahora la instalación es mucho más sencilla que antaño, gracias a que en Ubuntu 22 se ha metido el paquete "virtualbox-ext-pack", que busca y descarga las Extension Pack adecuadas. Antes había que hacerlo todo a mano.

viernes, 23 de febrero de 2024

Cada alumno con su portátil

En mi centro muchos portátiles tienen uno o dos alumnos asignados, de tal manera que solo deberían ser usados por ellos. Esto tiene como consecuencia que no suelan sufrir desperfectos ya que al ser nominativos se incentiva su cuidado.

Pero este curso, no sé por que motivo, nos hemos encontrado en que los alumnos estaban usando los portátiles de forma libre, cogiendo el de sus compañeros al azar. Me han pedido que controlemos eso, evitando que nadie pueda usar un portátil que no sea el que tiene asignado. Está es la solución que he implementado.

Por un lado un script que se ejecuta al inicio de la sesión de usuario con:
# cat /etc/xdg/autostart/CheckUser.desktop                                                                
#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Icon[es_ES]=
Exec=/usr/local/bin/check_user
Name[es_ES]=Check authorized user
Name=Check authorized user
El script sería:
# cat /usr/local/bin/check_user
#!/bin/bash

usuario=$USER
equipo=$HOSTNAME
fecha=$(date)
file=/var/cache/.asignaciones.txt

#Si no hay fichero de asignaciones, salimos
test -e "$file" || exit 0

#Buscamos usuarios permitidos
permitidos=$(grep "^${equipo};" $file| cut -d";" -f3)

#Si no hay usuarios asignados, permitimos que lo use cualquiera
test -z "$permitidos"  &&  exit 0
test "$permitidos" == "-"  && exit 0

#Buscamos si usuario actual está permitido    
autorizado=$(echo $permitidos | grep -w $usuario)
test -z "$autorizado" || exit 0

sleep 5

#Cerramos los navegadores para que el usuario vea el mensaje
killall -9 firefox
killall -9 google-chrome
#Si llegamos aqui estamos intentando hacer login un un usuario no autorizado en el portátil
zenity --error --text="Usuario no autorizado en este portátil. Avise al profesor." --timeout 10 --width=600 --height=100
xfce4-session-logout

exit 0
Lo que hace es obtener el nombre de usuario y máquina y busca en el fichero /var/cache/.asignaciones.txt si el usuario está permitido en dicha máquina. Si no lo está, le manda un aviso y cierra la sesión.

El fichero /var/cache/.asignaciones.txt lo distribuyo por puppet en todos los portátiles y tiene este formato:
...
porthp-o19;b0:5a:da:a2:2d:0c;agomeza02
porthp-o20;30:8d:99:1d:f6:30;irenarr01
porthp-o21;30:8d:99:1c:ce:f4;lblancoa06
porthp-o21;30:8d:99:1c:ce:f4;mgarcias02
porthp-o22;30:8d:99:1a:dd:09;acarrerag27
porthp-o23;30:bd:23:22:8d:01;-
...
En este ejemplo anterior el portátil porthp-o20 sólo sería usable por el alumno irenarr01, el porthp-o21 estaría permitido a lblancoa06 y a mgarcias02, mientras que porthp-o23 podría ser usado por cualquier persona.

Lo mejor de todo: la cara de algunos alumnos cuando han venido a decirme que el portátil no les autorizaba el acceso, autoinculpándose de coger un portátil ajeno X-DDD...¿se puede ser más pardillo?

Montaje de recurso SAMBA falla en el arranque de los clientes Linux

Volvemos tras este prolongado silencio. Tengo varios recursos compartidos en un servidor samba que montan muchos equipos del centro en el arranque desde /etc/fstab con una línea como esta:
//192.168.0.99/media /media/media cifs _netdev,auto,user=user,password=password,rw,iocharset=iso8859-1,dir_mode=0777,file_mode=0777,vers=2.0
Durante años esto ha funcionado, pero tras unos cambios de ubicación de diversos recursos me he encontrado con que en algunas máquinas ya no se montaba la carpeta de forma automática en el inicio. Si una vez arrancada la máquina hacía:
# mount /media/media
Si se montaba sin problema. En el syslog veía que se producía un error de montaje en el inicio que daba a entender que se estaba intentando montar antes de estuviera disponible la red. Eso es absurdo ya que el parámetro _netdev de la línea de montaje le dice al sistema "hasta que no haya red, no montes". Pero no funciona, algo estaba fallando.

La solución adoptada es crear un fichero ejecutable en /etc/network/if-up.d/mountsmb con:
#!/bin/sh
mount -a
Esto ejecuta el script una vez que la tarjeta de red recibe IP y hay red disponible. En el script la línea "mount -a" fuerza el montaje de todo lo que hay en fstab marcado con el parámetro "auto". Y con eso se arregla el problema, aunque sigamos sin saber que lo originó.

Como dice el proverbio chino: siempre hay más soluciones que problemas.

jueves, 23 de marzo de 2023

Script para chequear el árbol LDAP

Los servicios LDAP que tenemos en los centros se basan en OpenLDAP, que guarda información en una base de datos jerárquica. Las bases de datos jerárquicas son esas que estudias en la carrera antes de las bases relacionales y luego olvidas para siempre, porque tienen un uso mucho más limitado. Si quieres saber más de ellas pincha aquí.

Pese a sus ventajas, como la rapidez para algunas consultas, tienen ciertas desventajas. Una de ellas es que, en el caso de OpenLDAP, los datos quedan inconsistentes con cierta frecuencia, de tal manera que se va acumulando "información basura" dentro de las diversas ramas. Por ejemplo: ramas vacías, grupos con miembros no existentes, atributos duplicados...

Para un trabajo que estoy perpetrando, necesitaba tener el ldap de mi red limpito y consistente. Por ello he unificado diversos scripts que tenía en uno solo que recorre el árbol ldap y muestra todo lo que resulta sospechoso. Avisos:
  • OJO: este script no arregla nada, solo muestra las cosas rarunas que encuentra. El arreglo nos corresponde a nosotros a mano usando la herramienta web phpldapadmin.
  • IMPORTANTE: antes de tocar nada se aconseja hacer un backup de ldap por si la liamos parda, aquí un script de Esteban para hacer el backup y otro para restaurarlo.
El script de chequeo se puede encontrar en este enlace. Allí hay además una relación de las comprobaciones que se hacen.

Out!
Ya tenemos al Miura 1 en la rampa de lanzamiento, listo para su primer vuelo desde las instalaciones de El Arenosillo, en Huelva:
Esperemos que en las próximas semanas el inexistente programa espacial español dé un paso exitoso con el lanzamiento de esta maravilla.

viernes, 27 de enero de 2023

Restaurar imagen de clonezilla en disco mas pequeño que el original

A veces sucede que tenemos una imagen de clonezilla y nos encontramos que cuando queremos restaurarla sobre un disco vemos que no cabe, ya que el disco original desde donde hicimos la imagen tiene un tamaño mayor que el disco destino. Vamos a ver distintas soluciones para esto.

1. Hacer otra imagen mas pequeña.

Para ello restauramos la imagen en un tercer disco alternativo mas grande donde la imagen no tenga problemas de tamaño para entrar. Luego, con ayuda de la herramienta gparted (la podemos ejecutar desde cualquier disco live de Linux), reducimos todas las particiones de dicha imagen a un tamaño suficiente para que entre en el disco destino que nos daba problemas de tamaño y tras este paso podemos hacer una nueva imagen con clonezilla. Esta imagen reducida será la que restauremos. Se tarda tiempo, pero es un proceso sin complicaciones .

2. Intentar restaurar la imagen con las opciones de Experto de clonezilla.

Cuando restauramos una imagen con clonezilla, llega un punto del proceso en el que nos preguntan si queremos seguir en modo Basic o Expert. Normalmente elegimos el modo Basic, pero para esta vía deberemos coger el modo Expert. Para intentar encoger y meter la imagen en nuestro disco elegiremos en una de las pantallas posteriores la opcion "-icds" (no comprobar tamaño de disco) y en la siguiente pantalla la opción -k1 (construir las particiones de forma proporcional al tamaño del disco), tal como nos cuentan aquí.

Esto hará que la restauración de las particiones individuales mediante la herramienta partclone se ejecute con el parámetro -C (Don't check device size and free space). En resumen, lo que hacemos con esto es reducir todas las particiones originales proporcionalmente al tamaño del disco destino y meter la imagen sin comprobar nada a ver si hay suerte y cabe.

Si la imagen original tiene una sola partición puede que funcione. Mi experiencia es que rara vez me ha acabado con éxito, especialmente si hay varias particiones.

Hay al menos dos motivos para esto:

  • No siempre se pueden reducir todas las particiones proporcionalmente. La reducción se hace a costa del espacio libre que hay dentro de cada partición, pero puede que una de ellas esté demasiado llena y no deje espacio suficiente para reducirla en la medida en que queremos hacerlo. Por desgracia, no hay opción sencilla para reducir solo unas particiones y dejar las otras igual. La única vía con alguna posibilidad de éxito sería usar la opción k2 en lugar de k1 y crear las particiones a mano nosotros, lo cual es un proceso que habria que hacer con mucho cuidado.
  • Hay particiones ocultas o especiales (EFI, de sistema, reservadas, de la Agenda 2030, etc) que deben tener un tamaño y ubicación concreta en el disco y cualquier alteración de estos parámetros provoca que la clonación falle o que el sistema no arranque posteriormente. Esas aplicaciones deben restaurarse tal cual están en el disco original, sin quitar ni poner ni un byte.


3. Proceso manual partición a partición.

Esta vía es la que me ha llevado a documentar esta entrada del blog. Tengo una tarjeta SD de 32Gb con un sistema Rasbpian ya configurado que quiero clonar. Su estructura es:
# fdisk -l /dev/sdc
/dev/sdc1              8192   532479   524288   256M  c W95 FAT32 (LBA)
/dev/sdc2            532480 60579839 60047360  28,6G 83 Linux
Quiero restaurar la imagen en una tarjeta de 16Gb. Mis intentos de restaurarla usando el modo Experto de clonezilla (descrito en el paso anterior) han fracasado miserablemente.

Los ficheros que componen la imagen del disco son:
-rw-r--r-- 1 root root        449 ene 13 09:43 blkdev.list
-rw-r--r-- 1 root root        361 ene 13 09:44 blkid.list
-rw-r--r-- 1 root root       5878 ene 13 09:44 clonezilla-img
-rw-r--r-- 1 root root        159 ene 13 09:44 dev-fs.list
-rw-r--r-- 1 root root          4 ene 13 09:44 disk
-rw-r--r-- 1 root root      22062 ene 13 09:44 Info-dmi.txt
-rw-r--r-- 1 root root        187 ene 13 09:44 Info-img-id.txt
-rw-r--r-- 1 root root      27119 ene 13 09:44 Info-lshw.txt
-rw-r--r-- 1 root root       2986 ene 13 09:43 Info-lspci.txt
-rw-r--r-- 1 root root        161 ene 13 09:44 Info-packages.txt
-rw-r--r-- 1 root root         80 ene 13 09:44 Info-saved-by-cmd.txt
-rw-r--r-- 1 root root         10 ene 13 09:44 parts
-rw------- 1 root root   40735156 ene 13 09:44 sdd1.vfat-ptcl-img.gz.aa
-rw------- 1 root root 4096000000 ene 13 09:44 sdd2.ext4-ptcl-img.gz.aa
-rw------- 1 root root  953241799 ene 13 09:44 sdd2.ext4-ptcl-img.gz.ab
-rw-r--r-- 1 root root         36 ene 13 09:43 sdd-chs.sf
-rw-r--r-- 1 root root    4193792 ene 13 09:44 sdd-hidden-data-after-mbr
-rw-r--r-- 1 root root        512 ene 13 09:43 sdd-mbr
-rw-r--r-- 1 root root        327 ene 13 09:43 sdd-pt.parted
-rw-r--r-- 1 root root        303 ene 13 09:43 sdd-pt.parted.compact
-rw-r--r-- 1 root root        181 ene 13 09:43 sdd-pt.sf
En negrita he remarcado los ficheros que me importan: sdd-mbr (con la tabla de particiones y sector de arranque del disco), sdd1.vfat-* (con la imagen de la primera particion) y sdd2.ext4-* (con la imagen de la segunda partición).

Lo primero que haremos es restaurar la tabla de particiones y el MBR del disco original en el nuevo disco con:
# dd if=sdd-mbr of=/dev/sdc bs=512 count=1
Con esto creamos una tabla de particiones idéntica a la del disco original, lo cual no parece buena idea, ya que este disco es mucho mas pequeño. Lo que hago a continuación para arreglar esto es editar dicha tabla de particiones con:
# cfdisk /dev/sdc
Con cfdisk borramos a mano sdc2 (que es la partición grande que me obstaculiza la restauración de la imagen) y luego la creamos de nuevo ya ajustada al disco actual. La partición sdc1 es la partición de arranque, ocupa poco y tiene pinta de ser delicada, asi que para no sufrir represalias futuras del karma, mejor la dejamos como está. Tras editar la tabla de particiones como hemos descrito esta nos quedará:
/dev/sdc1              8192   532479   524288   256M  c W95 FAT32 (LBA)
/dev/sdc2            532480 30873599 30341120  14,5G 83 Linux
Ya creadas, podemos restaurar la partición scd1 usando clonezilla, como se ha hecho de toda la vida, y una vez restaurada podemos ponernos manos a la obra para meter la otra partición a martillazos en sdc2, que ha quedado mucho más pequeña. Arrancamos clonezilla, montamos la particion con las imágenes en /home/partimag y salimos a terminal para teclear allí:
# cd /home/partimag/nuestra-imagen-querida
# cat sdd2.ext4-ptcl-img.gz.a* | gunzip -d | partclone.restore -d -C -s - -o /dev/sdc2 
Lo que hemos hecho aquí es concatenar los ficheros que componen la imagen de la segunda partición (cat sdd2.ext4-ptcl-img.gz.a*), descomprimir el fichero resultante (gunzip -d) y restaurarlo sobre sdc2 usando partclone.restore con el parámetro -C (que omite comprobar si la imagen cabe o no en la partición). Esto parece muy aparatoso, pero es exactamente lo que hace clonezilla por debajo cuando restauramos una partición.

Tras acabar la restauración, vamos a ver si ha tenido éxito. Montamos la partición restaurada:
# mount /dev/sdc2 /mnt
mount: wrong fs type, bad option, bad superblock
...
Carajo, no se que ha liado pero no ha funcionado. No surrender, si lo anterior no nos funciona vamos a ver como hacerlo de otra manera:
# cat sdd2.ext4-ptcl-img.gz.a* | gunzip -d | partclone.restore -d -s - -o sdd2.ext4.img
En vez de descomprimir en una partición física llevamos todo al fichero sdd2.ext4.img. Ahora hacemos:
# resize2fs -M sdd2.ext4.img
# fsck.ext4 sdd2.ext4.img
Con los dos comandos anteriores encogemos el tamaño de la imagen para que ocupe lo mínimo posible ( -M: Shrink the filesystem to the minimum size) y hacemos un chequeo de disco para reajustar todo al nuevo tamaño. Esta partición encogida a mano si que debe entrar en el espacio que hemos quedado en /dev/sdc2.
# dd if=sdd2.ext4.img of=/dev/sdc2 bs=512 status=progress
Con el comando sobre estas líneas restauramos la imagen en la partición con un rústico "dd", la forma mas artesanal de clonado y restauración. Tras esto:
# mount /dev/sdc2 /mnt
# ls /mnt
# umount /mnt
Debería dejarnos montar y ver el contenido de la partición ya restaurada. Queda un último paso: expandir el sistema de ficheros restaurado para que ocupe toda la partición /dev/sdc2, ya que seguramente haya quedado bastante apretadito y es peligroso dejarlo asi. Vamos allá:
# e2fsck -f -y -v -C 0 /dev/sdc2
# resize2fs -p /dev/sdc2
Otra forma de hacer esto último es usando Gparted, con la opción Partición->Comprobar/Verificar. Que cada cual elija si quiere hacerlo con comandos o con ratón.

Después de esto ya tenemos lo que queríamos: una partición clonada con su tamaño natural y la otra reducida para entrar en el nuevo disco destino. Como el último método me ha funcionado no he seguido probando cosas más divertidas.

Taluec!