#!/bin/sh
# Shares a live Ubuntu CD/DVD over the network, so that
# PCs without a CD/DVD drive can use it for installation.

set -e
trap "cleanup" 0 1 2 3 9 11 13 15

printbold() {
    if [ -z "$printbold_first_time" ]; then
        printbold_first_time=true
        bold_face=$(tput bold 2>/dev/null) || true
        normal_face=$(tput sgr0 2>/dev/null) || true
    fi
    echo "${bold_face}$@${normal_face}"
}    

die() {
    printbold "Error: $@" >&2
    exit 1
}

cleanup() {
    trap - 0 1 2 3 9 11 13 15  # Stop trapping
    echo  # Skip the ^C line
    if [ -n "$modified_exports" ]; then
        printbold "Removing /cdrom from /etc/exports..."
        sed -i '/\/cdrom \*(ro,no_subtree_check,no_root_squash)/d' /etc/exports || true
        exportfs -ra || true
    fi
    if [ -n "$installed_nfs" ]; then
        printbold "Removing nfs-kernel-server..."
        apt-get --yes --auto-remove purge nfs-kernel-server || true
    fi
    if [ -n "$temp_dir" ]; then
        printbold "Removing temporary directory $temp_dir..."
        rm -rf "$temp_dir" || true
    fi
}

compare_version() {
# $1 = package name
# $2 = comparison operator, e.g. ge, gt, le, lt
# $3 = package version
    dpkg --compare-versions "$(dpkg-query -W -f '${Version}' "$1" 2>/dev/null)" $2 "$3"
}

get_temp_dir() {
    temp_dir=$(mktemp -d --tmpdir livecd-netboot.XXXXXXXX 2>/dev/null) || true
    if [ -z "$temp_dir" ]; then
        temp_dir=/tmp/livecd-netboot.IN45C2RV
    fi
}

check_requirements() {
    if [ $(id -u) -ne 0 ]; then
        die "livecd-netboot needs root privileges.
Usage: sudo $0
Exports the Ubuntu live CD over NFS, to enable clients to netboot with it.
Assumes that an external DHCP server is present (e.g. a router)."
    fi

    if compare_version dnsmasq-base lt "2.49"; then
        die "livecd-netboot requires dnsmasq-base >= 2.49."
    fi

    if compare_version syslinux le "0"; then
        die "livecd-netboot requires the syslinux package."
    fi

    if ! [ -e /cdrom/casper/vmlinuz ]; then
        die "Ubuntu live CD not mounted.
Please ensure that the live CD is mounted in /cdrom,
either by inserting it in the drive, or by doing something like:
  sudo mount -o loop ubuntu-9.10-desktop-i386.iso /media/cdrom0/"
    fi

    if netstat -nap 2>/dev/null | grep -q ":67 "; then
        die "A DHCP server is already running on port 67. You need to stop it
for livecd-netboot to function properly.
E.g. if you're using dhcp3-server, you may need to run:
  sudo service dhcp3-server stop
or, if you're using dnsmasq:
  sudo service dnsmasq stop"
    fi

    if netstat -nap 2>/dev/null | grep -q ":69 "; then
        die "A TFTP server is already running on port 69. You need to stop it
for livecd-netboot to function properly.
E.g. if you're using tftpd-hpa and openbsd-inetd, you may need to run:
  sudo service openbsd-inetd stop
or, if you're using dnsmasq:
  sudo service dnsmasq stop"
    fi
}

export_cdrom() {
    if compare_version nfs-kernel-server le "0"; then
        apt-get update
        printbold "Installing the nfs-kernel-server package to serve the live CD over NFS..."
        apt-get --yes install nfs-kernel-server
        installed_nfs=true
    fi

    if ! grep -q "^/cdrom" /etc/exports; then
        printbold "Adding /cdrom to /etc/exports..."
        echo '/cdrom *(ro,no_subtree_check,no_root_squash)' >> /etc/exports
        modified_exports=true
        exportfs -ra
    else
        printbold "Found /cdrom in /etc/exports, assuming that it's already exported correctly."
    fi
}

create_tftpboot() {
    def_iface=$(route -n | sed -n '/^0.0.0.0/s/.* //p')
    if [ -z "$SERVER_IP" ]; then
        SERVER_IP=$(ip -oneline -family inet addr show dev "$def_iface" | sed -n '/inet 127\./! {s,.* \(.*\)/.*,\1,p;q}')
    fi
    if [ -z "$SERVER_IP" ]; then
        die "Could not determine this PC's IP address. Please provide it manually, by running
  sudo SERVER_IP=1.2.3.4 $0"
    fi
    # If we're running on the live CD and the user has selected a language, use it.
    parameters=$(sed -n 's/.*\(debian-installer\/language.*\)/\1/p' /proc/cmdline)
    if [ -z "$parameters" ]; then
        case "$LANG" in
            "el_GR.UTF-8")
                parameters="debian-installer/language=el console-setup/layoutcode?=gr"
                ;;
        esac
    fi
    mkdir -p "$temp_dir/tftpboot/pxelinux.cfg"
    echo "DEFAULT casper/vmlinuz nfsroot=$SERVER_IP:/cdrom netboot=nfs ro file=/cdrom/preseed/ubuntu.seed boot=casper initrd=casper/initrd.lz -- $parameters" > "$temp_dir/tftpboot/pxelinux.cfg/default"
    ln -sf /cdrom/casper "$temp_dir/tftpboot/"
    ln -sf /usr/lib/syslinux/pxelinux.0 "$temp_dir/tftpboot/"
}

create_dnsmasq_conf() {
    cat >"$temp_dir/dnsmasq.conf" <<EOF
# Sample configuration for dnsmasq to function as a proxyDHCP server,
# enabling clients to boot from the network when an external, unmodifiable
# DHCP server is present.

# Don't function as a DNS server.
port=0

# Enable the builtin tftp server.
enable-tftp

# Set the root directory for files availble via FTP.
tftp-root=$temp_dir/tftpboot

# The boot filename.
dhcp-boot=$temp_dir/tftpboot/syslinux/pxelinux.0

# rootpath option, for NFS
dhcp-option=17,/cdrom

# kill multicast
dhcp-option=vendor:PXEClient,6,2b

# Disable re-use of the DHCP servername and filename fields as extra
# option space. That's to avoid confusing some old or broken DHCP clients.
dhcp-no-override

# PXE menu
# pxe-prompt="Press F8 for boot menu", 3

# The known types are x86PC, PC98, IA64_EFI, Alpha, Arc_x86,
# Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI and X86-64_EFI
pxe-service=X86PC, "Boot from network", $temp_dir/tftpboot/pxelinux

# A boot service type of 0 is special, and will abort the
# net boot procedure and continue booting from local media.
#pxe-service=X86PC, "Boot from local hard disk", 0

# This range(s) is for the public interface, where dnsmasq functions
# as a proxy DHCP server providing boot information but no IP leases.
# Any ip in the subnet will do, so you may just put your server NIC ip here.
dhcp-range=$SERVER_IP,proxy

# This range(s) is for the private network on 2-NIC servers,
# where dnsmasq functions as a normal DHCP server, providing IP leases.
#dhcp-range=192.168.0.20,192.168.0.250,8h
EOF
}

check_requirements
get_temp_dir
export_cdrom
create_tftpboot
create_dnsmasq_conf
printbold "
==> Press Ctrl+C to stop sharing the live CD over NFS.
"
dnsmasq -d -C "$temp_dir/dnsmasq.conf"
