#!/bin/bash
# lmz-network-boot
#  Manual changes to the paedML Linux system
#
# Depends: UDM
#
# Copyright (C) 2013-2018 Univention GmbH
#
# http://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.

set -u
set -e

LOGFILE=/var/log/paedml-network-boot.log

. /usr/share/univention-lib/all.sh
create_logfile_if_missing "${LOGFILE}" "root:adm" 640

# store stdout, it's redirected to the logfile later on
exec 5>&1

eval "$(ucr shell ucc/pxe/image ucc/efi/image ucc/pxe/assurance/image ldap/base)"

msg () {
    echo -e "$(date): ${@}" | tee -a "${LOGFILE}" >&5
}

err () {
    echo -e "$(date): ${@}" | tee -a "${LOGFILE}" >&5
}


# help function {{{2
help_function () {
    cat << END
USAGE: lmz-network-boot [OPTION]
Switch between network boot types PXE/UEFI.
Example: lmz-network-boot --efi

Options:
  -p | --pxe  | --PXE                         Set network boot type to pxe.
  -u | --uefi | --UEFI | -e | --efi  | --EFI  Set network boot type to uefi.

With no OPTION specified, the script will exit and just prints out current setup.
With more than one OPTION just the first OPTION will be read.
END
}

# description function {{{2
further_description () {
    cat << END
1. ucc/pxe/image, ucc/pxe/assurance/image and ucc/efi/image must be set.
2. ucc/pxe/assurance/image or ucc/efi/image must be equal to ucc/pxe/image.
3. Proper client registration policy must be set for ldap dhcp service object.
END
}

# Start execution {{{1
dhcp_service="cn=schule,cn=dhcp,ou=schule,${ldap_base}"
pxe_policy_dn="cn=client-registration,cn=boot,cn=dhcp,cn=policies,${ldap_base}"
efi_policy_dn="cn=client-registration-efi,cn=boot,cn=dhcp,cn=policies,${ldap_base}"

OPT_NOTHING=0
OPT_PXE=1
OPT_EFI=2

OPTION=${OPT_NOTHING}
if [[ $# -eq 0 ]]; then
    OPTION=${OPT_NOTHING}
    msg "No OPTION specified, print out current setup."
fi
if [[ $# -ge 1 ]]; then
    case "${1}" in
        -h | --help | -\?)
            help_function
            exit
            ;;
        -p | --pxe | --PXE)
            OPTION=${OPT_PXE}
            msg "Set network boot type to pxe."
            ;;
        -u | --uefi | --UEFI | -e | --efi  | --EFI)
            OPTION=${OPT_EFI}
            msg "Set network boot type to uefi."
            ;;
        "")
            # no option specified, but should be here due to if statement
            err "no option specified, but should be here due to if statement"
            exit 3
            ;;
        *)
            err "Could not parse the OPTION: ${1}"
            echo 1>&2
            help_function
            exit 1
            ;;
    esac
fi

function check_network_boot_pxe () {
    uniPolRef="univentionPolicyReference=${pxe_policy_dn}"
    if [[ "${ucc_pxe_image}" != "${ucc_efi_image}" ]] && \
       [[ "${ucc_pxe_assurance_image}" == "${ucc_pxe_image}" ]] && \
       [[ $(udm dhcp/service list --filter "${uniPolRef}") != "${uniPolRef}" ]] ; then
        # pxe boot
        echo 1
    else
        echo 2
    fi
}

function set_network_boot_pxe () {
    msg "Set network boot pxe."
    ucr set ucc/pxe/image="${ucc_pxe_assurance_image}"
    udm dhcp/service modify --dn "${dhcp_service}" \
        --policy-dereference "$efi_policy_dn"
    udm dhcp/service modify --dn "${dhcp_service}" \
        --policy-reference "$pxe_policy_dn"
}

function check_network_boot_efi() {
    uniPolRef="univentionPolicyReference=${efi_policy_dn}"
    if [[ "${ucc_pxe_image}" == "${ucc_efi_image}" ]] && \
       [[  "${ucc_pxe_assurance_image}" != "${ucc_pxe_image}" ]] && \
       [[ $(udm dhcp/service list --filter "${uniPolRef}") != "${uniPolRef}" ]] ; then
        # efi boot
        echo 1
    else
        echo 2
    fi
}

function set_network_boot_efi () {
    msg "Set network boot efi."
    ucr set ucc/pxe/assurance/image="${ucc_pxe_image}"
    ucr set ucc/pxe/image="${ucc_efi_image}"
    udm dhcp/service modify --dn "${dhcp_service}" \
        --policy-dereference "$pxe_policy_dn"
    udm dhcp/service modify --dn "${dhcp_service}" \
        --policy-reference "$efi_policy_dn"
}

# check all UCR-Variables
if [[ -z "${ucc_pxe_assurance_image+x}" ]]; then
    err "UCR-Variable ucc/pxe/assurance/image not set."
    exit 3
fi
if [[ -z "${ucc_efi_image+x}" ]]; then
    err "UCR-Variable ucc/efi/image not set."
    exit 3
fi

if ((${OPTION} == ${OPT_PXE})); then
    if [[ $(check_network_boot_efi) == 1 ]]; then
        set_network_boot_pxe
    elif [[ $(check_network_boot_pxe) == 1 ]]; then
        msg "Network boot type pxe already set."
    else
        err "Inconsistent boot type."
    fi
elif ((${OPTION} == ${OPT_EFI})); then
    if [[ $(check_network_boot_pxe) == 1 ]]; then
        set_network_boot_efi
    elif [[ $(check_network_boot_efi) == 1 ]]; then
        msg "Network boot type uefi already set."
    else
        err "Inconsistent boot type."
    fi
elif ((${OPTION} == ${OPT_NOTHING})); then
    if [[ $(check_network_boot_pxe) == 1 ]]; then
        msg "Network boot type pxe."
    elif [[ $(check_network_boot_efi) == 1 ]]; then
        msg "Network boot type uefi."
    else
        err "Inconsistent boot type:"
        err $(further_description)
    fi
else
    # Should not be possible to be here but ...
    err "Wrong option set."
fi 

# vi: ft=sh:tw=80:sw=4:ts=4:fdm=marker
