#!/bin/sh

## live-build(7) - System Build Scripts
## Copyright (C) 2006-2012 Daniel Baumann <daniel@debian.org>
##
## This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING.
## This is free software, and you are welcome to redistribute it
## under certain conditions; see COPYING for details.


set -e
set +x

# Including common functions
( . "${LIVE_BUILD}/scripts/build.sh" > /dev/null 2>&1 || true ) || . /usr/lib/live/build.sh

# Setting static variables
DESCRIPTION="$(Echo 'build rootfs image')"
HELP=""
USAGE="${PROGRAM} [--force]"

Arguments "${@}"

# Reading configuration files
Read_conffiles config/all config/common config/bootstrap config/chroot config/binary config/source config/ostree
Set_defaults

Echo_message "Begin building root filesystem image..."

# Requiring stage file
Require_stagefile .build/config .build/bootstrap .build/binary_chroot

# Checking stage file
Check_stagefile .build/ostree_commit

# Checking lock file
Check_lockfile .lock

# Creating lock file
Create_lockfile .lock

if [ ! -f chroot/chroot/etc/ostree-release ]; then 
	Echo_message "ostree-realese文件不存在，非ostree不可变系统"
	exit 0
fi

export info_version_string=
export meta_data_add_string=
export os_version_name=
export sign_position=

# 根据ostree 要求，将根分区下的etc目录拷贝至usr目录下
#rm chroot/chroot/dev/console chroot/chroot/dev/full chroot/chroot/dev/null chroot/chroot/dev/ptmx chroot/chroot/dev/random chroot/chroot/dev/tty chroot/chroot/dev/urandom chroot/chroot/dev/zero
find chroot/chroot/dev -type b -delete -o -type c -delete
cp -a chroot/chroot/etc chroot/chroot/usr/

#创建skip-file.txt文件存储需要跳过的文件路径
touch chroot/skip-files.txt
if [ -L chroot/chroot/usr/etc/.kyinfo ]; then
    echo "/usr/etc/.kyinfo" >>chroot/skip-files.txt
fi

if [ -L chroot/chroot/usr/etc/LICENSE ]; then
    echo "/usr/etc/LICENSE" >>chroot/skip-files.txt
fi

#ostree 物料中，不应存在casper、kylin-os-installer 物料
if [ -f chroot/chroot/usr/etc/casper.conf ]; then
    echo "/usr/etc/casper.conf" >>chroot/skip-files.txt
fi

if [ -L chroot/chroot/usr/etc/systemd/system/final.target.wants/casper.service ]; then
    echo "/usr/etc/systemd/system/final.target.wants/casper.service" >>chroot/skip-files.txt
fi

if [ -L chroot/chroot/usr/etc/systemd/system/graphical.target.wants/kylin-os-installer.service ]; then
    echo "/usr/etc/systemd/system/graphical.target.wants/kylin-os-installer.service" >>chroot/skip-files.txt
fi

while read os_release_file_line
do
	if [ "$os_release_file_line" = "[info]" ]; then
		sign_position=0
		continue
	fi

	if [ "$os_release_file_line" = "[metadata]" ]; then
		sign_position=1
		continue
	fi

	if [ "$sign_position" = "0" ] && [ "$os_release_file_line" != "[info]" ]; then
		info_version_string=$os_release_file_line
		continue
	fi

	if [ "$os_release_file_line" != "[metadata]" ]; then
		meta_data_add_string="$meta_data_add_string --add-metadata-string=$os_release_file_line"
	fi

done < "chroot/chroot/etc/ostree-release"

info_version_string=${info_version_string#*version=}
os_version_name=$(echo "$info_version_string" | awk -F ":" '{print $1}')
ostree_branch_name=$info_version_string
# 首先判断新版本kybuilder设置的LB_OSTREE_PUSH_BRANCH环境变量，从config/ostree读取的
if [ -n "$LB_OSTREE_PUSH_BRANCH" ]; then
    ostree_push_branch_name="$LB_OSTREE_PUSH_BRANCH"
else
    ostree_push_branch_name=$(echo "$info_version_string" | awk -F ":" '{print $2}')
fi
Echo_message "os_version_name: $os_version_name"
Echo_message "info_version_string: $info_version_string"
Echo_message "meta_data_add_string: $meta_data_add_string"
Echo_message "ostree_branch_name: $ostree_branch_name"

check_dir() {
    WHITELIST_FILE="chroot/chroot/usr/ost-ex.d/root-whitelist.txt"
    TARGET_DIR="chroot/chroot/"
	if [ -e $WHITELIST_FILE ]; then
    	whitelist=$(cat "$WHITELIST_FILE")
        for file in "$TARGET_DIR"*; do
        	# 获取文件名（不包括路径）
            filename=$(basename "$file")
            #echo "$filename"
            # 检查文件是否在白名单中
            found=false
            for item in $whitelist; do
                #echo "==$item=="
                if [ "$item" = "$filename" ]; then
                    found=true
                    break
                fi
            done
            # 如果文件不在白名单中，确认其是由哪个包带入的，提示并终止
            if [ "$found" = false ]; then
                if [ -e "chroot/chroot/usr/ost-ex.d/detect-pkgs.sh" ]; then
                    # 如果不在白名单中，则返回该文件并执行chroot检测
                    chroot "$TARGET_DIR" ./usr/ost-ex.d/detect-pkgs.sh "$filename"
                    if [ $? -ne 0 ]; then
                        echo "Error: Package creation detected for $file"
                        exit 1
                    fi
                fi
            else
                echo "exist in whitelist"
            fi
        done
	fi
}
#服务端根目录下控制
check_dir
# 删除etc目录
rm -r chroot/chroot/etc
# 复制内核文件
#kernel_vesion=`chroot ./chroot/chroot uname -r`
kernel_name=`readlink -f ./chroot/chroot/boot/vmlinuz`
kernel_version=$(echo $kernel_name | awk '{split($0, a, "vmlinuz-"); print a[2]}')
Echo_message "kernel_version: $kernel_version"
initrd_real_name=`readlink -f ./chroot/chroot/boot/initrd.img`
cp -a "chroot/chroot/boot/vmlinuz-$kernel_version" "chroot/chroot/usr/lib/modules/$kernel_version/vmlinuz"
cp -a "$initrd_real_name" "chroot/chroot/usr/lib/modules/$kernel_version/initramfs.img"

#echo "---------->>>>>>>>>000000 1"

# 修改ostree 对于opt、mnt、media、tmp目录的存储路径，全部放置到var目录下
mv chroot/chroot/opt chroot/chroot/var/
ln -s var/opt chroot/chroot/opt

mv chroot/chroot/mnt chroot/chroot/var/
ln -s var/mnt chroot/chroot/mnt

mv chroot/chroot/media chroot/chroot/run/
ln -s run/media chroot/chroot/media

mv chroot/chroot/tmp chroot/chroot/var/
ln -s var/tmp chroot/chroot/tmp

mv chroot/chroot/srv chroot/chroot/var/
ln -s var/srv chroot/chroot/srv

# 忽略安装开明包的目录
if [ -d chroot/chroot/var/opt/kaiming ]; then
    Echo_message "skip /var/opt/kaiming in ostree"
    echo "/var/opt/kaiming" >> chroot/skip-files.txt
fi

if [ -d chroot/chroot/var/opt/kaiming-ok ]; then
    Echo_message "skip /var/opt/kaiming-ok in ostree"
    echo "/var/opt/kaiming-ok" >> chroot/skip-files.txt
fi

[ -d sysroot ] || mkdir sysroot
[ -d chroot/sysroot ] || mkdir chroot/sysroot
[ -d chroot/chroot/data ] || mkdir chroot/chroot/data
[ -d chroot/chroot/backup ] || mkdir chroot/chroot/backup
[ -d chroot/chroot/sysroot ] || mkdir chroot/chroot/sysroot

Check_package chroot/usr/bin/ostree ostree
Install_package

cp -r chroot/chroot/usr/etc chroot/chroot/

#创建overlay目录
mkdir -p chroot/overlay_dir
mkdir -p chroot/overlay_dir/upper
mkdir -p chroot/overlay_dir/work
mkdir -p chroot/overlay_dir/merged

#挂载overlayfs
mount -t overlay overlay \
-o lowerdir=chroot/chroot,upperdir=chroot/overlay_dir/upper,workdir=chroot/overlay_dir/work \
chroot/overlay_dir/merged


#在overlay的merged层进行删包操作
chroot chroot/overlay_dir/merged /bin/sh -c '
    if (dpkg -l | grep -q kylin-os-installer) || (dpkg -l | grep -q casper); then
	dpkg -P kylin-os-installer casper ubiquity ukui-installer-wayland
	exit 0
    else
	exit 0
    fi
'

mkdir usr_etc_file

for etcfile in fstab passwd shadow group locale.gen localtime hostname hosts timezone subuid subgid
do
	chroot_etc_file="chroot/overlay_dir/merged/usr/etc/${etcfile}"
	if [ -e "$chroot_etc_file" ] || [ -L "$chroot_etc_file" ]; then
		mv "$chroot_etc_file" ./usr_etc_file/
	fi
done

#remove etc
if [ -d chroot/overlay_dir/merged/etc  ]; then
	rm -r chroot/overlay_dir/merged/etc/
fi

cat > binary.sh << EOF
#!/bin/sh
export LANG=C.UTF-8

METADATA_OPTIONS="$meta_data_add_string"

# 是否使用json格式的metadata
if [ -f /chroot/etc/ostree-release.json ]
then
	# 测试ostree支持json格式的metadata
	ostree commit --help | grep '\--add-metadata-from-json'
	ostree_support_json=\$?

	if [ \$ostree_support_json -eq 0 ]
	then
		METADATA_OPTIONS='--add-metadata-from-json=/chroot/etc/ostree-release.json'
		echo "Commit with json meta data."
	else
		echo "Commit with normal string"
    fi
fi

# ostree commit 附加选项
COMMIT_OPTIONS="\$METADATA_OPTIONS --skip-list=./skip-files.txt"

# 测试是否支持--add-sizeinfo选项
ostree commit --help | grep '\--add-sizeinfo'
ostree_support_size=\$?
if [ \$ostree_support_size -eq 0 ]
then
    COMMIT_OPTIONS="\$COMMIT_OPTIONS --add-sizeinfo"
fi

echo "---------->>>>>>>>>000000 1"
ostree admin init-fs sysroot

echo "---------->>>>>>>>>000000 2"
ln -s sysroot/ostree chroot/ostree

echo "---------->>>>>>>>>000000 3"
ostree admin os-init "$os_version_name" --sysroot=sysroot

echo "---------->>>>>>>>>000000 3.1 初始化一个archive-z2模式仓库"
ostree init --repo=./repo --mode=archive-z2

echo "---------->>>>>>>>>000000 4 archive-z2模式仓库提交commit"
commit_id=\$(ostree commit --repo=./repo -b "$ostree_push_branch_name" -s "$info_version_string" \$COMMIT_OPTIONS overlay_dir/merged/)

echo "---------->>>>>>>>>000000 5 ostree_push_branch_name commit:"
ostree log --repo=./repo "$ostree_push_branch_name"

echo "---------->>>>>>>>>000000 6 将archive-z2模式的仓库pull-local到sysroot的bare模式仓库"
ostree --repo=./sysroot/ostree/repo pull-local ./repo "\$commit_id"

echo "---------->>>>>>>>>000000 7 创建新分支指向相同的commit"
ostree refs --repo=./sysroot/ostree/repo --create="$ostree_branch_name" "\$commit_id"

echo "---------->>>>>>>>>000000 8 输出commit信息到base.commit, 之后要拷贝到binary/.disk/里"
ostree log --repo=./sysroot/ostree/repo "$ostree_branch_name" > base.commit
echo "---------- ostree_branch_name commit:"
cat base.commit

EOF
mv binary.sh chroot/

# chroot中执行commit脚本
chroot chroot /bin/sh binary.sh


# base.commit转移出来，因为chroot可能会在lb binary_rootfs中被删除
mv chroot/base.commit .

if [ -f config/ostree ]; then
    cat > binary-z2-repo.sh << EOF
#!/bin/sh
export LANG=C.UTF-8

ostree summary --repo=./repo -u
EOF
    mv binary-z2-repo.sh chroot/

    Chroot chroot "sh binary-z2-repo.sh"

    # ostree-push允许失败后重试数次
    set +e
    error_count=0
    MAX_RETRIES=5
    RETRY_DELAY=1

    while true; do
		Echo_message "尝试ostree-push ..."
		ostree-push --repo=./chroot/repo $LB_OSTREE_USER_NAME@$LB_OSTREE_IP:$LB_OSTREE_WARE_ADDRESS/$LB_OSTREE_REPO $ostree_push_branch_name

		if [ $? -eq 0 ]; then
			Echo_message "ostree-push成功！"
			break
		else
			error_count=$((error_count+1))
			Echo_warning "ostree-push失败 (错误次数: $error_count)"
		
			# 如果所有尝试都失败
            if [ $error_count -gt $MAX_RETRIES ]; then
                Echo_error "ostree-push 失败（最大重试次数: $MAX_RETRIES）"
                exit 1
            else
                Echo_message "等待 ${RETRY_DELAY} 秒后重试..."
                sleep "$RETRY_DELAY"
            fi
		fi
	done

    # 恢复命令错误检查
    set -e

    # 推送成功后删除本地仓库，减少磁盘占用
    rm -rf ./chroot/repo
    # 如果推送到远程已经存在的分支，远程的commit id会变，本地的base.commit文件内容就不一致了，不过content checksum会保持
else
	Echo_message "config/ostree文件不存在，跳过ostree-push"	
fi


#卸载overlay
umount chroot/overlay_dir/merged
rm -rf chroot/overlay_dir

rm -rf chroot/skip-files.txt
rm -r chroot/chroot/data chroot/chroot/backup chroot/chroot/sysroot

cp -a ./usr_etc_file/* chroot/chroot/usr/etc/

#提交完成后，将etc目录拷贝出来，外面则是一个完成的根文件系统
rm -r chroot/chroot/etc
cp -a chroot/chroot/usr/etc chroot/chroot
mv chroot/sysroot chroot/chroot/sysroot

#在/sysroot 中拷贝之前ostree commit 时移除的 etc 文件，安装器会将这些文件拷贝到部署的系统里面
mkdir -p chroot/chroot/sysroot/etc/
cp -a ./usr_etc_file/* chroot/chroot/sysroot/etc/

rm -r usr_etc_file


File_path="chroot/chroot/dev/null" # 将路径更改为要检查的文件路径
if [ -f "$File_path" ] ; then
    Echo_message "null 存在"

else
    Echo_message "null 不存在"
    mknod chroot/chroot/dev/null c 1 3
    chmod 666 chroot/chroot/dev/null
fi

unset info_version_string
unset meta_data_add_string
unset os_version_name
unset sign_position

Create_stagefile .build/ostree_commit
