#! /bin/sh
set -e

export LC_ALL=C

( . "${LIVE_BUILD}/scripts/build.sh" > /dev/null 2>&1 || true ) || . /usr/lib/live/build.sh

Arguments "${@}"

Read_conffiles config/all config/common config/bootstrap config/chroot config/binary config/source
Set_defaults

if [ -z "${PROJECT:-}" ]; then
    echo "PROJECT environment variable has to be set" >&2
    exit 1
fi

if [ "${IMAGEFORMAT:-}" = "ubuntu-image" ]; then
	# Use ubuntu-image instead of live-build
	env SNAPPY_STORE_NO_CDN=1 \
	ubuntu-image -c edge \
		-o livecd."$PROJECT".img livecd."$PROJECT".model-assertion
	xz -0 -T4 livecd."$PROJECT".img
	exit 0
fi

# Setup cleanup function
Setup_cleanup

preinstall_snaps() {
	lb chroot_resolv install
	chroot chroot sh -c '
		set -x;
		cd /var/lib/snapd/seed;
		SNAPPY_STORE_NO_CDN=1 snap download core'
	for snap in "$@"; do
		chroot chroot sh -c "
			set -x;
			cd /var/lib/snapd/seed;
			SNAPPY_STORE_NO_CDN=1 snap download \"$snap\""
	done
	lb chroot_resolv remove

	CORE_SNAP=$(cd chroot/var/lib/snapd/seed; ls -1 core_*.snap)

	cat <<EOF > chroot/var/lib/snapd/seed/seed.yaml
snaps:
 - name: core
   channel: stable
   file: ${CORE_SNAP}
EOF
	for snap in "$@"; do
		cat <<EOF >> chroot/var/lib/snapd/seed/seed.yaml
 - name: $snap
   channel: stable
EOF
		echo -n "   file: " >> chroot/var/lib/snapd/seed/seed.yaml
		(cd chroot/var/lib/snapd/seed; ls -1 ${snap}_*.snap) \
			>> chroot/var/lib/snapd/seed/seed.yaml
	done

	mkdir -p chroot/var/lib/snapd/seed/snaps \
		chroot/var/lib/snapd/seed/assertions
	mv chroot/var/lib/snapd/seed/*.assert \
		chroot/var/lib/snapd/seed/assertions/
	mv chroot/var/lib/snapd/seed/*.snap chroot/var/lib/snapd/seed/snaps/
}

rm -f binary.success
(
	if [ -d config/gnupg ]; then
		cat << @@EOF > config/gnupg/NEWKEY
Key-Type: DSA
Key-Length: 1024
Key-Usage: sign
Name-Real: Ubuntu Local Archive One-Time Signing Key
Name-Email: cdimage@ubuntu.com
Expire-Date: 0
@@EOF
		gpg --home config/gnupg --gen-key --batch < config/gnupg/NEWKEY \
			> config/gnupg/generate.log 2>&1 &
		GPG_PROCESS=$!
	fi

	lb bootstrap "$@"

	if [ "${SUBPROJECT:-}" = minimized ] \
	   && ! Chroot chroot dpkg -l tzdata 2>&1 |grep -q ^ii; then
		# workaround for tzdata purge not removing these files
		rm -f chroot/etc/localtime chroot/etc/timezone
	fi

	if [ "${SUBPROJECT:-}" = minimized ]; then
		# set up dpkg filters to skip installing docs on minimized system
		mkdir -p chroot/etc/dpkg/dpkg.cfg.d
		cat > chroot/etc/dpkg/dpkg.cfg.d/excludes <<EOF
# Drop all man pages
path-exclude=/usr/share/man/*

# Drop all documentation ...
path-exclude=/usr/share/doc/*

# ... except copyright files ...
path-include=/usr/share/doc/*/copyright

# ... and Debian changelogs
path-include=/usr/share/doc/*/changelog.Debian.*
EOF

		# Remove docs installed by bootstrap
		Chroot chroot dpkg-query -f '${binary:Package}\n' -W | Chroot chroot xargs apt-get install --reinstall

                # Add unminimizer script which restores default image behavior
                mkdir -p chroot/usr/local/sbin
                cat > chroot/usr/local/sbin/unminimize <<'EOF'
#!/bin/sh

set -e

echo "This system has been minimized by removing packages and content that are"
echo "not required on a system that users do not log into."
echo ""
echo "This script restores the content and packages that are found on a default"
echo "Ubuntu server system."
echo ""
echo "Reinstallation of packages may fail due to changes to the system"
echo "configuration, the presence of third-party packages, or for other"
echo "reasons."
read -p "Would you like to continue? [y/N]" REPLY
echo    # (optional) move to a new line
if [ "$REPLY" != "y" ] && [ "$REPLY" != "Y" ]
then
    exit 1
fi

if [ -f /etc/dpkg/dpkg.cfg.d/excludes ] || [ -f /etc/dpkg/dpkg.cfg.d/excludes.dpkg-tmp ]; then
    echo "Re-enabling installation of all documentation in dpkg..."
    if [ -f /etc/dpkg/dpkg.cfg.d/excludes ]; then
        mv /etc/dpkg/dpkg.cfg.d/excludes /etc/dpkg/dpkg.cfg.d/excludes.dpkg-tmp
    fi
    echo "Updating package list and upgrading packages..."
    apt-get update
    # apt-get upgrade asks for confirmation before upgrading packages to let the user stop here
    apt-get upgrade
    echo "Restoring system documentation..."
    echo "Reinstalling packages with files in /usr/share/man/ ..."
    # Reinstallation takes place in two steps because a single dpkg --verified
    # command generates very long parameter list for "xargs dpkg -S" and may go
    # over ARG_MAX. Since many packages have man pages the second download
    # handles a much smaller amount of packages.
    dpkg -S /usr/share/man/ |sed 's|, |\n|g;s|: [^:]*$||' | DEBIAN_FRONTEND=noninteractive xargs apt-get install --reinstall -y
    echo "Reinstalling packages with system documentation in /usr/share/doc/ .."
    # This step processes the packages which still have missing documentation
    dpkg --verify --verify-format rpm | awk '/..5......   \/usr\/share\/doc/ {print $2}' | sed 's|/[^/]*$||' | sort |uniq \
         | xargs dpkg -S | sed 's|, |\n|g;s|: [^:]*$||' | uniq | DEBIAN_FRONTEND=noninteractive xargs apt-get install --reinstall -y
    if dpkg --verify --verify-format rpm | awk '/..5......   \/usr\/share\/doc/ {exit 1}'; then
        echo "Documentation has been restored successfully."
        rm /etc/dpkg/dpkg.cfg.d/excludes.dpkg-tmp
    else
        echo "There are still files missing from /usr/share/doc/:"
        dpkg --verify --verify-format rpm | awk '/..5......   \/usr\/share\/doc/ {print " " $2}'
        echo "You may want to try running this script again or you can remove"
        echo "/etc/dpkg/dpkg.cfg.d/excludes.dpkg-tmp and restore the files manually."
    fi
fi

if ! dpkg-query --show --showformat='${db:Status-Status}\n' ubuntu-minimal 2> /dev/null | grep -q '^installed$'; then
    echo "Installing ubuntu-minimal package to provide the familiar Ubuntu minimal system..."
    DEBIAN_FRONTEND=noninteractive apt-get install -y ubuntu-minimal
fi

# unminimization succeeded, there is no need to mention it in motd
rm -f /etc/update-motd.d/60-unminimize

EOF
                chmod +x chroot/usr/local/sbin/unminimize

		# inform users about the unminimize script
		cat > "chroot/etc/update-motd.d/60-unminimize" << EOF
#!/bin/sh
#
# This file is not managed by a package.  If you no longer want to
# see this message you can safely remove the file.
echo "This system has been minimized by removing packages and content that are"
echo "not required on a system that users do not log into."
echo ""
echo "To restore this content, you can run the 'unminimize' command."
EOF

		chmod +x chroot/etc/update-motd.d/60-unminimize
        fi
	Chroot chroot "dpkg-divert --quiet --add \
		--divert /usr/sbin/update-initramfs.REAL --rename \
		/usr/sbin/update-initramfs"
	cat > chroot/usr/sbin/update-initramfs <<'EOF'
#! /bin/sh
if [ $# != 1 ] || [ "$1" != -u ]; then
	exec update-initramfs.REAL "$@"
fi
echo "update-initramfs: diverted by livecd-rootfs (will be called later)" >&2
exit 0
EOF
	chmod +x chroot/usr/sbin/update-initramfs

	cat > config/hooks/999-undivert-update-initramfs.chroot <<'EOF'
#! /bin/sh
rm -f /usr/sbin/update-initramfs
dpkg-divert --quiet --remove --rename /usr/sbin/update-initramfs
EOF

	lb chroot "$@"

	if [ -f config/oem-config-preinstalled ]; then

# This is cargo-culted almost verbatim (with some syntax changes for
# preinstalled being slightly different in what it doesn't ask) from
# debian-installer's apt-setup:

cat > chroot/etc/apt/sources.list << EOF
# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION main restricted
# deb-src $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION main restricted

## Major bug fix updates produced after the final release of the
## distribution.
deb $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION-updates main restricted
# deb-src $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION universe
# deb-src $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION universe
deb $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION-updates universe
# deb-src $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION multiverse
# deb-src $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION multiverse
deb $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION-updates multiverse
# deb-src $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION-updates multiverse

## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION-backports main restricted universe multiverse
# deb-src $LB_PARENT_MIRROR_BINARY $LB_DISTRIBUTION-backports main restricted universe multiverse

## Uncomment the following two lines to add software from Canonical's
## 'partner' repository.
## This software is not part of Ubuntu, but is offered by Canonical and the
## respective vendors as a service to Ubuntu users.
# deb http://archive.canonical.com/ubuntu $LB_DISTRIBUTION partner
# deb-src http://archive.canonical.com/ubuntu $LB_DISTRIBUTION partner

deb $LB_PARENT_MIRROR_BINARY_SECURITY $LB_DISTRIBUTION-security main restricted
# deb-src $LB_PARENT_MIRROR_BINARY_SECURITY $LB_DISTRIBUTION-security main restricted
deb $LB_PARENT_MIRROR_BINARY_SECURITY $LB_DISTRIBUTION-security universe
# deb-src $LB_PARENT_MIRROR_BINARY_SECURITY $LB_DISTRIBUTION-security universe
deb $LB_PARENT_MIRROR_BINARY_SECURITY $LB_DISTRIBUTION-security multiverse
# deb-src $LB_PARENT_MIRROR_BINARY_SECURITY $LB_DISTRIBUTION-security multiverse
EOF

	fi
	if [ -d chroot/var/lib/preinstalled-pool ]; then
		cat > config/indices/apt.conf <<-EOF
Dir {
 ArchiveDir "chroot/var/lib/preinstalled-pool";
 OverrideDir "config/indices";
 CacheDir "config/indices";
}
Default { Packages::Compress ". bzip2"; }
TreeDefault { Directory "pool"; }
Tree "dists/$LB_DISTRIBUTION"
{
 Sections "$LB_PARENT_ARCHIVE_AREAS";
 Architectures "$LB_ARCHITECTURES";
 BinOverride "override.$LB_DISTRIBUTION.\$(SECTION)";
 ExtraOverride "override.$LB_DISTRIBUTION.extra.\$(SECTION)";
 Contents " ";
}
EOF
		for component in $LB_PARENT_ARCHIVE_AREAS; do
			mkdir -p chroot/var/lib/preinstalled-pool/dists/$LB_DISTRIBUTION/$component/binary-$LB_ARCHITECTURES
		done
		apt-ftparchive generate config/indices/apt.conf
		cat << @@EOF > chroot/etc/apt/sources.list.preinstall
# This is a sources.list entry for a small pool of packages
# provided on your preinstalled filesystem for your convenience.
#
# It is perfectly safe to delete both this entry and the directory
# it references, should you want to save disk space and fetch the
# packages remotely instead.
#
deb file:/var/lib/preinstalled-pool/ $LB_DISTRIBUTION $LB_PARENT_ARCHIVE_AREAS
#
@@EOF

		cp chroot/etc/apt/sources.list chroot/etc/apt/sources.list.orig
		cp chroot/etc/apt/sources.list.preinstall chroot/etc/apt/sources.list

		echo "Waiting on gnupg ("$GPG_PROCESS") to finish generating a key."
		wait $GPG_PROCESS

		R_ORIGIN=$(lsb_release -i -s)
		R_CODENAME=$(lsb_release -c -s)
		R_VERSION=$(lsb_release -r -s)
		R_PRETTYNAME=$(echo $R_CODENAME | sed -e 's/^\(.\)/\U\1/')

		apt-ftparchive -o APT::FTPArchive::Release::Origin=$R_ORIGIN \
			-o APT::FTPArchive::Release::Label=$R_ORIGIN \
			-o APT::FTPArchive::Release::Suite=$R_CODENAME-local \
			-o APT::FTPArchive::Release::Version=$R_VERSION \
			-o APT::FTPArchive::Release::Codename=$R_CODENAME \
			-o APT::FTPArchive::Release::Description="$R_ORIGIN $R_PRETTYNAME Local" \
			release chroot/var/lib/preinstalled-pool/dists/$R_CODENAME/ \
				> config/gnupg/Release

		gpg --home config/gnupg --detach-sign --armor config/gnupg/Release
		mv config/gnupg/Release \
			chroot/var/lib/preinstalled-pool/dists/$R_CODENAME/Release
		mv config/gnupg/Release.asc \
			chroot/var/lib/preinstalled-pool/dists/$R_CODENAME/Release.gpg
		apt-key --keyring chroot/etc/apt/trusted.gpg add config/gnupg/pubring.gpg
		find chroot/var/lib/preinstalled-pool/ -name Packages | xargs rm

		Chroot chroot "apt-get update"
		cat chroot/etc/apt/sources.list.preinstall chroot/etc/apt/sources.list.orig \
			> chroot/etc/apt/sources.list
		rm chroot/etc/apt/sources.list.preinstall chroot/etc/apt/sources.list.orig
	fi
	case $PROJECT:$SUBPROJECT in
		ubuntu-server:live|ubuntu-mate:*)
			assertions_dir="chroot/var/lib/snapd/seed/assertions"
			model_assertion="$assertions_dir/generic-classic.model"
			account_key_assertion="$assertions_dir/generic.account-key"
			account_assertion="$assertions_dir/generic.account"

			mkdir -p "$assertions_dir"
			snap known --remote model series=16 \
				model=generic-classic brand-id=generic \
				> "$model_assertion"
			account_key=$(sed -n -e's/sign-key-sha3-384: //p' \
				< "$model_assertion")

			snap known --remote account-key \
				public-key-sha3-384="$account_key" \
				> "$account_key_assertion"
			account=$(sed -n -e's/account-id: //p' \
				< "$account_key_assertion")

			snap known --remote account account-id=generic \
				> "$account_assertion"
			;;
	esac

	# FIXME: this should not be a hard-coded list in this script; this
	# is an interim solution for 17.10.
	case $PROJECT:$SUBPROJECT in
		ubuntu-mate:*)
			SNAP_LIST=pulsemixer
			;;
	esac
	if [ -n "$SNAP_LIST" ]; then
		preinstall_snaps $SNAP_LIST
	fi

	if [ "$PROJECT" = "ubuntu-touch" ] || [ "$PROJECT" = "ubuntu-touch-custom" ]; then
		if [ "$ARCH" = "armhf" ]; then
			INFO_DESC="$(lsb_release -d -s)"
			echo "$INFO_DESC - $ARCH ($BUILDSTAMP)" >chroot/etc/media-info
			mkdir -p chroot/var/log/installer
			Chroot chroot "ln -s /etc/media-info /var/log/installer/media-info"
		fi
	fi
	if [ "$PROJECT" = "ubuntu-cpc" ]; then
		cat > chroot/etc/cloud/build.info << EOF
build_name: server
serial: $BUILDSTAMP
EOF
	fi

	# If the image pre-installs network-manager, let it manage all devices by
	# default. Installing NM on an existing system only manages wifi and wwan via
	# /usr/lib/NetworkManager/conf.d/10-globally-managed-devices.conf. When setting
	# the global backend to NM, netplan overrides that file.
	if [ -d chroot/usr/lib/NetworkManager ]; then
		echo "===== Enabling all devices in NetworkManager ===="
		mkdir -p chroot/etc/netplan
		cat <<EOF > chroot/etc/netplan/01-network-manager-all.yaml
# Let NetworkManager manage all devices on this system
network:
  version: 2
  renderer: NetworkManager
EOF
	else
		echo "==== NetworkManager not installed ===="
	fi

	echo "===== Checking size of /usr/share/doc ====="
	echo BEGIN docdirs
	(cd chroot && find usr/share/doc -maxdepth 1 -type d | xargs du -s | sort -nr)
	echo END docdirs

	lb binary "$@"
	touch binary.success
) 2>&1 | tee binary.log

# bash has trouble with the build.sh sourcing arrangement at the top of this
# file, so we use this cheap-and-cheerful approach rather than the more
# correct 'set -o pipefail'.
if [ -e binary.success ]; then
	rm -f binary.success
else
	exit 1
fi

# Link output files somewhere BuildLiveCD will be able to find them.
PREFIX="livecd.$PROJECT${SUBARCH:+-$SUBARCH}"

case $LB_INITRAMFS in
	casper)
		INITFS="casper"
		;;

	live-boot)
		INITFS="live"
		;;

	*)
		INITFS="boot"
		;;
esac

for OUTPUT in ext2 ext3 ext4 manifest manifest-remove size squashfs; do
	[ -e "binary/$INITFS/filesystem.$OUTPUT" ] || continue
	ln "binary/$INITFS/filesystem.$OUTPUT" "$PREFIX.$OUTPUT"
	chmod 644 "$PREFIX.$OUTPUT"
done

for ISO in binary.iso binary.hybrid.iso; do
	[ -e "$ISO" ] || continue
	ln "$ISO" "$PREFIX.iso"
	chmod 644 "$PREFIX.iso"
	break
done

if [ -e "binary/$INITFS/filesystem.dir" ]; then
	(cd "binary/$INITFS/filesystem.dir/" && tar -c *) | \
		gzip -9 --rsyncable > "$PREFIX.rootfs.tar.gz"
	chmod 644 "$PREFIX.rootfs.tar.gz"
elif [ -e binary-tar.tar.gz ]; then
	cp -a binary-tar.tar.gz "$PREFIX.rootfs.tar.gz"
fi

if [ "$PROJECT:${SUBPROJECT:-}" = "ubuntu-core:system-image" ]; then
    if [ -e "binary/$INITFS/filesystem.dir" ]; then
        rootfs="binary/$INITFS/filesystem.dir"

        for dir in lib/modules lib/firmware writable meta; do
            mkdir -p $rootfs/$dir
        done

        # get a proper version from the chroot
        . $rootfs/etc/os-release
        VERSION="$(echo $PRETTY_NAME | sed 's/[^0-9.]*//g')"

        CORENAME="ubuntu-core"
        cat > $rootfs/meta/snap.yaml <<EOF
name: $CORENAME
version: $VERSION
summary: The core runtime environment for snapd
architectures: [$ARCH]
type: os
EOF

        apt-get -y install snapcraft
        snapcraft snap $rootfs

        snapfile="$(ls ${CORENAME}*.snap)"
        cp -a $snapfile $PREFIX.os.snap
    fi
fi

if [ "$PROJECT" = "ubuntu-touch" ] || [ "$PROJECT" = "ubuntu-touch-custom" ]; then
	(cd "binary/$INITFS/custom.dir/" && tar -c *) | \
		gzip -9 --rsyncable > "$PREFIX.custom.tar.gz"
	chmod 644 "$PREFIX.custom.tar.gz"
fi

# '--initramfs none' produces different manifest names.
if [ -e "binary/$INITFS/filesystem.packages" ]; then
	ln "binary/$INITFS/filesystem.packages" "$PREFIX.manifest"
	chmod 644 "$PREFIX.manifest"
fi
if [ -e "binary/$INITFS/filesystem.packages-remove" ]; then
	# Not a typo, empty manifest-remove has a single LF in it. :/
	if [ $(cat binary/$INITFS/filesystem.packages-remove | wc -c) -gt 1 ]; then
		ln "binary/$INITFS/filesystem.packages-remove" "$PREFIX.manifest-remove"
		chmod 644 "$PREFIX.manifest-remove"
	fi
fi

# ubuntu-core and ubuntu-desktop-next splits kernel stuff into a "device" tarball so
# at this point we reset it to "none" as all the work to extract it was done already
# in a binary hook
case $PROJECT:${SUBPROJECT:-} in
        ubuntu-core:system-image|ubuntu-desktop-next:system-image)

    # create device tarball (for snappy only atm)
    if [ "$PROJECT:$SUBPROJECT" = "ubuntu-core:system-image" ]; then
      case $ARCH in
          armhf)
            subarches="generic raspi2"
            ;;
          arm64)
            subarches="generic dragonboard"
            ;;
          i386|amd64|powerpc|ppc64el|s390x)
            subarches="generic"
            ;;
      esac

      # create a clean chroot
      debootstrap --variant=minbase $LB_DISTRIBUTION chroot-device $LB_PARENT_MIRROR_BOOTSTRAP

      # ... but keep the PPA setup
      cp -a chroot/etc/apt/* chroot-device/etc/apt/

      # ... and move it in place
      rm -rf chroot
      mv chroot-device chroot

      for devarch in $subarches; do
        (echo "I: creating $devarch device tarball for $ARCH"
        HERE="$(pwd)"
        set -x

        linux_package="linux-image-$devarch"
        case $ARCH in
            amd64)
              linux_package="linux-signed-image-generic"
              ;;
            arm64)
              if [ "$devarch" = "dragonboard" ]; then
                  linux_package="linux-image-snapdragon linux-firmware-snapdragon"
              fi
              ;;
            armhf)
              if [ "$devarch" = "raspi2" ]; then
                  linux_package="linux-image-raspi2"
              fi
              ;;
            ppc64el|s390x)
              echo "I: skipping kernel and device tarball for $ARCH"
              return
              ;;
        esac

        # make sure all virtual filesystems are available
        lb chroot_proc install "$@"
        lb chroot_sysfs install "$@"
        lb chroot_devpts install "$@"

        # prepare the env
        Chroot chroot "apt-get -y update"
        Chroot chroot "apt-get -y purge linux-image-*"
        Chroot chroot "apt-get -y autoremove"
        rm -rf chroot/boot/initrd.img* chroot/boot/vmlinu?-* chroot/lib/modules/* \
            chroot/boot/abi-* chroot/boot/System.map-* chroot/boot/config-*
        mkdir -p chroot/etc/initramfs-tools/conf.d
        echo "COMPRESS=lzma" >chroot/etc/initramfs-tools/conf.d/snappy-device-tarball.conf

        # install needed packages and the kernel itself
        Chroot chroot "apt-get -y install initramfs-tools-ubuntu-core linux-firmware xz-utils"
        Chroot chroot "apt-get -y install $linux_package"

        Chroot chroot "dpkg -l" > chroot/dpkg.list
        
        # clean up
        lb chroot_devpts remove "$@"
        lb chroot_sysfs remove "$@"
        lb chroot_proc remove "$@"

        # now build the actual device tarball
        TMPDIR="$(mktemp -d)"
        mkdir -p $TMPDIR/system/
        mkdir -p $TMPDIR/assets/

        cd chroot
        cp -ar lib/modules/ $TMPDIR/system/
        cp -ar lib/firmware/ $TMPDIR/system/
        # FIXME: compat with the old kernel spec/old initramfs that
        #        expects lib/{modules,firmware}
        # 
        # FIXME2: update the initramfs-tools-ubuntu-core scripts/ubuntu-core
        #         to look at the new location        
        mkdir $TMPDIR/system/lib
        ln -s $TMPDIR/system/modules $TMPDIR/system/lib
        ln -s $TMPDIR/system/firmware $TMPDIR/system/lib

        # new assets handling
        if [ -f boot/vmlinu?-*.signed ]; then
            kernel=boot/vmlinu?-*.signed
        else
            kernel=boot/vmlinu?-*
        fi

        initrd=boot/initrd.img-*

        cp -ar $initrd $TMPDIR/assets/
        cp -ar $kernel $TMPDIR/assets/
        cp -ar boot/abi-* boot/System.map-* boot/config-* $TMPDIR/assets/

        dtbs=$(find lib/firmware -type d -name 'device-tree' -print0)
        if [ -n "$dtbs" ]; then
           mv "$dtbs" $TMPDIR/assets/dtbs
           case $devarch in
               raspi2)
                   # ubuntu-device-flash does not like subdirs here, we need to tar it up
                   if [ -e $TMPDIR/assets/dtbs/overlays ]; then
                       tar -C $TMPDIR/assets/dtbs -f $TMPDIR/assets/dtbs/overlays.tgz -czv overlays
                       rm -rf $TMPDIR/assets/dtbs/overlays
                   fi
                   ;;
               dragonboard)
                   cp $TMPDIR/assets/dtbs/qcom/apq8016-sbc-snappy.dtb $TMPDIR/assets/dtbs/apq8016-sbc.dtb
                   # add special link needed by the dragonboard wifi driver
                   mkdir -p $TMPDIR/system/lib/firmware/wlan/
                   ln -s /run/macaddr0 $TMPDIR/system/lib/firmware/wlan/
                   ;;
           esac
        fi

        # copy dpkg manifest
        cp -ar dpkg.list $TMPDIR/assets

        # create hardware.yaml
        # this assumes armhf == u-boot
        # and all others grub
        # common bits
        cat > $TMPDIR/hardware.yaml << EOF
kernel: assets/$(basename $kernel)
initrd: assets/$(basename $initrd)
partition-layout: system-AB
EOF
        # arch specific ones
        if [ "$ARCH" = "armhf" ]; then
          cat >> $TMPDIR/hardware.yaml << EOF
dtbs: assets/dtbs
bootloader: u-boot
EOF
        else
          cat >> $TMPDIR/hardware.yaml << EOF
bootloader: grub
EOF
        fi

        # compress everything
        cd $TMPDIR
        tarname="device.tar.gz"
        manifestname="device.manifest"
        if [ "$devarch" = "raspi2" ];then
            tarname="raspi2.$tarname"
            manifestname="$devarch.$manifestname"
        elif [ "$devarch" = "dragonboard" ];then
            tarname="$devarch.$tarname"
            manifestname="$devarch.$manifestname"
        fi
        # create tarfile
        tar -c -z -f $HERE/$PREFIX.$tarname system assets hardware.yaml

        # create device specific manifest to track kernel dpkg version
        cp assets/dpkg.list $HERE/$PREFIX.$manifestname

        # show size of initrd and kernel in the log
        ls -lh assets/

        # dump the content list into the log
        echo "I: device tarball contents for $PREFIX.$tarname:"
        find . -type f

        # azure wants its own device tarball
        if [ "$ARCH" = "amd64" ]; then
            cp $HERE/$PREFIX.$tarname $HERE/$PREFIX.azure.$tarname
        fi

        # create snap
        snapname="kernel.snap"
        metaname=canonical-pc-linux

        if [ "$devarch" = "raspi2" ];then
            metaname=canonical-pi2-linux
            snapname="$devarch.kernel.snap"
        elif [ "$devarch" = "generic" ] && [ "$ARCH" = "armhf" ];then
            metaname=canonical-bbb-linux
        elif [ "$devarch" = "dragonboard" ] && [ "$ARCH" = "arm64" ];then
            metaname=canonical-snapdragon-linux
            snapname="$devarch.kernel.snap"
        fi

        rm -rf $HERE/snap || true
        mkdir -p $HERE/snap/meta
        cp -a $TMPDIR/assets/* $HERE/snap
        cp -a $TMPDIR/system/* $HERE/snap

        cd $HERE/snap
        kernel="$(ls vmlinuz-*)"
        initrd="$(ls initrd.img-*)"
        # old kernel spec
        ln -s $kernel vmlinuz
        ln -s $initrd initrd.img
        # new kernel spec
        ln -s $kernel kernel.img
        kvers="$(ls vmlinuz-*|sed 's/^.*vmlinuz-//;s/-[a-z.]*$//')"

        VERSION=$kvers

        cat > meta/kernel.yaml <<EOF
version: $kvers
EOF
        
        cat > meta/snap.yaml <<EOF
name: $metaname
version: $VERSION
architectures: [$ARCH]
summary: The canonical $devarch $ARCH kernel
type: kernel

kernel: $(ls vmlinuz-*)
initrd: $(ls initrd.img-*)
modules: $(ls -d lib/modules/*)
firmware: lib/firmware
EOF
        if [ -d dtbs ]; then
            printf "dtbs: dtbs/ \n" >> meta/snap.yaml
        fi
        cd $HERE

        apt-get -y install snapcraft
        snapcraft snap snap

        snapfile="$(ls $metaname*.snap)"
        cp -a $snapfile $PREFIX.$snapname
        )
      done
    fi

    LB_LINUX_FLAVOURS=none
    ;;
esac

for FLAVOUR in $LB_LINUX_FLAVOURS; do
	if [ -z "$LB_LINUX_FLAVOURS" ] || [ "$LB_LINUX_FLAVOURS" = "none" ]; then
		continue
	fi
	if [ "$FLAVOUR" = "virtual" ]; then
		# The virtual kernel is named generic in /boot
		FLAVOUR="generic"
	fi
	KVERS="$( (cd "binary/$INITFS"; ls vmlinu?-* 2>/dev/null || true) | (fgrep -v .efi || true) | sed -n "s/^vmlinu.-\\([^-]*-[^-]*-$FLAVOUR\\)$/\\1/p" )"
	if [ -z "$KVERS" ]; then
		if [ -e "binary/$INITFS/vmlinuz" ]; then
			# already renamed by ubuntu-defaults-image
			break
		fi
		echo "No kernel output for $FLAVOUR!" >&2
		exit 1
	fi
	NUMKVERS="$(set -- $KVERS; echo $#)"
	if [ "$NUMKVERS" -gt 1 ]; then
		echo "Cannot handle more than one kernel for $FLAVOUR ($KVERS)!" >&2
		exit 1
	fi
	ln "binary/$INITFS/"vmlinu?-"$KVERS" "$PREFIX.kernel-$FLAVOUR"
	if [ -e "binary/$INITFS/"vmlinu?-"$KVERS.efi.signed" ]; then
		ln "binary/$INITFS/"vmlinu?-"$KVERS.efi.signed" "$PREFIX.kernel-$FLAVOUR.efi.signed"
		chmod 644 "$PREFIX.kernel-$FLAVOUR.efi.signed"
	fi
	chmod 644 "$PREFIX.kernel-$FLAVOUR"
	if [ -e "binary/$INITFS/initrd.img-$KVERS" ]; then
		ln "binary/$INITFS/initrd.img-$KVERS" "$PREFIX.initrd-$FLAVOUR"
		chmod 644 "$PREFIX.initrd-$FLAVOUR"
	fi
done

NUMFLAVOURS="$(set -- $LB_LINUX_FLAVOURS; echo $#)"
if [ "$NUMFLAVOURS" = 1 ] && [ "$LB_LINUX_FLAVOURS" != "none" ]; then
	# only one kernel flavour
	if [ -e "binary/$INITFS/vmlinuz" ]; then
		ln "binary/$INITFS/vmlinuz" "$PREFIX.kernel"
		chmod 644 "$PREFIX.kernel"
	else
		ln -sf "$PREFIX.kernel-$LB_LINUX_FLAVOURS" "$PREFIX.kernel"
	fi
	if [ -e "binary/$INITFS/initrd.lz" ]; then
		ln "binary/$INITFS/initrd.lz" "$PREFIX.initrd"
		chmod 644 "$PREFIX.initrd"
	else
		ln -sf "$PREFIX.initrd-$LB_LINUX_FLAVOURS" "$PREFIX.initrd"
	fi
fi

if [ "$SUBARCH" = "ac100" ] || [ "$SUBARCH" = "nexus7" ]; then
	# create the md5sum and size files for which we are actually doing all this
	md5sum $PREFIX.rootfs.tar.gz >chroot/installer.md5
	wc -c $PREFIX.rootfs.tar.gz >chroot/installer.size

	INFO_DESC="$(lsb_release -d -s)"
	INFO_STAMP=$(date +20%y%m%d-%H:%M)

	echo "$INFO_DESC - $ARCH ($INFO_STAMP)" >chroot/media-info

	# make sure update-initramfs feels cosy and warm in the environment
	lb chroot_proc install "$@"
	lb chroot_sysfs install "$@"
	lb chroot_devpts install "$@"

	# re-create initrd to contain the installer.md5 file
	Chroot chroot "env FLASH_KERNEL_SKIP=1 update-initramfs -k all -t -u -v"

	# create boot.img
	Chroot chroot "abootimg --create /boot/installer-${KVERS}.img -f /boot/bootimg.cfg-$SUBARCH -r /boot/initrd.img-${KVERS} -k /boot/vmlinuz-${KVERS}"

	if [ "$SUBARCH" = "nexus7" ]; then
		# roll the android rootfs images
		mkdir -p userdata
		mv $PREFIX.rootfs.tar.gz userdata/rootfs.tar.gz
		make_ext4fs -l 6G -s $PREFIX.ext4-$FLAVOUR userdata/
		mv userdata/rootfs.tar.gz $PREFIX.rootfs.tar.gz
		ln -sf "$PREFIX.ext4-$FLAVOUR" "$PREFIX.ext4"
	fi

	# clean up
	lb chroot_devpts remove "$@"
	lb chroot_sysfs remove "$@"
	lb chroot_proc remove "$@"

	cp "chroot/boot/installer-${KVERS}.img" "$PREFIX.bootimg-$FLAVOUR"
	ln -sf "$PREFIX.bootimg-$FLAVOUR" "$PREFIX.bootimg"

fi

if [ "$PROJECT" = "ubuntu-touch" ] || [ "$PROJECT" = "ubuntu-touch-custom" ]; then
	sourceslist="chroot/etc/apt/sources.list"

	lb chroot_proc install "$@"
	lb chroot_sysfs install "$@"
	lb chroot_devpts install "$@"

	if [ -e "$PREFIX.manifest" ]; then
		 Chroot chroot "click list" | while read line; do
			 echo "click:$line" >>"$PREFIX.manifest"
		 done
	fi

	if [ -e chroot/etc/resolv.conf ]; then
		mv chroot/etc/resolv.conf chroot/etc/resolv.conf.orig
	fi
	if [ -e /etc/resolv.conf ]; then
		cp /etc/resolv.conf chroot/etc/resolv.conf
	fi

	mv "${sourceslist}" "${sourceslist}.orig"
	mv "${sourceslist}.d" "${sourceslist}.d.orig"
	echo "deb $LB_PARENT_MIRROR_CHROOT ${LB_DISTRIBUTION} main universe multiverse restricted" >$sourceslist
	Chroot chroot "apt-get -y update"
	Chroot chroot "apt-get -y install android"

	if [ "$ARCH" = "armhf" ]; then
		touchsubarches="flo mako generic"
		for subarch in $touchsubarches; do
			cp -v chroot/usr/share/android/product/*-preinstalled-system-armel+${subarch}.img\
				"${PREFIX}.system-armel+${subarch}.img"
			cp -v chroot/usr/share/android/product/*-preinstalled-recovery-armel+${subarch}.img\
				"${PREFIX}.recovery-armel+${subarch}.img"
			cp -v chroot/usr/share/android/product/*-preinstalled-boot-armhf+${subarch}.img\
				"${PREFIX}.boot-armhf+${subarch}.img"
			# drop this following line once cdimage can handle -boot-*.img
			cp -v "${PREFIX}.boot-armhf+${subarch}.img" "${PREFIX}.bootimg-${subarch}"
		done
	fi
	if [ "$ARCH" = "i386" ]; then
		touchsubarches="generic_x86"
		for subarch in $touchsubarches; do
			cp -v chroot/usr/share/android/product/*-preinstalled-system-i386+${subarch}.img\
				"${PREFIX}.system-i386+${subarch}.img"
			cp -v chroot/usr/share/android/product/*-preinstalled-recovery-i386+${subarch}.img\
				"${PREFIX}.recovery-i386+${subarch}.img"
			cp -v chroot/usr/share/android/product/*-preinstalled-boot-i386+${subarch}.img\
				"${PREFIX}.boot-i386+${subarch}.img"
			# drop this following line once cdimage can handle -boot-*.img
			cp -v "${PREFIX}.boot-i386+${subarch}.img" "${PREFIX}.bootimg-${subarch}"
		done
	fi

	lb chroot_devpts remove "$@"
	lb chroot_sysfs remove "$@"
	lb chroot_proc remove "$@"

	rm -rf chroot/etc/init/*.override
fi

# LTSP chroot building (only in 32bit and for Edubuntu (DVD))
case $PROJECT in
	edubuntu-dvd)
		if [ "$ARCH" = i386 ]; then
			echo "Building LTSP chroot"
			ltsp-build-client --base $(pwd) --mirror $LB_PARENT_MIRROR_BOOTSTRAP --arch $ARCH --dist $LB_PARENT_DISTRIBUTION --chroot ltsp-live --late-packages ldm-edubuntu-theme,plymouth-theme-edubuntu --purge-chroot --skipimage
			mkdir -p images
			mksquashfs ltsp-live images/ltsp-live.img -e cdrom
			rm -Rf ltsp-live
			if [ -f images/ltsp-live.img ]; then
				mv images/ltsp-live.img livecd.$PROJECT-ltsp.squashfs
				chmod 0644 livecd.$PROJECT-ltsp.squashfs
				rmdir --ignore-fail-on-non-empty images
			else
				echo "LTSP: Unable to build the chroot, see above for details."
			fi
		fi
		;;
esac