#!/usr/bin/env python

import os
import sys
from optparse import OptionParser
import traceback
from distutils.log import warn as printf

try:
    from procszoo.c_functions import *
except ImportError:
    this_file_absdir = os.path.dirname(os.path.abspath(__file__))
    procszoo_mod_dir = os.path.abspath("%s/.." % this_file_absdir)
    sys.path.append(procszoo_mod_dir)
    from procszoo.c_functions import *

def get_options():
    propagation_types = ["slave", "shared", "private", "unchange"]
    progname = os.path.basename(sys.argv[0]) or 'richard_parker'
    project_url = "http://github.com/xning/procszoo"
    description = """A simple cli to create new namespaces env,
default it will enable each available namespaces."""
    epilog_str = "%s is part of procszoo: %s"  % (progname, project_url)
    parser = OptionParser(
        usage="Usage: %prog [options] cmd_run_in_namespaces",
        description=description)
    parser.__dict__['origin_format_help'] = parser.format_help
    parser.__dict__['format_help'] = lambda formatter=None: (
                "%(origin_format_help)s\n%(epilog)s\n" % ({
        'origin_format_help': parser.origin_format_help(formatter),
        'epilog': epilog_str}))
    parser.add_option("-n", "--namespace", action="append", dest="namespaces",
                        help="namespace that should be create")
    parser.add_option("-N", "--negative-namespace", action="append",
                          dest="negative_namespaces",
                          help="namespace that should not be create")
    parser.add_option("-r", "--maproot", action="store_true", dest="maproot",
                          default=True,
                          help="""map current effective user/group to root/root,
implies -n user""")
    parser.add_option("--no-maproot", action="store_false",
                        dest="maproot")
    parser.add_option("-u", "--user-map", action="append", dest="users_map",
                          type="string",
                          help="user map settings, implies -n user")
    parser.add_option("-g", "--group-map", action="append", dest="groups_map",
                          type="string",
                          help="group map settings, implies -n user")
    parser.add_option("--init-program", action="store", dest="init_prog",
                          type="string",
                          help="replace the my_init program by yours")
    parser.add_option(
        "-s", "--setgroups", action="store", type="string",
        dest="setgroups",
        help="""control the setgroups syscall in user namespaces,
        when setting to 'allow' will enable --no-maproot option and avoid --user-map
        and --group-map options""")
    parser.add_option("--mountproc", action="store_true", dest="mountproc",
                        help="remount procfs mountpoin, implies --n mount",
                      default=True)
    parser.add_option("--no-mountproc", action="store_false", dest="mountproc",
                        help="do not remount procfs")
    parser.add_option("--mountpoint", action="store", type="string",
                        dest="mountpoint",
                        help="dir that the new procfs would be mounted to")
    parser.add_option("-b", "--ns_bind_dir", action="store", type="string",
                        dest="ns_bind_dir",
                        help="dir that the new namespaces would be mounted to")
    parser.add_option(
        "--propagation", action="store", type="string", dest="propagation",
        help="modify mount propagation in mount namespace: %s" %
        "|".join(propagation_types))
    parser.add_option("-l", "--list", action="store_true",
                          dest="show_ns_status", default=False,
                          help="list namespaces status")
    parser.add_option("-v", "--version", action="store_true", default=False,
                          dest="show_version")
    parser.add_option("--available-c-functions", action="store_true",
                        dest="show_available_c_functions",
                        help="show available C functions",
                        default=False)

    (options, args) = parser.parse_args()
    return options, args

def show_version_then_quit():
    printf("version: %s\n" % __version__)
    sys.exit(0)

def show_namespaces_then_quit():
    for v in show_namespaces_status():
        printf("%-6s: %-5s" % v)
    sys.exit(0)

def show_available_c_functions_and_quit():
    printf("%s" % "\n".join(workbench.show_available_c_functions()))
    sys.exit(0)

def main():
    check_namespaces_available_status()
    options, args = get_options()
    nscmd = None
    if args: nscmd = args

    if options.show_version:
        show_version_then_quit()
    if options.show_ns_status:
        show_namespaces_then_quit()
    if options.show_available_c_functions:
        show_available_c_functions_and_quit()

    _exit_code = 0
    try:
        spawn_namespaces(
            namespaces=options.namespaces,
            negative_namespaces=options.negative_namespaces,
            maproot=options.maproot,
            mountproc=options.mountproc,
            mountpoint=options.mountpoint,
            ns_bind_dir=options.ns_bind_dir,
            propagation=options.propagation,
            nscmd=nscmd, users_map=options.users_map,
            groups_map=options.groups_map,
            setgroups=options.setgroups,
            init_prog=options.init_prog)
    except UnavailableNamespaceFound as e:
        printf(e)
        _exit_code = 1
    except NamespaceRequireSuperuserPrivilege as e:
        printf(e)
        _exit_code = 1
    except SystemExit:
        _exit_code = 0
    except Exception as e:
        printf(e)
        traceback.print_exc()
        _exit_code = 1
    sys.exit(_exit_code)

if __name__ == "__main__":
    main()
