Можно ли использовать Raspberry Pi для создания собственной резервной копии?

78

Этот вопрос отвечает на вопрос о том, как я использую внешний компьютер для создания резервной копии моего RPi.

Мне интересно, могу ли я создать резервную копию SD-карты, которая используется в настоящее время, и скопировать ее в файл на USB-устройстве хранения данных. Это возможно? Если нет, есть ли способ создать резервную копию RPi без участия другого компьютера?

Эрик Уилсон
источник
2
Конечно, но пропустите / tmp, / run, / proc, / sys, / dev и / mnt. Вам не нужно создавать изображение, вам нужна резервная копия, из которой вы можете создать или обновить изображение. Так что не используйте dd, посмотрите в rsync.
Златовласка
1
@goldilocks Мне бы очень понравилось, если бы вы добавили этот комментарий в более полный ответ, объясняющий процесс резервного копирования и восстановления, который вы имеете в виду.
Эрик Уилсон
Готово - извините, мне потребовалось несколько дней, чтобы найти время.
Златовласка
1
Если целевой том достаточно велик, перемонтирование файловой системы только для чтения и создание ddкопии с соответствующим размером блока, вероятно, будет самым быстрым для «новой» копии. Делать копирование файлов на флэш / SD-носитель - плохая идея.
Крис Страттон

Ответы:

86

Вот вступление к использованию rsyncдля резервного копирования на Pi. После создания первоначальной резервной копии ее обновление будет намного быстрее, чем постоянное копирование всего изображения. Вы можете сделать это на локальном жестком диске или по сети.

На самом деле вам не нужна полная копия работающей системы в качестве резервной копии, поскольку некоторые вещи якобы в файловой системе существуют только во время выполнения. Включение этого в резервную копию и последующее использование ее для воссоздания образа позже может создать проблемы для вас.

Есть и другие исключения. rsyncможет принять список ( глобальных ) шаблонов для исключения, и их можно прочитать из файла, поэтому давайте сначала рассмотрим, что должно быть в таком файле. Обратите внимание, что записи имеют форму, /directory/*а не /directory. Это потому, что мы хотим, чтобы они существовали, но мы не хотим копировать в них что-либо.

/proc/*
/sys/*

Они действительно не существуют на диске. Это интерфейс к ядру, который создает и поддерживает их в памяти . Если вы скопируете их, а затем скопируете обратно в систему и загрузите их, это будет (в лучшем случае) бессмысленно, поскольку ядро ​​использует их в качестве точек монтирования для интерфейсов [Если вы хотите увидеть, что происходит при монтировании раздела файловой системы в каталоге с данными, попробуйте. Это работает и не принесет никакого вреда, но то, что было в каталоге, теперь недоступно.]

Обратите внимание, что очень важно, чтобы точки монтирования /sysи /procсуществовали. Но они не должны содержать ничего. Следующий:

/dev/*

devКаталог не совсем то же самое , как procи , sysно для наших целей. Если вы считаете, что должны сохранить это, чтобы в резервной копии могли быть одинаковые узлы устройства или что-то в этом роде, вы ошибаетесь . Не беспокойся Не копируйте dev. Когда-то давным-давно Linux работал таким образом, но больше не работает.

/boot/*

Это особый случай с большинством (возможно, со всеми) дистрибутивов Pi, таких как Raspbian. На самом деле это точка монтирования первого, vfat, раздела. Мы собираемся разобраться с этим отдельно. Что бы вы ни делали, не стесняйтесь включать это здесь, потому что, опять же, это точка монтирования.

/tmp/*
/run/*

/runкак правило, не на диске, а в памяти. Возможно, /tmpможет быть слишком (это сэкономит немного действия SD-карты), но в любом случае, как видно из названий, это не места для хранения постоянных данных. Приложения, которые их используют, ожидают, что они могут быть удалены при каждой загрузке.

/mnt/*
/media/*

Это особенно важно, если вы планируете выполнять резервное копирование на жесткий диск или USB-накопитель, а устройство подключено /mntили /media(автомонтирование имеет тенденцию использовать последнее), потому что если вы не исключите расположение этих устройств в файловой системе, вы будете создайте цикл резервного копирования содержимого диска на себя, пока он не исчерпает пространство. Я думаю, rsync может быть достаточно умен, чтобы заметить что-то глупое, но постарайтесь не проверять предпосылку.

О фактическом резервном копировании: Создайте каталог для резервного копирования на локально смонтированном жестком диске, USB-устройстве и т. Д., Например, «pi_backup». Вы можете поочередно выполнять резервное копирование в удаленное местоположение с помощью ssh(см. Ниже) или с помощью сетевой файловой системы, но это, вероятно, займет некоторое время в первый раз.

Если файл, содержащий список для исключения, равен /rsync-exclude.txt1, а ваш диск - /mnt/usbhdдля выполнения фактического резервного копирования:

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

Обратите внимание, что на конце есть косая чертаpi_backup/ .

Это займет некоторое время и даст много выходных данных (если вы хотите проверить это в журнале, добавьте > rsync.log). --deleteпервый раз бессмысленно, но для сохранения резервной копии используйте его. Это гарантирует, что материал, который вы позже удалили на Pi, также будет удален из вашей резервной копии. aНаборы рекурсии в каталогах и убеждается все атрибуты файла соответствия. -Hдля сохранения жестких ссылок 2 , vдля многословных, поэтому вы получаете некоторые выходные данные (в противном случае rsyncтихо). Смотрите man rsyncбольше.

Существует ярлык, с помощью которого вы можете пропустить --exclude-fromфайл. Если вы уверены, что все вещи, которые вы не хотите копировать ( /tmpи т. Д.), Находятся в отдельных файловых системах, вы можете просто использовать:

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

-xбыл вставлен. Это краткая форма --one-file-system, которая говорит rsyncне пересекать границы файловой системы. Лично я предпочитаю --exclude-from, но, например, по умолчанию Raspbian, --one-file-systemбудет работать нормально. Вы можете использовать оба, если вы хотите быть -xосторожным: D

Это не совсем полная резервная копия. Достаточно, если вы ничего не вставили bootи у вас все в порядке с резервным копированием, чтобы просто восстановить систему, вставив карту в компьютер и запустив:

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

Вы также можете сделать это с картой с новым изображением (при условии, что она совпадает с вашим базовым изображением), хотя это немного неэффективно, если вам нужно создать изображение (потому что вы собираетесь перезаписать большую его часть). Вы также можете подключить другую SD-карту через USB-адаптер с таким изображением на нем и использовать описанный выше метод для сохранения дубликата карты.

Если вы добавили что-то /boot(например, собственное ядро), в том числе /boot/config.txt, вы тоже захотите это сделать (довольно просто - тут не так много). Просто сделайте это отдельно, и когда вы восстановите, этот материал будет помещен в первый раздел.

Посмотрите здесь, если вы хотите создать пустой образ в стиле Raspbian, который вы можете затем сделать резервную копию в. Вы можете использовать аналогичную методологию для создания пустой карты в стиле Raspbian - вместо того, чтобы иметь дело с .imgфайлом, вы будете иметь дело с реальным устройством (например /dev/sdb), то есть все, что вам нужно сделать, это создать таблицу разделов, fdiskа затем формат /dev/sdb1и sdb2(или что-то еще) с mkfs.

Но копировать все изображение проще! Зачем беспокоиться об этом?

Это не так сложно; Я восстановил на пустую карту (отформатированную по последней ссылке) за 10 минут. Да, просто использовать ddв целом все проще (если вы находите такие вещи, как слова, сбивающие с толку ...), НО тогда требуется довольно много времени каждый раз, когда вы хотите обновить резервную копию, потому что вы должны делать 100% каждый раз. Используя rsync, когда резервная копия существует, ее обновление происходит намного быстрее, поэтому вы можете настроить ее так, чтобы она происходила безболезненно каждый день через cron. По сети даже. Каждые шесть часов. Чем чаще вы это делаете, тем меньше времени это займет.

rsync через ssh

Вот пример:

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

«Опции» будут, например, -av --delete --exclude-from=/rsync-exclude.txtи «опции ssh» - это то, что вы обычно используете (если что-нибудь). Вы должны иметь корневой доступ через sshсделать это для целей резервного копирования системы (устанавливается PermitRootLogin=yesв /etc/ssh/sshd_configи перезапустить сервер).


1 Вы должны сохранить этот файл. Вы можете размещать комментарии в строке, начинающейся с #или ;. Это может включать в себя фактическую rsyncкоманду, которую можно скопировать позже, чтобы вам не приходилось запоминать ее каждый раз.

2 Спасибо Крису за то, что он rsyncне указал это автоматически.

Златовласка
источник
Златовласка. Это похоже на отличное использование rysync. Есть ли шанс свернуть это в сценарий для нас?
тоталитарный
Вместо того, чтобы вручную исключать все точки монтирования, почему бы mkdir /tmp/backupable && mount --bind / /tmp/backupableи не использовать rsync? Это также имеет преимущество в резервном копировании любых данных, хранящихся в местах, которые «затенены» чем-то, установленным там.
n.st
@ n.st Хорошая идея (смеется)! Я отредактировал предложение в вопросе, хотя я все еще думаю, что использование --exclude-from- лучшая идея. Если у вас есть время, вы можете записать это как отдельный ответ, у вас есть мой голос, и я могу сослаться на это. Этот ответ достаточно многословен.
Златовласка
1
@IgorGanapolsky Намерение состоит в том, чтобы не создавать изображение (читайте раздел «Но копировать все изображение проще! Зачем беспокоиться об этом?» ). В дополнение к тому, что этот метод проще и быстрее поддерживать после его создания, он, как правило, более гибкий. Если вы хотите использовать его позже, .imgвы можете создать ; это и это должно помочь объяснить, как они структурированы и могут быть созданы.
Златовласка
1
Смотрите абзац, который начинается: «Это не совсем полная резервная копия ...» . Это в основном то же самое в обратном направлении. Это может помочь с некоторыми понятиями, которые люди обычно путают с / о.
Златовласка
24

Рабочий сценарий от Raspberry Community, сделанный участником.

Вы можете повторно использовать и настраивать код так, как вам нравится. Он хорошо документирован и говорит сам за себя.

#!/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

Подумайте о том, чтобы добавить комментарии на оригинальный форум или опубликовать свою собственную версию, чтобы улучшить содержание. Возьми немного, дай немного.

* И спасибо, что вернули AndersW (Click for GIT script)

Петр Кула
источник
2
Что если файловая система (удаление файлов, добавление новых файлов) изменяется во время резервного копирования pi?
Keiki
2
Я делаю резервные копии нескольких дисков, пока они работают с rsync, и мне часто удавалось получить именно то, что мне нужно, из этих файловых резервных копий. Однако, как правило, файловая система Unix не может быть скопирована идеально (с каждым битом на месте и правильно), пока файловая система смонтирована (*). Копия, сделанная во время монтирования системы, иногда называется «грязной копией». Можно предпринять несколько мер для улучшения качества грязной копии (как в приведенном выше сценарии отключение cron и mysql), но она не может быть идеальной. Ура! * - Я ошибаюсь по этому поводу, это зависит от файловой системы.
Тай Вииникка
1
Вы можете посмотреть на рекомендуемые Debian утилиты резервного копирования и посмотреть, есть ли у них их порт. rsnapshotзвучит многообещающе
Петр Кула,
1
@TaiViinikka Вам не нужна идеальная копия. Вам нужна частичная копия, которая может быть (быстро и легко) повторно наложена на исходное базовое изображение. rsyncспособ идти; когда у меня будет время завтра я добавлю ответ. rsnapshotТакже стоит исследовать.
Златовласка
3
Основываясь на ответе ppumkins выше, я синхронизировал скрипт 'dd' с последними комментариями в оригинальной ветке и добавил некоторые незначительные улучшения сам. Конечный результат доступен здесь: < github.com/aweijnitz/pi_backup >. Пожалуйста, не стесняйтесь добавлять улучшения и присылать мне запросы.
AndersW
14

Я адаптировал ответ @goldilocks на rsync для резервного копирования на пи. Я делаю резервную копию на ext4раздел на жестком диске, установленном на Pi. Если жесткий диск не подключен, rsync будет копировать в каталог подключения (до тех пор, пока SD-карта не будет заполнена). Если жесткий диск не установлен в rwрежиме, появляются обильные сообщения об ошибках. Ничего из этого не желательно, поэтому я проверяю, что мой раздел смонтирован в rwрежиме, прежде чем продолжить.

ПРИМЕЧАНИЕ 2015-03-03 Я изменил свой ответ, чтобы точно копировать жесткие ссылки. Оригинал работал, но конвертировал много жестких ссылок в файлы. В дополнение к потере места, это ставит под угрозу многие виды использования, которые предполагают наличие жестких ссылок. (Мое текущее изображение имеет 869 ссылок, многие в самом Распбиане.)

Мой скрипт для этого следует. (Мой раздел PiDataустановлен на/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

Восстановите (или обновите другой Pi) с помощью следующего: -

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

Я улучшил, rsync-exclude.txtчтобы устранить ненужные файлы.

Первая группа - это каталоги, задокументированные @goldilocks https://raspberrypi.stackexchange.com/users/5538/

Вторая группа - это файлы и каталоги, созданные OS X, когда я получаю доступ к своему Pi с помощью AFP (Apple Filing Protocol). (Обычно они невидимы в OS X, но не в Raspbian. В любом случае резервное копирование не требуется.) Даже если вы никогда не используете AFP, это не принесет вреда.

Третья группа - это файлы, для которых не требуется резервное копирование (и, конечно, они не копируются на другой Pi). Примеры fake-hwclock.data, отчеты RPi-Monitor. У вас, вероятно, будут другие.

/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
источник
1
Есть ли способ сделать этот выходной файл .img ?
Игорь Ганапольский
@IgorGanapolsky Ну, учитывая, что все необходимые файлы есть (за исключением загрузочных файлов), это, очевидно, возможно, но если вы хотите, чтобы изображение сделало изображение. Вы должны задать новый вопрос в новом сообщении, а не в комментариях.
Milliways
@ Milliways, почему бы нам не использовать "sudo rsync ..."? Будут ли некоторые файлы, которые не могут быть синхронизированы?
Смилия
6

У меня есть три Pis, работающие в моей локальной сети, и мне нужно делать резервные копии на регулярной основе с помощью cron, когда они запущены и работают. Вот почему я создал скрипт, который может создавать резервные копии dd, tar и rsync и восстанавливать их. Я предпочитаю использовать rsync для своих резервных копий, но другие люди предпочитают dd или tar. Он уже используется многими людьми. Надеюсь, что это полезно и для других :-) raspibackup - Raspberry создает резервные копии себя

framp
источник
1
Нет, извините: просить пользователя запустить (как root!) Скрипт, загруженный по HTTP, безответственно. Пожалуйста, распространите этот скрипт по безопасному каналу.
Clément
1
Я не думаю, что это не по теме, и рут или не имеет большого значения. Дело в том, что программное обеспечение должно распространяться по безопасному каналу, а ваш ответ поощряет плохие методы обеспечения безопасности.
Клемент
1
Это было бы большим шагом вперед, да :)
Clément
2
Просто отметим, что доставка по HTTPS никоим образом не добавляет безопасности в этом случае! Вы все еще скачиваете и запускаете скрипт из интернета. Безопасный процесс состоит в том, чтобы загрузить сценарий (http / https не имеет значения), открыть сценарий в редакторе и прочитать его сверху вниз, проверить его на предмет странностей и ненадежности. Только когда вы удовлетворены, вы можете запустить его. Фрэмп может быть хакером для всех, кого мы знаем, и доставка через https только заставит его улыбнуться в этом случае :) (Кстати, это не обвинение Фрампа!)
Джулиан Найт
2
Я согласен. Вот почему есть два способа описать, как установить скрипт: 1. Используйте скрипт установки 2. Загрузите его вручную, проверьте код, а затем установите его вручную
Framp
3

Вот наш стабильный инструмент для таких целей: https://github.com/aktos-io/aktos-dcs-tools

Этот инструмент записывается make sshсоединений make backup-root, make mount-rootиз глубинки в виду в первую, а затем локальные сеансы добавляются. Таким образом, он поддерживает локальные резервные копии, прямые удаленные резервные копии, резервные копии по доверенности. Резервные копии создаются постепенно (передаются только разности), а каталоги резервного копирования автономны (просто выберите каталог / версию для восстановления, у любого каталога есть полная резервная копия). Конечно, у вас есть версии (backup.last-0 - самая новая). Вы можете прервать процесс резервного копирования в любое время и продолжить позже.

Вот инструкции для вашей конкретной проблемы:

 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

РЕДАКТИРОВАТЬ

Теперь добавлена ​​новая цель: вы можете создать физическую SD-карту из ваших резервных копий с помощью одной команды:

make create-disk-from-last-backup

Следуйте инструкциям, создайте свою SD-карту, загрузите RaspberryPi с этой вновь созданной SD-карты.

ceremcem
источник
1

Здесь совершенно другой подход. Вы можете использовать LVM ( L ogical V olume M anager) для создания последовательных резервных копий. Помимо других улучшений, таких как простое добавление, расширение и уменьшение объема хранилища или восстановление операционной системы до более раннего состояния из снимка, вы также можете создавать резервные копии. Вам не нужно беспокоиться о динамически изменяемых файлах во время резервного копирования, настройки файловых систем только для чтения, исключая определенные каталоги или что-то еще. С помощью LVM вы просто создаете моментальный снимок, монтируете этот моментальный снимок и делайте его резервные копии любым способом. Вы можете сделать копию с помощью cp -a, сделать зеркало с rsync, сделать архив с tarили сделать изображение сdd, Предполагая, что вы установили устройство резервного копирования, /mnt/usbhd/pi_backup/вы можете сделать, например:

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

Настройка LVM занимает всего один раз . Как это сделать, вы можете посмотреть на легкие резервные копии и снимки работающей системы с LVM .

Инго
источник
0

Я нашел инструмент резервного копирования, который делает устанавливаемые изображения.

Также есть утилиты для монтирования и сжатия изображений.

Это может быть полезно для других

Документация, которая идет с этим, очень кратка, поэтому я отмечаю следующее: -

  1. Распакуйте утилиты в любой каталог и сделайте скрипты исполняемыми.
  2. Смонтируйте ext4отформатированный раздел на вашем Pi в /mntили /media(любой формат, который допускает большие файлы и поддерживается Pi, например, exFAT или сетевой диск можно использовать).
  3. Для первоначального запуска вам будет предложено ввести имя образа резервной копии, например /mnt/Image/BusterBackup.img
  4. Вам будет предложено указать размер файловой системы Image ROOT (в МБ), это может быть 0 для наименьшего возможного или пустое для полного резервного копирования.
  5. При последующих запусках введите путь к образу резервной копии для постепенного обновления.
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"

Я немного изменил оригинал (для копирования точек монтирования), чтобы правильно рассчитать смещения и размеры разделов, и добавил пару комментариев.

#!/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
источник
-1

Откройте терминал и введите «lsblk -f».
Это должно показать все подключенные устройства хранения.
Затем введите 'dd if = / dev / [ИМЯ вашей SD-карты] bs = 1M'.
Это займет некоторое время, поэтому вы можете запустить его в фоновом режиме.
Это точно так же, как вы делаете резервную копию вашей SD-карты в Linux.

Джей Джей Джей
источник
Это резервное копирование ВСЕ, даже ненужные и нежелательные файлы.
Игорь Ганапольский
3
Это сделает противоречивую резервную копию, потому что на работающей системе все изменилось во время резервного копирования!
Инго