#!/bin/bash
# Copyright 1999-2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# /etc/conf.d/dolilo readout
if [ -e /etc/conf.d/dolilo ]; then
	append="$(sed -n "s:^APPEND[ ]*=[ ]*\(.*\)[ ]*:\1:p" /etc/conf.d/dolilo)"
	vga="$(sed -n "s:^VGA[ ]*=[ ]*\(.*\)[ ]*:\1:p" /etc/conf.d/dolilo)"
	bootdev="$(sed -n "s:^BOOTDEV[ ]*=[ ]*\(.*\)[ ]*:\1:p" /etc/conf.d/dolilo)"
	rootdev="$(sed -n "s:^ROOTDEV[ ]*=[ ]*\(.*\)[ ]*:\1:p" /etc/conf.d/dolilo)"
	serial="$(sed -n "s:^SERIAL[ ]*=[ ]*\(.*\)[ ]*:\1:p" /etc/conf.d/dolilo)"
	if [ -n "$(grep ^REWRITE /etc/conf.d/dolilo )" ]; then
		rewrite=1
	fi
	if [ -n "$(grep ^MOVEIMAGES /etc/conf.d/dolilo )" ]; then
		moveimages=1
	fi
	if [ -n "$(grep ^COMPACT /etc/conf.d/dolilo )" ]; then
		compact=1
	fi

	if [ -n "${rewrite}" ] && [ -z "${moveimages}" ]; then
		echo "The REWRITE option needs MOVEIMAGES to function correctly."
		echo "REWRITE has been disabled to avoid writing a non-functional configuration out."
		unset rewrite
	fi
elif [ -e /etc/conf.d/dolilo.example ]; then
	echo "You can move /etc/conf.d/dolilo.example to /etc/conf.d/dolilo and edit it to set your preferences."
fi

# boot= and root= device detection
if [ ! -n "${bootdev}" ]; then
	rootdev="$(mount | grep -v "tmpfs" | grep -v "rootfs" | grep "on / " | cut -f1 -d " ")"
	bootdev="$(echo ${rootdev} | sed "s:\(.*\).$:\1:")"
elif [ ! -e "${rootdev}" ] && [ "${rootdev}" = "/dev/ram0" ]; then
	touch /dev/ram0
fi

# /boot partition information
fstabstate="$(cat /etc/fstab | awk '!/^#|^[[:blank:]]+#|^\/dev\/BOOT/ {print $2}' | egrep "^/boot$" )"
procstate="$(cat /proc/mounts | awk '{print $2}' | egrep "^/boot$" )"
proc_ro="$(cat /proc/mounts | awk '{ print $2, $4 }' | sed -n '/\/boot/{ /[ ,]\?ro[ ,]\?/p }' )"

# locate bootable windows partitions, if any
winpart="$(fdisk -l ${bootdev} | grep NTFS | grep \* || fdisk -l ${bootdev} | grep FAT | grep \* )"
winboot="$(echo ${winpart} | cut -d " " -f1 )"
unset winpart

# Pre-flight check, if the /usr/src/linux symlink is broken we can't do anything useful.
if [ -z "$(ls -l /usr/src/linux | cut -d ">" -s -f2-)" ]; then
	echo "Your /usr/src/linux symlink is invalid or does not exist. Please fix that and rerun dolilo."
	exit 1
fi

# Build kernel version string
KMF_VERSION="$(sed -n "s:^VERSION[ ]*=[ ]*\(.*\)[ ]*:\1:p" /usr/src/linux/Makefile)"
KMF_PATCHLEVEL="$(sed -n "s:^PATCHLEVEL[ ]*=[ ]*\(.*\)[ ]*:\1:p" /usr/src/linux/Makefile)"
KMF_SUBLEVEL="$(sed -n "s:^SUBLEVEL[ ]*=[ ]*\(.*\)[ ]*:\1:p" /usr/src/linux/Makefile)"
KMF_EXTRAVERSION="$(sed -n "s:^EXTRAVERSION[ ]*=[ ]*\(.*\)[ ]*:\1:p" /usr/src/linux/Makefile)"
KV="${KMF_VERSION}.${KMF_PATCHLEVEL}.${KMF_SUBLEVEL}${KMF_EXTRAVERSION}"

# Build KOUTPUT string
KOUTPUT="$(sed -n "s:^KBUILD_OUTPUT[ ]*=[ ]*\(.*\)[ ]*:\1:p" /usr/src/linux/Makefile)"
KOUTPUT="${KOUTPUT/\$(VERSION)/${KMF_VERSION}}"
KOUTPUT="${KOUTPUT/\$(PATCHLEVEL)/${KMF_PATCHLEVEL}}"
KOUTPUT="${KOUTPUT/\$(SUBLEVEL)/${KMF_SUBLEVEL}}"
KOUTPUT="${KOUTPUT/\$(EXTRAVERSION)/${KMF_EXTRAVERSION}}"
unset KMF_VERSION KMF_PATCHLEVEL KMF_SUBLEVEL KMF_EXTRAVERSION

# Kernel-style ARCH sed magic
ARCH="$(uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                  -e s/arm.*/arm/ -e s/sa110/arm/ \
                                  -e s/s390x/s390/ -e s/parisc64/parisc/ )"

# Build up path to bzImage
if [ -z "${KOUTPUT}" ]; then
	KOUTPUT="/usr/src/linux"
fi
KIMAGE="${KOUTPUT}/arch/${ARCH}/boot/bzImage"
unset ARCH KOUTPUT

# Get /boot mounted r/w
if [ -n "${fstabstate}" ] && [ -n "${procstate}" ] && [ -n "${proc_ro}" ]; then
	mount -o remount,rw /boot &>/dev/null
	if [ "$?" -ne 0 ]; then
		echo "Your /boot partition is mounted read-only and an attempt to remount read-write failed."
		echo "Please do this manually."
		exit 2
	fi
elif [ -n "${fstabstate}" ] && [ -z "${procstate}" ]; then
	mount /boot -o rw &>/dev/null
	if [ "$?" -eq 0 ]; then
		unmount="1"
	else
		echo "You have a separate /boot partition, but it can't be automounted as read/write."
		echo "Please do this manually."
		exit 2
        fi
fi

# Move a newer kernel image in place if available, and MOVEIMAGES is on.
if [ -e "${KIMAGE}" ] && [ -n "${moveimages}" ]; then
	diff /boot/bzImage "${KIMAGE}" &>/dev/null
	if [ "$?" -ne 0 ]; then
		cp -b -S .old "${KIMAGE}" /boot/bzImage
		echo "New kernel image ${KIMAGE} moved in place as /boot/bzImage"
		if [ -e /boot/bzImage.old ]; then
			echo "Old /boot/bzImage backupped as /boot/bzImage.old"
		fi
	fi
elif [ -e /boot/bzImage ] && [ ! -e "${KIMAGE}" ] && [ -n "${moveimages}" ]; then
	echo "Warning: Expected kernel image ${KIMAGE} but nothing found. Continuing without touching /boot/bzImage."
elif [ ! -e /boot/bzImage ] && [ ! -e "${KIMAGE}" ] && [ -n "${moveimages}" ]; then
	echo "You appear to have already emerged kernel sources, but you still need to compile them."
	exit 3
fi

# Check if a newer initrd is available, if so, move it in place.
if [ -e "/boot/initrd-${KV}" ] && [ -n "${moveimages}" ]; then
	diff "/boot/initrd-${KV}" /boot/initrd &>/dev/null
	if [ "$?" -ne 0 ]; then
		cp -b -S .old "/boot/initrd-${KV}" /boot/initrd
		echo "Initrd for this ${KV} kernel moved in place as /boot/initrd"
		if [ -e /boot/initrd.old ]; then
			echo "Old /boot/initrd backupped as /boot/initrd.old"
		fi
	fi
fi

# If the rewrite option is active, we move the current config out of the way.
if [ -n "${rewrite}" ] && [ -e /etc/lilo.conf ]; then
	mv /etc/lilo.conf /etc/lilo.conf.backup
fi
# If no lilo config exists, we write one.
if [ -e "${rootdev}" ] && [ -e "${bootdev}" ] && [ -e /boot/bzImage ] && [ ! -e /etc/lilo.conf ]; then
	echo "boot=${bootdev}" > /etc/lilo.conf
	echo "root=${rootdev}" >> /etc/lilo.conf
	echo "lba32" >> /etc/lilo.conf
	echo "read-write" >> /etc/lilo.conf
	if [ -n "${compact}" ]; then
		echo "compact" >> /etc/lilo.conf
	fi
	if [ -n "${append}" ]; then
		echo "append=${append}" >> /etc/lilo.conf
	fi
	if [ -n "${serial}" ]; then
		echo "serial=${serial}" >> /etc/lilo.conf
		echo "prompt" >> /etc/lilo.conf
		echo "timeout=40" >> /etc/lilo.conf
	fi

	echo >> /etc/lilo.conf
	echo "image=/boot/bzImage" >> /etc/lilo.conf
	LABEL1=$(strings /boot/bzImage | grep root@ | sed "s:hardened:hrd:" | cut -d " " -f1 | cut -b1-15 | head -n1)
	echo "  label=${LABEL1}" >> /etc/lilo.conf

	if [ -e /boot/initrd ]; then
		echo "Adding initial ramdisk /boot/initrd to default kernel"
		echo "  initrd=/boot/initrd" >> /etc/lilo.conf
	else
		if [ -n "${vga}" ]; then
			echo "  vga=${vga}" >> /etc/lilo.conf
		fi
	fi
	echo >> /etc/lilo.conf

	echo "image=/boot/bzImage.old" >> /etc/lilo.conf
	if [ -e /boot/bzImage.old ]; then
		LABEL2=$(strings /boot/bzImage.old | grep root@ | sed "s:hardened:hrd:" | cut -d " " -f1 | cut -b1-15 | head -n1)
	else
		LABEL2="backup"
	fi
	if [ "${LABEL1}" == "${LABEL2}" ]; then
		LABEL2=$(echo "o${LABEL2}" | cut -b1-15)
	fi
	echo "  label=${LABEL2}" >> /etc/lilo.conf
	echo "  optional" >> /etc/lilo.conf

	if [ -e /boot/initrd.old ]; then
		echo "Adding initial ramdisk /boot/initrd.old to backup kernel"
		echo "  initrd=/boot/initrd.old" >> /etc/lilo.conf
	else
		if [ -n "${vga}" ]; then
			echo "  vga=${vga}" >> /etc/lilo.conf
		fi
	fi
        echo >> /etc/lilo.conf

	if [ -e /boot/memtest86/memtest.bin ]; then
		echo "Adding memtest86 image"
		echo "image=/boot/memtest86/memtest.bin" >> /etc/lilo.conf
		echo "  label=memtest86" >> /etc/lilo.conf
		echo >> /etc/lilo.conf
	fi

	if [ -e /boot/memtest86plus/memtest.bin ]; then
		echo "Adding memtest86+ image"
		echo "image=/boot/memtest86plus/memtest.bin" >> /etc/lilo.conf
		echo "  label=memtest86+" >> /etc/lilo.conf
		echo >> /etc/lilo.conf
	fi

	if [ -n "${winboot}" ]; then
		echo "Adding windows installation on ${winboot}"
		echo "other=${winboot}" >> /etc/lilo.conf
		echo "  label=windows" >> /etc/lilo.conf
		echo >> /etc/lilo.conf
	fi

	if [ -z "${append}" ]; then
		echo "A minimal /etc/lilo.conf has been generated. You may need to add/modify the append= line."
	fi
	echo "Lilo will boot the default kernel unless you hold Shift during boot, in that case a boot menu will appear."
elif [ ! -e "${bootdev}" ] && [ ! -e /etc/lilo.conf ]; then
	echo "Dolilo can not automatically detect your system settings, and therefore can not write /etc/lilo.conf"
	echo "for you. You will have to write /etc/lilo.conf yourself, with the help of /etc/lilo.conf.example"
	echo
	echo "A bug report on bugs.gentoo.org would be appreciated. Please include the following values:"
	echo "bootdev: 	${bootdev}"
	echo "rootdev: 	${rootdev}"
	echo "KIMAGE: 	${KIMAGE}"
	echo
	echo "Please mention whether you are installing from the LiveCD, or already actually running Gentoo."
	echo "Note that you should use the Query function first to see if a bug like this has been reported"
	echo "before, as the initial search has a very low yield."
	exit 5
elif [ -e "${rootdev}" ] && [ -e "${bootdev}" ] && [ ! -e /etc/lilo.conf ] && [ -z "${moveimages}" ]; then
	echo "Dolilo would be able to write a working boot configuration for you if a kernel image was available."
	echo "You may want to set the MOVEIMAGES option in /etc/conf.d/dolilo so dolilo is allowed to arrange this."
	exit 7
fi

# Run lilo, only show it's output to the user if it fails.
/sbin/lilo "$@" &>/tmp/lilo.out
if [ "$?" -eq 0 ]; then
	echo "Bootsector updated succesfully."
	rm /tmp/lilo.out
else
	echo "Bootsector update failed, lilo messages:"
	cat /tmp/lilo.out
	rm /tmp/lilo.out
	LILOERROR="1"
fi

# Restore original situation for /boot
if [ -n "${proc_ro}" ]; then
	mount -o remount,ro /boot &>/dev/null
	if [ "$?" -ne 0 ]; then
		echo "Your /boot partition was remounted read/write by dolilo, but can't be remounted read-only."
		echo "Please do this manually."
		exit 2
	fi
fi
if [ -n "${unmount}" ]; then
	umount /boot
	if [ "$?" -ne 0 ]; then
                echo "Your /boot partition was automounted by dolilo, but can't be unmounted."
                echo "Please do this manually."
                exit 2
        fi
fi

if [ -n "${LILOERROR}" ]; then
	exit 6
fi
