jueves, noviembre 11, 2010

Recuperar ficheros de texto de sistema de ficheros corrupto

Hace poco he tenido que vivir una de esas historias de terror que uno teme encontrar. Pues llegó. Un sistema de ficheros irrecuperable (RAID lineal con un par de discos que no responden) e información valiosa de la que no se hacía copia de seguridad. El hecho es que la información valiosa son ficheros de texto, código fuente que se hizo de modo improvisado y fuera de repositorios ni backups y que luego se echa de menos. La solución, está claro, sería hacer backup de lo valioso, pero eso ya se empieza a ver claro por los interesados :)

Bueno, al grano ¿Cómo recuperar esos archivos de código fuente? Aquí voy a dar una solución "sencilla", pero que tiene varias precondiciones:
- Que la controladora del disco responda y que se pueda leer del dispositivo
- Que el texto a encontrar tenga menos del tamaño de un bloque del sistema de ficheros. De otro modo también vale, pero tendremos que buscar trozos y ensamblarlos.
- Que dispongamos de un sistema de ficheros donde quepa el backup. (Se podría hacer este proceso por partes o "al vuelo", jugando con el skip de dd, pero se va de la recetilla que he aplicado)

Entonces lo primero de todo (aplicable a cualquier situación donde un disco empiece a hacer cosas raras) es volcar el contenido del disco

#dd if=/dev/sd[ndev] of=/[outfile] bs=[sizeblock] conv=sync,noerror

Donde ndev es el dispositivo en mal estado. En mi caso es en buen estado pero que formaba parte de un todo en mal estado. De todos modos la opción sync, noerror trata de lidiar con errores en disco y rellenar con ceros las partes no leídas. Para este método rellenar con ceros no sería necesario porque no vamos a tratar de reparar el sistema sino hacer un método más basto, suficiente para nuestros propósitos y sin modificar el contenido del disco. Primero usamos la "magia" de strings. En principio es un comando para encontrar información relevante en código objeto, pero va muy bien para encontrar texto en binario (que es su labor básicamente). El comando que he usado es:

$ strings -n20 -a -t d outfile > outfile.str

Dónde la magia está en que consideramos como "cadena mínima". En este caso, con el n se le indica que una cadena consta de al menos veinte caracteres imprimibles. Si alguien va a usar este método puede jugar con él, sabiendo el tamaño de linea a buscar.
Posteriormente se pueden hacer greps o buscar con less sobre outfile.str con la buena noticia de que strings nos ha puesto en la primera columna (gracias al parámetro -t d) en que posición está la cadena. Ahora podemos recuperar el fichero con el mágico dd:

$ dd if=sdb1 bs=1 skip=[pos-offset] count=filesize 2>/dev/null > file.c

Evidentemente tenemos que jugar con offset (la posición en la que se encontraba la cadena encontrada en el fichero) y filesize (el tamaño del fichero). Manual y un poco a pedales, pero si los datos que hemos perdido lo merecen...

Debo notar que es una técnica no destructiva y que es complementaria a la posibilidad de reparar el sistema de ficheros. Espero que le pueda servir a alguien y también se admiten sugerencias de administradores avezados acerca de cómo reparar RAIDs lineales por soft y/o recuperar información binaria de ellos.