Script os.backup này sử dụng các lệnh có sẳn trong Raspbian, backup 2 partition boot và rootfs 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 du và rsync. 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.txt và fstab, 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.txt và fstab 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 fdisk và dd (Bài sau)