¿Se puede usar una Raspberry Pi para crear una copia de seguridad de sí mismo?

78

Esta pregunta responde a la pregunta de cómo uso una computadora externa para crear una copia de seguridad de mi RPi.

Me pregunto si puedo crear una imagen de respaldo de la tarjeta SD que está actualmente en uso, y copiarla en un archivo en un dispositivo de almacenamiento USB. es posible? Si no, ¿hay alguna forma de crear una copia de seguridad de un RPi sin involucrar a otra computadora?

Eric Wilson
fuente
2
Claro, pero omita / tmp, / run, / proc, / sys, / dev y / mnt. No necesita crear una imagen, necesita una copia de seguridad desde la que pueda crear o actualizar una imagen. Así que no lo use dd, investigue rsync.
Ricitos de oro
1
@goldilocks Me encantaría que tuvieras este comentario en una respuesta más completa, explicando el proceso de copia de seguridad y restauración que tienes en mente.
Eric Wilson
Hecho, lo siento, me tomó unos días encontrar el tiempo.
Ricitos de Oro
1
Si su volumen de destino es lo suficientemente grande, volver a montar el sistema de archivos de solo lectura y hacer una ddcopia con un tamaño de bloque apropiado probablemente sea más rápido para una copia "nueva". Hacer una copia de archivo por archivo en medios flash / SD es probablemente una mala idea.
Chris Stratton

Respuestas:

86

Aquí hay una introducción al uso rsyncpara realizar copias de seguridad en el Pi. Una vez que se crea el respaldo inicial, mantenerlo actualizado de esta manera es mucho más rápido que extraer constantemente toda la imagen. Puede hacer esto en un disco duro local o en una red.

En realidad, no desea una copia completa de un sistema en ejecución como respaldo, ya que algunas de las cosas aparentemente en el sistema de archivos solo existen en tiempo de ejecución. Incluir eso en una copia de seguridad y luego usarlo para recrear una imagen más tarde puede crear problemas para usted.

Hay algunas otras excepciones también. rsyncpuede aceptar una lista de patrones ( glob ) para excluir, y esos se pueden leer desde un archivo, así que primero veamos qué debería estar en dicho archivo. Tenga en cuenta que las entradas son de la forma /directory/*y no /directory. Esto se debe a que queremos que existan, pero no queremos copiar nada en ellos.

/proc/*
/sys/*

Estos realmente no existen en el disco. Son una interfaz para el núcleo, que los crea y los mantiene en la memoria . Si copia estos y luego los copia de nuevo en un sistema y lo inicia, será (en el mejor de los casos) sin sentido, ya que el núcleo los usa como puntos de montaje para las interfaces [Si desea ver qué sucede cuando monta una partición del sistema de archivos en un directorio con datos, intente. Funciona y no hará ningún daño, pero las cosas que estaban en el directorio ahora son inaccesibles.]

Tenga en cuenta que es crítico que existan los puntos de montaje /sysy /proc. Pero no deberían contener nada. Próximo:

/dev/*

El devdirectorio no es exactamente lo mismo que procy syspero para nuestros propósitos se encuentra. Si cree que debe guardar esto para poder tener los mismos nodos de dispositivo en su copia de seguridad o algo así, está equivocado . No te molestes. No copie dev. Hace mucho tiempo, Linux funcionaba de esa manera, pero ya no lo hace.

/boot/*

Este es un caso especial con la mayoría (quizás todas) de las distribuciones específicas de Pi, como Raspbian. En realidad, es un punto de montaje para la primera partición, vfat. Vamos a lidiar con eso por separado. Hagas lo que hagas, no te molestes en incluirlo aquí, porque de nuevo, es un punto de montaje.

/tmp/*
/run/*

/rungeneralmente tampoco está en el disco, está en la memoria. Quizás también /tmppodría serlo (esto ahorraría un poco de acción de la tarjeta SD), pero en cualquier caso, como los nombres implican, estos no son lugares para almacenar datos persistentes. Las aplicaciones que los usan esperan que se eliminen en cada arranque.

/mnt/*
/media/*

Esto es importante especialmente si planea realizar una copia de seguridad en un disco duro o una memoria USB y el dispositivo está en /mnto /media(el montaje automático tiende a usar este último), porque si no excluye la ubicación de esos dispositivos en el sistema de archivos, lo hará cree un bucle que haga una copia de seguridad del contenido de la unidad, hasta que se quede sin espacio. Creo que rsync podría ser lo suficientemente inteligente como para detectar algo tan tonto, pero trate de evitar probar la premisa.

En la copia de seguridad real: cree un directorio para hacer una copia de seguridad en el disco duro montado localmente, USB, etc., por ejemplo, "pi_backup". Alternativamente, puede hacer una copia de seguridad en una ubicación remota a través de ssh(consulte a continuación) o utilizando un sistema de archivos montado en la red, pero esto probablemente tomará un tiempo la primera vez.

Si el archivo que contiene la lista para excluir es /rsync-exclude.txt1 y su unidad es /mnt/usbhd, para hacer la copia de seguridad real:

rsync -aHv --delete --exclude-from=/rsync-exclude.txt / /mnt/usbhd/pi_backup/

Observe que hay una barra inclinada finalpi_backup/ .

Esto tomará un tiempo y producirá una gran cantidad de resultados (si desea examinar eso en un registro, agregue > rsync.log). --deleteno tiene sentido la primera vez, pero para mantener la copia de seguridad actualizada úsela. Esto garantiza que las cosas que luego eliminó en el Pi también se eliminen de su copia de seguridad. La arecursividad conjuntos en los directorios y se asegura de todos los atributos de archivo partido. -Hes preservar los enlaces duros 2 , ves detallado , por lo que obtienes algo de salida (de lo contrario rsynces silencioso). Mira man rsyncpara más.

Hay un acceso directo mediante el cual puede omitir el --exclude-fromarchivo. Si está seguro de que todas las cosas que no desea copiar ( /tmpetc.) están en sistemas de archivos separados, puede usar:

rsync -axHv --delete-during / /mnt/usbhd/pi_backup/

-xha sido insertado. Esta es la forma abreviada de --one-file-system, que le dice que rsyncno cruce los límites del sistema de archivos. Personalmente, prefiero el --exclude-from, pero por ejemplo, Raspbian predeterminado, --one-file-systemfuncionará bien. Puedes usar ambos si quieres tener mucho -xcuidado: D

Eso no es una copia de seguridad completa. Es suficiente si no ha puesto nada booty está de acuerdo con usar la copia de seguridad para restaurar el sistema al pegar la tarjeta en una computadora y ejecutar:

rsync -av --delete-during /mnt/usbhd/pi_backup/ /mnt/sdcard_partition2/

También puede hacer esto con una tarjeta con una nueva imagen (suponiendo que sea la misma que su imagen base), aunque eso es un poco ineficiente si tiene que crear la imagen (porque luego sobrescribirá la mayor parte). También puede conectar otra tarjeta SD a través de un adaptador USB con dicha imagen y utilizar el método anterior para mantener una tarjeta duplicada.

Si ha agregado cosas /boot(por ejemplo, un núcleo personalizado), incluido /boot/config.txt, también querrá respaldar eso (bastante simple, no hay mucho). Simplemente hágalo por separado, y cuando restaure, esas cosas irán en la primera partición.

Vea aquí si desea crear una imagen de estilo Raspbian en blanco en la que luego podría hacer una copia de seguridad. Puede usar una metodología similar para crear una tarjeta de estilo Raspbian vacía: en lugar de tratar con un .imgarchivo, estaría tratando con un dispositivo real (por ejemplo /dev/sdb), lo que significa que todo lo que tiene que hacer es crear la tabla de particiones fdisky luego formato /dev/sdb1y sdb2(o lo que sea) con mkfs.

¡Pero copiar toda la imagen es más fácil! ¿Por qué molestarse con esto?

No es tan dificil; Restablecí a una tarjeta en blanco (formateada según el último enlace) en 10 minutos. Sí, solo usarlo ddtodo es más simple (si encuentra cosas como palabras confusas ...), PERO luego toma bastante tiempo cada vez que desea actualizar su copia de seguridad porque debe hacer el 100% de ella cada vez. Utilizando rsync, una vez que existe una copia de seguridad, la actualización es mucho más rápida, por lo que puede configurarlo para que ocurra sin problemas todos los días a través de cron. Sobre una red incluso. Cada seis horas Cuanto más lo haga, menos tiempo le llevará.

rsync vía ssh

Aquí hay un ejemplo:

rsync [options] --rsh="ssh [ssh options]" root@[the pi ip]:/ /backup/rpi/

"Opciones" sería, por ejemplo, -av --delete --exclude-from=/rsync-exclude.txty "opciones ssh" es lo que normalmente usa (si es que lo hace). Debe tener acceso root a través sshde hacer esto a los efectos de una copia de seguridad del sistema (fijado PermitRootLogin=yesen /etc/ssh/sshd_configy reiniciar el servidor).


1 Deberías conservar este archivo. Puede poner comentarios en las líneas que comienzan con #o ;. Esto podría incluir el rsynccomando real , que se puede copiar y pegar más tarde para que no tenga que recordarlo cada vez.

2 Gracias a Kris por señalar rsyncque no hace esto automáticamente.

Ricitos de oro
fuente
Encerrada dorada. Parece un gran uso de rysync. ¿Alguna posibilidad de convertirlo en un guión para nosotros?
totalitario
En lugar de excluir manualmente todos los puntos de montaje, ¿por qué no mkdir /tmp/backupable && mount --bind / /tmp/backupabley rsync eso? Eso también tiene la ventaja de hacer una copia de seguridad de los datos almacenados en lugares que están "sombreados" por algo montado allí.
n.st
@ n.st Buena idea (risas)! He editado la sugerencia en la pregunta, aunque todavía creo que usar --exclude-fromes una mejor idea. Si tiene tiempo, podría escribir esto como una respuesta separada, tiene mi voto y puedo hacer referencia a eso. Esta respuesta es bastante larga.
goldilocks
1
@IgorGanapolsky La intención es no crear una imagen (lea la parte "¡Pero copiar la imagen completa es más fácil! ¿Por qué molestarse con esto?" ). Además de ser más fácil y rápido de mantener una vez creado, este método generalmente es más flexible. Si quieres usarlo más tarde para crear un .imgpuedes; Esto y esto debería ayudar a explicar cómo están estructurados y pueden crearse.
Ricitos de oro
1
Vea el párrafo que comienza, "Esa no es una copia de seguridad completa ..." . Básicamente es exactamente lo mismo a la inversa. Esto puede ayudar con algunos conceptos con los que las personas se confunden comúnmente.
Ricitos de oro
24

Un script de trabajo de la Comunidad Raspberry hecho por un miembro allí.

Puede reutilizar y ajustar el código como quiera. Está bien documentado y se explica por sí mismo.

#!/bin/bash

# Setting up directories
SUBDIR=raspberrypi_backups
DIR=/hdd/$SUBDIR

echo "Starting RaspberryPI backup process!"

# First check if pv package is installed, if not, install it first
PACKAGESTATUS=`dpkg -s pv | grep Status`;

if [[ $PACKAGESTATUS == S* ]]
   then
      echo "Package 'pv' is installed."
   else
      echo "Package 'pv' is NOT installed."
      echo "Installing package 'pv'. Please wait..."
      apt-get -y install pv
fi

# Check if backup directory exists
if [ ! -d "$DIR" ];
   then
      echo "Backup directory $DIR doesn't exist, creating it now!"
      mkdir $DIR
fi

# Create a filename with datestamp for our current backup (without .img suffix)
OFILE="$DIR/backup_$(date +%Y%m%d_%H%M%S)"

# Create final filename, with suffix
OFILEFINAL=$OFILE.img

# First sync disks
sync; sync

# Shut down some services before starting backup process
echo "Stopping some services before backup."
service apache2 stop
service mysql stop
service cron stop

# Begin the backup process, should take about 1 hour from 8Gb SD card to HDD
echo "Backing up SD card to USB HDD."
echo "This will take some time depending on your SD card size and read performance. Please wait..."
SDSIZE=`blockdev --getsize64 /dev/mmcblk0`;
pv -tpreb /dev/mmcblk0 -s $SDSIZE | dd of=$OFILE bs=1M conv=sync,noerror iflag=fullblock

# Wait for DD to finish and catch result
RESULT=$?

# Start services again that where shutdown before backup process
echo "Start the stopped services again."
service apache2 start
service mysql start
service cron start

# If command has completed successfully, delete previous backups and exit
if [ $RESULT = 0 ];
   then
      echo "Successful backup, previous backup files will be deleted."
      rm -f $DIR/backup_*.tar.gz
      mv $OFILE $OFILEFINAL
      echo "Backup is being tarred. Please wait..."
      tar zcf $OFILEFINAL.tar.gz $OFILEFINAL
      rm -rf $OFILEFINAL
      echo "RaspberryPI backup process completed! FILE: $OFILEFINAL.tar.gz"
      exit 0
# Else remove attempted backup file
   else
      echo "Backup failed! Previous backup files untouched."
      echo "Please check there is sufficient space on the HDD."
      rm -f $OFILE
      echo "RaspberryPI backup process failed!"
      exit 1
fi

Considere agregar comentarios al foro original o publique su propia versión para ayudar a madurar el contenido. Dale un poco, dale un poco.

* Y gracias por devolver AndersW (Instrucciones para la escritura GIT)

Piotr Kula
fuente
2
¿Qué pasa si el sistema de archivos (eliminación de archivos, nuevos archivos agregados) cambia en el tiempo mientras el pi está haciendo una copia de seguridad?
keiki
2
Realicé copias de seguridad de varios discos mientras se ejecutan con rsync, y con frecuencia he podido obtener exactamente lo que necesito de estas copias de seguridad de archivos. Sin embargo, en general, un sistema de archivos Unix no se puede copiar perfectamente (con cada bit en su lugar y correcto) mientras el sistema de archivos está montado (*). Una copia realizada mientras se montaba el sistema a veces se denomina "copia sucia". Se pueden tomar varias medidas para mejorar la calidad de una copia sucia (como lo hace el script anterior, apagando cron y mysql) pero no puede ser perfecta. ¡Salud! * - Estoy equivocado sobre esto, depende del sistema de archivos.
Tai Viinikka
1
Puede ver las utilidades de respaldo recomendadas de Debian y ver si Pi tiene un puerto para ellas. rsnapshotsuena promocional
Piotr Kula
1
@TaiViinikka No necesitas una copia perfecta. Necesita una copia parcial que se pueda volver a imponer (rápida y fácilmente) en la imagen base original. rsynces el camino a seguir; cuando tenga tiempo mañana agregaré una respuesta. rsnapshotTambién vale la pena investigar.
Ricitos de oro
3
Basado en la respuesta anterior de ppumkins, sincronicé el script 'dd' con los últimos comentarios en el hilo original y agregué algunas mejoras menores. El resultado final está disponible aquí: < github.com/aweijnitz/pi_backup >. No dude en agregar mejoras y enviarme solicitudes de extracción.
AndersW
14

He adaptado la respuesta @goldilocks en rsync para hacer una copia de seguridad en el pi. Respaldo a una ext4partición en un HDD montado en el Pi. Si el HDD no está montado, rsync se copiaría en el directorio de montaje (hasta que la tarjeta SD esté llena). Si el HDD no está montado en rwmodo, se generan numerosos mensajes de error. Ninguno de estos es deseable, así que verifico que mi partición esté montada en rwmodo antes de continuar.

NOTA 2015-03-03 Modifiqué mi respuesta para copiar con precisión los enlaces duros. El original funcionó, pero convirtió muchos enlaces en archivos. Además de desperdiciar espacio, esto compromete muchos usos que suponen que los enlaces duros están en su lugar. (Mi imagen actual tiene 869 enlaces, muchos en Raspbian).

Mi guión para hacer esto sigue. (Mi partición está PiDatamontada en/mnt/PiData

#!/bin/bash
# script to synchronise Pi files to backup
BACKUP_MOUNTED=$(mount | awk '/PiData/ {print $6}' | grep "rw")
if [ $BACKUP_MOUNTED ]; then
    echo $BACKUP_MOUNTED
    echo "Commencing Backup"
    rsync -avH --delete-during --delete-excluded --exclude-from=/usr/bin/rsync-exclude.txt / /mnt/PiData/PiBackup/
else
    echo "Backup drive not available or not writable"
fi

Restaurar (o actualizar otra Pi) con lo siguiente: -

sudo rsync -avH /mnt/PiData/PiBackup/ /

He mejorado rsync-exclude.txtpara eliminar archivos innecesarios.

El primer grupo son los directorios documentados por @goldilocks https://raspberrypi.stackexchange.com/users/5538/

El segundo grupo son los archivos y directorios creados por OS X cuando accedo a mi Pi usando AFP (Apple Filing Protocol). (Normalmente son invisibles en OS X, pero no en Raspbian. En cualquier caso, no hay necesidad de hacer una copia de seguridad). Incluso si nunca usa AFP, no le harán daño.

El tercer grupo son archivos que no necesitan copia de seguridad (y ciertamente no se copian a otra Pi). Ejemplos fake-hwclock.data, informes RPi-Monitor. Probablemente tendrás otros.

/proc/*
/sys/*
/dev/*
/boot/*
/tmp/*
/run/*
/mnt/*

.Trashes
._.Trashes
.fseventsd
.Spotlight-V100
.DS_Store
.AppleDesktop
.AppleDB
Network Trash Folder
Temporary Items

.bash_history
/etc/fake-hwclock.data
/var/lib/rpimonitor/stat/
Milliways
fuente
1
¿Hay alguna manera de hacer que esa salida sea un archivo .img ?
IgorGanapolsky
@IgorGanapolsky Bueno, ya que todos los archivos esenciales están allí (excepto los archivos de arranque), obviamente es posible, pero si quieres una imagen, crea una imagen. Debe hacer cualquier pregunta nueva en una nueva publicación, no comentarios.
Milliways
@Milliways ¿por qué no deberíamos usar "sudo rsync ..."? ¿Habrá algunos archivos que no se pueden sincronizar?
Smilia
6

Tengo tres Pis corriendo en mi red local y necesito hacer una copia de seguridad de ellos en una base regular con cron cuando están en funcionamiento. Es por eso que creé un script que es capaz de crear copias de seguridad dd, tar y rsync y restaurarlas. Prefiero usar rsync para mis copias de seguridad, pero otras personas prefieren dd o tar. Ya lo usa mucha gente. Espero que sea útil para otros también :-) raspibackup - Raspberry crea copias de seguridad de sí mismo

framp
fuente
1
No, lo siento: pedirle al usuario que ejecute (como root) un script descargado a través de HTTP es irresponsable. Distribuya este script en un canal seguro.
Clément
1
No creo que esté fuera de tema, y ​​la raíz o no no importa mucho. El punto es que el software debe distribuirse a través de un canal seguro, y su respuesta es alentar las malas prácticas de seguridad.
Clément
1
Eso sería un gran paso adelante, sí :)
Clément
2
¡Solo para tener en cuenta que la entrega a través de HTTPS no agrega de ninguna manera ninguna seguridad en este caso! Todavía está descargando y ejecutando un script desde Internet. El proceso seguro es descargar la secuencia de comandos (http / https es irrelevante), abrir la secuencia de comandos en un editor y leerla de arriba a abajo, verifique si hay rarezas e inseguridades. Solo cuando esté satisfecho debe ejecutarlo. Framp podría ser un hacker para todos los que conocemos y la entrega a través de https solo lo haría sonreír en ese caso :) (Por cierto, ¡eso no es una acusación Framp!)
Julian Knight
2
Estoy de acuerdo contigo. Es por eso que se describen dos maneras de cómo instalar el script: 1. Use el instalador Script 2. Descárguelo manualmente, verifique el código y luego instálelo manualmente
desde el
3

Aquí está nuestra herramienta estable para tales propósitos: https://github.com/aktos-io/aktos-dcs-tools

Esta herramienta se escribe en make sshlas conexiones, make backup-root, make mount-rootdesde lugares remotos en mente al principio, y después se añaden sesiones locales. Por lo tanto, admite copias de seguridad locales, copias de seguridad remotas directas, copias de seguridad remotas proxy. Las copias de seguridad se realizan de forma incremental (solo se transfieren los diferenciales) y los directorios de copia de seguridad son independientes (simplemente elija un directorio / versión para restaurar, cualquier directorio tiene una copia de seguridad completa). Por supuesto, tiene versiones (backup.last-0 es la más nueva). Puede interrumpir el proceso de copia de seguridad en cualquier momento y continuar más tarde.

Aquí están las instrucciones para su problema específico:

 ssh to-your-raspberry
 cd /mnt/usb0/my-rpi-backups
 git clone https://github.com/ceremcem/aktos-dcs-tools backup-tools
 ln -s backup-tools/Makefile .

 ./backup-tools/configure # you do not need to make any settings for local sessions, just save the default 

 # just for the first time
 make set-local-session  # a flag file is created
 make init               # snapshots directory is created

 # anytime you want to back up
 make backup-root        # backup with rsync

EDITAR

Ahora hay un nuevo objetivo agregado: puede crear una tarjeta SD física a partir de sus copias de seguridad con un comando:

make create-disk-from-last-backup

Siga las instrucciones, cree su tarjeta SD, inicie RaspberryPi con esta tarjeta SD recién creada.

ceremcem
fuente
1

Aquí hay un enfoque completamente diferente. Puede usar LVM ( L gico V olumen M anager) para hacer copias de seguridad coherentes. Además de otras mejoras como agregar, expandir y reducir el almacenamiento fácilmente o restaurar el sistema operativo a un estado anterior desde una instantánea, también puede hacer copias de seguridad. No debe preocuparse por los archivos dinámicos modificados durante la copia de seguridad, configurar los sistemas de archivos de solo lectura, excluir directorios específicos u otra cosa. Con LVM , simplemente crea una instantánea, monta esta instantánea y realiza una copia de seguridad con el método que prefiera. Puede hacer una copia con cp -a, hacer un espejo con rsync, hacer un archivo con taro hacer una imagen condd. Suponiendo que haya montado un dispositivo de respaldo /mnt/usbhd/pi_backup/, puede hacer, por ejemplo:

rpi ~$ sudo lvcreate --snapshot --name rpi_snap --size 1G rpi_vg/root_lv
rpi ~$ sudo mkdir /mnt/snapshot
rpi ~$ sudo mount /dev/mapper/rpi_vg-rpi_snap /mnt/snapshot

# make backups
rpi ~$ sudo cp -a /mnt/snapshot/ /mnt/usbhd/pi_backup/
rpi ~$ sudo rsync -aH --delete /mnt/snapshot/ /mnt/usbhd/pi_backup/
rpi ~$ sudo tar -czf /mnt/usbhd/pi_backup/backup.tar.gz -V "Backup of my Raspberry Pi" -C /mnt/snapshot/ ./
rpi ~$ sudo dd if=/mnt/snapshot/ of=/mnt/usbhd/pi_backup/backup.img bs=4M

rpi ~$ sudo umount /mnt/snapshot/
rpi ~$ sudo lvremove rpi_vg/rpi_snap

Solo se necesita un poco de tiempo para configurar LVM . Para hacerlo, puede ver copias de seguridad e instantáneas fáciles de un sistema en ejecución con LVM .

Ingo
fuente
0

Encontré una herramienta de respaldo que hace imágenes instalables.

También tiene utilidades para montar y reducir imágenes.

Esto puede ser útil para otros.

La documentación que viene con ella es muy breve, así que noto lo siguiente:

  1. Extraiga las utilidades en cualquier directorio y haga que los scripts sean ejecutables.
  2. Monte una ext4partición formateada en su Pi en /mnto /media(cualquier formato que permita archivos grandes y sea compatible con Pi, por ejemplo, se puede usar exFAT o una unidad de red).
  3. Para la ejecución inicial, se le solicitará un nombre de imagen de copia de seguridad, por ejemplo /mnt/Image/BusterBackup.img
  4. Se le solicitará un tamaño de sistema de archivos RAÍZ de imagen (en MB), que puede ser 0 para el más pequeño posible o en blanco para una copia de seguridad completa.
  5. En ejecuciones posteriores, ingrese la ruta de la imagen de respaldo para actualizar de forma incremental.
An example of the commands I used:-
# Mount USB
sudo mount /dev/sda1 /mnt/Image/
# Update backup
sudo image-utils/image-backup /mnt/Image/BusterBackup.img
# Mount backup
sudo image-utils/image-mount /mnt/Image/BusterBackup.img  MountedImages
When done, run:
sudo umount MountedImages; sudo losetup -d /dev/loop0
# Compress backup
sudo sh -c "gzip -9c /mnt/Image/BusterBackup.img  > Images/BusterBackup.img.gz"

He modificado ligeramente el original (para copiar puntos de montaje), para calcular correctamente los desplazamientos y tamaños de partición y he añadido un par de comentarios.

#!/bin/bash
# Original https://raspberrypi.org/forums/viewtopic.php?p=1528736
# 2019-09-26    Modified to set size of boot sector

trap '{ stty sane; echo ""; errexit "Aborted"; }' SIGINT SIGTERM

ADDBLK=0

# Set BOOT_SIZE_MB to the Desired boot sector size (in MB) - should be multiple of 4MB
BOOT_SIZE_MB=256
BOOTSIZEM=$BOOT_SIZE_MB'M'

BOOTBEG=8192
BOOT_SIZE="$((BOOT_SIZE_MB * 1024 * 1024))"
ROUND_SIZE="$((4 * 1024 * 1024))"
# Ensure root sector starts on an Erase Block Boundary (4MB)
ROOTBEG=$(((BOOT_SIZE + ROUND_SIZE -1) / ROUND_SIZE * ROUND_SIZE / 512 + BOOTBEG))

MNTPATH="/tmp/img-backup-mnt"

ONEMB=$((1024 * 1024))

# create BOOT loop device
mkloop1()
{
  local INFO1=""
  local SIZE1=0
  local START1=0

  sync
  INFO1="$(sfdisk -d "${IMGFILE}")"
  START1=$(grep type=c <<< "${INFO1}" | sed -n 's|^.*start=\s\+\([0-9]\+\).*$|\1|p')
  SIZE1=$(grep type=c <<< "${INFO1}" | sed -n 's|^.*size=\s\+\([0-9]\+\).*$|\1|p')
  LOOP1="$(losetup -f --show -o $((${START1} * 512)) --sizelimit $((${SIZE1} * 512)) "${IMGFILE}")"
  if [ $? -ne 0 ]; then
    errexit "Unable to create BOOT loop device"
  fi
}

rmloop1()
{
  if [ "${LOOP1}" != "" ]; then
    sync
    losetup -d "${LOOP1}"
    LOOP1=""
 fi
}

# create ROOT loop device
mkloop2()
{
  local INFO2=""
  local SIZE2=0
  local START2=0

  sync
  INFO2="$(sfdisk -d "${IMGFILE}")"
  START2=$(grep type=83 <<< "${INFO2}" | sed -n 's|^.*start=\s\+\([0-9]\+\).*$|\1|p')
  SIZE2=$(grep type=83 <<< "${INFO2}" | sed -n 's|^.*size=\s\+\([0-9]\+\).*$|\1|p')
  LOOP2="$(losetup -f --show -o $((${START2} * 512)) --sizelimit $((${SIZE2} * 512)) "${IMGFILE}")"
  if [ $? -ne 0 ]; then
    errexit "Unable to create ROOT loop device"
  fi
}

rmloop2()
{
  if [ "${LOOP2}" != "" ]; then
    sync
    losetup -d "${LOOP2}"
    LOOP2=""
  fi
}

# Mount Image partitions
mntimg()
{
  MNTED=TRUE
  if [ ! -d "${MNTPATH}/" ]; then
    mkdir "${MNTPATH}/"
    if [ $? -ne 0 ]; then
      errexit "Unable to make ROOT partition mount point"
    fi
  fi
  mkloop2
  mount "${LOOP2}" "${MNTPATH}/"
  if [ $? -ne 0 ]; then
    errexit "Unable to mount image ROOT partition"
  fi
  if [ ! -d "${MNTPATH}/boot/" ]; then
    mkdir -p "${MNTPATH}/boot/"
    if [ $? -ne 0 ]; then
      errexit "Unable to make BOOT partition mount point"
    fi
  fi
  mkloop1
  mount "${LOOP1}" "${MNTPATH}/boot/"
  if [ $? -ne 0 ]; then
    errexit "Unable to mount image BOOT partition"
  fi
}

umntimg()
{
  umount "${MNTPATH}/boot/"
  if [ $? -ne 0 ]; then
    errexit "Unable to unmount image BOOT partition"
  fi
  rmloop1
  umount "${MNTPATH}/"
  if [ $? -ne 0 ]; then
    errexit "Unable to unmount image ROOT partition"
  fi
  rmloop2
  rm -r "${MNTPATH}/"
  MNTED=FALSE
}

errexit()
{
  echo ""
  echo "$1"
  echo ""
  if [ "${MNTED}" = "TRUE" ]; then
    umount "${MNTPATH}/boot/" &> /dev/null
    umount "${MNTPATH}/" &> /dev/null
    rm -rf "${MNTPATH}/" &> /dev/null
  fi
  rmloop1
  rmloop2
  exit 1
}

LOOP1=""
LOOP2=""
MNTED=FALSE

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

if [ $(id -u) -ne 0 ]; then
  errexit "$0 must be run as root user"
fi

PGMNAME="$(basename $0)"
for PID in $(pidof -x -o %PPID "${PGMNAME}"); do
  if [ ${PID} -ne $$ ]; then
    errexit "${PGMNAME} is already running"
  fi
done

rsync --version &> /dev/null
if [ $? -ne 0 ]; then
  errexit "rsync not installed (run: apt-get install rsync)"
fi

if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
  SYSTEMD=1
elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
  SYSTEMD=0
else
  errexit "Unrecognized init system"
fi

if [ ${SYSTEMD} -eq 1 ]; then
  ROOT_PART="$(mount | sed -n 's|^/dev/\(.*\) on / .*|\1|p')"
else
  if [ ! -h /dev/root ]; then
    errexit "/dev/root does not exist or is not a symlink"
  fi
  ROOT_PART="$(readlink /dev/root)"
fi

ROOT_TYPE=$(blkid "/dev/${ROOT_PART}" | sed -n 's|^.*TYPE="\(\S\+\)".*|\1|p')

ROOT_DEV="${ROOT_PART:0:(${#ROOT_PART} - 1)}"
if [ "${ROOT_DEV}" = "mmcblk0p" ]; then
  ROOT_DEV="${ROOT_DEV:0:(${#ROOT_DEV} - 1)}"
fi

PTUUID="$(blkid "/dev/${ROOT_DEV}" | sed -n 's|^.*PTUUID="\(\S\+\)".*|\1|p')"

DEVSIZE=$(blockdev --getsize64 "/dev/${ROOT_PART}")
BLKSIZE=$(blockdev --getbsz "/dev/${ROOT_PART}")
BLKCNT=$((${DEVSIZE} / ${BLKSIZE}))
INFO="$(df | grep /dev/root)"
DFKSIZE=$(awk '{print $2}' <<< "${INFO}")
DFKFREE=$(awk '{print $4}' <<< "${INFO}")
ROOTSIZE=$((${BLKCNT} * ${BLKSIZE}))
ROOTUSED=$(((${DFKSIZE} - ${DFKFREE}) * 1024))
IRFSMIN=$(((${ROOTUSED} + (${ADDBLK} * ${BLKSIZE}) + (${ONEMB} - 1)) / ${ONEMB}))
IRFSMAX=$(((${ROOTSIZE} + (${ONEMB} - 1)) / ${ONEMB}))

IMGFILE="$1"
if [ "${IMGFILE}" = "" ]; then
# Create Image file
  while :
  do
    echo ""
    read -r -e -i "${IMGFILE}" -p "Image file to create? " IMGFILE
    if [ "${IMGFILE}" = "" ]; then
      continue
    elif [[ ! "${IMGFILE}" =~ ^/mnt/.*$ && ! "${IMGFILE}" =~ ^/media/.*$ ]]; then
      echo ""
      echo "${IMGFILE} does not begin with /mnt/ or /media/"
      continue
    fi
    if [ -d "${IMGFILE}" ]; then
      echo ""
      echo "${IMGFILE} is a directory"
    elif [ -f "${IMGFILE}" ]; then
      echo ""
      echo -n "${IMGFILE} already exists, Ok to delete (y/n)? "
      while read -r -n 1 -s answer; do
        if [[ "${answer}" = [yYnN] ]]; then
          echo "${answer}"
          if [[ "${answer}" = [yY] ]]; then
            break 2
          else
            break 1
          fi
        fi
      done
    else
      break
    fi
  done
  IRFSSIZE=""
  while :
  do
    echo ""
    read -r -e -i "${IRFSSIZE}" -p "Image ROOT filesystem size (MB) [${IRFSMAX}]? " IRFSSIZE
    if [ "${IRFSSIZE}" = "" ]; then
      IRFSSIZE=${IRFSMAX}
      break
    elif [ ${IRFSSIZE} -ge ${IRFSMIN} ]; then
      break
    else
      echo ""
      echo "Requested image ROOT filesystem size (${IRFSSIZE}) is too small (Minimum = ${IRFSMIN})"
      IRFSSIZE=${IRFSMIN}
    fi
  done
  echo ""
  echo -n "Create ${IMGFILE} [${IRFSSIZE} MB] (y/n)? "
  while read -r -n 1 -s answer; do
    if [[ "${answer}" = [yYnN] ]]; then
      echo "${answer}"
      if [[ "${answer}" = [yY] ]]; then
        break
      else
        errexit "Aborted"
      fi
    fi
  done
  if [ -f "${IMGFILE}" ]; then
    rm "${IMGFILE}"
    if [ $? -ne 0 ]; then
      errexit "Unable to delete existing image file"
    fi
  fi
  ROOTEND=$((${ROOTBEG} + ((${IRFSSIZE} * ${ONEMB}) / 512) - 1))
  truncate -s $(((${ROOTEND} + 1) * 512)) "${IMGFILE}"
  if [ $? -ne 0 ]; then
    errexit "Unable to create image file"
  fi
# create image/partitions
  sync
  fdisk "${IMGFILE}" <<EOF > /dev/null
p
n
p
1
${BOOTBEG}
+${BOOTSIZEM}
t
c
p
n
p
2
${ROOTBEG}
${ROOTEND}
p
w
EOF

  mkloop1
  mkloop2
  mkfs.vfat "${LOOP1}" > /dev/null
  if [ $? -ne 0 ]; then
    errexit "Unable to create image BOOT filesystem"
  fi
  dosfsck "${LOOP1}" > /dev/null
  if [ $? -ne 0 ]; then
    errexit "Image BOOT filesystem appears corrupted"
  fi
  if [ "${ROOT_TYPE}" = "f2fs" ]; then
    mkfs.f2fs "${LOOP2}" > /dev/null
  else
    mkfs.ext4 -q -b ${BLKSIZE} "${LOOP2}" > /dev/null
  fi
  if [ $? -ne 0 ]; then
    errexit "Unable to create image ROOT filesystem"
  fi
  rmloop2
  rmloop1
# Initialise image PARTUUID
  fdisk "${IMGFILE}" <<EOF > /dev/null
p
x
i
0x${PTUUID}
r
p
w
EOF
# Create empty directories in image root partition
  mntimg
  mkdir "${MNTPATH}/dev/" "${MNTPATH}/media/" "${MNTPATH}/mnt/" "${MNTPATH}/proc/" "${MNTPATH}/run/" "${MNTPATH}/sys/" "${MNTPATH}/tmp/"
  if [ $? -ne 0 ]; then
    errexit "Unable to create image directories"
  fi
  chmod a+rwxt "${MNTPATH}/tmp/"
  umntimg
  echo ""
  echo "Starting full backup (for incremental backups, run: $0 ${IMGFILE})"
# END of create image/partitions
else

# Check existing Image
  if [[ ! "${IMGFILE}" =~ ^/mnt/.*$ && ! "${IMGFILE}" =~ ^/media/.*$ ]]; then
    errexit "${IMGFILE} does not begin with /mnt/ or /media/"
  fi
  if [ -d "${IMGFILE}" ]; then
    errexit "${IMGFILE} is a directory"
  elif [ ! -f "${IMGFILE}" ]; then
    errexit "${IMGFILE} not found"
  fi
  echo "Starting incremental backup to ${IMGFILE}"
fi

# rsync root partition
mntimg
sync
rsync -aDH --partial --numeric-ids --delete --force --exclude "${MNTPATH}" --exclude '/dev' --exclude '/media' --exclude '/mnt/*/*' --exclude '/proc' --exclude '/run' --exclude '/sys' \
--exclude '/tmp' --exclude 'lost\+found' --exclude '/etc/udev/rules.d/70-persistent-net.rules' --exclude '/var/lib/asterisk/astdb.sqlite3-journal' / "${MNTPATH}/"
if [[ $? -ne 0 && $? -ne 24 ]]; then
  errexit "Unable to create backup"
fi
sync
umntimg
Milliways
fuente
-1

Abra la terminal y escriba 'lsblk -f'.
Esto debería mostrar todos los dispositivos de almacenamiento conectados.
Luego escriba 'dd if = / dev / [el NOMBRE de su tarjeta sd] bs = 1M'.
Esto llevará un tiempo, por lo que es posible que desee ejecutarlo en segundo plano.
Esta es exactamente la misma forma en que hace una copia de seguridad de su tarjeta SD en Linux.

jay jayjay
fuente
Eso respalda TODO, incluso archivos innecesarios e indeseables.
IgorGanapolsky
3
¡Esto hará una copia de seguridad inconsistente porque en un sistema en ejecución las cosas cambiaron durante la copia de seguridad!
Ingo