#!/bin/sh

# Default PATH differs between shells, and is not automatically exported
# by klibc dash.  Make it consistent.
export PATH=/sbin:/usr/sbin:/bin:/usr/bin

[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir -m 0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
mkdir -p /var/lock
mount -t sysfs -o nodev,noexec,nosuid sysfs /sys
mount -t proc -o nodev,noexec,nosuid proc /proc

# shellcheck disable=SC2013
for x in $(cat /proc/cmdline); do
	case $x in
	initramfs.clear)
		clear
		;;
	quiet)
		quiet=y
		;;
	esac
done

if [ "$quiet" != "y" ]; then
	quiet=n
	echo "Loading, please wait..."
fi
export quiet

# Note that this only becomes /dev on the real filesystem if udev's scripts
# are used; which they will be, but it's worth pointing out
mount -t devtmpfs -o nosuid,mode=0755 udev /dev

# Prepare the /dev directory
[ ! -h /dev/fd ] && ln -s /proc/self/fd /dev/fd
[ ! -h /dev/stdin ] && ln -s /proc/self/fd/0 /dev/stdin
[ ! -h /dev/stdout ] && ln -s /proc/self/fd/1 /dev/stdout
[ ! -h /dev/stderr ] && ln -s /proc/self/fd/2 /dev/stderr

mkdir /dev/pts
mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts || true

# Export the dpkg architecture
export DPKG_ARCH=
. /conf/arch.conf

# Set modprobe env
export MODPROBE_OPTIONS="-qb"

# Export relevant variables
export ROOT=
export ROOTDELAY=
export ROOTFLAGS=
export ROOTFSTYPE=
export IP=
export DEVICE=
export BOOT=
export BOOTIF=
export UBIMTD=
export break=
export init=/sbin/init
export readonly=y
export rootmnt=/root
export debug=
export panic=
export blacklist=
export resume=
export resume_offset=
export noresume=
export drop_caps=
export fastboot=n
export forcefsck=n
export fsckfix=


# Bring in the main config
. /conf/initramfs.conf
for conf in conf/conf.d/*; do
	[ -f "${conf}" ] && . "${conf}"
done
. /scripts/functions

# Parse command line options
# shellcheck disable=SC2013
for x in $(cat /proc/cmdline); do
	case $x in
	init=*)
		init=${x#init=}
		;;
	root=*)
		ROOT=${x#root=}
		if [ -z "${BOOT}" ] && [ "$ROOT" = "/dev/nfs" ]; then
			BOOT=nfs
		fi
		;;
	rootflags=*)
		ROOTFLAGS="-o ${x#rootflags=}"
		;;
	rootfstype=*)
		ROOTFSTYPE="${x#rootfstype=}"
		;;
	rootdelay=*)
		ROOTDELAY="${x#rootdelay=}"
		case ${ROOTDELAY} in
		*[![:digit:].]*)
			ROOTDELAY=
			;;
		esac
		;;
	nfsroot=*)
		# shellcheck disable=SC2034
		NFSROOT="${x#nfsroot=}"
		;;
	initramfs.runsize=*)
		RUNSIZE="${x#initramfs.runsize=}"
		;;
	ip=*)
		IP="${x#ip=}"
		;;
	ostree=*)
		if [ -z "${BOOT}" ] && [ -f /scripts/ostree ];then
			BOOT=ostree
		fi
		;;
	boot=*)
		BOOT=${x#boot=}
		;;
	ubi.mtd=*)
		UBIMTD=${x#ubi.mtd=}
		;;
	resume=*)
		RESUME="${x#resume=}"
		;;
	resume_offset=*)
		resume_offset="${x#resume_offset=}"
		;;
	noresume)
		noresume=y
		;;
	drop_capabilities=*)
		drop_caps="-d ${x#drop_capabilities=}"
		;;
	panic=*)
		panic="${x#panic=}"
		;;
	ro)
		readonly=y
		;;
	rw)
		readonly=n
		;;
	debug)
		debug=y
		quiet=n
		if [ -n "${netconsole}" ]; then
			log_output=/dev/kmsg
		else
			log_output=/run/initramfs/initramfs.debug
		fi
		set -x
		;;
	debug=*)
		debug=y
		quiet=n
		set -x
		;;
	break=*)
		break=${x#break=}
		;;
	break)
		break=premount
		;;
	blacklist=*)
		blacklist=${x#blacklist=}
		;;
	netconsole=*)
		netconsole=${x#netconsole=}
		[ "$debug" = "y" ] && log_output=/dev/kmsg
		;;
	BOOTIF=*)
		BOOTIF=${x#BOOTIF=}
		;;
	fastboot|fsck.mode=skip)
		fastboot=y
		;;
	forcefsck|fsck.mode=force)
		forcefsck=y
		;;
	fsckfix|fsck.repair=yes)
		fsckfix=y
		;;
	fsck.repair=no)
		fsckfix=n
		;;
	esac
done

# Default to BOOT=local if no boot script defined.
if [ -z "${BOOT}" ]; then
	BOOT=local
fi

if [ -n "${noresume}" ] || [ "$RESUME" = none ]; then
	noresume=y
else
	resume=${RESUME:-}
fi

mount -t tmpfs -o "nodev,noexec,nosuid,size=${RUNSIZE:-10%},mode=0755" tmpfs /run
mkdir -m 0700 /run/initramfs

if [ -n "$log_output" ]; then
	exec >$log_output 2>&1
	unset log_output
fi

maybe_break top

# Don't do log messages here to avoid confusing graphical boots
run_scripts /scripts/init-top

if [ "$BOOT" != "local" ] && [ "$BOOT" != "ostree" ]; then
    trace_log "Non-local/ostree boot detected ($BOOT), waiting for udev settle"
    udevadm settle || true
fi

maybe_break modules
[ "$quiet" != "y" ] && log_begin_msg "Loading essential drivers"
[ -n "${netconsole}" ] && /sbin/modprobe netconsole netconsole="${netconsole}"
load_modules
[ "$quiet" != "y" ] && log_end_msg

starttime="$(_uptime)"
starttime=$((starttime + 1)) # round up
export starttime

if [ "$ROOTDELAY" ]; then
	sleep "$ROOTDELAY"
fi

maybe_break premount
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount"
run_scripts /scripts/init-premount
[ "$quiet" != "y" ] && log_end_msg

maybe_break mount
log_begin_msg "Mounting root file system"
# Always load local and nfs (since these might be needed for /etc or
# /usr, irrespective of the boot script used to mount the rootfs).
. /scripts/local
. /scripts/nfs
. /scripts/${BOOT}
parse_numeric "${ROOT}"
maybe_break mountroot
mount_top
mount_premount
mountroot
log_end_msg

REAL_BOOT=${BOOT}
if [ -e "${rootmnt}/live.flag" ]; then
        mount -o rw,remount ${rootmnt} 2>/dev/null
        rm -f ${rootmnt}/live.flag
        REAL_BOOT=live
        log_warning_msg "Switch to live mode."
fi

if [ -e "${rootmnt}/SystemdLocalfsDependencyFailed.flag" ]; then
	mount -o rw,remount ${rootmnt} 2>/dev/null
	rm ${rootmnt}/SystemdLocalfsDependencyFailed.flag
	if [ "${REAL_BOOT}" != "live" ]; then
		panic
	fi
fi

# Clean up the "/tmp/*" directory in the system disk to ensure that the available space of the
# "/" directory is > 500K
clean_system_disk() {
    # Define local variables
    local rootDiskStandard=500           # Required free space: > 500KB
    local RootIsFullFile="RootIsFull.flag"
    local RootIsFullFilePath="${rootmnt}/${RootIsFullFile}"
    local root_disk_cleaned_space=""

    # 1. Check if RootIsFull.flag exists
    if [ ! -e "${RootIsFullFilePath}" ]; then
        log_success_msg "${RootIsFullFilePath} not found. Skipping system disk cleanup."
        return 0
    fi

    # 2. Try to remount root as read-write (best effort)
    if ! mount -o rw,remount "${rootmnt}" 2>/dev/null; then
        log_warning_msg "Failed to remount ${rootmnt} as rw. Proceeding anyway."
        # Do not panic on remount failure and need to check free space
    fi

    # 3. Clean up /tmp directory
    rm -rf "${rootmnt}/tmp/"* 2>/dev/null || true

    # 4. Get available space on root filesystem (in KB)
    root_disk_cleaned_space=$(df -Bk "${rootmnt}" | awk 'END { print $(NF-2) }')

    # 5. Only panic if we successfully got a valid number AND it's <= threshold
    if [ -n "${root_disk_cleaned_space}" ] && echo "${root_disk_cleaned_space}" | grep -qE '^[0-9]+$'; then
        if [ "${root_disk_cleaned_space}" -gt "${rootDiskStandard}" ]; then
            # Sufficient space
            rm -f "${RootIsFullFilePath}" || true
            log_success_msg "System disk cleanup successful. Sufficient space: ${root_disk_cleaned_space} KB. Flag removed."
        else
            # Space is insufficient (valid measurement, but too small)
            echo "CRITICAL: Root disk space insufficient after cleanup: ${root_disk_cleaned_space} KB <= ${rootDiskStandard} KB"
            echo "We must ensure / available size > ${rootDiskStandard} KB"
            panic
        fi
    else
        # Failed to get valid space value (e.g., df failed, awk no match, etc.)
        log_warning_msg "Could not get valid available space for ${rootmnt}. Assuming sufficient space."
    fi
}



# Clean up data disk space by leveraging the existing bind-mounted /root/var.
# This ensures we are cleaning the persistent data even in an OSTree/OverlayFS environment.
# Target: /root/var/cache/apt/archives and /root/var/log
# Requirement: Ensure available space > 100MB
clean_data_disk() {
    # Define local variables
    local log_disk_threshold=20         # Threshold to clean logs (in MB)
    local data_disk_threshold=100       # Minimum required free space (in MB)
    local DataIsFullFile="DataIsFull.flag"
    local DataIsFullFilePath="${rootmnt}/${DataIsFullFile}"
    local target_var="${rootmnt}/var"   # In initramfs, this is usually the bind mount to vda5/persistent/var
    local log_used_dir_space=0
    local data_disk_cleaned_space=""

    # 1. Check if the flag file exists
    if [ ! -e "${DataIsFullFilePath}" ]; then
        log_success_msg "${DataIsFullFilePath} not found. Skipping data disk cleanup."
        return 0
    fi

    # 2. Remount /root/var as read-write to allow deletion
    # Note: Even if rootmnt is rw, bind mounts may need individual remounting
    if ! mount -o rw,remount "${target_var}" 2>/dev/null; then
        log_warning_msg "Failed to remount ${target_var} as rw. Attempting to proceed anyway."
    fi

    # 3. Clean APT archives
    # Path in v25: /var/cache/apt/archives/
    local apt_cache_path="${target_var}/cache/apt/archives"
    if [ -d "${apt_cache_path}" ]; then
        log_success_msg "Cleaning APT cache: ${apt_cache_path}"
        rm -rf "${apt_cache_path}/"* 2>/dev/null || true
    fi

    # 4. Clean /var/log if it exceeds the threshold
    local log_path="${target_var}/log"
    if [ -d "${log_path}" ]; then
        # Calculate used space in MB
        log_used_dir_space=$(du -sm "${log_path}" 2>/dev/null | awk '{print $1}' || echo "")

        if [ -n "${log_used_dir_space}" ] && echo "${log_used_dir_space}" | grep -qE '^[0-9]+$'; then
            if [ "${log_used_dir_space}" -gt "${log_disk_threshold}" ]; then
                log_warning_msg "Log size (${log_used_dir_space}MB) exceeds threshold (${log_disk_threshold}MB). Cleaning..."
                # Delete contents but keep the directory structure
                rm -rf "${log_path}/"* 2>/dev/null || true
            fi
        else
            log_warning_msg "Could not determine size of ${log_path}, skipping log cleanup."
        fi
    fi

    # 5. Get available space after cleanup (in MB)
    # df -Bm shows size in MB blocks. $(NF-2) is the 'Available' column.
    data_disk_cleaned_space=$(df -Bm "${target_var}" 2>/dev/null | awk 'END { print $(NF-2) }')

    # 6. Verify space and handle flags
    if [ -n "${data_disk_cleaned_space}" ] && echo "${data_disk_cleaned_space}" | grep -qE '^[0-9]+$'; then
        if [ "${data_disk_cleaned_space}" -lt "${data_disk_threshold}" ]; then
            # Critical failure: Space is still insufficient
            echo "CRITICAL: Data disk space insufficient after cleanup: ${data_disk_cleaned_space} MB < ${data_disk_threshold} MB"
            echo "Path: ${target_var}"
            panic
        else
            # Success: Space is enough, remove the flag to allow normal boot
            rm -f "${DataIsFullFilePath}" || true
            log_success_msg "Data disk check passed. Available space: ${data_disk_cleaned_space} MB. Flag removed."
        fi
    else
        log_warning_msg "Could not get valid available space for ${target_var}. Assuming sufficient space."
    fi
}

if [ "${REAL_BOOT}" != "live" ]; then
	clean_system_disk
	clean_data_disk
fi


uos_check_init() {
    local allowed_script="/usr/bin/deepinisocheck.sh"
    local os_release="/etc/os-release"
	local default_init="/sbin/init"

    # Only run this check on UOS systems
    if ! grep -q '^ID=uos$' "$os_release"; then
        return 0
    fi

    # Allow specific script directly without further checks
    if [ "$init" = "$allowed_script" ] || [ "$init" = "$default_init" ]; then
        return 0
    fi

    # Mount /boot only if it's defined in fstab
    if read_fstab_entry /boot; then
        log_begin_msg "Mounting /boot file system"
        if ! mountfs /boot; then
            log_warning_msg "Failed to mount /boot"
            return 1
        fi
        log_end_msg

        # Check GRUB config for password_pbkdf2 (menu encryption)
        local grub_cfg="${rootmnt}/boot/grub/grub.cfg"
        if [ -f "$grub_cfg" ] && ! grep -q '^password_pbkdf2' "$grub_cfg"; then
            log_warning_msg "GRUB encryption not detected, resetting init to default: /sbin/init"
            init=$default_init
        fi

        # Unmount /boot after use
        umount "${rootmnt}/boot"
    else
        log_warning_msg "/boot not found in fstab, skipping GRUB encryption check"
		init=$default_init
    fi
}
uos_check_init

if read_fstab_entry /usr; then
	log_begin_msg "Mounting /usr file system"
	mountfs /usr
	log_end_msg
fi

# Mount cleanup
mount_bottom
nfs_bottom
local_bottom

maybe_break bottom

trace_log "begin wait gpu device"
wait_for_gpu_device() {
	local count=0
	while [ $count -lt 2000 ]; do
		if [ -c "/dev/dri/card0" ] || [ -c "/dev/dri/card1" ] || [ -c "/dev/dri/card2" ]; then
			return 0
		fi

		if [ ! -f "/run/udev/queue" ]; then
			return 0
		fi

		sleep 0.005
		trace_log "No drm device,wait $count times"
		count=$((count + 1))
	done
	trace_log "No drm device,timeout"
	return 1
}
wait_for_gpu_device || true

[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom"
# We expect udev's init-bottom script to move /dev to ${rootmnt}/dev
run_scripts /scripts/init-bottom
[ "$quiet" != "y" ] && log_end_msg

# Move /run to the root
mount -n -o move /run ${rootmnt}/run

validate_init() {
	run-init -n "${rootmnt}" "${1}"
}

# Check init is really there
if ! validate_init "$init"; then
	echo "Target filesystem doesn't have requested ${init}."
	init=
	for inittest in /sbin/init /etc/init /bin/init /bin/sh; do
		if validate_init "${inittest}"; then
			init="$inittest"
			break
		fi
	done
fi

# No init on rootmount
if ! validate_init "${init}" ; then
	panic "No init found. Try passing init= bootarg."
fi

maybe_break init

# don't leak too much of env - some init(8) don't clear it
# (keep init, rootmnt, drop_caps)
unset debug
unset MODPROBE_OPTIONS
unset DPKG_ARCH
unset ROOTFLAGS
unset ROOTFSTYPE
unset ROOTDELAY
unset ROOT
unset IP
unset BOOT
unset BOOTIF
unset DEVICE
unset UBIMTD
unset blacklist
unset break
unset noresume
unset panic
unset quiet
unset readonly
unset resume
unset resume_offset
unset noresume
unset fastboot
unset forcefsck
unset fsckfix
unset starttime

# Move virtual filesystems over to the real filesystem
mount -n -o move /sys ${rootmnt}/sys
mount -n -o move /proc ${rootmnt}/proc

# Chain to real filesystem
# shellcheck disable=SC2086,SC2094
trace_log "end initramfs"
exec run-init ${drop_caps} "${rootmnt}" "${init}" "$@" <"${rootmnt}/dev/console" >"${rootmnt}/dev/console" 2>&1
echo "Something went badly wrong in the initramfs."
panic "Please file a bug on initramfs-tools."
