#!/bin/sh

#
# lxc: linux Container library

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library 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
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

. /usr/share/lxc/lxc.functions

usage() {
    echo "usage: $(basename $0) -n|--name <name> [-P|--lxcpath <lxc_path>] -- [netstat_options]" >&2
}

help() {
    usage
    echo >&2
    echo "Execute 'netstat' for the specified container." >&2
    echo >&2
    echo "  --name NAME               specify the container name" >&2
    echo "  --lxcpath LXC_PATH        use an alternate container path" >&2
    echo "  NETSTAT_OPTIONS           netstat command options (see \`netstat --help')" >&2
}

get_parent_cgroup()
{
    parent_cgroup=""

    # Obtain a list of hierarchies that contain one or more subsystems
    hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)

    # Iterate through the list until a suitable hierarchy is found
    for hierarchy in $hierarchies; do
        # Obtain information about the init process in the hierarchy
        fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
        if [ -z "$fields" ]; then continue; fi
        fields=${fields#*:}

        # Get a comma-separated list of the hierarchy's subsystems
        subsystems=${fields%:*}

        # Get the cgroup of the init process in the hierarchy
        init_cgroup=${fields#*:}

        # Get the filesystem mountpoint of the hierarchy
        mountpoint=$(awk -v subsysregex="(^|,)$subsystems(,|\$)" \
            '$3 == "cgroup" && $4 ~ subsysregex {print $2}' /proc/self/mounts)
        if [ -z "$mountpoint" ]; then continue; fi

        # Return the absolute path to the containers' parent cgroup
        # (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
        case ",$subsystems," in
            *,ns,*) parent_cgroup="${mountpoint}${init_cgroup%/}";;
            *) parent_cgroup="${mountpoint}${init_cgroup%/}/lxc";;
        esac
        break
    done
}

exec=""

while true; do
    case $1 in
        -h|--help)
            help; exit 1;;
        -n)
            # If we already have a value for $name, treat -n as being an
            # argument for netstat
            if [ -n "$name" ]
            then
                break
            else
                name="$2"; shift 2;
            fi
            ;;
        --name)
            name=$2; shift 2;;
	-P|--lxcpath)
            lxc_path="$2"; shift 2;;
        --exec)
            exec="exec"; shift;;
        --)
            shift; break;;
        *)
            break;;
    esac
done

if [ "$(id -u)" != "0" ]; then
    echo "$(basename $0): must be run as root" >&2
    exit 1
fi

if [ -z "$name" ]; then
    usage
    exit 1
fi

if [ -z "$lxc_path" ]; then
    echo "$(basename $0): no configuration path defined" >&2
    usage
    exit 1
fi

if [ -z "$exec" ]; then
    exec /usr/bin/lxc-unshare -s MOUNT -- $0 -n $name -P "$lxc_path" --exec -- "$@"
fi

if lxc-wait -n $name -P "$lxc_path" -s 'STOPPED' -t 0; then
    echo "$(basename $0): container '$name' is not running" >&2
    exit 1
fi

get_parent_cgroup
if [ ! -d "$parent_cgroup" ]; then
    echo "$(basename $0): no cgroup mount point found" >&2
    exit 1
fi

pid=$(head -1 $parent_cgroup/$name/tasks)

if [ -z "$pid" ]; then
    echo "$(basename $0): no process found for '$name'" >&2
    exit 1
fi

tmpdir=$(mktemp -d)

if [ -z "$tmpdir" -o ! -d "$tmpdir" ]; then
    echo "$(basename $0): unable to create temporary directory" >&2
    exit 1
fi

# Bind mount /proc/$pid/net onto /proc/net before calling 'netstat'.
# However, we can not simply bind mount on top of procfs, so we have
# to move procfs out of the way first.
mount -n --move /proc "$tmpdir" && \
    mount -n -t tmpfs tmpfs /proc && \
    mkdir /proc/root /proc/net && \
    mount -n --move "$tmpdir" /proc/root && \
    rmdir "$tmpdir" && \
    mount -n --bind /proc/root/$pid/net /proc/net && \
    exec netstat "$@"
