Tôi hiện đang làm việc trên khung cập nhật phần mềm tráo đổi. Là một sơ đồ cập nhật, tôi đã chọn phương pháp sao chép kép. Tôi đã cài đặt Ubuntu 20.04 trên thiết bị mục tiêu của mình (máy tính để bàn -> i5,32GB SSD, BIOS,..) để kiểm tra và phân vùng cho phù hợp.
/dev/sda1 --/boot
/dev/sda2 --/
/dev/sda3 --/root2
/dev/sda4 --/dữ liệu
Đối với mục đích thử nghiệm, tôi đã tạo một hình ảnh hệ thống tệp gốc từ hệ thống máy chủ (/ dev/sda2) bằng cách sử dụng lệnh "dd". Tôi đã gán một UUID mới và gắn nhãn cho hình ảnh bằng các lệnh "tune2fs" và "e2label".
dd if=/dev/sda2 of=rootfs.img status=progress
e2nhãn rootfs.img root2
e2fsck -fy rootfs.img
tune2fs -U rootfs.img ngẫu nhiên
Cần phải có cơ chế phối hợp giữa bộ tải khởi động và tác nhân cập nhật để khởi động hệ thống với phân vùng rootfs phụ sau khi cập nhật thành công.Bộ tải khởi động phải đảm bảo phân vùng rootfs nào (A hoặc B) được tải.
Ubuntu sử dụng GRUB làm bộ tải khởi động tiêu chuẩn. GRUB cung cấp một "khối môi trường" có thể được sử dụng để tiết kiệm một lượng nhỏ trạng thái (/boot/grub/grubenv). Tác nhân cập nhật "SWUpdate" có trình xử lý bộ nạp khởi động để quản lý tệp này. SWupdate có thể thêm các biến môi trường vào tệp này. SWupdate có thể gọi các tập lệnh trước và sau khi cài đặt hình ảnh (cài đặt trước và sau).
Tôi đã viết một tập lệnh bash đọc phân vùng rootfs hiện tại từ dòng lệnh kernel (/proc/cmdline) và các biến môi trường từ khối môi trường GRUB (/boot/grub/grubenv) để cập nhật phân vùng rootfs sau khi cập nhật xử lý thông qua tệp cấu hình bộ tải khởi động mặc định (/etc/default/grub) mà hệ thống được khởi động.
CONFIG_FILE=/etc/default/grub
ROOTFS1_UUID=$(blkid -o value -s UUID /dev/sda2)
ROOTFS2_UUID=$(blkid -o value -s UUID /dev/sda3)
hàm get_UUID_of_current_boot_device() {
cho tôi trong `cat /proc/cmdline`; làm
trường hợp "$i" trong
gốc=*)
ROOT="${i#root=UUID=}"
;;
esac
xong
}
hàm get_partition_number_of_current_boot_device() {
nếu [[ $ROOT = $ROOTFS1_UUID ]]; sau đó
CURRENT_PARTITION="2";
yêu tinh [[ $ROOT = $ROOTFS2_UUID ]]; sau đó
CURRENT_PARTITION="3";
khác
echo "Lỗi do Partitionshema!!"
fi
}
hàm get_bootloader_env() {
cho tôi trong `cat /boot/grub/grubenv`; làm
trường hợp "$i" trong
phần khởi động =*)
BOOT_DEVICE="${i#bootpart=}"
;;
esac
xong
}
hàm set_boot_device_UUID() {
nếu [ $BOOT_DEVICE = "2" ]; sau đó
BOOT_DEVICE_UUID="$ROOTFS1_UUID";
yêu tinh [ $BOOT_DEVICE = "3" ]; sau đó
BOOT_DEVICE_UUID="$ROOTFS2_UUID";
khác
tiếng vang "";
BOOT_DEVICE_UUID="$ROOT";
fi
}
Theo những gì tôi đã đọc cho đến nay, để sửa đổi vĩnh viễn các tham số dòng lệnh kernel, các tham số bắt buộc phải được định cấu hình trong dòng GRUB_CMDLINE_LINUX_DEFAULT hoặc trong dòng GRUB_CMDLINE_LINUX. Trong tập lệnh của mình, tôi đã sửa đổi dòng này để biến $BOOT_DEVICE_UUID luôn là phân vùng rootfs sẽ được khởi động sau khi khởi động lại.
sed -i "s/\(GRUB_CMDLINE_LINUX *= *\).*/\1\"$BOOT_DEVICE_UUID\"/" $CONFIG_FILE;
Thật không may, điều đó không hiệu quả, tôi nghĩ rằng giá trị của biến "root" hiện có trong dòng lệnh sẽ được thay thế bằng giá trị mà tôi đã chuyển.
Bộ tải khởi động bằng cách nào đó sẽ chọn thông qua các biến môi trường mà phân vùng Rootfs chứa hệ thống Linux sẽ được tải. Ai đó có thể vui lòng giải thích cho tôi biết lỗi của tôi ở đâu và ai đó có thể cho tôi một ví dụ cụ thể về chủ đề này không?