#! /bin/sh

. /usr/share/debconf/confmodule

ARCH="$(dpkg --print-architecture)"
SUBARCH="$(archdetect)"
SUBARCH="${SUBARCH#*/}"
CPUINFO=/proc/cpuinfo
UNAME_R="$(uname -r)"
KERNEL_MAJOR="$(echo "$UNAME_R" | cut -d . -f 1,2)"
KERNEL_VERSION="$(echo "$UNAME_R" | cut -d - -f 1)"
KERNEL_ABI="$(echo "$UNAME_R" | cut -d - -f 1,2)"
MACHINE="$(uname -m)"
NUMCPUS=

if [ -f /usr/lib/ubiquity/base-installer/kernel.sh ]; then
	. /usr/lib/ubiquity/base-installer/kernel.sh
else
	exit 0
fi

kernels="$(dpkg-query -f '${status} ${package}\n' \
		-W linux-image-\* linux-signed-image-\* 2>/dev/null | \
		grep '^install ok installed ' | cut -d' ' -f4 | xargs)"

flavour="$(arch_get_kernel_flavour || true)"
preferred_kernels="$(arch_get_kernel "$flavour")"
if db_get base-installer/kernel/altmeta && [ "$RET" ]; then
	preferred_kernels="$(echo "$preferred_kernels" | sed "s/$/-$RET/"; \
			     echo "$preferred_kernels")"
fi

# for kernels that are not on livefs, i.e. from the internet or cd-rom
# pool, i.e. linux-generic
# do not repeat it in compatible
install_new=
# for kernels that are preinstalled in the livefs
# must match linux-image-*
compatible=
# for kernels that we want to purge from target
incompatible=

# TODO cjwatson 2009-10-19: Nasty hack for PAE-capable systems; see
# https://launchpad.net/bugs/413135. We should generalise this somehow.
case $preferred_kernels in
    linux-generic-pae*)
	if [ "$(apt-cache search -n '^linux-generic-pae$')" ]; then
		install_new="${install_new:+$install_new }linux-generic-pae"
		for kernel in $kernels; do
			case $kernel in
			    *-generic-pae)
				compatible="${compatible:+$compatible }$kernel"
				;;
			    *)
				incompatible="${incompatible:+$incompatible }$kernel"
				;;
			esac
		done
	fi
	;;
esac

# If base-installer asks for a signed kernel, try hard to lay our hands on
# one.
candidates="$(dpkg-query -f '${status} ${package}\n' \
		-W linux-signed-\* 2>/dev/null | \
		grep '^install ok installed ' | cut -d' ' -f4 | xargs)"

for kernel in $preferred_kernels; do
	case $kernel in
	    linux-signed-*)
		if [ "$(apt-cache search -n "^$kernel\$")" ]; then
		    for candidate in $candidates; do
			case $candidate in
			    $kernel)
				install_new="${install_new:+$install_new }$kernel"
				;;
			esac
		    done
		fi
		;;
	esac
done

if [ -z "$compatible" ] && [ -z "$install_new" ]; then
	for kernel in $kernels; do
		# If base-installer didn't ask for a signed kernel, then
		# consider signed kernels incompatible.  This isn't
		# technically true - they'll boot - but it saves leaving a
		# kernel installed that users probably won't need but will
		# have to upgrade.
		case $preferred_kernels in
		    *linux-signed-*)
			;;
		    *)
			case $kernel in
			    linux-signed-*)
				incompatible="${incompatible:+$incompatible }$kernel"
				continue
				;;
			esac
			;;
		esac

		if arch_check_usable_kernel "$kernel" "$flavour"; then
			compatible="${compatible:+$compatible }$kernel"
		else
			if [ "${kernel%-$UNAME_R}" != "$kernel" ]; then
				echo 'Would try to remove running kernel;' \
				     'bailing out for sanity' >&2
				exit 0
			fi
			incompatible="${incompatible:+$incompatible }$kernel"
		fi
	done
fi

OEM_KERNEL=linux-oem-22.04
wants_oem_kernel() {
	if [ "$(apt-cache search -n "^${OEM_KERNEL}\$")" ]; then
        test -e /run/ubuntu-drivers-oem.autoinstall || return 1
        for pkg in $(cat /run/ubuntu-drivers-oem.autoinstall); do
            case $pkg in
                oem-*-meta)
                    oem_kernel="$(apt-cache show "$pkg" | grep-dctrl -v -XF Ubuntu-OEM-Kernel-Flavour default)"
                    if [ -n "$oem_kernel" ]; then
                        return
                    fi
                    ;;
            esac
        done
    fi
    return 1
}
wants_nvidia() {
    test -e /run/ubuntu-drivers.autoinstall || return
    for pkg in $(cat /run/ubuntu-drivers.autoinstall); do
        case $pkg in
            nvidia-driver-*)
                echo $pkg | sed 's/nvidia-driver-/nvidia-/'
                break
            ;;
        esac
    done
}
nvidia_stem="$(wants_nvidia)"

if wants_oem_kernel; then
    depends_on_generic_hwe="$(apt-cache show "$OEM_KERNEL" | grep-dctrl -F Depends linux-generic-hwe-)"
    if [ -n "$compatible" ]; then
        i="${incompatible:+$incompatible }$compatible"
        compatible=""
        incompatible=""
        for incompat in ${i}; do
            # We want the oem, it's not incompatible with us, don't remove it.
            if [ "${incompat#*-oem}" != "${incompat}" ]; then
                continue
            fi

            # If oem kernel metapackage depends on generic-hwe kernel,
            # do not remove generic-hwe kernel.
            if [ "$depends_on_generic_hwe" ] && \
                [ "${incompat#*-generic-hwe}" != "${incompat}" ]; then
                continue
            fi

            # If the linux-image package rdepends generic-hwe kernel
            # metapackage, and oem depends on generic-hwe, do not remove it.
            if [ "$depends_on_generic_hwe" ] && \
                [ "${incompat#linux-image-}" != "${incompat}" ] && \
                (apt-cache rdepends "^$incompat\$" | grep -- -generic-hwe); then
                continue
            fi

            incompatible="${incompatible:+$incompatible }$incompat"
        done
    fi

    install_new="${install_new:+$install_new }${OEM_KERNEL}"
    if [ "$nvidia_stem" ]; then
        install_new="${install_new} linux-modules-${nvidia_stem}-${OEM_KERNEL#linux-}"
    fi
fi

kernel_to_headers () {
	echo "$1" | sed 's/linux\(-signed\|\)\(-image\|\)/linux-headers/'
}
kernel_image_to_meta () {
    echo "$1" | sed -n 's/^linux-image-/linux-/p' | xargs dpkg-query -W -f'${Package}\n' 2>/dev/null
}
kernel_image_to_modules () {
    echo "$1" | sed -n 's/^linux-image-/linux-modules-/p' | xargs dpkg-query -W -f'${Package}\n' 2>/dev/null
    if [ "$nvidia_stem" ]; then
        echo "$1" | sed -n "s/^linux-image-/linux-modules-${nvidia_stem}-/p" | xargs dpkg-query -W -f'${Package}\n' 2>/dev/null
    fi
}

if [ -z "$compatible" ] && [ -z "$install_new" ]; then
	# We must be wrong. After all, we got this far ...
	echo 'No usable kernel found; assuming foreign package naming' >&2
else
	mkdir -p /var/lib/ubiquity
	for meta in $install_new; do
		echo "$meta" >>/var/lib/ubiquity/install-kernels
	done
	for kernel in $compatible; do
		apt-install "$(kernel_image_to_meta "$kernel")"
	done
	for kernel in $incompatible; do
		echo "$kernel" >> /var/lib/ubiquity/remove-kernels
		case $kernel in
		    linux-signed-*)
			# If the entire flavour is incompatible, then we'll
			# find out about that separately.  Otherwise,
			# removing the signed kernel doesn't merit removing
			# headers too.
			;;
		    *)
			kernel_to_headers "$kernel" >>/var/lib/ubiquity/remove-kernels
			kernel_image_to_meta "$kernel" >>/var/lib/ubiquity/remove-kernels
			kernel_image_to_modules "$kernel" >>/var/lib/ubiquity/remove-kernels            
			;;
		esac
	done
fi

exit 0
