0x0000000000000000
 +'    # Copyright (C) 2011 Canonical Ltd.
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
#
# Author: Scott Moser <scott.moser@canonical.com>
# Author: Juerg Haefliger <juerg.haefliger@hp.com>
#
# This file is part of cloud-init. See LICENSE file for license information.

"""Resizefs: cloud-config module which resizes the filesystem"""

import errno
import getopt
import os
import re
import shlex
import stat
from textwrap import dedent

from cloudinit.config.schema import (
    get_schema_doc, validate_cloudconfig_schema)
from cloudinit.settings import PER_ALWAYS
from cloudinit import util

NOBLOCK = "noblock"

frequency = PER_ALWAYS
distros = ['all']

schema = {
    'id': 'cc_resizefs',
    'name': 'Resizefs',
    'title': 'Resize filesystem',
    'description': dedent("""\
        Resize a filesystem to use all avaliable space on partition. This
        module is useful along with ``cc_growpart`` and will ensure that if the
        root partition has been resized the root filesystem will be resized
        along with it. By default, ``cc_resizefs`` will resize the root
        partition and will block the boot process while the resize command is
        running. Optionally, the resize operation can be performed in the
        background while cloud-init continues running modules. This can be
        enabled by setting ``resize_rootfs`` to ``true``. This module can be
        disabled altogether by setting ``resize_rootfs`` to ``false``."""),
    'distros': distros,
    'examples': [
        'resize_rootfs: false  # disable root filesystem resize operation'],
    'frequency': PER_ALWAYS,
    'type': 'object',
    'properties': {
        'resize_rootfs': {
            'enum': [True, False, NOBLOCK],
            'description': dedent("""\
                Whether to resize the root partition. Default: 'true'""")
        }
    }
}

__doc__ = get_schema_doc(schema)  # Supplement python help()


def _resize_btrfs(mount_point, devpth):
    # If "/" is ro resize will fail. However it should be allowed since resize
    # makes everything bigger and subvolumes that are not ro will benefit.
    # Use a subvolume that is not ro to trick the resize operation to do the
    # "right" thing. The use of ".snapshot" is specific to "snapper" a generic
    # solution would be walk the subvolumes and find a rw mounted subvolume.
    if (not util.mount_is_read_write(mount_point) and
            os.path.isdir("%s/.snapshots" % mount_point)):
        return ('btrfs', 'filesystem', 'resize', 'max',
                '%s/.snapshots' % mount_point)
    else:
        return ('btrfs', 'filesystem', 'resize', 'max', mount_point)


def _resize_ext(mount_point, devpth):
    return ('resize2fs', devpth)


def _resize_xfs(mount_point, devpth):
    return ('xfs_growfs', mount_point)


def _resize_ufs(mount_point, devpth):
    return ('growfs', '-y', mount_point)


def _resize_zfs(mount_point, devpth):
    return ('zpool', 'online', '-e', mount_point, devpth)


def _get_dumpfs_output(mount_point):
    return util.subp(['dumpfs', '-m', mount_point])[0]


def _get_gpart_output(part):
    return util.subp(['gpart', 'show', part])[0]


def _can_skip_resize_ufs(mount_point, devpth):
    # extract the current fs sector size
    """
    # dumpfs -m /
    # newfs command for / (/dev/label/rootfs)
      newfs -L rootf -O 2 -U -a 4 -b 32768 -d 32768 -e 4096 -f 4096 -g 16384
            -h 64 -i 8192 -j -k 6408 -m 8 -o time -s 58719232 /dev/label/rootf
    """
    cur_fs_sz = None
    frag_sz = None
    dumpfs_res = _get_dumpfs_output(mount_point)
    for line in dumpfs_res.splitlines():
        if not line.startswith('#'):
            newfs_cmd = shlex.split(line)
            opt_value = 'O:Ua:s:b:d:e:f:g:h:i:jk:m:o:L:'
            optlist, _args = getopt.getopt(newfs_cmd[1:], opt_value)
            for o, a in optlist:
                if o == "-s":
                    cur_fs_sz = int(a)
                if o == "-f":
                    frag_sz = int(a)
    # check the current partition size
    """
    # gpart show /dev/da0
=>    