#!/bin/sh
# minc-core : Pure shell script mini container core script
#
# Copyright (C) 2014,2015 Masami Hiramatsu <masami.hiramatsu@gmail.com>
# This program is released under the MIT License, see LICENSE.

LIBEXEC=/usr/libexec/mincs
MINCCAGE=$LIBEXEC/minc-cage
MINCCORE=$LIBEXEC/minc-core
MINCDENS=$LIBEXEC/minc-dens

# Exit if any errors
set -e
test "$MINC_DEBUG" && set -x

:;: 'Ignore signal interrupts';:
trap '' INT QUIT

:;: "Ensure parameters are set";:
test "$MINC_BASEDIR"
test -d "$MINC_TMPDIR"

:;: "Save current setting parameters" ;:
env | grep ^MINC_ > $MINC_TMPDIR/settings

TRAPCMD=$MINC_BACKGROUND
if [ "$MINC_BACKGROUND" ]; then
  :;: 'Ignore SIGHUP';:
  trap "" HUP
fi

port_mapping() {
  if [ "$MINC_PORT_MAP" ] ; then
    :;: 'Map container port to host port (DNAT)';:
    for p in $MINC_PORT_MAP; do
      addmincport $MINC_IP $p
      TRAPCMD="delmincport $MINC_IP $p; $TRAPCMD"
      trap "$TRAPCMD" EXIT
    done
    echo $MINC_PORT_MAP > $MINC_TMPDIR/portmap
  fi
}

if [ $MINC_QEMU ]; then
  if [ -z "$MINC_NOPRIV" ]; then
    . $MINCDENS
    mkmincbr
    :;: 'Setup ip addr for ermine kernel';:
    export MINC_NETNSIF="tap-minc$$"
    TRAPCMD="delmincip $MINC_NETNSIF; $TRAPCMD"
    trap "$TRAPCMD" EXIT
    setmincip $MINC_NETNSIF
    export MINC_KERNEL_OPT="ip=$MINC_IP::$MINC_GWIP:$MINC_NETMASK::eth0::8.8.8.8:"
    echo $MINC_IP > $MINC_TMPDIR/ipv4
    :;: 'We do NOT use NETNS for QEMU mode';:
    MINC_NETNS=
    :;: 'But we can map ports';:
    port_mapping
  else
    MINC_KERNEL_OPT=""
  fi
fi

if [ "$MINC_NETNS" ]; then
  :;: "Setup Network Namespace";:
  ip netns add $MINC_NETNS
  TRAPCMD="ip netns del $MINC_NETNS; $TRAPCMD"
  trap "$TRAPCMD" EXIT
  IP_NETNS="ip netns exec $MINC_NETNS "
  if [ "$MINC_NETMODE" = dens ]; then
  . $MINCDENS
  mkmincbr
  :;: 'Make an vether pair';:
  export MINC_NETNSIF=veth0-$MINC_NETNS
  ip link add name $MINC_NETNSIF type veth peer name veth1-$MINC_NETNS
  addmincif veth1-$MINC_NETNS

  :;: 'Setup container internal interface';:
  TRAPCMD="delmincip $MINC_NETNSIF; $TRAPCMD"
  trap "$TRAPCMD" EXIT
  MINC_IP=`addmincip $MINC_NETNSIF $MINC_NETNS`
  echo $MINC_IP > $MINC_TMPDIR/ipv4

  port_mapping
  else # raw mode
    IF=${MINC_NETMODE#raw,}
    if [ -n "$IF" -a "$IF" != "$MINC_NETMODE" ]; then
      :;: "Move $IF to $MINC_NETNS namespace" ;:
      ip link set $IF netns $MINC_NETNS
    fi
  fi
else
  IP_NETNS=
fi

echo nameserver 8.8.8.8 > $MINC_TMPDIR/resolv.conf
[ "$MINC_UTSNAME" ] || MINC_UTSNAME=`hostname`
echo "127.0.0.1	localhost" > $MINC_TMPDIR/hosts
ip a | grep -w inet | sed 's/.*inet \([0-9.]*\)[^0-9]*.*/\1/' | xargs printf "%s\t$MINC_UTSNAME\n" >> $MINC_TMPDIR/hosts

if [ "$MINC_CPUMASK" ]; then
  :;: "Setup CPU limitations by CPUSET";:
  taskset -ap $MINC_CPUMASK $$ > /dev/null
fi

CAGECMD=`$MINCCAGE --prepare $$`
if [ "$CAGECMD" ]; then
  TRAPCMD="$CAGECMD;$TRAPCMD"
  :;: 'Setup a "cage" for the container';:
  . $MINCCAGE
fi

if [ -f "$MINC_FTRACE" ]; then
  if [ "$MINC_NOPRIV" ]; then
    echo "You can not control ftrace in non-privilege container"
    exit 1
  fi
  :;: 'Prepare ftrace script for the container';:
  cp $MINC_FTRACE $MINC_TMPDIR/ftrace.sh
  TRAPCMD="rm $MINC_TMPDIR/ftrace.sh;$TRAPCMD"
  MINC_FTRACE=$MINC_TMPDIR/ftrace.sh
fi

:;: "Prepare cleanup commands";:
trap "rm -f $MINC_TMPDIR/pid;$TRAPCMD" EXIT

:;: 'Enable interrupts for exit' ;:
trap "cat $MINC_TMPDIR/pid | xargs kill -INT" INT
trap "cat $MINC_TMPDIR/pid | xargs kill -QUIT" QUIT

:;: 'Enter new namespace and execute command';:
UNSHARE_OPT=
[ "$MINC_NOPRIV" ] && UNSHARE_OPT=--map-root-user
$IP_NETNS unshare $UNSHARE_OPT -iumpf $MINCCORE "$@"
