这个问题回答了我如何使用外部计算机创建RPi备份的问题。
我想知道是否可以创建当前正在使用的SD卡的备份映像,并将其复制到USB存储设备上的文件中。这可能吗?如果不是,是否有任何方法可以创建RPi的备份而不涉及另一台计算机?
dd
对于“新”副本而言,以只读方式重新挂载文件系统并以适当的块大小进行复制可能最快。逐个文件复制到Flash / SD介质可能是个坏主意。
这个问题回答了我如何使用外部计算机创建RPi备份的问题。
我想知道是否可以创建当前正在使用的SD卡的备份映像,并将其复制到USB存储设备上的文件中。这可能吗?如果不是,是否有任何方法可以创建RPi的备份而不涉及另一台计算机?
dd
对于“新”副本而言,以只读方式重新挂载文件系统并以适当的块大小进行复制可能最快。逐个文件复制到Flash / SD介质可能是个坏主意。
Answers:
这是rsync
在Pi上进行备份的介绍。创建初始备份后,以这种方式保持最新状态要比不断撕裂整个映像快得多。您可以对本地硬盘驱动器或通过网络执行此操作。
实际上,您不希望将正在运行的系统的完整副本作为备份,因为表面上文件系统中的某些内容仅在运行时存在。将其包括在备份中,然后在以后使用它来重新创建映像可能会给您带来问题。
也有其他一些例外。rsync
可以接受要排除的(glob)模式列表,并且可以从文件中读取这些模式,因此让我们首先了解一下该文件中应包含的内容。请注意,条目的格式为/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.txt
1,而您的驱动器为/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/
您也可以使用上面有新图像的卡(假设它与基本图像相同)来执行此操作,尽管如果必须创建图像,这会有点效率低下(因为这时您将要覆盖其中的大部分图像)。您也可以通过USB适配器连接另一个SD卡,上面带有这样的图像,并使用上述方法来维护重复的卡。
如果您已经在其中添加了一些东西/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选项”(如果有的话)。你必须有root权限通过ssh
这样做系统备份的目的(设置PermitRootLogin=yes
在/etc/ssh/sshd_config
并重新启动服务器)。
1您应该保留此文件。您可以在以#
或开头的行中添加注释;
。这可能包括实际的rsync
命令,以后可以将其复制粘贴,因此您不必每次都记住它。
2感谢Kris指出rsync
不会自动执行此操作。
mkdir /tmp/backupable && mount --bind / /tmp/backupable
与rsync同步?这还具有备份存储在被安装在其中的某些东西“遮盖”的地方的任何数据的优点。
--exclude-from
是一个更好的主意,但我已将建议编辑为问题。如果您有时间,可以将其写成一个单独的答案,如果有我的投票,我可以参考。这个答案已经足够长了。
.img
,可以;这和这应有助于解释他们是如何结构化和可以被创建。
您可以根据自己的喜好重复使用和调整代码,它有充分的文档证明和自我解释。
#!/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
考虑在原始论坛中添加评论或发布您自己的版本以帮助使内容成熟。给一点点。
rsnapshot
听起来令人振奋
rsync
是要走的路;明天我有时间的时候,我会添加一个答案。 rsnapshot
也值得调查。
我已经在rsync上修改了@goldilocks答案,以便在pi上进行备份。我备份到ext4
Pi上安装的HDD上的分区。如果未装载HDD,则rsync将复制到装载目录(直到SD卡已满)。如果未以rw
模式安装HDD,则会产生大量错误消息。这些都不是理想的,因此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/记录的目录
第二组是当我使用AFP(Apple归档协议)访问我的Pi时由OS X创建的文件和目录。(这些通常在OS X上不可见,而在Raspbian上则不可见。无论如何,都不需要备份。)即使您从未使用过AFP,也不会造成任何伤害。
第三组是不需要备份的文件(当然也不必复制到其他Pi)。例如,RPi-Monitor报告的fake-hwclock.data。您可能还会有其他人。
/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/
我的本地网络中运行着三台Pi,当它们启动并运行时,需要使用cron定期备份它们。这就是为什么我创建了一个脚本,该脚本能够创建dd,tar和rsync备份并进行还原。我更喜欢使用rsync进行备份,但其他人更喜欢dd或tar。它已经被很多人使用。希望它对其他人也有用:-) raspibackup-Raspberry创建自己的备份
这是我们用于此类目的的稳定工具: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卡,并使用此新创建的SD卡启动RaspberryPi。
这是一种完全不同的方法。您可以使用LVM(大号 ogical V olume 中号 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的运行系统的轻松备份和快照。
我发现了一个可以安装映像的备份工具。
它还具有安装和缩小图像的实用程序。
这可能对其他人有用
它随附的文档非常简短,因此请注意以下几点:
ext4
以/mnt
或/media
(在Pi 上可以使用允许大文件的任何格式,例如exFAT或网络驱动器)在Pi上安装格式化分区。/mnt/Image/BusterBackup.img
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
打开终端并输入'lsblk -f'。
这应该显示所有连接的存储设备。
然后输入“ dd if = / dev / [sd卡的名称] bs = 1M”。
这将需要一段时间,因此您可能需要在后台运行它。
这与在Linux中备份SD卡的方法完全相同。
dd
,研究rsync
。