#!/bin/sh

# $Id: create_slackware_openvz_template.sh,v 1.5 2015/05/20 09:48:11 root Exp root $
# Copyright 2014, 2015  Eric Hameleers, Eindhoven, NL 
# All rights reserved.
#
#   Permission to use, copy, modify, and distribute this software for
#   any purpose with or without fee is hereby granted, provided that
#   the above copyright notice and this permission notice appear in all
#   copies.
#
#   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
#   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
#   IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#   SUCH DAMAGE.
# -----------------------------------------------------------------------------
#

# This script creates a template for a Slackware OS, to be deployed with openvz.

# Stamp today in the filename:
THEDATE=$(date +%Y%m%d)

# Slackware version to install:
SL_VERSION=${SL_VERSION:-"14.1"}

# Slackware architecture to install:
SL_ARCH=${SL_ARCH:-"x86_64"}

# Directory suffix, arch dependent:
if [ "$SL_ARCH" = "x86_64" ]; then
  DIRSUFFIX="64"
else
  DIRSUFFIX=""
fi

# Root directory of a Slackware local mirror tree:
SL_REPO=${SL_REPO:-"/home/ftp/pub/Linux/Slackware"}

# Package root directory:
SL_PKGROOT=${SL_REPO}/slackware${DIRSUFFIX}-${SL_VERSION}/slackware${DIRSUFFIX}

# Patches root directory:
SL_PATCHROOT=${SL_REPO}/slackware${DIRSUFFIX}-${SL_VERSION}/patches/packages

# Directory where we will install the root filesystem:
VZ_ROOTDIR=${VZ_ROOTDIR:-"/mnt/openzvz_temp"}

# Directory where the template archive will be written:
OUTPUT=${OUTPUT:-"/tmp"}

# Slackware minimal package list:
SL_PKGLIST="
aaa_base
aaa_elflibs
aaa_terminfo
acl
attr
bash
bin
binutils
bison
bzip2
coreutils
cpio
cxxlibs
dcron
dev86
devs
dhcpcd
dialog
diffutils
dmidecode
e2fsprogs
elvis
etc
file
findutils
flex
floppy
gawk
gcc
glibc-solibs
glibc-zoneinfo
gnupg
gnutls
gptfdisk
grep
groff
gzip
infozip
iptables
iputils
kernel-firmware
kernel-headers
kmod
less
libmpc
libtermcap
lilo
links
logrotate
lvm2
make
man
man-pages
mkinitrd
mpfr
mtr
nano
ncurses
net-tools
network-scripts
openssh
openssl-solibs
parted
pkgtools
polkit
procps
quota
rsync
screen
sed
shadow
sharutils
slackpkg
slocate
strace
sudo
sysklogd
syslinux
sysvinit
sysvinit-scripts
tar
udev
usbutils
utempter
util-linux
wget
which
whois
xz
"
# Action!

# Some sanity checks first.
if [ ! -d ${SL_REPO} ]; then
  echo "-- Slackware repository root '${SL_REPO}' does not exist! Exiting."
  exit 1
fi

# Create output directory for template file:
mkdir -p ${OUTPUT}
if [ $? -ne 0 ]; then
  echo "-- Creation of output directory '${OUTPUT}' failed! Exiting."
  exit 1
fi

# Create working directory:
if [ ! -d ${VZ_ROOTDIR} ]; then
  mkdir -p ${VZ_ROOTDIR}
  if [ $? -ne 0 ]; then
    echo "-- Creation of working directory '${VZ_ROOTDIR}' failed! Exiting."
    exit 1
  fi
else
  echo "-- Found an existing openvz root filesystem at '${VZ_ROOTDIR}'".
  echo "-- After 10 seconds we will proceed and wipe it."
  echo "-- If you do not want to delete this, please press Ctrl-C now!"
  read -t 10 -p "-- Continue [Y/n] ?"
  if [ "x$REPLY" = "xn" -o "x$REPLY" = "xN" ]; then
    echo "-- OK: exiting now."
  fi
fi
echo
rm -rf --one-file-system ${VZ_ROOTDIR}/*
chmod 775 ${VZ_ROOTDIR}

# Find packages and install them into the temporary root:
for PKG in $(echo $SL_PKGLIST); do
  FULLPKG=$(find ${SL_PATCHROOT} -name "${PKG}-*.t?z" | grep -E "${PKG}-[^-]+-[^-]+-[^-]+.t?z")
  if [ "x${FULLPKG}" = "x" ]; then
    FULLPKG=$(find ${SL_PKGROOT} -name "${PKG}-*.t?z" | grep -E "${PKG}-[^-]+-[^-]+-[^-]+.t?z")
  else
    echo "-- $PKG found in patches"
  fi
  if [ "x${FULLPKG}" = "x" ]; then
    echo "-- Package $PKG was not found in Slackware ${SL_VERSION} !"
  else
    installpkg --terse --root ${VZ_ROOTDIR} ${FULLPKG}
  fi
done

# Next step, prepare the root filesystem for use as an openvz container.

# Clean out the unneeded stuff:
rm -f ${VZ_ROOTDIR}/boot/*
rm -f ${VZ_ROOTDIR}/tmp/[A-Za-z]*
rm -f ${VZ_ROOTDIR}/var/mail/*

# Disable unneeded services:
[ -f ${VZ_ROOTDIR}/etc/rc.d/rc.acpid ] && chmod -x ${VZ_ROOTDIR}/etc/rc.d/rc.acpid
[ -f ${VZ_ROOTDIR}/etc/rc.d/rc.pcmcia ] && chmod -x ${VZ_ROOTDIR}/etc/rc.d/rc.pcmcia
[ -f ${VZ_ROOTDIR}/etc/rc.d/rc.udev ] && chmod -x ${VZ_ROOTDIR}/etc/rc.d/rc.udev

# Remove ssh server keys - new unique keys will be generated
# at first boot of a container: 
rm -f ${VZ_ROOTDIR}/etc/ssh/*key*

# Delete /etc/mtab and make it a symlink to /proc/mounts:
rm -f ${VZ_ROOTDIR}/etc/mtab
ln -s /proc/mounts ${VZ_ROOTDIR}/etc/mtab

# Change /etc/rc.d/rc.S so that Slackware does not remove our /etc/mtab symlink:
sed -i -e '/ \/etc\/mtab/s/^/# /' ${VZ_ROOTDIR}/etc/rc.d/rc.S

# No hardware clock present:
sed -i -e '/^if \[ -x \/sbin\/hwclock/,/^fi$/s/^/#/' ${VZ_ROOTDIR}/etc/rc.d/rc.S

# We need this to skip the WRITE check at next boot, which would drop us in a
# recovery shell and halt the boot process:
sed -i -e '/^if touch \/fsrwtestfile/,/^fi$/s/^/#/' ${VZ_ROOTDIR}/etc/rc.d/rc.S

# Better to disable the root filesystem check altogether:
sed -i -e '/^if \[ ! \$READWRITE = yes/,/^fi # Done checking root filesystem/s/^/#/' ${VZ_ROOTDIR}/etc/rc.d/rc.S

# Setterm is not useful here:
sed -i -e '/\/bin\/setterm/s/^/# /' ${VZ_ROOTDIR}/etc/rc.d/rc.M

# We can not write to the hardware clock:
sed -i -e '/systohc/s/^/# /' ${VZ_ROOTDIR}/etc/rc.d/rc.6

# Skip all filesystem checks at boot:
touch ${VZ_ROOTDIR}/etc/fastboot

# Sanitize /etc/fstab :
cat <<EOT > ${VZ_ROOTDIR}/etc/fstab
devpts           /dev/pts         devpts      gid=5,mode=620   0   0
tmpfs            /dev/shm         tmpfs   defaults,nodev,nosuid,mode=1777  0   0
EOT

# Edit /etc/inittab so that console login processes are not spawned:
sed -i -e "/agetty/s/^c/#c/" ${VZ_ROOTDIR}/etc/inittab

# Reduce the number of local consoles, two should be enough:
sed -i -e '/^c3\|^c4\|^c5\|^c6/s/^/# /' ${VZ_ROOTDIR}/etc/inittab

# Edit /etc/shadow and invalidate the root password.
# The openvz tools will set the password instead:
sed -i -e '/^root/s/^root::/root:!:/' ${VZ_ROOTDIR}/etc/shadow

# Make sure we can access DNS:
cat <<EOT >> ${VZ_ROOTDIR}/etc/resolv.conf
nameserver 8.8.4.4
nameserver 8.8.8.8

EOT

# Enable a Slackware mirror for slackpkg:
cat <<EOT >> ${VZ_ROOTDIR}/etc/slackpkg/mirrors
http://mirrors.slackware.com/slackware/slackware${DIRSUFFIX}-${SL_VERSION}/
EOT

# Blacklist the l10n packages;
cat << EOT >> ${VZ_ROOTDIR}/etc/slackpkg/blacklist

# Blacklist the l10n packages;
calligra-l10n-
kde-l10n-

EOT

# Update the cache for slackpkg:
echo "-- Creating slackpkg cache, takes a few seconds..."
chroot ${VZ_ROOTDIR} /usr/sbin/slackpkg update gpg 2>/dev/null
chroot ${VZ_ROOTDIR} /usr/sbin/slackpkg update 2>/dev/null

# Create a locate cache:
echo "-- Creating locate cache, takes a few seconds..."
chroot ${VZ_ROOTDIR} /etc/cron.daily/slocate 2>/dev/null

# Compress the tree into an OpenVZ template:
echo "-- Creating the template..."
cd ${VZ_ROOTDIR}
  tar -Jcvf ${OUTPUT}/slackware-${SL_VERSION}-${SL_ARCH}-minimal-${THEDATE}.tar.xz .
  if [ $? -eq 0 ]; then
    echo "-- Created ${OUTPUT}/slackware-${SL_VERSION}-${SL_ARCH}-minimal-${THEDATE}.tar.xz"
  else
    echo "-- Non-zero exitcode, something went wrong."
  fi
cd -

