#!/usr/bin/python

import os
import sys
import pwd
import grp

from stat import S_ISREG, ST_MODE
from os.path import join, isdir
from optparse import OptionParser
from pprint import pformat

from rainbow.inject import inject
from rainbow.permissions import PermissionSet
from rainbow.util import make_reporter, enable_verbose_tracebacks
from rainbow.util import unshare, CLONE_NEWNS, read_envdir

enable_verbose_tracebacks()

def main():
    parser = OptionParser(version='0.1')
    parser.add_option('-v', '--verbose', default=0, action='count',
                      help='Verbosity. Repeat for more verbose output.')
    parser.add_option('-q', '--quiet', default=False, action='store_true',
                      help='Quiet. Disable all output.')
    parser.add_option('-s', '--spool', default=None,
                      help='Location of the rainbow spool.')
    parser.add_option('-e', '--envdir', default=None,
                      help="Location of an envdir describing the desired environment.")
    parser.add_option('-E', '--env', default=[], action='append',
                      help="Environment bindings to override.")
    parser.add_option('-c', '--cwd', default=None,
                      help="Working directory.")
    parser.add_option('-f', '--fd', default=[], action='append',
                      help="File descriptor number to leave open.")
    parser.add_option('-i', '--id', default=[], action='append',
                      help="ID of shared-data group.")
    parser.add_option('-o', '--option', default=[], action='append',
                      help="Options: video, audio, serial, constant-uid, x11, network.")
    parser.add_option('-p', '--permissions', default=None,
                      help="Location of a permissions.info file.")
    parser.add_option('-u', '--user', default=None,
                      help="Owning user.")
    parser.add_option('-r', '--resume-user', default=None,
                      help="Resume <user>.")
    parser.add_option('-a', '--assistant', default=None,
                      help="Task-specific assistant.")
    parser.add_option('-G', '--group', default=[], action='append',
                      help="Extra groups.")
    opts, args = parser.parse_args()
    if len(args) == 0:
        parser.print_help()
        exit(1)

    report = make_reporter(opts.verbose, opts.quiet, sys.stdout)

    def check_spool(opts):
        return opts.spool

    def check_env(opts):
        return read_envdir(opts.envdir, opts.env)

    def check_argv(args):
        return args

    def check_cwd(opts):
        return opts.cwd

    def check_fds(opts):
        return [int(s) for s in opts.fd]

    def check_owner(opts):
        p = pwd.getpwnam(opts.user)
        return p.pw_uid, p.pw_gid

    def check_groups(opts):
        return [grp.getgrnam(g)[2] for g in opts.group]

    def check_x11(opts):
        return 'x11' in opts.option

    def check_constant_uid(opts):
        return 'constant-uid' in opts.option

    def check_audio(opts):
        return 'audio' in opts.option

    def check_video(opts):
        return 'video' in opts.option

    def check_serial(opts):
        return 'serial' in opts.option

    def check_network(opts):
        return 'network' in opts.option

    def check_resume_user(opts):
      uid = None
      if opts.resume_user:
          uid = pwd.getpwnam(opts.resume_user).pw_uid
          assert 10000 <= uid and uid < 60000
      return uid

    def check_data_ids(opts):
        return opts.id

    def check_assistant(opts):
        return opts.assistant

    uid, gid = check_owner(opts)
    spool = check_spool(opts)

    # Use empty env? Use partial env? Fail unless perfect?
    env = check_env(opts)
    argv = check_argv(args)
    cwd = check_cwd(opts)

    safe_fds = check_fds(opts)

    groups = check_groups(opts)
    pset = PermissionSet(opts.permissions or [])

    # Dirty hack -- pass 'constant-uid' and 'strace' in as permissions. <MS>
    for perm in ('constant-uid', 'audio', 'video', 'serial', 'network'):
        pset._permissions.setdefault(perm, locals()['check_'+perm.replace('-','_')](opts))

    data_ids = check_data_ids(opts)
    assistant = check_assistant(opts)
    x11 = check_x11(opts)

    resume_uid = check_resume_user(opts)
    if resume_uid: report(1, "resuming uid (%d)", resume_uid)

    args = (report, spool, env, argv, cwd, pset, safe_fds, uid, gid, resume_uid, groups, data_ids, assistant, x11)
    report(1, 'rainbow:\n%s', pformat(args))

    unshare(CLONE_NEWNS)
    return inject(*args)

if __name__ == '__main__':
    main()

# vim : et sw=4 ts=4 sts=4 :
