import errno
import logging
import os

from subprocess import call


def dictbool(dct, key):
    """Check if a key exists and is True in a dictionary.

    :param dct: The dictionary to check.
    :type dct: dict
    :param key: The key to check
    :type key: any
    """
    return key in dct and isinstance(dct[key], bool) and dct[key]


def getlogger(log, name):
    """Gets a logger given a logger and a package.

    Will return the given logger if the name is not generated from
    the current package, otherwise generate a logger based on __name__.

    :param log: Logger to start with.
    :type log: logging.Logger
    :param name: The __name__ of the caller.
    :type name: str
    """
    return (
        log if isinstance(log, logging.Logger)
        and not log.name.startswith(name.partition('.')[0])
        else logging.getLogger(name))


def bind(src, dest, create=False, log=None, recursive=False, **_kwargs):
    """Set up a bind mount.

    :param src: The source location to mount.
    :type src: str
    :param dest: The destination to mount on.
    :type dest: str
    :param create: Whether to create the destination.
    :type create: bool
    :param log: A logger to use for logging.
    :type log: logging.Logger
    :param recursive: Whether to use a recursive bind mount.
    :type recursive: bool
    """
    log = getlogger(log, __name__)
    if src not in ['proc', 'sysfs', 'tmpfs']:
        src = os.path.realpath(src)
    dest = os.path.realpath(dest)

    if create:
        try:
            if not os.path.isdir(src) and src not in ['proc', 'sysfs', 'tmpfs']:
                os.makedirs(os.path.dirname(dest))
            else:
                os.makedirs(dest)
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                raise

        if not os.path.isdir(src) and src not in ['proc', 'sysfs', 'tmpfs']:
            open(dest, 'w').close()

    if not os.path.exists(src) and src not in ['proc', 'sysfs', 'tmpfs']:
        raise MountError('Attempt to bind mount nonexistent source path "{}"'.format(src))
    elif not os.path.exists(dest):
        raise MountError('Attempt to bind mount on nonexistent path "{}"'.format(dest))

    if src in ['proc', 'sysfs', 'tmpfs']:
        status = call(['mount', '--no-mtab', '-t', src, src, dest])
    else:
        # do the bind mount by shelling out to mount
        log.debug("  Bind mounting '{}' on '{}'".format(src, dest))
        status = call(['mount', '--no-mtab', '--rbind' if recursive else '--bind', src, dest])

    if status != 0:
        raise MountError('Mount failed')

        if status != 0:
            raise MountError('Mount failed')


class MountError(Exception):

    """Exception that is raised when there is an error creating a bind mount."""
    pass


# vim:et:ts=4:sw=4:tw=120:sts=4:ai:

@@ -60,16 +60,93 @@
 rt call%0A
+try:%0A    from libmount import Context%0Aexcept ImportError:%0A    Context = None%0A
 %0A%0Adef di
@@ -2339,56 +2339,110 @@
     
+f
 st
-atus = call(%5B'mount', '--no-mtab', '-t', src, 
+ype = src%0A        mount_options = %5B%5D%0A        log.debug(%22  mounting '%7B%7D' filesystem on '%7B%7D'%22.format(
 src,
@@ -2446,17 +2446,17 @@
 rc, dest
-%5D
+)
 )%0A    el
@@ -2471,52 +2471,82 @@
     
-# do the bind mount by shelling out to mount
+fstype = 'none'%0A        mount_options = %5B'rbind' if recursive else 'bind'%5D
 %0A   
@@ -2567,9 +2567,9 @@
 (%22  
-B
+b
 ind 
@@ -2614,163 +2614,369 @@
 t))%0A
+%0A
     
-    status = call(%5B'mount', '--no-mtab', '--rbind' if recursive else '--bind', src, dest%5D)%0A%0A    if status != 0:%0A        raise MountError('Mount failed'
+if Context is not None:%0A        context = Context(source=src, target=dest, fstype=fstype, options=','.join(mount_options))%0A        try:%0A            context.mount()%0A        except Exception as ex:%0A            raise MountError(str(ex))%0A    else:%0A        status = call(%5B'mount', '--no-mtab', '--types', fstype, '--options', ','.join(mount_options), src, dest%5D
 )%0A%0A 

use libmount from util-linux if it is installed rather than shelling out