Чи можна використовувати 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/*

Це свого роду окремий випадок з найбільш (мабуть, усіма) з пі-специфічних дистрибутивів, таких як 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 Завдяки Kris за те, що вказав, rsyncце не робиться автоматично.


Золотинки. Це виглядає як чудове використання рисинк. Будь-який шанс перетворити його на сценарій для нас?
тоталітарна

Замість того, щоб вручну виключати всі точки монтажу, чому б не зробити mkdir /tmp/backupable && mount --bind / /tmp/backupableта rsync це? Це також має перевагу резервного копіювання будь-яких даних, що зберігаються в місцях, "затінених" чимось встановленим там.
n.st

@ n.st Хороша ідея (LOL)! Я відредагував пропозицію у питанні, хоча все ще думаю, що використання --exclude-fromє кращою ідеєю. Якщо у вас є час, ви можете написати це як окрему відповідь, у вас є мій голос, і я можу на це посилатися. Ця відповідь досить звивиста.
золотинки

1
@IgorGanapolsky Наміром є не створювати зображення (читайте розділ "Але копіювати все зображення простіше! Чому це турбує?" ). Окрім того, що легше та швидше підтримувати один раз створений, цей метод, як правило, є більш гнучким. Якщо ви хочете використовувати його пізніше, щоб створити .imgви можете; це і це повинно допомогти пояснити, як вони структуровані та які можуть бути створені.
золотинки

1
Дивіться параграф, який починається: "Це не зовсім повне резервне копіювання ..." . Це в основному те саме, що відбувається в зворотному порядку. Це може допомогти з деякими поняттями, які люди часто плутають з приводу.
золотинки

24

Робочий сценарій з малинової громади, зроблений членом там.

Ви можете повторно використовувати та налаштувати код як завгодно. Він добре документований і пояснює себе.

#!/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 (Клацніть для сценарію GIT)


2
Що робити, якщо файлова система (видалення файлу, додані нові файли) змінюється за час, коли пі створюється резервна копія?
keiki

2
Я створюю резервну копію декількох дисків під час роботи з rsync, і мені часто вдалося отримати саме те, що мені потрібно з цих резервних копій файлів. Однак, загалом, файлову систему Unix неможливо скопіювати ідеально (з кожним бітом на місці та правильним), поки файлова система змонтована (*). Копія, зроблена під час монтажу системи, іноді називається "брудною копією". Для покращення якості брудної копії можна вжити декілька заходів (як це робиться вище написаний сценарій, вимикаючи cron та mysql), але це не може бути ідеальним. Ура! * - Я помиляюся з цього приводу, це залежить від файлової системи.
Tai Viinikka

1
Ви можете подивитися рекомендовані утиліти резервного копіювання Debian і побачити, чи є у Pi їх порт. rsnapshotзвучить рекламно
Piotr Kula

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 посилань, багато в самій Raspbian.)

Мій сценарій для цього слід наступним чином. (Мій розділ 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/

1
Чи є спосіб зробити такий вихід .img- файлом?
ІгорГанапольський

@IgorGanapolsky Ну, побачити, як усі необхідні файли є (крім завантажувальних файлів), це, очевидно, можливо, але якщо ви хочете зображення, зробіть зображення. Вам слід задати будь-яке нове запитання в новій публікації, а не коментарі.
Міллівей

@Milliways чому б нам не використовувати "sudo rsync ..."? Будуть файли, які неможливо синхронізувати?
Смілія

6

У мене в моїй локальній мережі три піски, і мені потрібно їх регулярно створювати резервні копії кроном, коли вони працюють і працюють. Тому я створив сценарій, який здатний створити резервні копії dd, tar та rsync та відновити їх. Я вважаю за краще використовувати rsync для своїх резервних копій, але інші люди віддають перевагу DD або Tar. Це вже використовується багатьма людьми. Сподіваюся, що це корисно і для інших :-) raspibackup - Малина створює резервні копії себе


1
Ні, вибачте: прохання користувача запустити (як root!) Скрипт, завантажений через HTTP, є безвідповідальним. Будь ласка, поширюйте цей сценарій по безпечному каналу.
Клімент

1
Я не думаю, що це поза темою, і root або не має великого значення. Справа в тому, що програмне забезпечення має поширюватися по захищеному каналу, а ваша відповідь заохочує погану практику безпеки.
Клімент

1
Це був би чудовий крок вперед, так :)
Клемент

2
Зауважимо лише, що доставка через HTTPS жодним чином не додає безпеки в цьому випадку! Ви все ще завантажуєте і запускаєте сценарій з Інтернету. Безпечний процес - це завантажити сценарій (http / https не має значення), відкрити скрипт у редакторі та прочитати його зверху донизу, перевірити його на дивацтва та невпевненість. Тільки коли ти задоволений, ти повинен запускати його. Framp може бути хакером для всіх, хто нас знає, і доставка через https тільки змусить його посміхнутися в такому випадку :) (BTW, це не обвинувачуючий Framp!)
Джуліан Найт

2
Я погоджуюсь з тобою. Ось чому описано два способи встановлення скрипту: 1. Використовуйте installerScript 2. Завантажте його вручну, перевірте код, а потім встановіть його вручну
фрейм

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

EDIT

Тепер додано нову ціль: Ви можете створити фізичну SD-карту із резервних копій за допомогою однієї команди:

make create-disk-from-last-backup

Дотримуйтесь інструкцій, створіть свою SD-карту, завантажте RaspberryPi за допомогою цієї новоствореної SD-карти.


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 потрібно лише один раз трохи зусиль . Як це зробити, ви можете подивитися на Easy резервні копії та знімки запущеної системи з 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

-1

Відкрийте термінал і введіть 'lsblk -f'.
Це має відображати всі підключені пристрої зберігання даних.
Потім введіть 'dd if = / dev / [ІМЕНЕ SD-карти] bs = 1M'.
Це займе деякий час, тому ви, можливо, захочете запустити його у фоновому режимі.
Це той же самий спосіб резервного копіювання SD-карти в Linux.


Це створює резервну копію ВСІХ, навіть непотрібних та небажаних файлів.
ІгорГанапольський

3
Це зробить непослідовну резервну копію, оскільки в запущеній системі все змінилося під час резервного копіювання!
Інго
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.