#!/bin/bash
MODE="${1}"
DESTDIR="${2}"
PKGARG="${3}"

PACMAN="pacman --root "${DESTDIR}" --config /tmp/pacman.conf --noconfirm --noprogressbar"

# name of kernel package
KERNELPKG="linux"
[[ "$(cat /proc/cmdline | grep -w BOOT_IMAGE=.*lts)" ]] && KERNELPKG="linux-lts"
# name of the kernel image
VMLINUZ="vmlinuz-${KERNELPKG}"
# detect systemd running
[[ "$(cat /proc/cmdline | grep -w init=/bin/systemd)" ]] && SYSTEMD="1"

usage() {
    echo "quickinst <install_mode> <destdir> <package_directory|server_url>"
    echo
    echo "This script is for users who would rather partition/mkfs/mount their target"
    echo "media manually than go through the routines in the setup script."
    echo
    echo "First make sure you have all your filesystems mounted under <destdir>."
    echo "e.g. mount -t iso9660 /dev/cdrom /src "
    echo "Then run this script to install all base packages to <destdir>."
    echo
    
    if [[ -e "/usr/bin/curl" ]]; then
        echo "<install_mode> must be either 'net' or 'media'"
    else
        echo "<install_mode> must be 'media'"
    fi
    
    echo
    echo "Examples:"
    
    if [[ -e "/usr/bin/curl" ]]; then
        if [[ "$(uname -m)" = "x86_64" ]]; then
                echo "  quickinst net /mnt ftp://ftp.archlinux.org/core/os/x86_64"
                echo "  quickinst net /mnt http://ftp.archlinux.org/core/os/x86_64"
        else
                echo "  quickinst net /mnt ftp://ftp.archlinux.org/core/os/i686"
                echo "  quickinst net /mnt http://ftp.archlinux.org/core/os/i686"
        fi
    fi

    echo "  quickinst media /mnt /packages/core-$(uname -m)/pkg"
    echo ""
    exit 0
}

# pacman_conf()
# creates temporary pacman.conf file
pacman_conf() {
    if [[ "${MODE}" = "media" ]]; then
        serverurl="file://${PKGARG}"
    elif [[ "${MODE}" = "net" ]]; then
        serverurl="${PKGARG}"
    fi
    # Setup a pacman.conf in /tmp
    cat << EOF > /tmp/pacman.conf
[options]
Architecture = auto
SigLevel = PackageRequired
CacheDir = ${DESTDIR}/var/cache/pacman/pkg
CacheDir = /packages/core-$(uname -m)/pkg
CacheDir = /packages/core-any/pkg

[core]
Server = ${serverurl}

EOF
}

# pacman_conf_extra()
# adds extra repository for net installation mode
pacman_conf_extra() {
    serverurl="${PKGARG}"
    # Setup a pacman.conf in /tmp
    echo "[extra]" >> /tmp/pacman.conf
    echo "Server =  ${serverurl}" >> /tmp/pacman.conf
}

# pacman needs a masterkey before checking signed packages
prepare_pacman_keychain() {
    # Generate initial keychain, use haveged then no user interaction is required
    if  [[ -f /var/run/haveged.pid ]]; then
        kill $(cat /var/run/haveged.pid)
    fi
    haveged
    pacman-key --init >/dev/null 2>&1
    ### HACK: fix accept of master keys!
    sed -i -e 's#"${GPG_PACMAN\[\@\]}" --quiet --lsign-key "${key_id}"#"${GPG_PACMAN\[\@\]}" --batch --yes --quiet --lsign-key "${key_id}"#g' \
    /usr/bin/pacman-key
    pacman-key --populate archlinux >/dev/null 2>&1
    sed -i -e 's#"${GPG_PACMAN\[\@\]}" --batch --yes --quiet --lsign-key "${key_id}"#"${GPG_PACMAN\[\@\]}" --quiet --lsign-key "${key_id}"#g' \
    /usr/bin/pacman-key
    kill $(cat /var/run/haveged.pid)
}

# configures pacman and syncs db on destination system
# params: none
# returns: 1 on error
prepare_pacman() {
    # Set up the necessary directories for pacman use
    [[ ! -d "${DESTDIR}/var/cache/pacman/pkg" ]] && mkdir -m 755 -p "${DESTDIR}/var/cache/pacman/pkg"
    [[ ! -d "${DESTDIR}/var/lib/pacman" ]] && mkdir -m 755 -p "${DESTDIR}/var/lib/pacman"
    prepare_pacman_keychain
    ${PACMAN} -Sy
}

# chroot_mount()
# prepares target system as a chroot
#
chroot_mount()
{
    [[ -e "${DESTDIR}/sys" ]] || mkdir "${DESTDIR}/sys"
    [[ -e "${DESTDIR}/proc" ]] || mkdir "${DESTDIR}/proc"
    [[ -e "${DESTDIR}/dev" ]] || mkdir "${DESTDIR}/dev"
    mount -t sysfs sysfs "${DESTDIR}/sys"
    mount -t proc proc "${DESTDIR}/proc"
    mount -o bind /dev "${DESTDIR}/dev"
}

# chroot_umount()
# tears down chroot in target system
#
chroot_umount()
{
    umount "${DESTDIR}/proc"
    umount "${DESTDIR}/sys"
    umount "${DESTDIR}/dev"
}

# package_installation
install_packages() {
    if [[ "${MODE}" = "media" ]]; then
        PKGFILE="/tmp/.pkglist"
        cp "${PKGARG}/packages.txt" "${PKGFILE}"
        if [[ ! -f "${PKGFILE}" ]]; then
            echo "error: Could not find package list: ${PKGFILE}"
            exit 1
        fi
        PACKAGES=
        # fix pacman list!
        sed -i -e 's/-i686//g' -e 's/-x86_64//g' -e 's/-any//g' -e 's/"//g' ${PKGFILE}
        for pkg in $(cat ${PKGFILE} | grep 'base/' | cut -d/ -f2); do
            pkgname=${pkg%-*-*}
            PACKAGES="${PACKAGES} ${pkgname}"
        done
    else
        PACKAGES="$(pacman -Sg base | awk '{print $2}')"
    fi
    # Add packages which are not in core repository
    if [[ "$(grep -w uvesafb /proc/cmdline)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w v86d)" ]] && PACKAGES="${PACKAGES} v86d"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep ntfs)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w ntfs-3g)" ]] && PACKAGES="${PACKAGES} ntfs-3g"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep ntfs)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w ntfs-3g)" ]] && PACKAGES="${PACKAGES} ntfs-3g"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep btrfs)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w btrfs-progs)" ]] && PACKAGES="${PACKAGES} btrfs-progs"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep nilfs2)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w nilfs-utils)" ]] && PACKAGES="${PACKAGES} nilfs-utils"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep ext)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w e2fsprogs)" ]] && PACKAGES="${PACKAGES} e2fsprogs"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep reiserfs)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w reiserfsprogs)" ]] && PACKAGES="${PACKAGES} reiserfsprogs"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep xfs)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w xfsprogs)" ]] && PACKAGES="${PACKAGES} xfsprogs"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep jfs)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w jfsutils)" ]] && PACKAGES="${PACKAGES} jfsutils"
    fi
    if [[ "$(blkid -c /dev/null -o value -s TYPE | grep vfat)" ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w dosfstools)" ]] && PACKAGES="${PACKAGES} dosfstools"
    fi
    if [[ -e /var/state/dhcp/dhclient.leases ]]; then
        ! [[ "$(echo ${PACKAGES} | grep -w dhclient)" ]] && PACKAGES="${PACKAGES} dhclient"
    fi

    # Only install the booted kernel image!
    PACKAGES="$(echo ${PACKAGES} | sed -e "s#\ linux\ # #g" -e "s#\ linux-lts\ # #g")"
    PACKAGES="${KERNELPKG} ${PACKAGES}"
    # remove not needed initscripts and sysvinit package with systemd and add compat package
    if [[ "${SYSTEMD}" = "1" ]]; then
        PACKAGES="$(echo ${PACKAGES} | sed -e "s#\ initscripts\ # #g" -e  "s#\ sysvinit\ # #g" -e "s#\ systemd\ # #g")"
        PACKAGES="${PACKAGES} systemd systemd-sysvcompat"
    else
        PACKAGES="$(echo ${PACKAGES} | sed -e "s#\ systemd-sysvcompat\ # #g")"
    fi
    ${PACMAN} -S ${PACKAGES}
}

if [[ "${PKGARG}" = "" ]]; then
    usage
fi

! [[ -d /tmp ]] && mkdir /tmp

# prepare pacman
pacman_conf
if [[ "${INSTMODE}" = "net" ]]; then
    pacman_conf_extra
fi
prepare_pacman
if [[ $? -ne 0 ]]; then
    echo "Pacman preparation FAILED!"
    return 1
fi

# mount proc/sysfs first, so mkinitcpio can use auto-detection if it wants
chroot_mount

# install packages
install_packages
if [[ $? -gt 0 ]]; then
    echo
    echo "Package installation FAILED."
    echo
    chroot_umount
    exit 1
fi

# umount chroot
chroot_umount

echo
echo "Package installation complete."
echo
echo "Please install a bootloader.  Edit the appropriate config file for"
echo "your loader. Please use ${VMLINUZ} as kernel image."
echo "Chroot into your system to install it into the boot sector:"
echo "  # mount -o bind /dev ${DESTDIR}/dev"
echo "  # mount -t proc none ${DESTDIR}/proc"
echo "  # mount -t sysfs none ${DESTDIR}/sys"
echo "  # chroot ${DESTDIR} /bin/bash"
echo
echo "For GRUB:"
echo "  # install-grub /dev/sda /dev/sdaX (replace with your boot partition)"
echo "  (or install manually by invoking the GRUB shell)"
echo "HINT XFS FILESYSTEM:"
echo "If you have created xfs filesystems, freeze them before and unfreeze them after"
echo "installing grub (outside the chroot):"
echo "- freeze:"
echo "  # xfs_freeze -f ${DESTDIR}/boot"
echo "  # xfs_freeze -f ${DESTDIR}/"
echo "- unfreeze:"
echo "  # xfs_freeze -u ${DESTDIR}/boot"
echo "  # xfs_freeze -u ${DESTDIR}/"
echo
echo "For LILO:"
echo "  # lilo"
echo
echo "Next step, initramfs setup:"
echo "Edit your /etc/mkinitcpio.conf and /etc/mkinitcpio.d/${KERNELPKG}-fallback.conf"
echo "to fit your needs. After that run:"
echo "# mkinitcpio -p ${KERNELPKG}"
echo
echo "Then exit your chroot shell, edit ${DESTDIR}/etc/fstab and"
echo "${DESTDIR}/etc/rc.conf, and reboot!"
echo
exit 0

# vim: set ts=4 sw=4 et:
