Una de las principales preocupaciones de la gente es cómo hacer copias de seguridad de una forma sencilla y sin errores.
:-)
Vale, no conozco a NADIE que le importen un pimiento las copias de seguridad. Pero yo soy así de rarito, y desde siempre he tenido una especial preocupación por encontrar una forma de que el ordenador haga él solito todo lo necesario para mantener a salvo la información. Al fin y al cabo, para eso es un ordenador,¿no?: para manipular y conservar la información al mismo tiempo que para automatizar las tareas rutinarias.
Con Windows no pude hacerlo. Con OS/2 hice algún intento (Dios,que bueno era el OS/2, Santa IBM lo tenga en su seno). Pero fue con Linux con lo que la cosa cuajó de verdad y a mi gusto.
Tras una limpieza del disco duro, me he encontrado con un montón de megas libres que pretendo organizar para dejar una partición libre, especialmente volcando a CDs todo lo que no uso nunca (sobre todo kernels antiguos, documentos sobre cosas raras bajados de Internet, etc)
El caso es que voy a crear un nuevo script (en realidad, varios scripts que trabajen juntos) para hacer copias de seguridad automatizadas. Será un sistema de backup personalizado diseñado para que funcione a mi gusto, y lo voy a hacer como suelo hacer las cosas: progresivamente, empezando por lo sencillo y complicandolo cada vez más. Y qué menos que contaroslo a vosotros en directo, ¿no?. ;-)
Ahora tengo una especie de partición "home" en la que se encuentran casi todos los datos a salvar. Eso incluye los discos virtuales de dosemu (donde trabajo a veces) y algunas cosas más como música mp3 etc. Obviamente, no todo se va a salvar a la copia de seguridad, puesto que por ejemplo la música mp3 se puede volver a ripear desde el CD correspondiente. Por otro lado, hay directorios que sí deben protegerse pero no están en esa partición, como por ejemplo /etc o /root. Bien, pues vamos a hacer una cosa sencillita, de andar por casa. Para ello creamos un script llamado "seguridad" y que sea tal que así:
----------------inicio script seguridad----------------- #!/bin/bash # Este script sirve para hacer copias de seguridad # usando grupos de CD-RW rotatorios # --------------------------------- DIRS1="/datos/textos \ /datos/personal \ /datos/profesional" DIRS2="/datos/compartidos \ /datos/evolution_lacofi \ /datos/evolution_maria \ /datos/externos" DIRS3="/home \ /etc \ /root \ /datos/dosemu \ /datos/imagen" TEMP="/datos/seguridad/zap" FECHA=`date +%d%b%Y` IMAGEN="/datos/seguridad/cd" # Poner todo a cero rm -Rf /datos/seguridad/zap/*.tar.bz2 rm -Rf /datos/seguridad/cd/*.iso # Ahora creamos ficheros tar con la copia de seguridad # y luego los pasamos a imágenes ISO, listas para grabar for NUM in 1 2 3 do tar cjf $TEMP/serie$NUM-$FECHA.tar.bz2 `eval echo '$DIRS'$NUM` &> /dev/null mkisofs -r -o $IMAGEN/serie$NUM-$FECHA.iso \ $TEMP &> /dev/null rm $TEMP/*.tar.bz2 done ---------------final script seguridad-----------------
Este script lo coloco en /datos/programas-usuario y le hago un link a un directorio en el path, concretamente /usr/local/bin, pero en realidad funcionaría igual esté donde esté.
Tan solo queda crear los directorios donde iran las copias de seguridad en la forma "tar" y en la forma "iso":
[19:16:32/0][lacofi@claudia:~]$ su password: [19:17:02/0][root@claudia:/home/lacofi]# cd /datos [19:17:11/0][root@claudia:/datos]# mkdir seguridad [19:17:14/0][root@claudia:/datos]# cd seguridad [19:17:19/0][root@claudia:/datos/seguridad]# mkdir cd zap [19:17:23/0][root@claudia:/datos/seguridad]# exit
Y eso es todo. Con esto ya funciona minimamente. Por supuesto, primero me he asegurado de que esos directorios sin comprimir ocupan menos de 700 Mb en cada serie (DIRS1, DIRS2, DIRS3), con lo que garantizo que, comprimidos, cabrán en un CD.
Si ejecutamos este script, se harán tres imagenes ISO que luego, cuando queramos, podemos grabar en CD. No es desatendido, todavía, aunque bastaría con añadir una entrada en el cron. Tampoco hace copias incrementales, y no toma ninguna decisión. Es poco sofisticado, en resumen.
Pero, ¡eh!, dije que lo haríamos pasito a paso, ¿no?. ;-) Pues hasta otro día.
Hemos creado un script muy elemental para construir imágenes ISO con nuestras copias de seguridad. Se podría meter en el cron, para que se ejecute automáticamente, pongamos, una vez cada quince días. Pero nos falta algo muy importante, claro: hay que sacar esas imágenes ISO a CD-RW.
Habitualmente, yo hago mis copias de seguridad de forma rotatoria, en dos grupos (par e impar) que se van alternando, por lo que necesitaré seis CD-RW. Tres para el grupo par, y otros tres para la semana siguiente, el grupo impar, y así sucesivamente, según este esquema:
Si alguien se pregunta por qué carajos los llamo serie "par" y serie "impar", pues el nombre le viene de antiguo, cuando hacía copias de seguridad completas mensuales (e incrementales diarias). Tenía dos juegos de CD, uno para los meses pares y otro para los meses impares. ¿entendido?.
Y lógicamente, hay que automatizar el grabado. Para ello, hacemos un script que nos vaya pidiendo los CDs:
-------------- Comienza script cdsalva --------------- #!/bin/sh numero=1 grupo=`cat /var/log/volcado_duro.dir` equipo="dev=1,0,0" opciones="speed=16 driveropts=burnproof" if [ "$grupo" = "impar" ] ; then grunum="2" echo "par" > /var/log/volcado_duro.dir else grunum="1" echo "impar" > /var/log/volcado_duro.dir fi for archivo in `find /datos/seguridad/cd/* -print` do echo "Grabando" > /var/log/volcado_cd.dir echo -e " " echo -e "-----------------------------" echo -e "Introduce el CD-RW "$numero" del grupo "$grupo "("$grunum"/"$numero")" echo -e "y pulsa la tecla Intro" read seleccion echo -e "Borrando el CD-RW" nice -20 cdrecord $equipo blank=fast > /dev/null 2>&1 echo -e "Grabando la imagen "$archivo nice -20 cdrecord $opciones $carga $equipo $archivo > /dev/null 2>&1 numero=`expr $numero + 1` done echo "Hecho" >> $estado -------------- Termina script cdsalva ----------------
Podemos meterlo en nuestro path (por ejemplo, /datos/programas-usuario y hacer un link a /usr/local/bin), o bien convertirlo en una función de bash. En cualquier caso, una vez ejecutado debería ir pidiendo los CD adecuados.
Bien, ahora observad que este script hace un pequeño registro de lo que está haciendo. Cuando se prepara para iniciar la copia, graba un fichero de log con la palabra "Grabando". Cuando la copia terminó con éxito, lo sobreescribe con la palabra "Salvado". De esta forma nos informa a nosotros y a otros scripts que hagamos en el futuro, de si la copia se ha interrumpido por algún error, o si está ya en CD, con lo que tenemos los datos verdaderamente a salvo.
Observad también que el script revisa un segundo fichero de log para comprobar si la última copia de seguridad fue de la serie par o impar, hace lo contrario, y luego cambia el fichero de log. De esta forma, el script pedirá la serie par, pero la próxima vez que se ejecute, pedirá la impar, y así sucesivamente, alternando los backups.
Pero ahora, vamos a retocar un poco el script que hicimos ayer, al que llamamos "seguridad": pondremos una cláusula para que si lo ejecutamos con el parámetro "reset" nos cree los directorios adecuados para el funcionamiento del script; también añadiremos una opción que hará que los CD sean autoarrancables; y también usaremos el fichero de log del script anterior para que lo sobreescriba con la palabra "Pendiente" cuando haya creado las imagenes ISO, pero aún se ha ejecutado el script "cdsalva". Pongo los cambios en color cian y negrita para resaltarlos de lo hecho ayer.
----------------inicio script seguridad----------------- #!/bin/bash # Este script sirve para hacer copias de seguridad # usando grupos de CD-RW rotatorios # --------------------------------- DIRS1="/datos/textos \ /datos/personal \ /datos/profesional" DIRS2="/datos/compartidos \ /datos/evolution_lacofi \ /datos/evolution_maria \ /datos/externos" DIRS3="/home \ /etc \ /root \ /datos/dosemu \ /datos/imagen" TEMP="/datos/seguridad/zap" FECHA=`date +%d%b%Y` IMAGEN="/datos/seguridad/cd" RIP="arranque/rip.img" CAT="arranque/catalogo.cat" if [ "$1" = "reset" ]; then if [ -f /var/log/volcado_duro.dir ]; then echo "El status es: "`cat /var/log/volcado_duro.dir` else echo "impar" > /var/log/volcado_duro.dir fi if [ -d "/datos/seguridad" ]; then echo "/datos/seguridad existe" else echo "Creando /datos/seguridad" mkdir /datos/seguridad fi if [ -d "/datos/seguridad/cd" ]; then echo "/datos/seguridad/cd existe" else echo "Creando /datos/seguridad/cd" mkdir /datos/seguridad/cd fi if [ -d "/datos/seguridad/zap" ]; then echo "/datos/seguridad/zap existe" else echo "Creando /datos/seguridad/zap" mkdir /datos/seguridad/zap fi if [ -d "/datos/seguridad/zap/arranque" ]; then echo "/datos/seguridad/zap/arranque existe" else echo "Creando /datos/seguridad/zap/arranque" mkdir /datos/seguridad/zap/arranque echo "Debes colocar en /datos/seguridad/zap/arranque" echo "una imagen de rescate, preferiblemente RIP" fi exit fi # Poner todo a cero rm -Rf /datos/seguridad/zap/*.tar.bz2 rm -Rf /datos/seguridad/cd/*.iso # Ahora creamos ficheros tar con la copia de seguridad # y luego los pasamos a imágenes ISO, listas para grabar for NUM in 1 2 3 do tar cjf $TEMP/serie$NUM-$FECHA.tar.bz2 `eval echo '$DIRS'$NUM` &> /dev/null mkisofs -r -o $IMAGEN/serie$NUM-$FECHA.iso \ -b $RIP -c $CAT $TEMP &> /dev/null rm $TEMP/*.tar.bz2 done if [ -f "$IMAGEN/serie1-$FECHA.iso" ] || [ -f "$IMAGEN/serie2-$FECHA.iso" ] || [ -f "$IMAGEN/serie3-$FECHA.iso" ]; then echo "Pendiente" > /var/log/volcado_cd.dir fi ----------------termina script seguridad----------------
Lo que queda por hacer es colocar la imagen de alguna minidistribución linux (ya sabes, esas que caben en un solo disquette) y meterla en el directorio /datos/seguridad/zap/arranque. Yo te recomiendo RIP. Es muy completa y tiene varias versiones (en CD, en floppy...). Naturalmente, la que nos interesa aquí es la versión floppy. Podeis bajaros el binario (por ejemplo el fichero "RIP-3.1-1680.bin") y copiarlo a /datos/seguridad/zap/arranque/rip.img
Eso es todo lo necesario para que el CD sea autoarrancable. El programa mkisofs buscará en ese subdirectorio la imagen de RIP y la usará para crear un autoarranque según el protocolo "El Torito". Chulo, ¿no?. Ahora puedes acceder a tus copias de seguridad desde cualquier máquina, tenga o no tenga linux instalado.
Esta idea, así como otras que usaré después, está sacada del artículo de Alan Keates Easy Backup and Restore - Linux. Vete echándole un vistazo, que merece la pena.
Basta por hoy.
Hoy vamos a retocar los dos scripts anteriores, aunque en realidad el funcionamiento será el mismo. Los cambios están dirigidos a que el sistema pueda recoger información sobre cómo ha ido la copia de seguridad. Más adelante, otros scripts podrían usar esa información para saber qué es lo que tienen que hacer a continuación. Y también nos servirá a nosotros para saber cómo va la cosa, claro. En segundo lugar, haremos que nuestros scripts comprueban las sumas MD5 tanto del fichero ISO como de la copia en CD, después de grabarla. Si son idénticas, esto garantiza que la copia sea exacta. Es muy importante, porque la grabación del CD es un procedimiento crítico y que puede fallar: tened en cuenta que un error en un solo byte puede mandar al carajo vuestro fichero tar con todos vuestros datos dentro pero inaccesibles. Con la suma md5 nos daremos cuenta de ello inmediatamente, pues la suma se altera con un único byte equivocado. Del mismo modo, también haremos que nuestros logs recojan el código de error (o códigos de salida) de los programas tar y mkisofs (sabiendo que código cero significa: no hubo errores en la ejecución). :-)
En primer lugar, modificaremos el script "seguridad". Los cambios, en cian y negrita.
--------------Comienza script "seguridad" ------------- #!/bin/bash # Este script sirve para hacer copias de seguridad # usando grupos de CD-RW rotatorios # --------------------------------- DIRS1="/datos/textos \ /datos/personal \ /datos/profesional" DIRS2="/datos/compartidos \ /datos/evolution_lacofi \ /datos/evolution_maria \ /datos/externos" DIRS3="/home \ /etc \ /root \ /datos/dosemu \ /datos/imagen" TEMP="/datos/seguridad/zap" FECHA=`date +%d%b%Y` IMAGEN="/datos/seguridad/cd" RIP="arranque/rip.img" CAT="arranque/catalogo.cat" ESTADO="/var/log/estado.log" if [ "$1" = "reset" ]; then if [ -f /var/log/volcado_duro.dir ]; then echo "El status es: "`cat /var/log/volcado_duro.dir` else echo "impar" > /var/log/volcado_duro.dir fi if [ -d "/datos/seguridad" ]; then echo "/datos/seguridad existe" else echo "Creando /datos/seguridad" mkdir /datos/seguridad fi if [ -d "/datos/seguridad/cd" ]; then echo "/datos/seguridad/cd existe" else echo "Creando /datos/seguridad/cd" mkdir /datos/seguridad/cd fi if [ -d "/datos/seguridad/zap" ]; then echo "/datos/seguridad/zap existe" else echo "Creando /datos/seguridad/zap" mkdir /datos/seguridad/zap fi if [ -d "/datos/seguridad/zap/arranque" ]; then echo "/datos/seguridad/zap/arranque existe" else echo "Creando /datos/seguridad/zap/arranque" mkdir /datos/seguridad/zap/arranque echo "Debes colocar en /datos/seguridad/zap/arranque" echo "una imagen de rescate, preferiblemente RIP" fi echo "El registro ha sido reseteado" > $ESTADO echo "-----------------------------" >> $ESTADO exit fi # Poner todo a cero rm -Rf /datos/seguridad/zap/*.tar.bz2 rm -Rf /datos/seguridad/cd/*.iso rm -Rf /var/log/md5_*.log # Ahora creamos ficheros tar con la copia de seguridad # y luego los pasamos a imágenes ISO, listas para grabar for NUM in 1 2 3 do echo "Creando serie$NUM-$FECHA.tar.bz2" >> $ESTADO tar cjf $TEMP/serie$NUM-$FECHA.tar.bz2 `eval echo '$DIRS'$NUM` &> /dev/null status=$? echo "La compresión se ejecutó con código $status" >> $ESTADO mkisofs -r -o $IMAGEN/serie$NUM-$FECHA.iso \ -b $RIP -c $CAT $TEMP &> /dev/null status=$? echo "La imagen ISO se creó con código $status" >> $ESTADO sumamd5=`md5sum $IMAGEN/serie$NUM-$FECHA.iso | awk '{print $1}'` echo $sumamd5 >> /var/log/md5_$NUM.log rm $TEMP/*.tar.bz2 done if [ -f "$IMAGEN/serie1-$FECHA.iso" ] || [ -f "$IMAGEN/serie2-$FECHA.iso" ] || [ -f "$IMAGEN/serie3-$FECHA.iso" ]; then echo "Pendiente" > /var/log/volcado_cd.dir echo "Copia de seguridad almacenada en el dico duro" >> $ESTADO echo "La copia de seguridad no está a salvo" >> $ESTADO fi --------------Final de script "seguridad" -------------
Ahora modificamos también el script "cdsalva". Atentos a los comentarios, en este script:
--------------Inicio del script "cdsalva" ------------- #!/bin/sh numero=1 grupo=`cat /var/log/volcado_duro.dir` equipo="dev=1,0,0" opciones="speed=16 driveropts=burnproof" estado="/var/log/estado.log" carga="-eject" echo "----------------------------" >> $estado echo "La última serie fue $grupo" >> $estado if [ "$grupo" = "impar" ] ; then grunum="2" echo "par" > /var/log/volcado_duro.dir else grunum="1" echo "impar" > /var/log/volcado_duro.dir fi echo "La serie actual es `cat /var/log/volcado_duro.dir`" >> $estado echo "----------------------------" >> $estado for archivo in `find /datos/seguridad/cd/* -print` do echo "Grabando" > /var/log/volcado_cd.dir echo "Grabando CD-RW $grunum/$numero" >> $estado echo -e " " echo -e "-----------------------------" echo -e "Introduce el CD-RW "$numero" del grupo "$grupo "("$grunum"/"$numero")" echo -e "y pulsa la tecla Intro" read seleccion echo -e "Borrando el CD-RW" nice -20 cdrecord $equipo blank=fast > /dev/null 2>&1 echo -e "Grabando la imagen "$archivo nice -20 cdrecord $opciones $carga $equipo $archivo > /dev/null 2>&1 status=$? if [ "$status" -eq 0 ]; then echo "Salvado" > /var/log/volcado_cd.dir echo "Grabado con éxito. Copia a salvo." >> $estado fi # Mi CD-RW no puede leer el CD recien grabado salvo # que se saque y se vuelva a cargar. Por eso, el comando cdrecord anterior lo # sacó con la opción -eject, y ahora hay que volver a cargarlo con -load # para que se pueda leer y comprobar el md5. Al ejecutar el script habrá un # movimiento de recarga automática de la bandeja del CD. carga="-load" nice -20 cdrecord $carga $equipo # Mi sistema usa autofs, con lo que monta automáticamente todos los CD. Si # vosotros no usais autofs, tendreis que añadir un comando que lo haga: # mount /mnt/cdrw echo -e $rojo"Comprobando "$nocolor"el CD-RW "$grunum/$numero echo "Comprobando CD-RW $grunum/$numero" >> $estado nbloques=`df -k /mnt/cdrw | grep cdrw | cut -c 25-30` md5cd=`dd if=/dev/scd0 count=$nbloques bs=1024 | md5sum | awk '{print $1}'` echo "El MD5 del CD-RW $grunum/$numero es $md5cd" >> $estado md5iso=`cat /var/log/md5_$numero.log` echo "El MD5 de la iso $grunum/$numero es $md5iso" >> $estado # y salvo que useis autofs, también un comando que desmonte # antes de abrir la bandeja para cambiar el CD: # umount /mnt/cdrw carga="-eject" nice -20 cdrecord $carga $equipo numero=`expr $numero + 1` done echo "Hecho" >> $estado -------------- Final del script "cdsalva" -------------
Con esto, los scripts son ya completamente funcionales. No lo hacen todo, así que esto no ha terminado (por ejemplo, no hacen copias incrementales, solo completas o "full backup"). Pero lo que hacen ya es lo suficientemente sofisticado para que nos sea útil, así que lo metemos en el cron para que empiece a ser desatendido. Para ello solo hay que hacerse root y editar el fichero /etc/crontab dejandolo así (lo añadido en color cian y negrita):
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
33 1 15 * * root /usr/local/bin/seguridad
17 1 30 * * root /usr/local/bin/seguridad
Esto ejecutará nuestros scripts dos veces al mes, el día 15 a las 1:33 y el día 30 a las 1:17. Mi ordenador está casi siempre encendido, esté o no en casa (entre otras cosas, para que funcione el mldonkey), por lo que las horas nocturnas son buenas para que el ordenador se encargue de estas cosas: yo no estoy usándolo, y él no tiene nada mejor que hacer. Solo tengo que ocuparme de ejecutar el script "cdsalva" el día 1 y el 16 para pasarlo todo a CD. Claro que más adelante haremos que él nos lo recuerde, claro. :-)
Pero las cosas a su tiempo, porque el siguiente paso será crear copias de seguridad incrementales diarias, naturalmente también desatendidas. Eso queda para otro día, ¿vale?. :-)
Hoy un par de cambios menores. Uno para preparar la creación de copias incrementales, el otro para que el script de grabación de error si el tamaño de la imagen es excesivo. También haremos que solo root pueda ejecutar los scripts. Al fin y al cabo, uno de ellos será ejecutado siempre por el cron, automáticamente. Y el otro permite sacar datos de otros usuarios a CD. A mi no me importa porque es un ordenador privado, pero dice la teoría que esa sería una labor crítica que solo root debería hacer.
Empezamos por modificar el script "seguridad", el que ejecutará siempre cron.
--------------Comienza script "seguridad" ------------- #!/bin/bash # Este script sirve para hacer copias de seguridad # usando grupos de CD-RW rotatorios # --------------------------------- DIRS1="/datos/textos \ /datos/personal \ /datos/profesional" DIRS2="/datos/compartidos \ /datos/evolution_lacofi \ /datos/evolution_maria \ /datos/externos" DIRS3="/home \ /etc \ /root \ /datos/dosemu \ /datos/imagen" TEMP="/datos/seguridad/zap" FECHA=`date +%d%b%Y` IMAGEN="/datos/seguridad/cd" RIP="arranque/rip.img" CAT="arranque/catalogo.cat" ESTADO="/var/log/estado.log" CONTROL="/var/log/backup" if [ "$UID" = "0" ]; then if [ "$1" = "reset" ]; then if [ -f /var/log/volcado_duro.dir ]; then echo "El status es: "`cat /var/log/volcado_duro.dir` else echo "impar" > /var/log/volcado_duro.dir fi if [ -d "/datos/seguridad" ]; then echo "/datos/seguridad existe" else echo "Creando /datos/seguridad" mkdir /datos/seguridad fi if [ -d "/datos/seguridad/cd" ]; then echo "/datos/seguridad/cd existe" else echo "Creando /datos/seguridad/cd" mkdir /datos/seguridad/cd fi if [ -d "/datos/seguridad/zap" ]; then echo "/datos/seguridad/zap existe" else echo "Creando /datos/seguridad/zap" mkdir /datos/seguridad/zap fi if [ -d "/datos/seguridad/zap/arranque" ]; then echo "/datos/seguridad/zap/arranque existe" else echo "Creando /datos/seguridad/zap/arranque" mkdir /datos/seguridad/zap/arranque echo "Debes colocar en /datos/seguridad/zap/arranque" echo "una imagen de rescate, preferiblemente RIP" fi echo "El registro ha sido reseteado" > $ESTADO echo "-----------------------------" >> $ESTADO exit fi # Poner todo a cero rm -Rf /datos/seguridad/zap/*.tar.bz2 rm -Rf /datos/seguridad/cd/*.iso rm -Rf /var/log/md5_*.log rm -Rf $CONTROL*.log # Ahora creamos ficheros tar con la copia de seguridad # y luego los pasamos a imágenes ISO, listas para grabar for NUM in 1 2 3 do echo "Creando serie$NUM-$FECHA.tar.bz2" >> $ESTADO tar cjf $TEMP/serie$NUM-$FECHA.tar.bz2 --listed-incremental=$CONTROL$NUM.log \ `eval echo '$DIRS'$NUM` &> /dev/null status=$? echo "La compresión se ejecutó con código $status" >> $ESTADO mkisofs -r -o $IMAGEN/serie$NUM-$FECHA.iso \ -b $RIP -c $CAT $TEMP &> /dev/null status=$? echo "La imagen ISO se creó con código $status" >> $ESTADO sumamd5=`md5sum $IMAGEN/serie$NUM-$FECHA.iso | awk '{print $1}'` echo $sumamd5 >> /var/log/md5_$NUM.log rm $TEMP/*.tar.bz2 done if [ -f "$IMAGEN/serie1-$FECHA.iso" ] || [ -f "$IMAGEN/serie2-$FECHA.iso" ] || [ -f "$IMAGEN/serie3-$FECHA.iso" ]; then echo "Pendiente" > /var/log/volcado_cd.dir echo "Copia de seguridad almacenada en el dico duro" >> $ESTADO echo "La copia de seguridad no está a salvo" >> $ESTADO fi else echo "¡Solo root puede hacer eso!" fi --------------Final de script "seguridad" -------------
Y ahora modificamos el script "cdsalva".
--------------Inicio del script "cdsalva" ------------- #!/bin/sh numero=1 grupo=`cat /var/log/volcado_duro.dir` equipo="dev=1,0,0" opciones="speed=16 driveropts=burnproof" estado="/var/log/estado.log" carga="-eject" valido="si" declare -i megas if [ "$UID" = "0" ]; then echo "----------------------------" >> $estado echo "La última serie fue $grupo" >> $estado if [ "$grupo" = "impar" ] ; then grunum="2" echo "par" > /var/log/volcado_duro.dir else grunum="1" echo "impar" > /var/log/volcado_duro.dir fi echo "La serie actual es `cat /var/log/volcado_duro.dir`" >> $estado echo "----------------------------" >> $estado for archivo in `find /datos/seguridad/cd/* -print` do # Un CD-RW no puede sobrepasar los 700 Mb megas=`du -m $archivo | awk '{print $1}'` if [ "$megas" -gt 700 ]; then echo "El CD-RW $grunum/$numero tendría $megas Mb" >> $estado echo "Operación cancelada" >> $estado echo "El CD-RW $grunum/$numero tendría $megas Mb" echo "Revisa tus configuraciones o no podrás sacar nada a CD" valido="no" fi if [ "$valido" = "si" ]; then echo "Grabando" > /var/log/volcado_cd.dir echo "Grabando CD-RW $grunum/$numero, de $megas Mb" >> $estado echo -e " " echo -e "-----------------------------" echo -e "Introduce el CD-RW "$numero" del grupo "$grupo "("$grunum"/"$numero")" echo -e "y pulsa la tecla Intro" read seleccion echo -e "Borrando el CD-RW" nice -20 cdrecord $equipo blank=fast > /dev/null 2>&1 echo -e "Grabando la imagen "$archivo nice -20 cdrecord $opciones $carga $equipo $archivo > /dev/null 2>&1 status=$? if [ "$status" -eq 0 ]; then echo "Salvado" > /var/log/volcado_cd.dir echo "Grabado con éxito. Copia a salvo." >> $estado fi # Mi CD-RW no puede leer el CD recien grabado salvo # que se saque y se vuelva a cargar. Por eso, el comando cdrecord anterior lo # sacó con la opción -eject, y ahora hay que volver a cargarlo con -load # para que se pueda leer y comprobar el md5. Al ejecutar el script habrá un # movimiento de recarga automática de la bandeja del CD. carga="-load" nice -20 cdrecord $carga $equipo # Mi sistema usa autofs, con lo que monta automáticamente todos los CD. Si # vosotros no usais autofs, tendreis que añadir un comando que lo haga: # mount /mnt/cdrw echo -e $rojo"Comprobando "$nocolor"el CD-RW "$grunum/$numero echo "Comprobando CD-RW $grunum/$numero" >> $estado nbloques=`df -k /mnt/cdrw | grep cdrw | cut -c 25-30` md5cd=`dd if=/dev/scd0 count=$nbloques bs=1024 | md5sum | awk '{print $1}'` echo "El MD5 del CD-RW $grunum/$numero es $md5cd" >> $estado md5iso=`cat /var/log/md5_$numero.log` echo "El MD5 de la iso $grunum/$numero es $md5iso" >> $estado # y salvo que useis autofs, también un comando que desmonte # antes de abrir la bandeja para cambiar el CD: # umount /mnt/cdrw carga="-eject" nice -20 cdrecord $carga $equipo fi numero=`expr $numero + 1` done echo "Hecho" >> $estado else echo "¡Solo root puede hacer eso" fi -------------- Final del script "cdsalva" -------------
Con una sencilla opción --listed-incremental, hemos añadido ya lo necesario para preparar las copias incrementales. Ahora, nuestro fichero "seguridad" quincenal no solo creará un tar y lo pasará a ISO, sino que también creará un fichero de control en el que registra qué se ha guardado, y que podrá usar otro script para las copias diarias.
Habrá que crear ese nuevo script, claro, pero eso queda para otra vez.
Hoy vamos a dar poner en marcha las copias incrementales. Primero, alguna pequeña modificación en el script "seguridad". Hay que crear el directorio /datos/seguridad/diario, bien a mano, o bien usando el propio script con la opción reset, una vez modificado.
--------------Comienza script "seguridad" ------------- #!/bin/bash # Este script sirve para hacer copias de seguridad # usando grupos de CD-RW rotatorios # --------------------------------- DIRS1="/datos/textos \ /datos/personal \ /datos/profesional" DIRS2="/datos/compartidos \ /datos/evolution_lacofi \ /datos/evolution_maria \ /datos/externos" DIRS3="/home \ /etc \ /root \ /datos/dosemu \ /datos/imagen" TEMP="/datos/seguridad/zap" FECHA=`date +%d%b%Y` IMAGEN="/datos/seguridad/cd" DIARIO="/datos/seguridad/diario" RIP="arranque/rip.img" CAT="arranque/catalogo.cat" ESTADO="/var/log/estado.log" CONTROL="/var/log/backup" if [ "$UID" = "0" ]; then if [ "$1" = "reset" ]; then if [ -f /var/log/volcado_duro.dir ]; then echo "El status es: "`cat /var/log/volcado_duro.dir` else echo "impar" > /var/log/volcado_duro.dir fi if [ -d "/datos/seguridad" ]; then echo "/datos/seguridad existe" else echo "Creando /datos/seguridad" mkdir /datos/seguridad fi if [ -d "/datos/seguridad/cd" ]; then echo "/datos/seguridad/cd existe" else echo "Creando /datos/seguridad/cd" mkdir /datos/seguridad/cd fi if [ -d "/datos/seguridad/zap" ]; then echo "/datos/seguridad/zap existe" else echo "Creando /datos/seguridad/zap" mkdir /datos/seguridad/zap fi if [ -d "/datos/seguridad/diario" ]; then echo "/datos/seguridad/diario existe" else echo "Creando /datos/seguridad/zap" mkdir /datos/seguridad/diario fi if [ -d "/datos/seguridad/zap/arranque" ]; then echo "/datos/seguridad/zap/arranque existe" else echo "Creando /datos/seguridad/zap/arranque" mkdir /datos/seguridad/zap/arranque echo "Debes colocar en /datos/seguridad/zap/arranque" echo "una imagen de rescate, preferiblemente RIP" fi echo "El registro ha sido reseteado" > $ESTADO echo "-----------------------------" >> $ESTADO exit fi # Poner todo a cero rm -Rf /datos/seguridad/zap/*.tar.bz2 rm -Rf /datos/seguridad/cd/*.iso rm -Rf /var/log/md5_*.log rm -Rf $CONTROL*.log rm -Rf $DIARIO/*.tar.bz2 # Ahora creamos ficheros tar con la copia de seguridad # y luego los pasamos a imágenes ISO, listas para grabar for NUM in 1 2 3 do echo "Creando serie$NUM-$FECHA.tar.bz2" >> $ESTADO tar cjf $TEMP/serie$NUM-$FECHA.tar.bz2 \ --listed-incremental=$CONTROL$NUM.log \ `eval echo '$DIRS'$NUM` &> /dev/null status=$? echo "La compresión se ejecutó con código $status" >> $ESTADO mkisofs -r -o $IMAGEN/serie$NUM-$FECHA.iso \ -b $RIP -c $CAT $TEMP &> /dev/null status=$? echo "La imagen ISO se creó con código $status" >> $ESTADO sumamd5=`md5sum $IMAGEN/serie$NUM-$FECHA.iso | awk '{print $1}'` echo $sumamd5 >> /var/log/md5_$NUM.log rm $TEMP/*.tar.bz2 done if [ -f "$IMAGEN/serie1-$FECHA.iso" ] || [ -f "$IMAGEN/serie2-$FECHA.iso" ] || [ -f "$IMAGEN/serie3-$FECHA.iso" ]; then echo "Pendiente" > /var/log/volcado_cd.dir echo "Copia de seguridad almacenada en el dico duro" >> $ESTADO echo "La copia de seguridad no está a salvo" >> $ESTADO fi else echo "¡Solo root puede hacer eso!" fi --------------Final de script "seguridad" -------------
Ahora vamos a crear un nuevo script, llamado "completar", que será el encargado de hacer las copias de seguridad diarias:
--------------Inicio de script "completar" ------------ #!/bin/sh DIRS1="/datos/textos \ /datos/personal \ /datos/profesional" DIRS2="/datos/compartidos \ /datos/evolution_lacofi \ /datos/evolution_maria \ /datos/externos" DIRS3="/home \ /etc \ /root \ /datos/dosemu \ /datos/imagen " TEMP="/datos/seguridad/zap" FECHA=`date +%d%b%Y` IMAGEN="/datos/seguridad/cd" DIARIO="/datos/seguridad/diario" ESTADO="/var/log/estado.log" CONTROL="/var/log/backup" if [ "$UID" = "0" ]; then for NUM in 1 2 3 do tar cjf $DIARIO/$FECHA-diario$NUM.tar.bz2 \ --listed-incremental=$CONTROL$NUM.log `eval echo '$DIRS'$NUM` &> /dev/null status=$? echo "----------------------------------------------" >> $ESTADO echo "Se ha añadido el fichero incremental" >> $ESTADO echo "diario$NUM-$FECHA.tar.bz2" >> $ESTADO echo "con el código de salida $status" >> $ESTADO done else echo "¡Solo root debería hacer eso!" fi --------------Final de script "completar" -------------
Este script lo activamos usando cron, y para ello modificaremos nuestro /etc/crontab dejandolo así (cambios en cian y negrita):
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
33 1 15 * * root /usr/local/bin/seguridad
17 1 30 * * root /usr/local/bin/seguridad
11 0 * * * root /usr/local/bin/completar
De esta forma, el script "seguridad" se encargará de borrar todas las copias diarias situadas en /datos/seguridad/diario, y luego hacer una copia completa. Esto ocurre dos veces al mes. Mientras tanto, cada día, el script "completar" va añadiendo copias diarias de los ficheros añadidos o modificados desde el día anterior, y seguirá haciéndolo hasta que toque copia completa y el script "seguridad" lo vuelva a borrar.
Pero nos queda algo importante: modificar nuestro script "cdsalva" de tal forma que nos permita sacar a CD también las copias incrementales. Para ello usaremos un CD-RW aparte (un cuarto CD), que se grabará en formato multisesión, lo que nos permite ir añadiendo datos a medida que se vayan creando más backups incrementales. Pero eso lo haremos otro día. ;-)
Hoy vamos a completar nuestro script "cdsalva", de tal forma que sirva no solo para grabar los CD-RW con las copias totales, sino también el CD-RW con las copias incrementales. Y no solo eso, sino que decida él solito cuándo toca lo uno o lo otro, y la mejor forma de hacerlo. Para que nuestro script pueda tomar esas decisiones, usará un pequeño fichero de control que los otros scripts han ido creando: "/var/log/volcado_duro.dir". Aquí es donde empezamos a ver su auténtica utilidad. Así quedaría, como siempre con los cambios en cian y negrita:
--------------Inicio de script "cdsalva" ------------- #!/bin/sh numero=1 grupo=`cat /var/log/volcado_duro.dir` equipo="dev=1,0,0" opciones="speed=16 driveropts=burnproof" multisesion="-R -J -r -T" temporal="/datos/seguridad/cd/diario.iso" estado="/var/log/estado.log" carga="-eject" registro=`cat /var/log/volcado_cd.dir` diario="/datos/seguridad/diario" declare -i megas if [ "$registro" = "Pendiente" ]; then valido="si" else valido="no" fi # Copias de seguridad incrementales if [ "$registro" = "Actualizando" ]; then echo -e "Actualizando las copias incrementales" >> $estado echo -e "Grabando CD-RW 4 Multisesión. Iniciando Multisesión" echo -e " " echo -e "-----------------------------" echo -e "Introduce el CD-RW 4 Multisesión para " echo -e "Copias Incrementales y pulsa la tecla Intro" read seleccion echo -e "Preparando la copia de archivos" codigo=`cdrecord -msinfo $equipo` mkisofs $multisesion -C $codigo -N -M /dev/scd0 -o $temporal $diario status=$? if [ "$status" -eq 0 ]; then echo "Preparada copia incremental con salida $status" >> $estado fi echo -e "Grabando nuevos archivos en CD-RW" nice -20 cdrecord $opciones -multi $carga $equipo -data $temporal > /dev/null 2>&1 status=$? if [ "$status" -eq 0 ]; then echo "Grabada copia incremental con salida $status." >> $estado rm -Rf $diario/*.tar.bz2 rm -Rf /datos/seguridad/cd/diario.iso fi fi if [ "$registro" = "Salvado" ]; then echo "Actualizando" > /var/log/volcado_cd.dir echo -e "--------------------------------------" >> $estado echo -e "Empezando a hacer copias incrementales" >> $estado echo -e "Grabando CD-RW 4 Multisesión. Iniciando Multisesión" echo -e " " echo -e "-----------------------------" echo -e "Introduce el CD-RW 4 Multisesión para " echo -e "Copias Incrementales y pulsa la tecla Intro" read selecccion echo -e "Preparando la copia de archivos" mkisofs -V "Incremental" $multisesion -o $temporal $diario status=$? if [ "$status" -eq 0 ]; then echo "Preparada copia incremental con salida $status" >> $estado fi echo -e "Borrando el CD-RW" nice -20 cdrecord $equipo blank=fast > /dev/null 2>&1 echo -e "Grabando copias diarias." nice -20 cdrecord $opciones -multi $carga $equipo -data $temporal > /dev/null 2>&1 status=$? if [ "$status" -eq 0 ]; then echo "Grabada copia incremental con salida $status." >> $estado echo "Iniciada nueva serie incremental" >> $estado echo "--------------------------------" >> $estado rm -Rf $diario/*.tar.bz2 rm -Rf $temporal fi fi # Y ahora las copias totales if [ "$UID" = "0" ]; then #------ pero solo si eres root if [ "$valido" = "si" ]; then echo "----------------------------" >> $estado echo "La última serie fue $grupo" >> $estado if [ "$grupo" = "impar" ] ; then grunum="2" echo "par" > /var/log/volcado_duro.dir else grunum="1" echo "impar" > /var/log/volcado_duro.dir fi echo "La serie actual es `cat /var/log/volcado_duro.dir`" >> $estado echo "----------------------------" >> $estado fi # Un bucle de oro ---------------------------------------- for archivo in `find /datos/seguridad/cd/* -print 2>/dev/null` do # Un CD-RW no puede sobrepasar los 700 Mb megas=`du -m $archivo | awk '{print $1}'` if [ $megas -gt 700 ]; then echo -e "El CD-RW $grunum/$numero tendría $megas Mb" >> $estado echo -e "Operación cancelada" > $estado echo -e "El CD-RW $grunum/$numero tendría $megas Mb" echo -e "Revisa tus configuraciones o no podrás sacar nada a CD" valido="no" fi if [ "$valido" = "si" ]; then echo "Grabando" > /var/log/volcado_cd.dir echo "Grabando CD-RW $grunum/$numero, de $megas Mb" >> $estado echo -e " " echo -e "-----------------------------" echo -e "Introduce el CD-RW "$numero" del grupo "$grupo "("$grunum"/"$numero")" echo -e "y pulsa la tecla Intro" read seleccion echo -e "Borrando el CD-RW" nice -20 cdrecord $equipo blank=fast > /dev/null 2>&1 echo -e "Grabando el archivo "$archivo nice -20 cdrecord $opciones $carga $equipo $archivo > /dev/null 2>&1 status=$? if [ "$status" -eq 0 ]; then echo "Salvado" > /var/log/volcado_cd.dir echo "Grabado con éxito. Copia a salvo." >> $estado rm -Rf $archivo fi # Mi CD-RW no puede leer el CD recien grabado salvo # que se saque y se vuelva a cargar. Por eso, el comando cdrecord anterior lo # sacó con la opción -eject, y ahora hay que volver a cargarlo con -load # para que se pueda leer y comprobar el md5. Al ejecutar el script habrá un # movimiento de recarga automática de la bandeja del CD. carga="-load" nice -20 cdrecord $carga $equipo > /dev/null 2>&1 # Mi sistema usa autofs, con lo que monta automáticamente todos los CD. Si # vosotros no usais autofs, tendreis que añadir un comando que lo haga: # mount /mnt/cdrw echo -e "Comprobando el CD-RW "$grunum/$numero echo "Comprobando CD-RW $grunum/$numero" >> $estado nbloques=`df -k /mnt/cdrw | grep cdrw | cut -c 25-30` md5cd=`dd if=/dev/scd0 count=$nbloques bs=1024 | md5sum | awk '{print $1}'` echo "El MD5 del CD-RW $grunum/$numero es $md5cd" >> $estado md5iso=`cat /var/log/md5_$numero.log` echo "El MD5 de la iso $grunum/$numero es $md5iso" >> $estado # y salvo que useis autofs, también un comando que desmonte # antes de abrir la bandeja para cambiar el CD: # umount /mnt/cdrw carga="-eject" nice -20 cdrecord $carga $equipo > /dev/null 2>&1 fi # ---------sumamos uno a NUM y reiniciamos el bucle numero=`expr $numero + 1` done echo "Hecho" >> $estado else # ------------- Si no eres root... echo "¡Solo root puede hacer eso!" fi # --------------- Y aquí termina --------------Final de script "cdsalva" --------------
Con esto, los tres scripts son ya completamente funcionales y a través de crontab se ocupan ellos solitos de todo. Lo único que hay que hacer es ejecutar al final de la jornada el script "cdsalva". Él nos pedirá lo que necesita: los CD-RW de la serie adecuada, para hacer copias completas, o solo el CD-RW número 4 para hacer copias incrementales que se van añadiendo sucesivamente mediante multisesión. Si un día nos olvidamos de hacerlo, no pasa nada, porque el próximo día copiará simplemente los ficheros incrementales del día y también los previos, si hay alguno.
Eso sí, aún se pueden hacer múltiples cambios estéticos, como añadir colores a la salida en consola, o depurar los registros para que queden más bonitos. No pondré aquí esas chorradas, pero si quieres echarles un vistazo tú mismo, solo tienes que bajarte el fichero tal y como funciona actualmente en mi ordenador. Aquí tienes los scripts:
Y recuerda que, si quieres más seguridad, el directorio /datos/seguridad debería estar realmente situado en otra partición, solo accesible por root. Y mejor si permanece montada solo el tiempo necesario para que funcionen los scripts. Pero en fin, eso ya depende de manías personales...
Que lo disfrutes. ;-)
Nuestro script está funcionando sin problemas, de forma desatendida salvo para hacer funcionar el script "cdsalva" una vez al día. La cosa parece que funciona, y lo hace bien. Pero todo en esta vida es mejorable, naturalmente. ¿Qué tal, por ejemplo, un interfaz gráfico?. ¿Y hacer que la salida log sea coloreada?. :-)
Se puede hacer ambas cosas, claro que sí. Eso y más. Para ello solo necesitamos el programa zenity o gdialog, incluido en casi todas las distribuciones actuales. Zenity permite a un script bash normal sacar cuadros de diálogo gnome, para información o para introducir datos.
Hoy cambiaremos nuestro script "cdsalva" para conseguir varias cosas:
Puedes volver a ver los scripts, tal y como están ahora, justo debajo. Observa especialmente los cambios en "cdsalva" y las referencias a zenity. Observa cómo uso las variables (en especial $TERM para que el script decida cuándo usar zenity y cuándo la salida estandar.
Bien, ahora hay que modificar el fichero /etc/sudoers y meter una entrada tal que así:
lacofi ALL= NOPASSWD: /datos/programas-usuario/cdsalva
Y ahora creamos un icono en nuestro escritorio que ejecute el comando "sudo /datos/programas-usuario/cdsalva". Ya está, ahora basta con hacer click para que se ponga en marcha el script, con cuadros de diálogo gráficos y todo.
Y por último, creamos un alias, metiendo en nuestro ".bashrc" o donde sea, el siguiente comando:
alias status='cat /var/log/estado.log'
Con lo cual, basta con teclear "status", para que nos salga nuestro log coloreado en el que poder comprobar cómo han ido nuestras copias de seguridad.
Hoy en día, los discos duros externos USB de alta capacidad (160 Gb o más) se han vuelto tan comunes y tan baratos que se han convertido en el mejor sistema de copia de seguridad que puede existir: cabe todo, se pueden desenchufar y llevar a otro lado, nos liberan del uso de ningún compresor y de la falta de espacio... todo son ventajas. Si tienes la oportunidad cómprate uno, ya sea firewire o USB 2.0. Te aseguro que no te arrepentirás.
Y por si fuera poco, nuestro script de copia de seguridad también se simplifica brutalmente. Casi es un juego de niños.
Para un disco duro externo Firewire de 160 Gb, utilizo fdisk y lo divido en varias particiones: una de 60 Gb para almacenar música, programas, y datos viejos que tenía dispersos por montones de CD, otra de 30 Gb para una partición de seguridad que llamaremos "lacie_uno", otra de 30 Gb para otra partición de seguridad que llamaremos "lacie_dos", y el resto (unos 40 Gb) lo dejamos ahí sin particionar para cuando necesitemos más sitio, porque ahora no hace ninguna falta. Después, creamos un sistema de ficheros ext3 en ambas particiones usando el comando "mke2fs -j /dev/sdf2 && mke2fs -j /dev/sdf3". Suponiendo, naturalmente, que nuestro disco duro externo está en /dev/sdf.
Ahora creamos los directorios /mnt/lacie_uno y /mnt/lacie_dos. Y añadimos las entradas apropiadas en /etc/fstab, tal que así:
/dev/sdf2 /mnt/lacie_uno ext3 user,noauto,ro 0 0 /dev/sdf3 /mnt/lacie_dos ext3 user,noauto,ro 0 0
Observad un par de cosas: Ambas particiones se crean con la opción NOAUTO. Eso significa que siempre estarán DESmontadas y NO accesibles. Se pueden montar a mano ("mount /mnt/lacie_uno", por ejemplo), pero entonces lo harán con la opción RO, es decir, "solo lectura", con lo que siempre estarán a salvo de cualquier error, incluso cuando las estemos usando para recuperar algún dato. Naturalmente, nuestro script las montará en forma de "lectura escritura", pero siempre automatizado, siempre en forma desatendida, y solo el tiempo justo de hacer la copia de seguridad.
Ahora montamos las particiones y creamos los ficheros de control que vamos a necesitar. Lo hacemos como root.
[15:16:58/0][root@jeanette:~]# mount /dev/sdf2 /mnt/lacie_uno -t ext3 -o rw [15:16:59/0][root@jeanette:~]# mount /dev/sdf2 /mnt/lacie_dos -t ext3 -o rw [15:17:00/0][root@jeanette:~]# touch /mnt/lacie_uno/.lacie_uno [15:17:01/0][root@jeanette:~]# touch /mnt/lacie_dos/.lacie_dos [15:17:02/0][root@jeanette:~]# mkdir /mnt/lacie_uno/espejo /mnt/lacie_dos/espejo [15:17:04/0][root@jeanette:~]# umount /mnt/lacie_uno [15:17:08/0][root@jeanette:~]# umount /mnt/lacie_dos [15:17:10/0][root@jeanette:~]# echo 1 > /var/log/contador_salvaguarda.reg [15:17:11/0][root@jeanette:~]# echo uno > /var/log/contador_serie.reg [15:17:13/0][root@jeanette:~]# touch /var/log/seguridad.log [15:17:15/0][root@jeanette:~]# touch /etc/seguridad.dir
Y ahora editamos el fichero /etc/seguridad.dir y metemos ahí todos los directorios que queremos salvar, uno por línea. Por ejempllo:
/home /mnt/datos1 /mnt/datos2 /etc /opt/programas-usuario /opt/sunrise-0.42c /root /usr/local/bin
Y por último, el script. Mucho más sencillo que los anteriores, como veréis.
----------------- Comienza script "salvaguarda" ----------------------- #!/bin/bash # Primero definir una cuantas variables -------------------- declare -i numero declare -i nivel contador=/var/log/contador_salvaguarda.reg marca=/var/log/contador_serie.reg log=/var/log/seguridad.log directorios=/etc/seguridad.dir fecha=`date` numero=`cat $contador` serie=`cat $marca` rojo=$'\e[1;31m' verde=$'\e[1;32m' amarillo=$'\e[1;33m' cian=$'\e[1;36m' normal=$'\e[0;39m' abortar="no" destino="/mnt/lacie_$serie/espejo" nivel=30 opcion="" # Deducir donde estamos, exactamente ----------------------- if [ $numero -eq $nivel ]; then case $serie in uno) echo dos > $marca dispositivo=sdf2 ;; dos) echo uno > $marca dispositivo=sdf3 ;; *) echo uno > $marca echo "$marca no tiene información válida." >> $log echo "Esto no debería estar pasando. Asumiremos serie uno." >> $log exit 1 ;; esac opcion="--delete --whole-file" numero=1 else case $serie in uno) dispositivo=sdf2 ;; dos) dispositivo=sdf3 ;; *) echo "$marca no tiene información válida." >> $log echo "Esto no debería estar pasando. Abortamos." >> $log exit 1 ;; esac opcion="--update" numero=`expr $numero+1` fi echo $numero > $contador # Venga, vamos alla ---------------------------------------- if [ "$UID" = "0" ]; then # Primero montar ----------------------------------- echo " " >> $log echo "--- $fecha - Serie $serie / Nivel $numero ---" >> $log mount -t ext3 -o rw /dev/$dispositivo /mnt/lacie_$serie error=$? if [ $error -eq 0 ]; then echo "Se ha montado el disco duro externo /mnt/lacie_$serie" >> $log else echo "No se pudo montar lacie_$serie!!" >> $log if [ -f /mnt/lacie_$serie/.lacie_$serie ]; then echo "Sin embargo parece estar ya montado. Seguimos." >> $log else echo "La unidad FireWire no funciona. COMPRUEBA ESO." >> $log abortar="si" fi fi # Ahora copiar ------------------------------------- if [ "$abortar" = "no" ]; then for directorio in `cat $directorios` do rsync -qarzH $opcion $directorio $destino error=$? if [ $error -eq 0 ]; then echo "Sincronizado correctamente $directorio" >> $log else echo "Ha fallado la sincronizacion de $directorio" >> $log fi done fi # Y luego desmontar --------------------------------- umount /mnt/lacie_$serie if [ $error -eq 0 ]; then echo "Se ha desmontado el disco duro externo /mnt/lacie_$serie" >> $log else echo "No se pudo desmontar lacie_$serie!!" >> $log fi # Y si no eres root, pues nada ------------------------------ else echo -ne "${rojo}Solo root${normal} puede usar este comando." fi function xwindow { zenity --info --info-text "Copia de seguridad actualizada" } function consola { echo "Copia de seguridad actualizada" } if [ "$TERM" = "xterm" ] || [ "$TERM" = "dumb" ]; then xwindow else consola fi ----------------- Termina script "salvaguarda" -----------------------
Este script debería pertenecer a root.root y tener permisos de ejecución para root. Y ya está. Solo tenemos que poner el script en nuestro crontab para que se ejecute todos los dias, por ejemplo a las 6 de la mañana, cuando no estorbe. Y él se encargará de todo, incluso de ir rotando las copias de seguridad.
Como sabes, soy un fanático de las copias de seguridad, a veces hasta extremos realmente paranoicos. Pero no debería extrañarte, teniendo en cuenta que me gusta juguetear mucho con las configuraciones y las particiones del disco duro, así que es relativamente normal que tarde o temprano cometa un error infinitesimal. Sin entrar en detalles, la verdad es que mi paranoia respecto al backup me ha salvado el cuello tantas veces que ya he perdido la cuenta.
El caso es que he usado varios sistemas de backup automatizados a lo largo de los años. En CD, en DVD, en disco duro USB, pero siempre en forma de scripts automáticos y desatendidos que dejo metidos en crontab para que ellos se ocupen de todo. De hecho, esos scripts son tan desatendidos que nunca o casi nunca tengo que prestarles atención una vez funcionando. Están ahí, y ellos lo hacen todo... durante meses o años hasta que un día me doy cuenta de que necesito un dato atrasado. Una gozada, de verdad.
Lo que ahora te presento aquí es mi último script, esta vez hecho en lenguaje Perl. Es más sofisticado que los anteriores y hace alguna que otra virguería. Si te interesa, solo tienes que descargarlo. Probablemente puedas usarlo directamente con tan solo un par de modificaciones para adaptarlo a tu sistema.
El script es demasiado largo para ponertelo en pantalla, pero voy a contarte un poco lo que hace y cómo funciona.
Vale, en primer lugar tienes que crear tres ficheros que debes colocar en el directorio /etc/backup. El fichero /etc/backup/directorios.conf indica qué directorios quieres salvar a las copias de seguridad, así que debe contener algo así:
/home/lacofi /home/maria /home/imagen /etc /opt /root /usr/local/bin /media/varios /var/lib /var/log
El fichero /etc/backup/excluidos.conf contiene aquellos ficheros o directorios que NO quieres que se salven a las copias de seguridad, por el motivo que sea. El listado puede ser en forma de expresiones regulares, así que ojito.
.gvfs varios/fake/ wuala/direct/
Por ejemplo, el directorio /home/lacofi/wuala/direct no se copiaría aunque /home/lacofi sí está en el listado anterior. El motivo, es que ahí se monta una unidad de red comercial (una unidad en la nube, de esas).
Vale, ahora asegúrate de que creas el fichero de logs, que es donde irá registrándose todo lo sucedido en la sesión de backup. El script no saca ningún listado en pantalla: irá todo al log (se supone que funcionará siempre en el crontab).
[lacofi@selene ~]$ su password: [root@selene /home/lacofi]# touch /var/log/backup.log [root@selene /home/lacofi]# exit [lacofi@selene ~]$
El fichero /etc/backup/backup.conf es la madre del cordero porque contiene la configuración, y debe contener algo así:
# Configuración de backup total=1 maximo=30 contador=30 nivelultra=60 serie=par directorios=/etc/backup/directorios.conf excluidos=/etc/backup/excluidos.conf log=/var/log/seguridad.log tipo=ext3 disco1=6d98f4d7-c644-43cc-8764-d1efe2bffa75 disco2=238e8f5c-844f-484e-9c5a-c742a7308b36 ultradev=ea8b4fd1-7bd1-4244-b5af-d25f6eaab544 ultrauni=/media/Lacie1Tb
Bueno, pues ahora te cuento lo que hace el script y de paso te explico lo que significan las entradas del fichero /etc/backup/backup.conf (es muy sencillo).
Lo primero que necesitas es un par de discos duros USB para hacer los backup. A ser posible, te recomiendo discos de 1Tb, aunque eso depende de la cantidad de datos que quieras salvar. Uno de esos discos será el principal. El otro será secundario y solo hará un backup muy de vez en cuando (en mi caso, una vez cada dos meses).
Toma el disco duro principal (de 1Tb) y reparticiona en dos mitades, de 500Gb cada una. Ahora mete dos entradas en /etc/fstab para que se monten como /media/Backup_par y /media/Backup_impar pero siempre en modo de solo lectura. Obviamente, los UUID que debes poner son los tuyos, no los mios, tanto en el fstab como en /etc/backup/backup.conf.
UUID=6d98f4d7-c644-43cc-8764-d1efe2bffa75 /media/Backup_impar ext3 user,noauto,ro 0 0 UUID=238e8f5c-844f-484e-9c5a-c742a7308b36 /media/Backup_par ext3 user,noauto,ro 0 0 UUID=ea8b4fd1-7bd1-4244-b5af-d25f6eaab544 /media/Lacie1Tb ext3 user,noauto,rw 0 0
El disco duro secundario también debe estar en /etc/fstab, pero no necesita preparación. En realidad podría prescindirse de él, pero prefiero tenerlo para cubrir un caso de pura catástrofe: que el ordenador se averíe mientras hace el backup, dañándose a sí mismo y al mismo tiempo la tabla de particiones del disco de backup. Es una avería realmente complicada, pero vale más pensar mal. Bueno, en ese caso no lo perderías todo: aún queda el disco duro secundario con una copia de como mucho dos meses atrás.
Ahora se mete el script en el crontab (por ejemplo, puedes meterlo en /etc/cron.daily). Y se pondrá en marcha todos los días, por la noche. ¿Qué hace, exactamente ?.
Bueno, lo primero que hace es leer la configuración de /etc/backup/backup.conf. Ahí se encuentra con que el valor de "contador" coincide con el valor de "maximo", así que asume que hay que cambiar de set. Pone el contador en 1 y cambia la serie de par a impar. Luego desmonta el disco /media/Backup_impar, y lo vuelve a montar pero en modo de lectura y escritura. A continuación borra el directorio /media/Backup_impar/espejo y hace una compia de seguridad completa con rsync. Después desmonta /media/Backup_impar y lo vuelve a montar en modo de solo lectura, para que no pueda dañarse accidentalmente. Y a continuación, graba el fichero de log con un registro de todo lo que ha hecho.
Al día siguiente, volverá a hacer lo mismo. Pero esta vez verá que el valor de "contador" es 1, así que sigue con el mismo set "impar", y se limita a poner "contador" en 2. La copia de seguridad será solo incremental (únicamente los cambios). Y así será día tras día, hasta que "contador" vuelva a coincidir con "maximo" (entonces pondrá el "contador" en 1 y volverá a cambiar de set).
El valor de "total" se irá incrementando siempre en uno. Pero una vez cada dos meses su valor será un múltiplo entero de "nivelultra". Ese día, además de la copia de seguridad normal, hará otra copia extra completa en el disco duro secundario y luego borrará la precedente.
Y ya está. En caso de pérdida de datos, tendrás siempre una copia de seguridad actualizada hace menos de 24 horas. En caso de fallo lógico del disco de backup, aún te quedará el otro set con una copia actualizada hace menos de 1 mes. Y en caso de fallo físico del disco, aún tienes el otro disco actualizado hace menos de 2 meses.
Puedes consultar el fichero /var/log/seguridad.log si quieres ver lo que el script va haciendo día a día. Verías algo tal que así:
--- Sun Nov 1 07:58:56 CET 2009 - Serie impar / Nivel 14 (ejecución nº44) --- Se ha montado la unidad /media/Backup_impar Sincronizado /home/lacofi correctamente Sincronizado /home/maria correctamente Sincronizado /home/imagen correctamente Sincronizado /etc correctamente Sincronizado /opt correctamente Sincronizado /root correctamente Sincronizado /usr/local/bin correctamente Sincronizado /media/varios correctamente Sincronizado /var/lib correctamente Sincronizado /var/log correctamente La ocupación de la unidad impar es del 45% (194G de 459G) --- Mon Nov 2 07:46:54 CET 2009 - Serie impar / Nivel 15 (ejecución nº45) --- Se ha montado la unidad /media/Backup_impar Sincronizado /home/lacofi correctamente Sincronizado /home/maria correctamente Sincronizado /home/imagen correctamente Sincronizado /etc correctamente Sincronizado /opt correctamente Sincronizado /root correctamente Sincronizado /usr/local/bin correctamente Sincronizado /media/varios correctamente Sincronizado /var/lib correctamente Sincronizado /var/log correctamente La ocupación de la unidad impar es del 45% (196G de 459G)
También puedes arrancar el script a mano con la opción "--simulacro". En ese caso, todo se ejecutará normalmente, pero el fichero de configuración no será actualizado, rsync será ejecutado en modo "--dry-run" (simulacro), y el registro de lo que se hace saldrá a pantalla y no al fichero de log.
Y además, cuando el script lea el fichero /etc/backup/backup.conf comprobará cuidadosamente todas las variables, y no se ejecutará si hay alguna errónea (dejará la queja apropiada en el log para que la veas).
Hay algún secretito más por ahí oculto. Pero dejo que lo descubras por tí mismo. Bájatelo y échale un vistazo. Considera el código como de dominio público. Y que lo disfrutes.