====== [SCRIPT] RestoreMenu ====== ====== Descripcion ====== Ver el post del blog: http://blog.ciberterminal.net/index.php/2012/01/20/script-de-copia-y-restauracion-de-un-sistema-windows ====== Acciones a realizar ====== Instalar un sistema linux base con las siguientes dependencias: * bash >= 4.0 * sudo * dd * gzip/gunzip * [[http://www.tuxera.com/community/ntfs-3g-download/|ntfsprogs]] * acpi (comprobación de batería en portátil) * dmidecode (revisamos el serial, el script hay que configurarlo cada vez) * pigz (para proceso en paralelo) ===== Pasos generales ===== * Se particiona el disco. * Instalamos windows * Instalamos un linux "minimal", y dependencias necesarias para que el script funcione * Añadimos nuestro script. * Modificamos los parámetros de configuración necesarios en el mismo * Creamos un usuario de sistema sin privilegios, modificamos //~/.bashrc// para lanzar automáticamente el script cuando se logue el usuario. * Deshabilitamos la posibilidad de salir del script (//trap//) para evitar problemas. * Nos guardamos el pass de root ;-) * Modificamos grub para que el menú diga algo como Restore or similar y el usuario no se asuste viendo //GNU/Linux// * Informar al usuario de como funciona el entorno, aunque es muy muy sencillo) ===== Script ===== ==== Codigo ==== #!/bin/bash # Coded by dodger # More information on # http://blog.ciberterminal.net/index.php/2012/01/20/script-de-copia-y-restauracion-de-un-sistema-windows SNAPSHOTDIR=/home/snapshots WINDOWSDEV=/dev/sda1 SERIAL="serialnumber" HOST="hostname" INITIAL_IMAGE="INITIAL-IMAGE_20120119-115923_mar-eee.img.gz" COMPRESSOR=/usr/bin/pigz COMPRESSOPTIONS="-9fc" UNCOMPRESSOR=/bin/gunzip UNCOMPRESSOPTIONS="-dc" NTFSCLONE="/root/ntfs-3g_ntfsprogs-2011.4.12/ntfsprogs/ntfsclone" NTFSRESIZE="/root/ntfs-3g_ntfsprogs-2011.4.12/ntfsprogs/ntfsresize" # AUTOCONFIG unset IMAGELIST unset IMAGESIZE [ ! -d ${SNAPSHOTDIR} ] && mkdir $SNAPSHOTDIR trap_it() { [[ "$(kill -l | tail -1 | tr '+' '-')" =~ ([0-9]{1,})\)[[:space:]]{1,}[A-Z0-9\-]{3,15}(.|)$ ]] local TRAPIT=$(eval echo {1..${BASH_REMATCH[1]}}) trap 'echo "NO PERMITIDO"' ${TRAPIT} } print_main_menu() { local let OPTION=0 clear cat > /dev/stdout < " read OPTION OPTION=${OPTION:-98} [[ ! ${OPTION} =~ ^[0-9]{1,}$ ]] && OPTION=0 done return ${BASH_REMATCH[0]} } test() { local MENU=$1 local let OPTION=0 case $MENU in "main" ) ;; "restore" ) ;; "clone" ) ;; * ) ;; esac } help() { clear cat > /dev/stdout < " read YN [[ ! ${YN} =~ ^[yY]$ ]] && return 1 return 0 } restore_clone_main() { local ACTION=$1 local IMAGEFILE=$2 local DDPID=0 check_cable show_agree [ ! $? -eq 0 ] && return 1 case "$ACTION" in "clone") ${NTFSCLONE} --save-image --output - ${WINDOWSDEV} | $COMPRESSOR $COMPRESSOPTIONS > ${IMAGEFILE} ;; "restore") $UNCOMPRESSOR $UNCOMPRESSOPTIONS $IMAGEFILE | ${NTFSCLONE} --restore-image --overwrite ${WINDOWSDEV} - ;; *) echo "Error, REPORT" return 1 ;; esac echo "Completado, Pulse ENTER para continuar" read return 0 } restore_menu() { local let OPTION=99 local YN=n clear echo "##################################################" echo "Menu de restauracion" echo "Paso 1: Elegir imagen:" list_images for ((x=0; x<${#IMAGELIST[*]} ; x++)) ; do echo "${x} ) ${IMAGELIST[$x]}" done echo -e "\nIntroduce el numero de imagen a restaurar" while [ ${OPTION} = 99 ] do printf "%s" "-> " read OPTION OPTION=${OPTION:-99} [ ${OPTION} -lt 0 ] || [ ${OPTION} -ge ${#IMAGELIST[*]} ] || [[ ! ${OPTION} =~ ^[0-9]{1,}$ ]] && OPTION=99 done echo "##################################################" echo "Paso 2: Restaurar imagen: ${IMAGELIST[$OPTION]}" echo "La descripcion de la imagen es:" cat ${SNAPSHOTDIR}/$(basename ${IMAGELIST[$OPTION]} .img.gz).description echo "Estas seguro?" printf "%s" "(y/N)-> " read YN [[ ${YN} =~ ^[yY]$ ]] && restore_clone_main restore "${SNAPSHOTDIR}/${IMAGELIST[$OPTION]}" if [ $? -eq 0 ] ; then echo "Es necesario reiniciar el Ordenador..." sleep 2 reboot_machine fi } clone_menu() { MYDATE="$(date +%Y%m%d-%H%M%S)" local let OPTION=99 local YN=n local DESCRIPTION="" local USEDSPACE="$(${NTFSRESIZE} -i --no-action ${WINDOWSDEV} 2>&1 | grep "freeing" | awk '{print $5}')" USEDSPACE=$(($USEDSPACE/1024/2)) local FREESPACE="$(df -P ${SNAPSHOTDIR} | grep "%" | awk '{print $4}')" clear echo "##################################################" echo "Menu de Clonado" [ $USEDSPACE -gt $FREESPACE ] && echo "El espacio necesario es mayor que el libre, es necesario hacer espacio (borrar imagenes)" && return 1 while [[ ! $DESCRIPTION ]] ; do echo "Introduce una descripcion para la imagen y pulsa ENTER" printf "%s" "-> " read DESCRIPTION echo "${DESCRIPTION}" > "${SNAPSHOTDIR}/${MYDATE}_${HOST}.description" done restore_clone_main clone "${SNAPSHOTDIR}/${MYDATE}_${HOST}.img.gz" return 0 } delete_menu() { local let OPTION=98 local YN=n clear list_images list_image_size [ ${#IMAGELIST[@]} -eq 1 ] && echo -e "No hay imagenes que borrar,\nPresione ENTER" && read && return 0 echo "##################################################" echo "Menu de Borrado" echo "Paso 1: Elegir imagen para borrar:" for ((x=0; x<${#IMAGELIST[@]} ; x++)) ; do [[ ! "${IMAGELIST[$x]}" =~ ^${INITIAL_IMAGE}$ ]] && echo "$x ) \"${IMAGELIST[$x]}\" , Tamaño : ${IMAGESIZE[$x]} MB" done echo -e "\nIntroduce el numero de imagen a eliminar o 99 para salir" while [ ${OPTION:-98} = 98 ] do printf "%s" "-> " read OPTION OPTION=${OPTION:-98} [ ${OPTION} -eq 99 ] && return 1 [ ${OPTION} -lt 0 ] || [ ${OPTION} -gt ${#IMAGELIST[*]} ] || [[ ! ${OPTION} =~ ^[0-9]{1,}$ ]] && OPTION=98 done echo "Estas seguro?" printf "%s" "(y/N)-> " read YN if [[ ${YN} =~ ^[yY]$ ]] then echo "Borrando ${IMAGELIST[$OPTION]}" if [[ ! "${IMAGELIST[$OPTION]}" =~ ^${INITIAL_IMAGE}$ ]] then rm -fv "${SNAPSHOTDIR}/${IMAGELIST[$OPTION]}" rm -fv "${SNAPSHOTDIR}/$(basename ${IMAGELIST[$OPTION]} .img.gz).description" fi fi } list_menu() { local let OPTION=98 local YN=n clear list_images list_image_size echo "##################################################" echo "Lista de imagenes" for ((x=0; x<${#IMAGELIST[@]} ; x++)) ; do echo "$x ) Nombre: \"${IMAGELIST[$x]}\" , Tamaño : ${IMAGESIZE[$x]} MB" done echo "##################################################" echo "Presiona ENTER para continuar" read } main() { trap_it while true ; do local let OPTION=0 print_main_menu OPTION=$? case $OPTION in 1) restore_menu ;; 2) clone_menu ;; 3) delete_menu ;; 4) list_menu ;; 5) help ;; 99) reboot_machine ;; *) ;; esac done } main ==== Variables ==== ^ Variable ^ Valor por defecto ^ Descripcion ^ | ''SNAPSHOTDIR'' | ''/home/snapshots'' | Directorio donde se almacenarán los snapshots y descripciones | | ''WINDOWSDEV'' | ''/dev/sda1'' | Partición que contiene Windows | | ''SERIAL'' | ''"8BOAAQ256174"'' | El nº de serie del equipo, se puede ver con la dependencia ''dmidecode'' | | ''HOST'' | ''"my-hostname"'' | Nombre del host, únicamente se usa para generar un nombre de imagen | | ''COMPRESSOR'' | ''/usr/bin/pigz'' | Comando usado para comprimir, en este caso [[http://blog.ciberterminal.net/index.php/2011/11/15/ciclo-herramientas-gnulinux-v-pbzip2/|pigz]] para aprovechar los procesadores multi-core. | | ''COMPRESSOPTIONS'' | ''"-9fc"'' | Opciones para la compresión | | ''UNCOMPRESSOR'' | ''/bin/gunzip'' | Ídem pero para descomprimir | | ''UNCOMPRESSOPTIONS'' | ''"-dc"'' | Opciones para la descompresión | | ''NTFSCLONE'' | ''"/root/ntfs-3g_ntfsprogs-2011.4.12/ntfsprogs/ntfsclone"'' | Donde está el binario de ntfsclone, a veces puede ser necesario compilar (ver [[restore_menu#Troubleshooting|Troubleshooting]]) | | ''NTFSRESIZE'' | ''"/root/ntfs-3g_ntfsprogs-2011.4.12/ntfsprogs/ntfsresize"'' | Ídem que antes, si hemos compilado | ==== Ejemplo de Configuración restante ==== === grub === # general configuration: timeout 2 default 0 color light-blue/black light-cyan/blue # (0) Windows title Windows rootnoverify (hd0,0) makeactive chainloader +1 # (1) Arch Linux title Recovery Mode root (hd0,1) kernel /boot/vmlinuz-linux root=/dev/sda2 ro initrd /boot/initramfs-linux.img === .bashrc === # # ~/.bashrc # sudo /root/restore_menu.sh === sudoers === username ALL=(ALL) NOPASSWD: /root/restore_menu.sh ====== Troubleshooting ====== ===== ntfsclone ===== ERROR: $Bitmap size is smaller than expected Solución: http://www.tuxera.com/forum/viewtopic.php?f=2&t=27527