#!/bin/bash

#
# template script for generating plamo container for LXC
#
# ref. https://github.com/Ponce/lxc-slackware/blob/master/lxc-slackware
#      lxc-ubuntu script

MIRRORSRV=${MIRRORSRV:-"ftp.ne.jp"}
MIRRORPATH=${MIRRORPATH:-"/Linux/distributions/plamolinux"}
release=${release:-5.x}
PACKAGES=${PACKAGES:-" \
00_base/aaa_base \
00_base/attr \
00_base/acl \
00_base/bash \
00_base/bzip2 \
00_base/coreutils \
00_base/cracklib \
00_base/dcron \
00_base/dhcp \
00_base/dialog \
00_base/glibc \
00_base/etc \
00_base/file \
00_base/findutils \
00_base/gawk \
00_base/grep \
00_base/groff \
00_base/gzip \
00_base/hdsetup \
00_base/iproute2 \
00_base/iputils \
00_base/less \
00_base/libcap \
00_base/libgcc \
00_base/linux_pam \
00_base/logrotate \
00_base/man \
00_base/mlocate \
00_base/ncurses \
00_base/net_tools \
00_base/netkit_combo \
00_base/network_configs \
00_base/nvi \
00_base/openbsd_inetd \
00_base/openssh \
00_base/openssl \
00_base/procps_ng \
00_base/readline \
00_base/rsyslog \
00_base/sed \
00_base/shadow \
00_base/sudo \
00_base/sysvinit \
00_base/tar \
00_base/tcp_wrappers \
00_base/tcsh \
00_base/traceroute \
00_base/udev \
00_base/util_linux \
00_base/xz \
00_base/zlib \
00_base/libtirpc"}

if [ -r /etc/default/lxc ]; then
    . /etc/default/lxc
fi

configure_plamo()
{
    rootfs=$1
    hostname=$2

    # configure the network using the dhcp
    cat <<EOF > $rootfs/var/run/inet1-scheme
dhcp
EOF

    # set the hostname
    cat <<EOF > $rootfs/etc/HOSTNAME
$hostname
EOF
    # set minimal hosts
    cat <<EOF > $rootfs/etc/hosts
127.0.0.1 localhost $hostname
EOF

    # suppress log level output for udev
    sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf

    # /etc/fstab
    cat <<EOF > $rootfs/etc/fstab
none	/proc	proc	defaults	0 0
none	/sys	sysfs	defaults	0 0
none	/dev	tmpfs	defaults	0 0
none	/tmp	tmpfs	defaults	0 0
none	/dev/pts	devpts	gid=5,mode=620	0 0
none	/proc/bus/usb	usbfs	noauto	0 0
none	/var/lib/nfs/rpc_pipefs	rpc_pipefs	defaults	0 0
EOF

    # /etc/inittab
    cat <<EOF > /tmp/inittab.patch
--- inittab.dist	2012-01-13 15:36:32.796542568 +0900
+++ inittab	2012-01-13 15:36:15.799822828 +0900
@@ -45,12 +45,11 @@
 #
 # Note: for 'agetty' you use linespeed, line.
 # for 'getty_ps' you use line, linespeed and also use 'gettydefs'
+1:1235:respawn:/sbin/agetty 38400 console
 c1:1235:respawn:/sbin/agetty 38400 tty1 linux
 c2:1235:respawn:/sbin/agetty 38400 tty2 linux
 c3:1235:respawn:/sbin/agetty 38400 tty3 linux
 c4:1235:respawn:/sbin/agetty 38400 tty4 linux
-c5:1235:respawn:/sbin/agetty 38400 tty5 linux
-c6:12345:respawn:/sbin/agetty 38400 tty6 linux
 
 # Serial lines
 #s1:12345:respawn:/sbin/agetty 19200 ttyS0 vt100
EOF
    ( cd $rootfs/etc
        patch -p0 < /tmp/inittab.patch
        rm -f /tmp/inittab.patch
    )

    # /etc/rc.d/rc.S
    cat <<EOF > $rootfs/etc/rc.d/rc.S
#!/bin/sh

# Set the path.
PATH=/sbin:/usr/sbin:/bin:/usr/bin

#mkdir /dev/shm
#chmod 1777 /dev/shm

mknod /dev/null -m 0666 c 1 3
#mknod /dev/ppp -m 0660 c 108 0
#mknod /dev/loop0 -m 0660 b 7 0
#chgrp disk /dev/loop0
#mknod /dev/md0 -m 0660 b 9 0
#chgrp disk /dev/md0
#mknod /dev/fd0 -m 0660 b 2 0
#chgrp floppy /dev/fd0
#ln -sf /proc/self/fd /dev/fd
#ln -sf /proc/self/fd/0 /dev/stdin
#ln -sf /proc/self/fd/1 /dev/stdout
#ln -sf /proc/self/fd/2 /dev/stderr

# Start udev.
#echo "Starting udev..."
#/sbin/udevd --daemon

# Clean /etc/mtab* and create new one with a root entry.
/bin/rm -f /etc/mtab*
/sbin/mount -f -v -o remount /
/sbin/mount -f -v /proc
/sbin/mount -f -v /sys
/sbin/mount -f -v /dev

# Set the hostname.
echo -n "Set the hostname: "
if [ ! -r /etc/HOSTNAME ]; then
    # If there's no /etc/HOSTNAME, fall back on this default.
    echo "darkstar.frop.org" > /etc/HOSTNAME
fi
HOST=\`cat /etc/HOSTNAME\`
HOST=\${HOST%%.*}
echo "\$HOST."
/bin/hostname "\$HOST"
# Suppless system logs displayed into console.
if [ -x /sbin/rsyslogd ]; then
    echo "*.info /bootlog" > /bootlog.conf
    if [ ! -d /var/run ]; then
        # Workaround when /var is on non-root partition.
        mkdir /var/run
        /sbin/rsyslogd -m 0 -f /bootlog.conf
        sleep 1
        mv -f /var/run/rsyslogd.pid /
        rmdir /var/run
    else
        /sbin/rsyslogd -m 0 -f /bootlog.conf
        sleep 1
        mv -f /var/run/rsyslogd.pid /
    fi
fi

if [ ! -d /tmp ]; then
    mkdir /tmp
fi
if [ ! -d /media ]; then
    mkdir /media
fi
/sbin/mount -v -o mode=0755 -t tmpfs /media /media
/sbin/mount -v -t tmpfs /tmp /tmp
chmod 1777 /tmp
mkdir /tmp/.ICE-unix
chmod 1777 /tmp/.ICE-unix

# Clean up temporary files on the /etc and /var volume.
/bin/rm -f /etc/nologin /etc/shutdownpid /fastboot
/bin/rm -f /var/run/utmp /var/run/*.pid /var/run/*/*pid /var/run/gpm* /var/run/news/*

# Looks like we have to create this.
cat /dev/null > /var/run/utmp
/bin/chown root:utmp /var/run/utmp
/bin/chmod 664 /var/run/utmp

UNS=\`uname -s\`; UNR=\`uname -r\`; UNV=\`uname -v\`; UNM=\`uname -m\`; UNP=\`uname -p\`
makemsg () {
    /usr/bin/sed -e "s/%s/\$UNS/g" -e "s/%r/\$UNR/g" -e "s/%v/\$UNV/g" \
                 -e "s/%m/\$UNM/g" -e "s/%p/\$UNP/g" \$1.in > \$1
}
makemsg /etc/issue
makemsg /etc/motd

EOF

    # /etc/rc.d/rc.M
    cat <<EOF > /tmp/rc.M.patch
--- rc.M.orig	2013-04-26 19:44:11.740808853 +0900
+++ rc.M	2013-04-26 19:46:19.874592125 +0900
@@ -28,14 +28,6 @@
 #echo "Updating shared library links..."
 #ldconfig
 
-# Screen blanks after 15 minutes idle time.
-setterm -blank 15
-
-# Look for a CD-ROM and mount it on /cdrom if any.
-if [ -x /etc/rc.d/rc.cdrom ] ; then
-  . /etc/rc.d/rc.cdrom
-fi
-
 # Initialize ip6tables.
 #if [ -x /usr/sbin/ip6tables -a -f /etc/sysconfig/ip6tables ] ; then
 #  ip6tables-restore /etc/sysconfig/ip6tables
@@ -53,30 +45,6 @@
   fi
 fi
 
-# Initialize sysctl.
-if [ -x /sbin/sysctl -a -f /etc/sysctl.conf ] ; then
-  sysctl -p /etc/sysctl.conf
-fi
-
-# Initialize ALSA sound mixer.
-look_mod () {
-  [ -n "\$(find /lib/modules/\`uname -r\` -name \$1.ko)" ]
-}
-if [ -d /proc/asound ] ; then
-  echo "Initializing ALSA sound mixer..."
-  if look_mod snd-pcm-oss ; then
-    modprobe snd-pcm-oss
-  fi
-  if look_mod snd-seq-oss ; then
-    modprobe snd-seq-oss
-  fi
-  if [ -x /usr/sbin/alsactl -a -f /etc/asound.state ] ; then
-    alsactl restore
-  else
-    aumix -q -v75 -w75 -c75
-  fi
-fi
-
 echo "Starting services:"
 
 # Start the rsyslogd daemon.
@@ -245,6 +213,4 @@
 echo
 echo -n "The system is ready."
 
-sync
-
 # All done.
EOF

    ( cd $rootfs/etc/rc.d
        patch -p0 < /tmp/rc.M.patch
        rm -f /tmp/rc.M.patch
    )

    # /etc/rc.d/rc.inet1
    cat <<EOF > $rootfs/etc/rc.d/rc.inet1
HOSTNAME=\`cat /etc/HOSTNAME\`

# Attach the loopback device.
/sbin/ifconfig lo 127.0.0.1
/sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo

if [ -f /var/run/inet1-scheme ] ; then
  INET1_SCHEME=\`cat /var/run/inet1-scheme\`
else
  INET1_SCHEME="fixed"
fi

if [ "\$INET1_SCHEME" = "fixed" ] ; then
  IPADDR="192.168.0.100"
  NETMASK="255.255.255.0"
  NETWORK="192.168.0.0"
  BROADCAST="192.168.0.255"
  GATEWAY="192.168.0.254"
  /sbin/ifconfig eth0 \${IPADDR} broadcast \${BROADCAST} netmask \${NETMASK}

  if [ ! \$? = 0 ]; then
    cat << END
Your ethernet card was not initialized properly.
END
  fi

  if [ ! "\$GATEWAY" = "" ]; then
   /sbin/route add default gw \${GATEWAY} netmask 0.0.0.0 metric 1
  fi
elif [ "\$INET1_SCHEME" = "dhcp" -o "\$INET1_SCHEME" = "DHCP" ] ; then
  if [ -x /usr/sbin/dhclient ] ; then
    /usr/sbin/dhclient eth0
  else
    cat << END
/usr/sbin/dhclient was not found.
Please install ISC DHCP.
END
  fi
fi
EOF

    # create /dev
    ( cd $rootfs/dev
        mknod -m 666 zero c 1 5
        mknod -m 666 random c 1 8
        mknod -m 666 urandom c 1 9
        mkdir -m 755 pts
        mknod -m 666 tty c 5 0
        mknod -m 600 console c 5 1
        mknod -m 666 tty0 c 4 0
        mknod -m 666 tty1 c 4 1
        mknod -m 666 tty2 c 4 2
        mknod -m 666 tty3 c 4 3
        mknod -m 666 tty4 c 4 4
        mknod -m 666 full c 1 7
        mknod -m 600 initctl p
        mknod -m 666 ptmx c 5 2
    )

    # localtime (JST)
    ( cd $rootfs/etc
        ln -s ../usr/share/zoneinfo/Asia/Tokyo ./localtime
    )

    # root password
    echo "Please change root-password !"
    echo "root:root" | chroot $rootfs chpasswd

    return 0
}

download_plamo()
{
    cache=$1
    arch=$2
    release=$3

    # check the mini plamo was not already downloaded
    mkdir -p "$cache/partial-$release-$arch"
    if [ $? -ne 0 ]; then
        echo "Failed to create '$cache/partial-$arch' directory"
        return 1
    fi

    # download a mini plamo into a cache
    echo "Downloading Plamo-$release minimal ..."
cat<<EOF > /tmp/getpkg
#!/usr/bin/lftp
open ${MIRRORSRV}
EOF

for p in $PACKAGES
do
    cat<<EOF >> /tmp/getpkg
mget ${MIRRORPATH}/Plamo-${release}/${arch}/plamo/${p}*.t?z
EOF
done

cat <<EOF >> /tmp/getpkg
close
EOF

    cd $cache/partial-$release-$arch
    lftp -f /tmp/getpkg
    if [ $? -ne 0 ]; then
        echo "Failed to download the rootfs, aborting."
            return 1
    fi
    rm -f /tmp/getpkg

    mv "$1/partial-$release-$arch" "$1/cache-$release-$arch"


    echo "Download complete."

    return 0
}

copy_plamo()
{
    cache=$1
    arch=$2
    rootfs=$3

    # make a local copy of the mini plamo
    echo -n "Copying $cache/rootfs-$release-$arch to $rootfs ..."
    mkdir -p $rootfs
    cp -a $cache/rootfs-$release-$arch/* $rootfs || return 1
    return 0
}

install_plamo()
{
    rootfs=$1
    arch=$2
    release=$3
    cache="/var/cache/lxc/"

    mkdir -p /var/lock/subsys/
    (
	flock -n -x 200
	if [ $? -ne 0 ]; then
	    echo "Cache repository is busy."
	    return 1
	fi

	echo "Checking cache download in $cache/cache-$release-$arch ... "
	if [ ! -e "$cache/cache-$release-$arch" ]; then
            download_plamo $cache $arch $release
	    if [ $? -ne 0 ]; then
		echo "Failed to download 'plamo $release base'"
		return 1
	    fi
	fi

        echo "Installing packages to $cache/rootfs-$release-$arch ..."
        if [ ! -e "$cache/rootfs-$release-$arch" ]; then
            mkdir -p $cache/rootfs-$release-$arch            
            for package in $PACKAGES
            do
                filename=`basename $package`
                installpkg -root $cache/rootfs-$release-$arch -priority ADD $cache/cache-$release-$arch/$filename*.t?z
            done
        fi

	echo "Copy $cache/rootfs-$arch to $rootfs ... "
	copy_plamo $cache $arch $rootfs
	if [ $? -ne 0 ]; then
	    echo "Failed to copy rootfs"
	    return 1
	fi

	return 0

	) 200>/var/lock/subsys/lxc

    return $?
}

copy_configuration()
{
    path=$1
    rootfs=$2
    name=$3
    arch=$4

    if [ $arch = "i386" ]; then
        arch="i686"
    fi

    cat <<EOF >> $path/config
lxc.utsname = $name

lxc.tty = 4
lxc.pts = 1024
lxc.rootfs = $rootfs
lxc.mount  = $path/fstab
lxc.arch = $arch

lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
#lxc.cgroup.devices.allow = c 4:0 rwm
#lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
#fuse
lxc.cgroup.devices.allow = c 10:229 rwm
EOF

    cat <<EOF > $path/fstab
proc            $rootfs/proc         proc    nodev,noexec,nosuid 0 0
sysfs           $rootfs/sys          sysfs defaults  0 0
EOF

    if [ $? -ne 0 ]; then
	echo "Failed to add configuration"
	return 1
    fi

    return 0
}

trim()
{
    rootfs=$1
    release=$2

    # nothing do in Plamo Linux
}

post_process()
{
    rootfs=$1
    release=$2
    trim_container=$3

    if [ $trim_container -eq 1 ]; then
        trim $rootfs $release
    fi
}

do_bindhome()
{
    rootfs=$1
    user=$2

    # bind-mount the user's path into the container's /home
    h=`getent passwd $user | cut -d: -f 6`
    mkdir -p $rootfs/$h
    echo "$h $rootfs/$h none bind 0 0" >> $path/fstab

    # copy /etc/passwd, /etc/shadow, and /etc/group entries into container
    pwd=`getent passwd $user`
    if [ $? -ne 0 ]; then
        echo 'Warning: failed to copy password entry for $user'
    else
        echo $pwd >> $rootfs/etc/passwd
    fi
    shad=`getent shadow $user`
    echo $shad >> $rootfs/etc/shadow
}

clean()
{
    release=$1
    arch=$2
    cache="/var/cache/lxc/rootfs-$release-$arch"
    downloadcache="/var/cache/lxc/cache-$release-$arch"

    if [ ! -e $cache -o ! -e $downloadcache ]; then
	exit 0
    fi

    # lock, so we won't purge while someone is creating a repository
    (
	flock -n -x 200
	if [ $? != 0 ]; then
	    echo "Cache repository is busy."
	    exit 1
	fi

	echo -n "Purging the download cache..."
	rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
	rm --preserve-root --one-file-system -rf $downloadcache && echo "Done." || exit 1
	exit 0

    ) 200>/var/lock/subsys/lxc
}

usage()
{
    cat <<EOF
$1 -h|--help -p|--path=<path> --clean [-a|--arch] [-b|--bindhome <user>] [-r|--release] [-x|--trim]
release: 5.0
bindhome: bind <user>'s home into the container
arch: x86_64 or x86: defaults to host arch
trim: (do nothing)
EOF
    return 0
}

options=$(getopt -o a:b:hp:r:xn:c -l arch:,bindhome:,help,path:,release:,trim,name:,clean -- "$@")
if [ $? -ne 0 ]; then
    usage $(basename $0)
    exit 1
fi
eval set -- "$options"

bindhome=
arch=`uname -m`
echo $arch

trim_container=0
hostarch=$arch
while true
do
    case "$1" in
    -h|--help)      usage $0 && exit 0;;
    -p|--path)      path=$2; shift 2;;
    -n|--name)      name=$2; shift 2;;
    -c|--clean)     clean=$2; shift 2;;
    -r|--release)   release=$2; shift 2;;
    -b|--bindhome)  bindhome=$2; shift 2;;
    -a|--arch)      arch=$2; shift 2;;
    -x|--trim)      trim_container=1; shift 1;;
    --)             shift 1; break ;;
        *)              break ;;
    esac
done

if [ "$arch" == "i686" ]; then
    arch=x86
fi

if [ ! -z "$clean" -a -z "$path" ]; then
    clean || exit 1
    exit 0
fi

if [ $hostarch = "i686" -a $arch = "x86_64" ]; then
    echo "can't create amd64 container on i386"
    exit 1
fi

type installpkg
if [ $? -ne 0 ]; then
    echo "'installpkg' command is missing"
    exit 1
fi

if [ -z "$path" ]; then
    echo "'path' parameter is required"
    exit 1
fi

if [ "$(id -u)" != "0" ]; then
    echo "This script should be run as 'root'"
    exit 1
fi

rootfs=$path/rootfs

install_plamo $rootfs $arch $release
if [ $? -ne 0 ]; then
    echo "failed to install plamo $release"
    exit 1
fi

configure_plamo $rootfs $name
if [ $? -ne 0 ]; then
    echo "failed to configure ubuntu $release for a container"
    exit 1
fi

copy_configuration $path $rootfs $name $arch
if [ $? -ne 0 ]; then
    echo "failed write configuration file"
    exit 1
fi

post_process $rootfs $release $trim_container
if [ ! -z $bindhome ]; then
	do_bindhome $rootfs $bindhome
fi

if [ ! -z $clean ]; then
    clean $release $arch || exit 1
    exit 0
fi
