Script backup Raspbian

Script os.backup này sử dụng các lệnh có sẳn trong Raspbian, backup 2 partition bootrootfs thành một file ảnh img giống như file cài đặt của Raspbian. File ảnh này có thể ghi ra thẻ nhớ để khởi động hoặc có thể chỉ restore một số file trong file ảnh.

Câu lệnh

os.backup [backup_folder=/tmp]
  • backup_folder là tên thư mục chứa file backup img
  • Ngoài ra script trên còn dùng file exclude.txt chứa tên file hay thư mục không cần backup như /tmp, /var/log, /var/swap… do người dùng tự soạn thảo, giúp giảm kích thước file backup. File này lần lượt được tìm ở backup_folder, thư mục chứa script
#!/bin/bash
# os.backup
# Raspbian backup script, version 20191021
# © 2019 LNT <lnt@ly-le.info>
#
[[ -z "$#" ]] && cat >&2 <<EOF

Sao lưu Raspbian
Syntax: $(basename $0) [backup_folder=/tmp]

EOF

DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd`
SECONDS=0
if [[ ! -z "$1" && -d "$1" ]]; then
  path="$1"
else
  path=/tmp
fi

img="${path}/$(date '+%Y-%m-%d').$(hostname).img"
if [ -f "$path/exclude.txt" ]; then
  excl="$path/exclude.txt"
elif [ -f "$DIR/exclude.txt" ]; then
  excl="$DIR/exclude.txt"
else
  excl=/tmp/exclude.txt
  touch $excl
fi

printf "Tính dung lượng file ảnh ..."
cnt=`sudo du -xls -B1M -X "$excl" / | sed 's/^\([0-9]\+\).*/\1/'`
read inod_cnt inod_siz <<< $(sudo dumpe2fs -h $(findmnt -n -o source /) 2> /dev/null| sed '/Inode \(count\|size\):/!d;{s/[^0-9]*\([0-9]*\)$/\1 /}'|tr -d '\n')
cnt=$(( $cnt + $inod_cnt*$inod_siz/1048576 + 220 ))
printf "\b\b\b\b: $cnt MB\n"
[ -f $img ] && rm -f $img
printf "Tạo file ảnh $img ..."
sudo dd if=/dev/zero of="$img" bs=1M count=0 seek=$cnt &> /dev/null
printf "\b\b\b\b: xong\n"

printf "Gắn đĩa ảo vào RPi ..."
dev=`sudo losetup -Pf --show $img`
printf "\b\b\b\b: ${dev}\n"

printf "Phân vùng đĩa ảo ..."
echo -e "n\n\n1\n2048\n+200M\nt\nc\nn\np\n2\n\n\nw\nq\n" | sudo fdisk $dev &> /dev/null
printf "\b\b\b\b: xong\n"

printf "Định dạng đĩa ảo ..."
(
sudo mkfs.fat -F32 "${dev}p1"
sudo fatlabel "${dev}p1" BOOT
sudo mkfs.ext4 "${dev}p2"
sudo e2label "${dev}p2" rootfs
sudo sync $dev
) &> /dev/null
printf "\b\b\b\b: xong\n"

PTUUID=`sudo blkid ${dev} | grep -Po '(?<=PTUUID=")([0-9a-f]{8})'`
mount=$(mktemp -d)

echo -e "\nSao lưu phân vùng boot:"
sudo mount "${dev}p1" "$mount"
sudo rsync -a --info=progress2 /boot/ $mount
sudo cp -f $mount/cmdline.txt $mount/cmdline.org
sudo sed -E "/^#/d;s/PARTUUID=\S+/PARTUUID=${PTUUID}-02/" -i $mount/cmdline.txt
sudo sed '/^#/d;/init_resize.sh/!s/\( quiet\)/\1 init=\/usr\/lib\/raspi-config\/init_resize.sh/' -i $mount/cmdline.txt
sudo umount "$mount"

echo -e '\nSao lưu phân vùng root:'
sudo mount "${dev}p2" "$mount"
sed 's/^\///' $excl > /tmp/exclude1.txt
sudo rsync -ax --info=progress2 --exclude-from=/tmp/exclude1.txt /
sudo cp -f $mount/etc/fstab $mount/etc/fstab.org
sudo sed "/^#/d;/^\s*$/d;/PARTUUID/{/\/boot\s/{s/=\S\+/=${PTUUID}-01/;bx};/\s\/\s/{s/=\S\+/=${PTUUID}-02/;bx};s/^/#/};:x" -i $mount/etc/fstab

printf "\nChuẩn bị cho resize2fs-once ..."
cat <<'EOF' | sudo tee -i $mount/usr/local/sbin/auto-expand-fs &> /dev/null
#!/usr/bin/env bash
root_dev=$(/bin/findmnt / -o source -n)
/sbin/resize2fs "${root_dev}"
/bin/rm -v "/usr/local/sbin/auto-expand-fs" "/etc/cron.d/auto-expand-fs"
EOF
cat <<'EOF' | sudo tee -i $mount/etc/cron.d/auto-expand-fs &> /dev/null
@reboot root /bin/bash /usr/local/sbin/auto-expand-fs
EOF
printf "\b\b\b\b: xong\n"
sudo umount "$mount"
rmdir $mount

echo -e "\nKiểm tra đĩa ảo:"
lst=`sudo fsck -N ${dev}* | cut -s -d' ' -f5- | sed "/^$/d ; \:${dev} $:d"`
while read chk part; do
  echo -e "\n*** $part:"
  sudo $chk -fy $part
done <<< "$lst"

sudo sync $dev
sudo losetup -d $dev

duration=$SECONDS
echo "\nSao lưu vào $img, $cnt MB data, trong $(( $duration / 60 )) phút và $(( $duration % 60 )) giây!"

Mẫu file exclude.txt

File này dùng cho lệnh dursync. Cần viết đúng theo mẫu, thư mục kết thúc bằng /* trong khi file thì không.

/media/pi/*
/var/swap
/var/log/*
/var/tmp/*
/tmp/*
/home/pi/Downloads/*
/home/pi/.cache/*
sudo reboot

Thí dụ

Gắn USB Flash vào RPi để chứa file backup.

Nếu Raspbian không automount thì ta phải tìm tên thiết bị và tự mount nó vào một thư mục:

sudo fdisk -l

Giả sử tên partition là /dev/sdb1

mkdir /tmp/backup
sudo mount /dev/sdb1 /tmp/backup

Chạy script

os.backup /tmp/backup

Kết thúc

sudo umount /tmp/backup

Sao lưu 4856 MB data, trên USB Flash mất 9 phút, trên SSD mất 3 phút

Chú thích

1. Để bảo đảm thẻ nhớ được ghi từ file ảnh có thể khởi động được, script có thay đổi cmdline.txtfstab, các file gốc được lưu với đuôi .org

2. Khi restore chỉ các file trong các partition, cần phải phục hồi các file cmdline.txtfstab từ các file .org, hoặc dùng script os.restore

3. Để giảm kích thước file img, script os.backup chỉ chừa khoảng trống tối thiểu trong file ảnh. Khi khởi động lần đầu tiên, phân vùng root sẽ tự động được mở rộng sang phần đĩa chưa sử dụng.

4. Có một cách đơn giản khác để tạo backup toàn bộ thẻ nhớ với dung lượng tối thiểu mà chỉ dùng lệnh fdiskdd (Bài sau)

Comments Off on Script backup Raspbian

Filed under Software

Comments are closed.