#!/bin/bash

# A simple tool to grab and extract debian-installer netboot images.
#
# Copyright (C) 2008 Frank Lin PIAT <fpiat@klabs.be>
# latest version is available from:
#     http://wiki.debian.org/DebianInstaller/NetbootAssistant
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St - Suite 330, Boston, MA 02110, USA.

# ------------------ Declare the constants ------------------- #
TRUE="true"
FALSE= #false#
PACKAGE_NAME=di-netboot-assistant
PACKAGE_VERSION=0.37

# -------------- Initialize the global variables ------------- #
OFFLINE=$FALSE
DEBUG=$FALSE
DISOURCELIST=/etc/di-netboot-assistant/di-sources.list
SYSLINUX=/usr/lib/syslinux/
ELILO=/usr/lib/elilo/
DL_CACHE=/var/cache/di-netboot-assistant
STATUS_LIB=/var/lib/di-netboot-assistant
TEMPLATES=/etc/di-netboot-assistant
TFTP_ROOT=/var/lib/tftpboot
REPO_ALIAS=""
REWRITEPKGPATH='\(debian\|ubuntu\)-installer'
EXTRA_DL_FILES="MD5SUMS"
DI_ARGS=
TARGET_ARGS=
ARCH=
DEFAULT_ARCH=""
#MIRROR_REGEXPS=# Not defined on purpose, so user can pass the variable
umask $(umask | sed -e 's/.$/2/')              # files must be public.

if [ -f "$HOME/.di-netboot-assistant/di-netboot-assistant.conf" ]; then
	. "$HOME/.di-netboot-assistant/di-netboot-assistant.conf"
else
	if [ -f "/etc/di-netboot-assistant/di-netboot-assistant.conf" ]; then
		. "/etc/di-netboot-assistant/di-netboot-assistant.conf"
	fi
fi

VERBOSE=$FALSE
WGET_VERBOSITY="--quiet"
CURL_VERBOSITY="--silent"
RM_VERBOSITY=
MV_VERBOSITY=
CP_VERBOSITY=
TAR_VERBOSITY=

# ------------------- Declare the functions ------------------ #


# ------------------------------------------------------------ #
# usage()
#	Print script usage help.
# Parameters: release
# Returns: (EXIT STATUS) 0=Success
# ------------------------------------------------------------ #
usage() {
	cat <<XXX
Usage: $PACKAGE_NAME [options] install DI-DIST [--offline] [--arch=ARCH] [--alias=NAME]
       $PACKAGE_NAME [options] [purge|uninstall|uncache] DI-DIST [--arch=ARCH]
       $PACKAGE_NAME [options] rebuild-menu
       $PACKAGE_NAME [--help|--version|--rebuild-menu]

A simple tool to grab and extract debian-installer netboot images.

DI-DIST
	The name of a debian-installer repository (as listed in
	the file '$DISOURCELIST')

Commands:
    install      - download and extract a netboot image.
    uninstall    - remove a previously installed netboot image.
    uncache      - remove downloaded files from the cache.
    purge        - equivalent to uninstall plus uncache.
    rebuild-menu - rebuild the top level menu.

Options:
  -h, --help      Print this message and exit
  -V, --version   Print script version and exit
  -v, --verbose   Verbose messages
  --offline       Don't download the file (simply re-extract and build menu)
  --di-args=      DI arguments to be appended to "install" entry.
  --target-args=  Target system boot arguments to be appended to "install".
  --alias=NAME    Rename the downloaded repository (optional).
  --arch=ARCH     A comma separated list of architecture to Install/Purge,
                  or the keyword "all". It use the current machine's
                  architecture by default.

See the $PACKAGE_NAME(1) manual page for more information.
XXX
}

# ------------------------------------------------------------ #
# detect_current_arch()
#	Detect's the system's current architecture
# Parameters: none
# Returns: (STRING) architecture
# ------------------------------------------------------------ #
detect_current_arch() {
	local s
	if which dpkg >/dev/null 2>&1; then
		dpkg --print-architecture
	elif  which rpm >/dev/null 2>&1; then
		s=$(rpm --eval "%{_arch}")
		s=$(tr -d " " < /usr/lib/rpm/rpmrc | grep "^buildarchtranslate:$a:")
		s=$(echo $s|cut -d: -f3)
		s=$(echo $s | sed -e 's/^x86_64$/amd64/' -e 's/^sparc[0-9]*$/sparc/' -e 's/ppc[0-9]*$/powerpc/' -e 's/^armv[3456]*$/armel/' -e 's/^armv7hl$/armhf/' -e 's/^m68kmint$/m68k/')
		echo $s
	else
		echo "i386"
	fi
}

# ------------------------------------------------------------ #
# check_di_source_list()
#	Check the validity of di-source.list
# Parameters: release
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
check_di_source_list() {
	local valid_regex='^(#.*|[[:blank:]]*|[[:alnum:]_\\.-]+[	][[:alnum:]_\\.-]+[	][^	]+([	][^" ]+)+)$'

	if [ ! -f "$DISOURCELIST" ]; then
		echo "E: Debian Installer source file missing ($DISOURCELIST)" 1>&2
		return 1
	fi

	if grep -qvEl "$valid_regex"  "$DISOURCELIST" ; then
		echo -n "E: Syntax error lines #"  1>&2
		grep -vnE "$valid_regex" "$DISOURCELIST" \
			| cut -d ":" -f 1 | tr "\n" "," 1>&2
		echo " in file '$DISOURCELIST'." 1>&2
		return 1
	fi
}

# ------------------------------------------------------------ #
# list_declared_arch_for_repo()
#	List archs declared for the repository in di-sources.list
# Parameters: repository
# Returns: (STRING) List of architectures
# ------------------------------------------------------------ #
list_declared_arch_for_repo() {
	local release=$1

	echo -n "I: Declared architecures for $1 are: " 1>&2
	get_declared_arch_for_repo "$release" | tr '\n' ' ' 1>&2
	echo "" 1>&2
}

# ------------------------------------------------------------ #
# get_declared_arch_for_repo()
#	List archs declared for the repository in di-sources.list
# Parameters: repository
# Returns: (STRING) List of architectures
# ------------------------------------------------------------ #
get_declared_arch_for_repo() {
	local release=$1

	if [ "$1" ]; then
		grep -E "^$release\>" "$DISOURCELIST" | cut -f 2 | sort -u
	fi
	echo -n ""
}

# ------------------------------------------------------------ #
# print_do_not_edit_header()
#	Print a "Do no edit this file" warning
# Parameters: templatename
# Returns: (STRING) file header comment
# ------------------------------------------------------------ #
print_do_not_edit_header() {
	local templatename=$1		# Template filename

	echo "##"
	echo "## DO NOT EDIT THIS FILE"
	echo "##"
	echo "## It is automatically generated by $PACKAGE_NAME using templates"
	echo "## from $templatename "
	echo "##"
}

# ------------------------------------------------------------ #
# find_file()
#	Return the name of the first file matching criteria.
# Parameters: dir name
# Returns: (STRING) file
# ------------------------------------------------------------ #
find_file() {
	if [ "$1" -a "$2" ]; then
		find "$2" -type f -name $1 | head -n 1
	else
		echo ""
	fi
}

# ------------------------------------------------------------ #
# version_lte()
#	Compare two "software" version (like 1.2.1 and 1.3)
# Parameters: V1 V2
# Returns: (EXIT STATUS) 0=v1 <= v2, 1= V1 > V2
# ------------------------------------------------------------ #
version_lte() {
	if which dpkg > /dev/null 2>&1; then
		dpkg --compare-versions "$1" "<=" "$2"
		return $?
	else
		printf "$1\n$2\n" | sort -V | head -n 1 | grep -q "^$1\$"
		return $?
	fi
}

# ------------------------------------------------------------ #
# copy_syslinux_bin()
#	Install pxelinux binaries in the target folder.
# Parameters: src dst
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
copy_syslinux_bin() {
	local src=$1			# Source directory
	local dst=$2			# Target directory
	local c32_dir=$dst/pxelinux.cfg
	local f srcf oldbin newbin pxe_new_ver pxe_cur_ver

	[ ! "$src" -o ! "$dst" ] && return 1

	newbin=$(find_file pxelinux.0 "$src" 2>/dev/null)
	[ ! -f "$dst/pxelinux.0" -a ! -f "$newbin" ] && return 1

	pxe_new_ver="$(pxelinux_version "$newbin")"
	pxe_cur_ver="$(pxelinux_version "$dst/pxelinux.0")"
	if version_lte "$pxe_new_ver" "$pxe_cur_ver"; then
		return 0
	fi

	echo "I: Upgrading PXELinux ($pxe_cur_ver to $pxe_new_ver)"

	for f in pxelinux.0 menu.c32 vesamenu.c32; do
		srcf="$(find_file $f "$src")"
		[ "${f#*c32}" ] || f="pxelinux.cfg/$f"
		[ -L "$dst/$f" ] && rm "$dst/$f"
		if [ -f "$srcf" ]; then
			cp "$srcf" "$dst/$f"
		else
			[ -f "$dst/$f" ] && rm "$dst/$f"
		fi
	done
	# Smooth transition to vesamenu
	[ ! -f "$c32_dir/menu.c32" ] && ln -s "vesamenu.c32" $c32_dir/menu.c32
	return 0
}

# ------------------------------------------------------------ #
# copy_elilo_bin()
#	Install elilo binaries in the target folder.
# Parameters: src dst
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
copy_elilo_bin() {
	local src=$1			# Source directory
	local dst=$2			# Target directory
	local f srcf newbin elilo_new_ver elilo_cur_ver

	[ ! "$src" -o ! "$dst" ] && return 1

	newbin=$(find_file elilo.efi "$src" 2>/dev/null)
	[ ! -f "$dst/elilo.efi" -a ! -f "$newbin" ] && return 1

	elilo_new_ver="$(elilo_version "$newbin")"
	elilo_cur_ver="$(elilo_version "$dst/elilo.efi")"
	if version_lte "$elilo_new_ver" "$elilo_cur_ver"; then
		return 0
	fi

	echo "I: Upgrading elilo ($elilo_cur_ver to $elilo_new_ver)"

	for f in elilo.efi; do
		srcf="$(find_file $f "$src")"
		if [ -f "$srcf" ]; then
			cp -p "$srcf" "$dst/$f"
		else
			[ -f "$dst/$f" ] && rm "$dst/$f"
		fi
	done

	return 0
}

# ------------------------------------------------------------ #
# update_menu()
#	Create the bootloaders top menu.
# Parameters: (NONE)
# Returns: (NULL)
# ------------------------------------------------------------ #
update_menu() {
	if [ ! -d "$TFTP_ROOT/debian-installer" ]; then
		return
	fi
	cd "$TFTP_ROOT/debian-installer"

	update_pxelinux_menu
	update_elilo_menu

	if find "$TFTP_ROOT/debian-installer" -mindepth 1 -type d | grep -q "." ; then
		sed -e 's/^\s*//' > "$TFTP_ROOT/debian-installer/README.txt" <<xREADMEx
		!!! Attention !!!
		All files in this folder are managed di-netboot-assistant.

		Any modification and any added file may be canceled at any time by
		di-netboot-assistant.
xREADMEx
	else
		rm "$TFTP_ROOT/debian-installer/README.txt" > /dev/null 2>&1 || true
	fi
	rmdir --ignore-fail-on-non-empty "$TFTP_ROOT/debian-installer"
}

# ------------------------------------------------------------ #
# update_pxelinux_menu()
#	Create PXElinux bootloader top menu.
# Parameters: (NONE)
# Returns: (NULL)
# ------------------------------------------------------------ #
update_pxelinux_menu() {
	local x i

	[ ! -d "pxelinux.cfg" ] && mkdir "pxelinux.cfg"
	[ "$VERBOSE" ] && echo "I: Building PXE-Linux' top-menu"
	print_do_not_edit_header "$TEMPLATES/pxelinux.HEAD" > pxelinux.cfg/default
	if [ -n "$(find "$TFTP_ROOT/debian-installer" -type d -name pxelinux.cfg.serial-9600 2>/dev/null)" ]; then
		cp pxelinux.cfg/default pxelinux.cfg/default.serial-9600
	else
		[ -f "pxelinux.cfg/default.serial-9600" ] && rm pxelinux.cfg/default.serial-9600
	fi
	[ -f $TEMPLATES/pxelinux.HEAD ] && grep -Ev "^##" $TEMPLATES/pxelinux.HEAD >> pxelinux.cfg/default

	i=0
	for x in $(ls "$STATUS_LIB/"*.pxelinux.menu.fragment 2>/dev/null ); do
		i=$(($i + 1))
		grep -Ev "^##" $x >> pxelinux.cfg/default
		echo "" >> pxelinux.cfg/default
	done
	[ $i -eq 0 ] && rm pxelinux.cfg/default
	rm pxelinux.cfg/default.mig-bak 2>/dev/null || true

	i=0
	if [ -f "pxelinux.cfg/default.serial-9600" ]; then
		i=$(($i + 1))
		[ -f $TEMPLATES/pxelinux.HEAD ] && cat $TEMPLATES/pxelinux.HEAD >> pxelinux.cfg/default.serial-9600
		for x in "$STATUS_LIB/"*pxelinux.menu.serial-9600.fragment ; do
			grep -Ev "^##" "$x" >> pxelinux.cfg/default.serial-9600
			echo "" >> pxelinux.cfg/default.serial-9600
		done
		[ $i -eq 0 ] && rm pxelinux.cfg/default.serial-9600
	fi

	if [ -f pxelinux.cfg/default ]; then
		for x in $(sed -n -e "s,^\s*KERNEL\s[\s:/]*\(.*menu.c32\).*,\1,p " pxelinux.cfg/default | sort -u ); do
			[ ! -f ../$x ] && echo "W: Some menu binaries are missing. Install the package syslinux"
		done
	else
		find pxelinux.cfg/ -iregex '.*\(\.c32\|\.bak.*\|~\)$' \
			| xargs -r rm

		[ -d pxelinux.cfg ] && rmdir --ignore-fail-on-non-empty pxelinux.cfg
		[ ! -d pxelinux.cfg -a -e pxelinux.0 ] && rm pxelinux.0
	fi
}

# ------------------------------------------------------------ #
# update_elilo_menu()
#	Create Elilo bootloader top menu.
# Parameters: (NONE)
# Returns: (NULL)
# ------------------------------------------------------------ #
update_elilo_menu() {
	local x i

	[ "$VERBOSE" ] && echo "I: Building Elilo's top-menu"
	print_do_not_edit_header "$TEMPLATES/elilo.HEAD" > elilo.conf
	[ -f $TEMPLATES/elilo.HEAD ] && grep -Ev "^##" "$TEMPLATES/elilo.HEAD" >> elilo.conf

	i=0
	for x in $(ls "$STATUS_LIB/"*.elilo.conf.fragment 2>/dev/null ); do
		i=$(($i + 1))
		grep -Ev "^##" $x >> elilo.conf
		echo "" >> elilo.conf
	done

	if [ $i -eq 0 ]; then
		rm elilo.conf
		[ -f elilo.efi ] && rm elilo.efi
	fi
}

# ------------------------------------------------------------ #
# check_tftp_root()
#	Check that declared TFTP root directory is valid.
# Parameters: (NONE)
# Returns: (NULL)
# ------------------------------------------------------------ #
check_tftp_root() {
	if [ -z "$TFTP_ROOT" -o "$TFTP_ROOT" = "." -o "$TFTP_ROOT" = "/" ]; then
		echo "E: Invalid TFTP root specified ($TFTP_ROOT)" 1>&2
		exit 1
	fi

	if [ ! -d "$TFTP_ROOT" ]; then
		echo "E: TFTP root directory doesn't exists ($TFTP_ROOT)" 1>&2
		echo "I: Make sure you installed a tftp server like tftpd-hpa or atftpd."
		exit 1
	fi

	[ ! -d "$TFTP_ROOT/debian-installer" ] && mkdir "$TFTP_ROOT/debian-installer"
	if [ ! -w "$TFTP_ROOT/debian-installer" ]; then
		echo "E: Can't write to DI directory ($TFTP_ROOT/debian-installer)" 1>&2
		exit 1
	fi
}


#This function should be kept in sync with function "uninstall_repo" in debian/postrm

# ------------------------------------------------------------ #
# uninstall_repo()
#	Remove the specfied repository
# Parameters: dist_conf
# Returns: (EXIT STATUS) 0
# ------------------------------------------------------------ #
uninstall_repo() {
	dist_conf="$1"			# Repository's .conf file
	local s metadatabasename tarfile expand_dir dist_dir

	metadatabasename="$(echo $dist_conf | sed -e 's/\.conf$//' )"

	#remove di-netboot-assistant < 0.37 cached files.
	tarfile="$(grep -E "^[[:blank:]]*dl_file=" "$dist_conf" | sed -e 's/^[[:blank:]]*dl_file=//')"
	if [ "$(echo $tarfile | sed -n -e 's/^\(.\).*/\1/p')" = "/" ]; then
		[ -f "$tarfile" ] && rm "$tarfile"
	fi

	expand_dir="$(grep -E "^[[:blank:]]*expand_dir=" "$dist_conf" | sed -e 's/^[[:blank:]]*expand_dir=//')"
	[ "$expand_dir" != "/" -a -d "$expand_dir" ] && rm -Rf "$expand_dir"

	dist_dir="$(echo  "$expand_dir" | sed -e 's,/[^/]\+$,,')"
	rmdir --ignore-fail-on-non-empty "$dist_dir"

	s="$metadatabasename.pxelinux.menu.fragment"
	[ -f "$s" ] && rm "$s"

	s="$metadatabasename.pxelinux.menu.serial-9600.fragment"
	[ -f "$s" ] && rm "$s"

	s="$metadatabasename.elilo.conf.fragment"
	[ -f "$s" ] && rm "$s"

	rm "$dist_conf"
}

# ------------------------------------------------------------ #
# get_installed_repos()
#	List the installed repositories
# Parameters: none
# Returns: (STRINGS) Installed repos
# ------------------------------------------------------------ #
get_installed_repos() {
	find  "$STATUS_LIB/"  -name \*--\*.conf \
		| sed -e 's,^.*/,,' -e 's/--.*\.conf//' \
		| tr '\n' ' '
}

# ------------------------------------------------------------ #
# uninstall_repos()
#	Remove the specfied repository for all specified archs.
# Parameters: repo ignore_missing
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
uninstall_repos() {
	local repo="$1"			# Name of the repository
	local ignore_missing="$2"	# Don't repo.
	local a archs installed_archs installed_repos

	[ "$DEBUG" ] && set -x

	if [ ! -d "$STATUS_LIB" ]; then
		echo "E: Failed to uninstall repository, lib folder not found." 1>&2
		exit 1
	fi

	installed_archs="$(find  "$STATUS_LIB/"  -name \*$repo--\*.conf | sed -e 's/^.*--//' -e 's/\.conf//' | tr '\n' ' ')"
	if [ ! "$installed_archs" -a "$ignore_missing" != "ignore_missing" ]; then
		installed_repos="$(get_installed_repos)"
		echo "E: Repository '$repo' not installed." 1>&2
		echo "I: (installed repositories are: $installed_repos)" 1>&2
		exit 1
	fi

	[ ! "$ARCH" ] && ARCH=$DEFAULT_ARCH

	if [ "$(echo $ARCH | grep -E "\<all\>")" ]; then
		archs="$installed_archs"
	else
		archs="$(echo $ARCH | tr ',' ' ')"
	fi

	for a in $archs ; do
		if [ -f "$STATUS_LIB/$repo--$a.conf" ]; then
			uninstall_repo "$STATUS_LIB/$repo--$a.conf"
		else
			if [ "$ignore_missing" != "ignore_missing" ]; then
				echo "E: Repository '$repo' for architecture '$a' doesn't exists." 1>&2
				echo "I: (installed arch are: $(echo $installed_archs | tr "\n" " "))"
				return 1
			fi
		fi
	done

	[ "$DEBUG" ] && set +x
}


#This function should be kept in sync with function "url2filename" in debian/postrm

# ------------------------------------------------------------ #
# url2filename()
#	Convert an URL into a valid filename.
# Parameters: (PIPE) url
# Returns: (STRING) filename
# ------------------------------------------------------------ #
url2filename() {
	sed -e 's#//\+#/#g' -e 's#[^[:alnum:]@+_~\.-]#_#g'
}


#This function should be kept in sync with function "remove_repocache" in debian/postrm

# ------------------------------------------------------------ #
# remove_repocache()
#	Remove the cached file.
# Parameters: metadatafile
# Returns: (EXIT STATUS) 0
# ------------------------------------------------------------ #
remove_repocache() {
	local metadatafile="$1"		# repository to uncache
	local base file

	base=$(echo $metadatafile | sed -e 's/~~.*$//' )

	for file in $(sed -n -e 's/^[[:blank:]]*dl_file=[[:blank:]]*//p' $metadatafile); do
		rm $rm_verbosity ${base}_"$(echo $file| url2filename)"
	done

	#Purge remaing files (MD5SUMs...) if there are no more cached
	#distribution from the same repository.
	if [ ! "$(ls -1 ${base}~~*.meta | grep -v "$metadatafile")" ]; then
		rm $rm_verbosity ${base}_*
	fi

	[ -f $metadatafile ] && rm $metadatafile

}

# ------------------------------------------------------------ #
# remove_repocacheq()
#	Remove the cached file.
# Parameters: metadatafile
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
remove_repocaches() {
	local del_repo="$1"
	local ignore_missing="$2"
	local count cached_archs archs metadatafile a

	[ "$DEBUG" ] && set -x

	if [ ! -d "$DL_CACHE" ]; then
		echo "E: Failed to clean the cache, cache folder not found." 1>&2
		exit 1
	fi

	cached_archs="$(find $DL_CACHE -name "*~~$del_repo--*.meta" | sed -e 's/^.*--//' -e 's/\.meta//' | tr '\n' ' ')"
	if [ ! "$cached_archs" -a "$ignore_missing" != "ignore_missing" ]; then
		cached_repos="$(find $DL_CACHE -name \*~~\*--\*.meta | sed -e 's/^.*~~//' -e 's/--.*//' | tr '\n' ' ')"
		echo "E: Repository '$del_repo' not cached." 1>&2
		echo "I: (cached repositories are: $cached_repos)" 1>&2
		exit 1
	fi

	[ ! "$ARCH" ] && ARCH=$DEFAULT_ARCH

	if [ "$(echo $ARCH | grep -E "\<all\>")" ]; then
		archs="$cached_archs"
	else
		archs="$(echo $ARCH | tr ',' ' ')"
	fi

	for a in $archs ; do
		count=0
		for metadatafile in $(find $DL_CACHE/ -name "*~~${del_repo}--${a}.meta"); do
			remove_repocache "$metadatafile"
			count=$(( $count + 1 ))
		done

	        if [ $count -eq 0 -a "$ignore_missing" != "ignore_missing" ]; then
			echo "E: Repository '$del_repo' for architecture '$a' doesn't exists." 1>&2
			echo "I: (cached archs are: $cached_archs)" 1>&2
			exit 1
		fi
	done

	[ "$DEBUG" ] && set +x
}

# ------------------------------------------------------------ #
# check_sum()
#       Validate a file's checksum
# Parameters: csum_bin csum_file fname actual_file
# Returns: (EXIT STATUS) 0=checksum is ok, 1=checksum mismatch
# ------------------------------------------------------------ #
check_sum() {
	local csum_bin=$1		# checksum program
	local csum_file=$2		# file containing checksum
	local fname=$3			# file to check
	local actual_file=$4		# original filename
	local sum

	if [ ! -f "$actual_file" -o ! -f "$csum_file" ]; then
		return 1
	fi
	sum=$($csum_bin  $actual_file | cut -d " " -f 1)
	if ! grep -qiE "^$sum[[:blank:]]+(\./|)$fname[[:blank:]]*$" $csum_file ; then
		return 1
	fi
	return 0
}

# ------------------------------------------------------------ #
# fetch_files()
#       Download netboot image, and save them in the cache
# Parameters: relase arch baseurl repo_loc tarfile
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
fetch_files() {
	local release="$1"		# Release (or variant)
	local arch="$2"			# Architecture
	local baseurl="$3"		# Download base URL
	local repo_loc="$4"		# Destination dir
	local tarfile="$5"		# File to download
	local file givenfile metadatafile succeed getter
	local f csum_bin csum_file skip_csum url cached
	local fetch_date

	[ "$DEBUG" ] && set -x

	if [ ! "$OFFLINE" ]; then
		if which wget > /dev/null ; then
			getter="wget -c -x $WGET_VERBOSITY -O"
		elif which curl > /dev/null ; then
			getter="curl --fail $CURL_VERBOSITY -o"
		else
			echo "E: Can't download file. no download tool detected (wget or curl)." 1>&2
			return 1
		fi
	fi

	metadatafile="$DL_CACHE/$(echo ${repo_loc}~~${release}--${arch}.meta | url2filename)"

	succeed=$TRUE
	csum_bin=
	csum_file=/dev/null
	for givenfile in $EXTRA_DL_FILES $tarfile ; do
		f=$(echo $givenfile | sed -e 's#^\./##' -e 's#^/##' -e 's#//#/#g')
		url="$baseurl/$f"
		file="$DL_CACHE/$(echo $repo_loc/$f | url2filename)"
		[ -e $file.tmp ] && rm $file.tmp

		# Does the checksum of the previous file match the new one?
		cached=$FALSE
		skip_csum=$FALSE
		if [ "$givenfile" = "MD5SUMS" ]; then
			csum_bin=md5sum
			csum_file="$file.tmp"
			[ "$OFFLINE" ] && cp "$file" "$file.tmp"
			skip_csum=true
		elif [ "$csum_bin" ]; then
			if check_sum $csum_bin $csum_file $givenfile $file; then
				cached=true
				cp "$file" "$file.tmp"
				[ "$VERBOSE" ] && echo "I: File $givenfile is already cached"
			else
				[ -f "$file.tmp" ] && rm "$file.tmp"
				[ "$VERBOSE" -a "$OFFLINE" ] && echo "I: $givenfile not cached, or obsolete."
				[ "$OFFLINE" ] && succeed=$FALSE
			fi
		fi

		# Download the file, if needed.
		if [ ! "$OFFLINE" -a ! "$cached" ]; then
			[ 0$VERBOSE -eq 1 ] && echo "I: Downloading $givenfile"
			if $getter "$file.tmp" -- "$url" ; then
				if check_sum $csum_bin $csum_file $givenfile $file.tmp || [ "$skip_csum" ] ; then
					fetch_date="$(date -R)"
				else
					echo "E: Checksum verification failed (file $givenfile)." 1>&2
					break
				fi
			else
				echo "$EXTRA_DL_FILES" | tr " " "\n" | grep -qx $f || succeed=$FALSE
				echo "E: Can't download '$release' for '$arch' ($url)." 1>&2
				[ -f "$file.tmp" ] && rm $RM_VERBOSITY "$file.tmp"
				if [ -f "$file" ]; then
					echo "I: You have a previous version in your cache (see --offline option)."
				fi
			fi
		else
			if [ ! -f "$file.tmp" ]; then
				succeed=$FALSE
				echo "E: Can't process '$release' in offline mode, the file is missing:" 1>&2
				echo "E: (expecting '$file' from '$url')" 1>&2
				break
			else
				fetch_date="$( grep "^fetch_date=" "$metadatafile" | cut -d "=" -f 2- 2>/dev/null )"
				
				# Fall back, in case the file is manually added to the cache.
				[ -z "$fetch_date" ] && fetch_date="$(date -R --reference="$file.tmp" )"
			fi
		fi
	done

	if [ ! "$csum_bin" ]; then
		echo "W: No checksum found."
	fi

	[ "$VERBOSE" ] && echo "I: Moving/Removing temporary file(s)."
	for givenfile in $EXTRA_DL_FILES $tarfile ; do
		f=$(echo $givenfile | sed -e 's#^\./##' -e 's#^/##' -e 's#//#/#g')
		file="$DL_CACHE/$(echo $repo_loc/$f | url2filename)"
		if [ "$succeed" ]; then
			[ -f "$file.tmp" -a -f "$file" ] && rm $RM_VERBOSITY "$file"
			[ -f "$file.tmp" ] && mv $MV_VERBOSITY "$file.tmp" "$file"
		else
			[ -f "$file.tmp" ] && rm $RM_VERBOSITY "$file.tmp"
		fi
	done

	# Save metadata
	if [ "$succeed" ]; then
		if [ ! "$OFFLINE" ]; then
			echo "#$PACKAGE_NAME for '$release' ($arch)" > $metadatafile
			echo "format=1.0" >> $metadatafile
			echo "fetch_date=$fetch_date" >> $metadatafile
			echo "repo=$baseurl" >> $metadatafile
			echo "dl_file=$tarfile" >> $metadatafile
			echo "dist=$release" >> $metadatafile
		fi

		return 0
	else
		return 1
	fi
	[ "$DEBUG" ] && set +x
}

# ------------------------------------------------------------ #
# extract_files()
#	Extract (or copy) netboot image.
# Parameters: repo_loc file expand_dir
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
extract_files() {
	local repo_loc=$1		# Repository URL
	local file=$2			# Downloaded (tar) file
	local expand_dir=$3		# Target location fo extracted files
	local dl_file tar_opts

	file=$(echo $file | sed -e 's#^\./##' -e 's#^/##' -e 's#//#/#g')
	dl_file="$DL_CACHE/$(echo $repo_loc/$file | url2filename)"

	[ "$VERBOSE" ] && echo "I: Extracting... "

	if [ -d "$expand_dir" ]; then
		rm -Rf "$expand_dir/*"		# get existing metadata from the downloaded repository
	else
		mkdir -p "$expand_dir"
	fi
:
	tar_opts="$dl_file --directory $expand_dir --no-same-permissions"
	case "$(echo "$dl_file" | sed -e 's#^.*/##' )" in
		*.tar.gz)
			tar $TAR_VERBOSITY -zxf $tar_opts --strip-components 3 --exclude "./pxelinux.0" --exclude "./pxelinux.cfg"
			tar $TAR_VERBOSITY -zxf $tar_opts ./version.info 2>/dev/null || true
			;;
		*.tar.bz2)
			tar $TAR_VERBOSITY -jxf $tar_opts --strip-components 3 --exclude "./pxelinux.0" --exclude "./pxelinux.cfg"
			tar $TAR_VERBOSITY -jxf $tar_opts ./version.info 2>/dev/null || true
			;;
		*.img)
			cp $CP_VERBOSITY "$dl_file" "$expand_dir/$(basename "$file")"
			;;
		*)
			echo "E: Don't know how to handle (unpack...) the file: $dl_file" 1>&2
			return 1
			;;
	esac
	return 0

}


# ------------------------------------------------------------ #
# pxelinux_version()
#       Retrieve PXElinux version
# Parameters: bin
# Returns: (STRING) PXElinux version
# ------------------------------------------------------------ #
pxelinux_version() {
	local bin="$1"		# pxelinux.0 file

	if [ -f "$bin" ]; then
		tr -c '[:print:] ' '\n' < $1 | sed -n -r "/PXELINUX [.0-9]+/ s/^[^ ]* ([0-9^.]+).*/\1/ p" | sort -r | head -n 1
	else
		echo ""
	fi
}

# ------------------------------------------------------------ #
# elilo_version()
#       Retrieve Elilo version (or use timestamp as version)
# Parameters: bin
# Returns: (STRING) elilo version
# ------------------------------------------------------------ #
elilo_version() {
	local bin="$1"		# elilo.efi file

	if [ -f "$bin" ]; then
		date --reference=$bin +0.%Y-%m-%d.%H-%M-%S
	else
		echo ""
	fi
}

# ------------------------------------------------------------ #
# tweak_syslinux_arguments()
#       Tweak the kernel arguments in pxelinux configuration
#	files.
# Parameters: (PIPE) pristine configuration file
# Returns: (STRING) tweaked configuration file
# ------------------------------------------------------------ #
tweak_syslinux_arguments() {
	sed -e "/^[[:blank:]]*label[[:blank:]]\+install\$/I,/^\([[:blank:]]*label[[:blank:]]^+[^\(install\)]\|[[:blank:]]*\)\$/I{s!append \(.*\)--\(.*\)!append \1 $DI_ARGS -- \2 $TARGET_ARGS!}"
}

# ------------------------------------------------------------ #
# tweak_elilo_arguments()
#       Tweak the kernel arguments in pxelinux configuration
#	files.
# Parameters: (PIPE) pristine configuration file
# Returns: (STRING) tweaked configuration file
# ------------------------------------------------------------ #
tweak_elilo_arguments() {
	sed -e "/^[[:blank:]]*label=install\$/,/^\([[:blank:]]*label=[^\(install\)]\|[[:blank:]]*\)\$/{s!append=\"\([^\"]*\)--\([^\"]*\)*\"!append=\"\1 $DI_ARGS -- \2 $TARGET_ARGS\"!}"
}

# ------------------------------------------------------------ #
# setup_syslinux()
#       Install and configure syslinux menu.
# Parameters: (PIPE) release arch metadatabasename expand_dir 
# Returns: (EXIT STATUS) 0
# ------------------------------------------------------------ #
setup_syslinux() {
	local release=$1			# D-I image release name
	local arch=$2			# Architecture
	local metadatabasename=$3	# metadata location
	local expand_dir=$4		# Target installation dir.
	local pxelinuxbin pxelinuxcfg ver f
	local menufragment menufragment_serial9600

	pxelinuxbin="$(find "$expand_dir" -type f -name "pxelinux.0" 2>/dev/null )"
	if [ ! "$pxelinuxbin" ]; then
		return
	fi
	pxelinuxcfg="${pxelinuxbin%%.0}.cfg/default"
	ver="$(sed -ne 's/# D-I config version \(.*\)/\1/p' "$pxelinuxcfg" 2>/dev/null)"
	if [ ! -f "$pxelinuxcfg" ] || echo "${ver:-1.0}" | grep -q -v "^[12]\.0" ; then
		echo "W: The format of this image may not be supported." 1>&2
	fi
	[ ! -d "$TFTP_ROOT/debian-installer/pxelinux.cfg" ] && mkdir "$TFTP_ROOT/debian-installer/pxelinux.cfg"

	copy_syslinux_bin "$SYSLINUX" "$TFTP_ROOT/debian-installer/" || false
	if ! copy_syslinux_bin "$expand_dir" "$TFTP_ROOT/debian-installer/" ; then
		echo "E: No PXELinux menu installed. Please file a bug." 1>&2
	fi

	for f in $(find "$expand_dir" -type f -a \( -name "default" -o -name "boot.txt" -o -name '*.cfg' \) ); do
		mv "$f" "$f.ORIG"
		print_do_not_edit_header "$release netboot image" > "$f"
		sed -e "s#$REWRITEPKGPATH/$arch/#::/debian-installer/$REPO_ALIAS/$arch/#" "$f.ORIG" \
			| tweak_syslinux_arguments >> "$f"
	done
	menufragment="$metadatabasename.pxelinux.menu.fragment"
	menufragment_serial9600="$metadatabasename.pxelinux.menu.serial-9600.fragment"
	echo "## This is a fragment of syslinux/pxelinux menu file." > $menufragment
	echo "##" >> $menufragment
	echo "## DO NOT EDIT THIS FILE" >> $menufragment
	echo "##" >> $menufragment
	echo "## It is automatically generated by $PACKAGE_NAME" >> $menufragment
	echo "##" >> $menufragment

	if [ "$(find $expand_dir -type d -name pxelinux.cfg.serial-9600 2>/dev/null)" ]; then
		cp $menufragment $menufragment_serial9600
	else
		[ -f "$menufragment_serial9600" ] && rm "$menufragment_serial9600"
	fi

	# Create top-menu fragment (use the most appropriate **menu.c32) 
	echo  "LABEL ${REPO_ALIAS}-$arch" >> $menufragment
	printf "	MENU LABEL Debian Installer %-26s [SUB-MENU]\n" "($REPO_ALIAS, $arch)" >> $menufragment

	if [ "$(grep -Eiq "^[[:blank:]]*prompt[[:blank:]]+0" "$expand_dir/pxelinux.cfg/default" && grep -Eiq "^[[:blank:]]*default[[:blank:]].*/vesamenu.c32" "$expand_dir/pxelinux.cfg/default" && echo ok)" ]; then

		echo -n  "	KERNEL " >> $menufragment
		grep -Ei "^[[:blank:]]*default[[:blank:]].*/vesamenu.c32" \
			$expand_dir/pxelinux.cfg/default \
			| sed -e 's/^[[:blank:]]*default[[:blank:]]//' \
			>> $menufragment

		echo -n  "	APPEND " >> $menufragment
		if grep -qEi "^[[:blank:]]*include[[:blank:]]" $expand_dir/pxelinux.cfg/default ; then
			grep -Ei "^[[:blank:]]*include[[:blank:]]" \
				$expand_dir/pxelinux.cfg/default \
				| sed -e 's/^[[:blank:]]*include[[:blank:]]//' \
				>> $menufragment
		else
			echo   "	APPEND debian-installer/$REPO_ALIAS/$arch/pxelinux.cfg/default" >> $menufragment
		fi

	else
		echo   "	KERNEL ::/debian-installer/pxelinux.cfg/menu.c32" >> $menufragment
		echo   "	APPEND ::/debian-installer/$REPO_ALIAS/$arch/pxelinux.cfg/default" >> $menufragment
	fi

	if [ -f "$menufragment_serial9600" ]; then
		(
		echo   "LABEL ${REPO_ALIAS}-$arch"
		printf "	MENU LABEL Debian Installer %-26s [SUB-MENU]\n" "($REPO_ALIAS, $arch)"
		echo   "	KERNEL ::/debian-installer/pxelinux.cfg/menu.c32"
		echo   "	APPEND ::/debian-installer/$REPO_ALIAS/$arch/pxelinux.cfg.serial-9600/default"
		) >> $menufragment_serial9600
	fi
}

# ------------------------------------------------------------ #
# setup_elilo()
#       Install and configure elilo menu.
# Parameters: (PIPE) release arch metadatabasename expand_dir 
# Returns: (EXIT STATUS) 0
# ------------------------------------------------------------ #
setup_elilo() {
	local release=$1		# D-I image release name
	local arch=$2			# Architecture
	local metadatabasename=$3	# metadata location
	local expand_dir=$4		# Target installation dir.
	local f menufragment

	if [ ! "$(find "$expand_dir" -type f -name 'elilo.conf' )" ]; then
		return
	fi

	#Install elilo from locally installed package (if any)
	copy_elilo_bin "$ELILO" "$TFTP_ROOT/debian-installer/" || false

	#Install/Upgrade elilo with package version included in the tarball.
	if ! copy_elilo_bin "$expand_dir" "$TFTP_ROOT/debian-installer/" ; then
		echo "E: No Elilo menu installed. Please file a bug." 1>&2
	fi

	#Rewrite existing menus
	for f in $(find "$expand_dir" -type f -name 'elilo.conf' ); do
		mv "$f" "$f.ORIG"
		print_do_not_edit_header "release" > "$f"
		sed -e "s#^\([[:blank:]]*\(image\|initrd\|message\|f[0-9]\+\)=\)#\1debian-installer/$REPO_ALIAS/$arch/#" < "$f.ORIG" >> "$f"
	done

	#Create overview menu.
	menufragment="$metadatabasename.elilo.conf.fragment"
	echo "## This is a fragment of elilo menu file." > $menufragment
	echo "##" >> $menufragment
	echo "## DO NOT EDIT THIS FILE" >> $menufragment
	echo "##" >> $menufragment
	echo "## It is automatically generated by $PACKAGE_NAME" >> $menufragment
	echo "##" >> $menufragment

	echo "# ### $release ($REPO_ALIAS) $arch ### " >> $menufragment
	awk '/^image=/,/^$/' "$expand_dir/elilo.conf" \
		| tweak_elilo_arguments \
		| sed -e "s/^[[:blank:]]*label=.*$/\0-${REPO_ALIAS}-$arch/" \
		| sed -e "s/^\([[:blank:]]*description\)=\"\([^\"]\+\)\"/\1=\"\2 ($release $arch)\"/" \
		>> $menufragment
	echo "" >> $menufragment
}

# ------------------------------------------------------------ #
# install_repo_for_arch()
#	Extract/Copy the downloaded file a given arch.
# Parameters: arch release
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
install_repo_for_arch() {
	local arch=$1			# Architecture
	local release=$2		# D-I image release name
	local reg metadatabasename file fetch_date
	local metadatafile repo_orig repo_mirror expand_dir

	echo "I: Processing $release/$arch."
	[ "$DEBUG" ] && set -x

	metadatabasename="$STATUS_LIB/${REPO_ALIAS}--${arch}"
	metadatafile="$metadatabasename.conf"

	repo_orig="$(grep -E "^$release[[:blank:]]$arch\>" "$DISOURCELIST")"
	repo_mirror="$repo_orig"
	for reg in $MIRROR_REGEXPS "s=/$==" ; do
		repo_mirror="$(echo "$repo_mirror" | sed -e "$reg")"
	done

	repo="$(echo "$repo_orig" | cut -f 3 | sed -e 's#\([^:]/\)/#\1#g' -e 's#/$##' )"
	repo_mirror="$(echo "$repo_mirror" | cut -f 3 | sed -e 's#\([^:]/\)/#\1#g' -e 's#/$##' )"

	if [ -z "$repo" ]; then
		echo "E: There is no entry declared for architecture '$arch' for " 1>&2
		echo "E: repository '$release' in $DISOURCELIST" 1>&2
		list_declared_arch_for_repo "$release"
		return 1
	fi

	if [ "$release" != "$REPO_ALIAS" -a "$VERBOSE" ]; then
		echo "I: Repository '$release' filed as '$REPO_ALIAS'."
	fi

	repo_loc="$(echo $repo | sed -e 's#^[^:]\+://##')"
	expand_dir="$TFTP_ROOT/debian-installer/$REPO_ALIAS/$arch"

	file=$(grep -E "^$release[[:blank:]]$arch" "$DISOURCELIST" | cut -f 4- )
	fetch_date=""
	if ! fetch_files "$release" "$arch" "$repo_mirror" "$repo_loc" $file; then
		return 1
	fi
	if ! extract_files "$repo_loc" "$file" "$expand_dir"; then
		return 1
	fi

	# save metadata of this repository
	grep -v -E "^format=.*" \
		"$DL_CACHE/$(echo ${repo_loc}~~${release}--${arch}.meta | url2filename)" \
		| sed -e "s/^fetch_date=/format=1.0\n\0/" \
		> $metadatafile
	echo "expand_dir=$expand_dir" >> $metadatafile
	echo "di_args=$DI_ARGS" >> $metadatafile
	echo "target_args=$TARGET_ARGS" >> $metadatafile


	# PXELINUX MENUs (i386, amd64)
	setup_syslinux "$release" "$arch" "$metadatabasename" "$expand_dir"

	# ELILO MENU (ia64, and some ia32)
	setup_elilo "$release" "$arch" "$metadatabasename" "$expand_dir"

	return 0
	[ "$DEBUG" ] && set +x
}

# ------------------------------------------------------------ #
# install_repo_for_archs()
#	Extract/Copy the downloaded file for specified archs.
# Parameters: release
# Returns: (EXIT STATUS) 0=Success, 1=Error
# ------------------------------------------------------------ #
install_repo_for_archs() {
	local release="$1"		# release name to install
	local archs

	if [ -z "$release" ]; then
		echo "E: No repository specified (valid repositories are: $releases)" 1>&2
		return 1
	fi

	if ! grep -Eq "^$release\>" "$DISOURCELIST" ; then
		echo "E: Invalid repository name specified ($release)" 1>&2
		echo "I: Declared repositories are: $releases"
		return 1
	fi

	[ ! "$ARCH" ] && ARCH=$DEFAULT_ARCH

	if [ "$(echo $ARCH | grep -E "\<all\>")" ]; then
		archs="$(get_declared_arch_for_repo $release)"
	else
		archs="$(echo $ARCH | tr ',' ' ')"
	fi


	if [ -z "$( echo "$archs" | sed -e 's/[[:blank:]\?]*//g' )" ]; then
		echo "E: No architecture specified." 1>&2
		list_declared_arch_for_repo "$release"
		return 1
	fi

	for arch in $archs ; do
		if ! install_repo_for_arch $arch $release; then
			return $?
		fi
	done

	return 0
}

# ---------------------------  Main  ------------------------- #

ACTION=
COUNT=0

for option in "$@"; do
    case "$option" in
    -h | --help)
	usage
	exit 0 ;;
    -V | --version)
	echo "$PACKAGE_NAME $PACKAGE_VERSION"
	exit 0 ;;
    --arch| --arch=*)
	ARCH="$(echo $option | sed -e 's/--arch[=]\?//' -e 's/,,/,/' -e 's/^,\+//' -e 's/,\+$//' )"
	#Note:
	if [ "$(echo $ARCH | grep -E '^[[:alnum:]_,]\+$')" ]; then
		echo "E: Invalid architecture specified ($ARCH)" 1>&2
		exit 1
	fi ;;
    --alias| --alias=*)
	REPO_ALIAS="$(echo $option | sed -e 's/--alias[=]\?//' | grep -E "^[[:alnum:]_-]+$" )"
	#Note:
	if [ "$(echo $REPO_ALIAS | grep -E '^[[:alnum:]_,]\+$')" ]; then
		echo "E: Invalid alias name ($option)" 1>&2
		exit 1
	fi ;;
    --di-args=*)
	DI_ARGS="$DI_ARGS ${option#--di-args=}"
	;;
    --target-args=*)
	TARGET_ARGS="$TARGET_ARGS ${option#--target-args=}"
	;;
    --offline)
	OFFLINE=$TRUE ;;
    -v | --verbose)
	VERBOSE=$(( 0$VERBOSE + 1 ))
	if [ $VERBOSE -gt 1 ]; then
		WGET_VERBOSITY=""
		CURL_VERBOSITY=""
		RM_VERBOSITY="-v"
		MV_VERBOSITY="-v"
		CP_VERBOSITY="-v"
		TAR_VERBOSITY="-v"
	fi
	;;
    --debug)
	# This is an undocumented feature...
	DEBUG=$TRUE ;;
    --di-args| --target-args)
	echo "E: Option $option requires a value after equal sign." 1>&2
	exit 1
        ;;
    -*)
	echo "E: Unrecognized option ($option)" 1>&2
	exit 1
	;;
    rebuild-menu|install|uninstall|uncache|purge)
	#Actions are processed in the loop below
    	if [ "$ACTION" ]; then
		echo "E: Unexpected command '$option'. '$ACTION' was already specified." 1>&2
		exit 1
	fi
	ACTION=$option
	;;
    *)
	COUNT=$(( $COUNT + 1 ))
	;;
    esac
done

DEFAULT_ARCH="$(detect_current_arch)"

if ! check_di_source_list; then
	exit $?
fi

releases="$(grep -vE '^#' "$DISOURCELIST" | cut -f 1 | sort -u | tr "\n" " " | sed -e 's/^[[:blank:]]\+//' )"

if [ "$REPO_ALIAS" ]; then
	if [ "$ACTION" = "install" -a $COUNT -gt 1 ]; then
        	echo "E: Option --alias can't be used with multiple repositories." 1>&2
        	exit 1
	fi
fi

case "$ACTION" in
    '')
    	#Skip, if no action specified
    	;;
    rebuild-menu)
        if [ $COUNT -ne 0 ]; then
        	echo "E: Unexpected argument after command '$ACTION'." 1>&2
        	exit 1
	fi
        ;;
    *)
        if [ $COUNT -eq 0 ]; then
        	echo "E: No repository name was passed for '$ACTION'." 1>&2
        	[ ! "$OFFLINE" -a "$ACTION" = "install" ] && echo "I: Declared repositories are: $releases"
		cached_repos="$( find $DL_CACHE -name "*~~*--*.meta" | sed -e 's/^.*~~//' -e 's/--.*\.meta//' | sort -u | tr "\n" " " )"
		installed_repos="$(get_installed_repos)"
		purgabled_repos="$(echo $cached_repos $installed_repos | tr " " "\n" | sort -u | tr "\n" " ")"
        	[ "$ACTION" = "uncache" ] && echo "I: Cached repositories are: $cached_repos"
        	[ "$ACTION" = "uninstall" ] && echo "I: Installed repositories are: $installed_repos"
        	[ "$ACTION" = "purge" ] && echo "I: Purgable repositories are: $purgabled_repos"
        	exit 1
        fi
        ;;
esac


ACTION=
COUNT=0
for option in "$@"; do
    case "$option" in
    -*)
    	# Ignore options on this pass
    	;;
    install|uninstall|uncache|purge)
	ACTION=$option
	;;
    rebuild-menu)
	ACTION=$option
        update_menu
        ;;
    *)
	[ ! "$REPO_ALIAS" ] && REPO_ALIAS=$option
	case "$ACTION" in
		install)
			check_tftp_root
			cd "$TFTP_ROOT/debian-installer"
			if install_repo_for_archs "$option" ; then
				update_menu
			else
				rmdir --ignore-fail-on-non-empty "$TFTP_ROOT/debian-installer"
			fi
			;;
		uninstall)
			uninstall_repos "$option"
			update_menu
			;;
		uncache)
			remove_repocaches "$option"
			;;
		purge)
			uninstall_repos "$option" ignore_missing 
			update_menu
			remove_repocaches "$option" ignore_missing
			;;
		rebuild-menu)
			echo "W: Argument '$option' ignored ($ACTION expects no argument)." 1>&2
			;;
		*)
			echo "E: Unexpected keyword: '$option'. No action were specified." 1>&2
			exit 1
			;;
	esac
	COUNT=$(( $COUNT + 1 ))
    esac
done

if [ ! "$ACTION" ]; then
	usage 1>&2
	exit 1
fi

