G A C E T A   D E   L I N U X
...haciendo a Linux un poco más divertido!
Una experiencia recuperando ficheros
Por C.E.C. Artime y J.A. Baro
Traducción al español por Jesús Marcos Sáenz
el día 22 de Enero 2003, para La Gaceta de Linux

 

Describimos un intento de recuperar datos inadvertidamente eliminados en un sistema de ficheros ext2. Conscientes de que el curso de los acontecimientos no fue ni mucho menos el deseado, nos vemos en el compromiso de que nuestros lectores no cometan los mismos errores y, para ilustrar el conjunto de cosas que uno puede aprender durante una crisis, detallamos la historia completa.

Preludio: la racha de desastres

La arena

Hardware

Dos computadoras, llamadas Fish y Bell. Fish es una Sun E250. Bell es un Pentium 3 (450 MHz). Se encuentran dentro de la misma subred Ethernet.

Software

Bell ejecuta una distribución Debian GNU/Linux 3.0r0 tras una actualización sin dificultades de la versión 2.2r7. La versión del Kernel es Linux 2.4.18.

Fish también ejecuta una Debian 3.0r0, para una Sparc64. Una actualización reciente de la versión 2.2r7 dio un único problema: XFree no funcionó para usuarios normales (si lo hacía para root). El Kernel es Linux 2.4.18-SMP.

Todos los sistemas de ficheros son ext2.

Cómo lo hechamos a perder

En Fish, Xfree funciona para root, pero no para usuarios normales. La razón: o un problema con los permisos o con los ficheros de configuración del usuario.
Solución: Añadir un usuario y copiar los directorios precedidos de punto de root a su directorio inicial:

root@fish# adduser judas
Enter new UNIX password:
Retype new UNIX password:
root@fish# cp --recursive /root/.[a-zA-Z]* /home/judas
root@fish# chown --recursive judas:judas /home/judas/.*

[¿Ha observado la diferencia entre los argumentos de expresiones regulares para cp y chown?]

Tras las suficientes pruebas y errores, el problema con las X es finalmente solucionado; es el momento de eliminar el usuario.
Tratando de acelerar el procedimiento un poco, un estudio minucioso de una breve página de manual revela una opción atractiva:

root@fish# deluser --remove-all-files judas

¡Cha-ching! ¡empieza el desastre! La desafortunada opción hace que deluser rastree todo el disco buscando ficheros propiedad de judas y ¡eliminándolos!

Los contenidos de /home desaparecieron.
Dos minutos después, desmontamos su correpondiente dispositivo (/dev/sda8).

Copia

Primer intento

Las primeras precauciones implicaban obtener una copia de los bytes no procesados dentro del dispositivo matado.
No queda espacio en Fish, así que vamos a hacer una copia en el disco duro de Bell:

root@fish# ftp bell
ftp> put '|dd if=/dev/sda8' fishbackup

En realidad, este paso no fue tan sencillo debido a un problema con la red: la transmisión de ficheros grandes se interrumpió tras un rato. El fichero debe estar dividido. La partición /dev/sda8 tiene un tamaño de 10142 Mb.
Recurriendo a la herramienta factor de las shellutils (GNU):

root@fish# factor 10142
10142: 2 11 461

nos dio un tamaño adecuado para cada una de las partes del dispositivo.

Un camino seguro

En lugar de FTP, usamos la suite OpenSSL para el siguiente paso.
Primero intercambiamos passwords para usar el modo batch:

root@fish# ssh-keygen 
artime@bell$ ssh-keygen
root@fish# scp /root/.ssh/identity.pub artime@bell:/home/artime/.ssh/authorized.keys
root@fish# scp artime@bell:~/.ssh/identity.pub ~/.ssh/authorized.keys

Vamos a ejecutar este script en Fish:

#!/bin/sh
for i in $(seq 0 460)
do
  dd if=/dev/sda8 bs=$((2*11*1024)) skip=$i of=fula
  scp --batch fula artime@bell:~/fiback.$i
done

Juntamos las piezas en Bell:

for i in $(seq 0 460)
do cat fiback.$i >> fiback.raw
done

Podríamos hacer lo mismo en un sólo paso ejecutando en Fish:

#!/bin/sh
for i in $(seq 0 460)
do
  dd if=/dev/sda8 bs=$((2*11*1024)) skip=$i | ssh artime@bell "cat >> fiback.raw"
done

Buscando datos perdidos

Podemos recurrir al Linux Ext2fs undeletion mini-HOWTO, de Aaron Crane; al Ext2fs undeletion of directory structures mini-HOWTO, de Tomas Ericsson; al programa recover de Tom Pycke; o al parche de Torsten Werner para el funcionamiento de debugfs en i386.

Un vago intento

Recover es una herramienta para recuperar ficheros individuales. Como en nuestro caso hemos perdido de repente cientos de ficheros, no parecía la mejor opción con la que comenzar. La forma más directa es utilizar el parche de Werner para debugfs; ahora tenemos una copia del sistema de ficheros dañado almacenada en una máquina i386, así que podemos emplear el binario encontrado en twerner.debian.org:

artime@bell$ ./debugfs fishback.raw
debugfs> restore
debugfs> quit
artime@bell$ mkdir mnt
artime@bell$ mount -t ext2 -o loop fishback.raw mnt
artime@bell$ ls -l mnt

¡No encontramos ficheros! Parece que desmontamos /dev/sda8 un poco tarde. Como T. Werner indica en su página, su herramienta únicamente puede recuperar ficheros que todavía tienen nombre.

Esto se paga leyendo

Crane's undeletion howto

Esta herramienta que escogimos en The Linux Documentation Project nos enseñó como encontrar inodes (más o menos, las localizaciones) de los ficheros perdidos y como recuperarlos con el comando dump de debugfs. Finalizamos con un montón de ficheros variados en el mismo directorio, pero había un subconjunto de los eliminados. Como se mencionó anteriormente, un plan minucioso de recuperación fichero a fichero como se indicaba en este CÓMO no es factible en nuestro caso.

Ericsson's directory undeletion howto

Aquí aprendimos cómo distinguir entre ficheros eliminados y directorios. Seguimos las instrucciones.
El script de la sección 7 necesitaba de algunas adaptaciones adicionales para nuestra versión de debugfs

#!/bin/sh
awk '{ print "mi <" $1 ">\n"\
             "\n\n\n\n\n\n\n"\
             "0\n"\
             "1\n"\
             "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" }'

De todas maneras, fallamos al buscar los nombres de los directorios y continuamos con la sección 8. Así que debemos mirar en otra parte.

Páginas de manual

una última oportunidad fue

$ man debugfs

donde encontramos el comando rdump, no mencionado en los cómos. Aplicando el siguiente script a los inodes de los directorios localizados en lsdel.out de la sección 6 del Ext2fs Undeletion of Directory Structures mini-HOWTO:

#!/bin/sh
awk '{ print "rdump <" $1 "> folders\n" }'

muchos directorios son recuperados en el dierctorio folders. ¡Pero sin nombre! Así que finalmente tenemos que asignar individualmente doscientas carpetas a los usuarios ¡mirando su contenido! Aún tras esto, perdimos algunos ficheros, especialmente un contenedor de e-mails. Intentamos una búsqueda a mano:

$ strings fishback.raw | grep -B1 -A99 "To: lisistrata" > lisistrata.mbox

Epílogo

Algunas cosas que nos gustaría recalcar.

RTFM (Lea el ###!!@#!! manual)

Y nunca use una nueva opción como root la primera vez.

Cintas magnéticas

Fish tenía una unidad de cinta magnética. Las herramientas GNU mt y tar son útiles para catalogar copias de seguridad. El howto de Aaron Crane incluye enlaces interesantes respecto a este tema.

Expresiones regulares

El uso de expresiones regulares en comandos shell es muy peligroso, especialmente cuando tratamos con ficheros que comienzan por punto. Quizá el superusuario root debería usar una shell con un soporte limitado (mejor que "extendido") de expresiones regulares. Nosotros pensamos en esh.

PDA

Este artículo fue escrito en su mayor parte con una Agenda VR3, un PDA de software libre único, en una playa de Gran Canaria.

 

[BIO] C.E.C. Artime es un fan de GNU y un partidario del software libre desde el 2000.

[BIO] J.A. Baro es usuario de Linux y is a Linux user and a Perl hacker since 1996.


Copyright © 2003, C.E.C. Artime and J.A. Baro. Copying license http://www.linuxgazette.com/copying.html
Publicado en el número 86 de Linux Gazette, Enero 2003