DragonOS/user/default.nix

246 lines
7.0 KiB
Nix
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
lib,
pkgs,
nixpkgs,
system,
target,
fenix,
buildDir,
testOpt,
rootfsType ? "vfat",
diskPath,
partitionType ? "mbr",
}:
let
image = import ./rootfs-tar.nix {
inherit
lib
pkgs
nixpkgs
system
target
fenix
testOpt
;
};
# parted 使用 msdos 而不是 mbr
partedLabel = if partitionType == "mbr" then "msdos" else partitionType;
# 根据文件系统类型生成 mkfs 命令
mkfsCommand =
if rootfsType == "vfat" then
''sudo mkfs.vfat "''${LOOP_DEV}p1"''
else if rootfsType == "ext4" then
''sudo mkfs.ext4 -F "''${LOOP_DEV}p1"''
else
''sudo mkfs -t ${rootfsType} "''${LOOP_DEV}p1"'';
# vfat 特殊处理脚本片段
vfatProcessing = ''
echo " Processing rootfs for vfat (excluding /nix/store, dereferencing symlinks)..."
EXTRACT_DIR=$(mktemp -d)
FILTERED_TAR="${buildDir}/rootfs-filtered.tar"
# tar /nix/store
echo " Extracting and not filtering..."
chmod +w -R "$TEMP_DIR" "$EXTRACT_DIR"
fakeroot tar --owner=0 --group=0 --numeric-owner --exclude='proc' --exclude='dev' \
--exclude='sys' -xf "$OUTPUT_TAR" -C "$EXTRACT_DIR"
#
echo " Re-packing with dereferenced links..."
fakeroot tar --owner=0 --group=0 --numeric-owner --dereference --hard-dereference -cf "$FILTERED_TAR" -C "$EXTRACT_DIR" .
FILTERED_SIZE=$(du -h "$FILTERED_TAR" | cut -f1)
echo " Re-packed rootfs.tar created ($FILTERED_SIZE)"
FINAL_TAR="$FILTERED_TAR"
'';
# 非 vfat 不需要特殊处理
nonVfatProcessing = ''
FINAL_TAR="$OUTPUT_TAR"
'';
# 根据 rootfsType 选择处理逻辑
rootfsProcessing = if rootfsType == "vfat" then vfatProcessing else nonVfatProcessing;
# guestfish 写盘逻辑
guestfishWrite = ''
echo " Using guestfish (unprivileged mode)..."
export LIBGUESTFS_CACHEDIR=/tmp
export LIBGUESTFS_BACKEND=direct
# 使 guestfish tar
echo " Initializing disk and copying rootfs..."
guestfish -a "$TEMP_IMG" <<EOF
run
part-init /dev/sda ${partitionType}
part-add /dev/sda primary 2048 -2048
mkfs ${rootfsType} /dev/sda1
mount /dev/sda1 /
tar-in $FINAL_TAR /
chmod 0755 /
umount /
sync
shutdown
EOF
'';
# loop 设备写盘逻辑
loopWrite = ''
echo " Using loop device (privileged mode, faster)..."
# 使 parted
echo " Creating partition table..."
parted -s "$TEMP_IMG" mklabel ${partedLabel}
parted -s "$TEMP_IMG" mkpart primary ${rootfsType} 1MiB 100%
# loop
echo " Setting up loop device..."
LOOP_DEV=$(sudo losetup --find --show --partscan "$TEMP_IMG")
echo " Loop device: $LOOP_DEV"
# loop
# shellcheck disable=SC2317,SC2329
cleanup_loop() {
echo " Cleaning up loop device..."
sudo umount "''${LOOP_DEV}p1" 2>/dev/null || true
sudo losetup -d "$LOOP_DEV" 2>/dev/null || true
}
trap 'cleanup_loop; chmod +w -R "$TEMP_DIR" 2>/dev/null && rm -rf "$TEMP_DIR"; [ -n "$EXTRACT_DIR" ] && chmod +w -R "$EXTRACT_DIR" 2>/dev/null && rm -rf "$EXTRACT_DIR"' EXIT
#
echo " Waiting for partition device..."
for _ in $(seq 1 10); do
if [ -b "''${LOOP_DEV}p1" ]; then
break
fi
sleep 0.1
done
if [ ! -b "''${LOOP_DEV}p1" ]; then
echo "Error: Partition device ''${LOOP_DEV}p1 not found"
exit 1
fi
#
echo " Formatting partition as ${rootfsType}..."
${mkfsCommand}
#
MOUNT_DIR=$(mktemp -d)
echo " Mounting partition to $MOUNT_DIR..."
sudo mount "''${LOOP_DEV}p1" "$MOUNT_DIR"
# trap MOUNT_DIR
# shellcheck disable=SC2317,SC2329
cleanup_loop() {
echo " Cleaning up..."
sudo umount "$MOUNT_DIR" 2>/dev/null || true
sudo losetup -d "$LOOP_DEV" 2>/dev/null || true
rm -rf "$MOUNT_DIR" 2>/dev/null || true
}
trap 'cleanup_loop; chmod +w -R "$TEMP_DIR" 2>/dev/null && rm -rf "$TEMP_DIR"; [ -n "$EXTRACT_DIR" ] && chmod +w -R "$EXTRACT_DIR" 2>/dev/null && rm -rf "$EXTRACT_DIR"' EXIT
# tar
echo " Extracting rootfs to partition..."
sudo tar -xf "$FINAL_TAR" -C "$MOUNT_DIR"
sudo chmod 0755 "$MOUNT_DIR"
#
echo " Syncing and unmounting..."
sync
sudo umount "$MOUNT_DIR"
sudo losetup -d "$LOOP_DEV"
rm -rf "$MOUNT_DIR"
# trap
trap 'chmod +w -R "$TEMP_DIR" 2>/dev/null && rm -rf "$TEMP_DIR"; [ -n "$EXTRACT_DIR" ] && chmod +w -R "$EXTRACT_DIR" 2>/dev/null && rm -rf "$EXTRACT_DIR"' EXIT
'';
# 构建脚本 - 在bin/目录下构建
buildScript = pkgs.writeShellApplication {
name = "dragonos-rootfs";
runtimeInputs = [
pkgs.coreutils
pkgs.gnutar
pkgs.libguestfs-with-appliance
pkgs.findutils
pkgs.parted
pkgs.dosfstools
pkgs.e2fsprogs
pkgs.util-linux
];
text = ''
set -euo pipefail
# Ensure build directory exists
mkdir -p "${buildDir}"
OUTPUT_TAR="${buildDir}/rootfs.tar"
echo "==> Generating rootfs"
#
TEMP_DIR=$(mktemp -d)
EXTRACT_DIR="" # vfat
trap 'chmod +w -R "$TEMP_DIR" 2>/dev/null && rm -rf "$TEMP_DIR"; [ -n "$EXTRACT_DIR" ] && chmod +w -R "$EXTRACT_DIR" 2>/dev/null && rm -rf "$EXTRACT_DIR"' EXIT
# layer.tar (rootfs)
echo " Extracting rootfs layer..."
cd "$TEMP_DIR"
tar -xzf ${image}
# layer.tar bin/
LAYER_TAR=$(find . -name "layer.tar" | head -1)
if [ -z "$LAYER_TAR" ]; then
echo "Error: layer.tar not found in docker image"
exit 1
fi
cp "$LAYER_TAR" "$OLDPWD/$OUTPUT_TAR"
cd "$OLDPWD"
chmod +w "$OUTPUT_TAR"
TAR_SIZE=$(du -h "$OUTPUT_TAR" | cut -f1)
echo " rootfs.tar created ($TAR_SIZE)"
# rootfsNix
${rootfsProcessing}
echo "==> Building disk image at ${diskPath}"
#
echo " Creating disk image..."
TEMP_IMG="${diskPath}.tmp"
# tar + 1G
TAR_SIZE_KB=$(du -k "$FINAL_TAR" | cut -f1)
DISK_SIZE_KB=$(( TAR_SIZE_KB + 1024 * 1024 ))
truncate -s "''${DISK_SIZE_KB}K" "$TEMP_IMG"
# 使guestfish
if [ "''${DRAGONOS_UNPRIVILEGED_BUILD:-0}" = "1" ]; then
${guestfishWrite}
else
${loopWrite}
fi
mv "$TEMP_IMG" "${diskPath}"
IMG_SIZE=$(du -h "${diskPath}" | cut -f1)
echo " disk image created ($IMG_SIZE)"
echo "==> Build complete!"
echo " Rootfs tar: $OUTPUT_TAR"
echo " Disk image: ${diskPath}"
'';
};
in
buildScript