Build and properly escape a zfs command

    .. note::

        Input is not considered safe and will be passed through
        to_auto(from_auto('input_here')), you do not need to do so
        your self first.

def _command(source, command, flags=None, opts=None,
             property_name=None, property_value=None,
             filesystem_properties=None, pool_properties=None,
             target=None):
    '''
    Build and properly escape a zfs command

    .. note::

        Input is not considered safe and will be passed through
        to_auto(from_auto('input_here')), you do not need to do so
        your self first.

    '''
    # NOTE: start with the zfs binary and command
    cmd = [_zpool_cmd() if source == 'zpool' else _zfs_cmd(), command]

    # NOTE: append flags if we have any
    if flags is None:
        flags = []
    for flag in flags:
        cmd.append(flag)

    # NOTE: append options
    #       we pass through 'sorted' to garentee the same order
    if opts is None:
        opts = {}
    for opt in sorted(opts):
        if not isinstance(opts[opt], list):
            opts[opt] = [opts[opt]]
        for val in opts[opt]:
            cmd.append(opt)
            cmd.append(to_str(val))

    # NOTE: append filesystem properties (really just options with a key/value)
    #       we pass through 'sorted' to garentee the same order
    if filesystem_properties is None:
        filesystem_properties = {}
    for fsopt in sorted(filesystem_properties):
        cmd.append('-O' if source == 'zpool' else '-o')
        cmd.append('{key}={val}'.format(
            key=fsopt,
            val=to_auto(fsopt, filesystem_properties[fsopt], source='zfs', convert_to_human=False),
        ))

    # NOTE: append pool properties (really just options with a key/value)
    #       we pass through 'sorted' to garentee the same order
    if pool_properties is None:
        pool_properties = {}
    for fsopt in sorted(pool_properties):
        cmd.append('-o')
        cmd.append('{key}={val}'.format(
            key=fsopt,
            val=to_auto(fsopt, pool_properties[fsopt], source='zpool', convert_to_human=False),
        ))

    # NOTE: append property and value
    #       the set command takes a key=value pair, we need to support this
    if property_name is not None:
        if property_value is not None:
            if not isinstance(property_name, list):
                property_name = [property_name]
            if not isinstance(property_value, list):
                property_value = [property_value]
            for key, val in zip(property_name, property_value):
                cmd.append('{key}={val}'.format(
                    key=key,
                    val=to_auto(key, val, source=source, convert_to_human=False),
                ))
        else:
            cmd.append(property_name)

    # NOTE: append the target(s)
    if target is not None:
        if not isinstance(target, list):
            target = [target]
        for tgt in target:
            # NOTE: skip None list items
            #       we do not want to skip False and 0!
            if tgt is None:
                continue
            cmd.append(to_str(tgt))

    return ' '.join(cmd)