#!/usr/bin/python2.6
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2011  Marek Marczykowski <marmarek@mimuw.edu.pl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#

from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException
from optparse import OptionParser
import subprocess
import os
import re

qvm_run_path = "/usr/bin/qvm-run"

def parse_size(size):
    units = [ ('K', 1024), ('KB', 1024),
        ('M', 1024*1024), ('MB', 1024*1024),
        ('G', 1024*1024*1024), ('GB', 1024*1024*1024),
    ]

    size = size.strip().upper()
    if size.isdigit():
        return size

    for unit, multiplier in units:
        if size.endswith(unit):
            size = size[:-len(unit)].strip()
            return int(size)*multiplier
    
    print "Invalid size: {0}.".format(size)
    exit(1)

def main():
    usage = "usage: %prog <vm-name> <size>"
    parser = OptionParser (usage)

    (options, args) = parser.parse_args ()
    if (len (args) != 2):
        parser.error ("You must specify VM name and new size!")
    vmname = args[0]
    size = args[1]

    qvm_collection = QubesVmCollection()
    qvm_collection.lock_db_for_reading()
    qvm_collection.load()
    qvm_collection.unlock_db()

    vm = qvm_collection.get_vm_by_name(vmname)
    if vm is None:
        print "A VM with the name '{0}' does not exist in the system.".format(vmname)
        exit(1)

    if vm.is_running() and os.geteuid() != 0:
        print "You must be root to grow private.img on running VM."
        exit(1)

    size_bytes = parse_size(size)

    if size_bytes < vm.get_private_img_sz():
        print "Cannot shrink private.img ({0} < {1})".format(size_bytes, vm.get_private_img_sz())
        exit(1)

    try:
        vm.resize_private_img(size_bytes)
    except (IOError, OSError, QubesException) as err:
        print "ERROR: {0}".format(err)
        exit (1)

    if vm.is_running():
        # find loop device
        p = subprocess.Popen (["losetup", "--associated", vm.private_img],
                stdout=subprocess.PIPE)
        result = p.communicate()
        m = re.match(r"^(/dev/loop\d+):\s", result[0])
        if m is None:
            print "ERROR: Cannot find loop device!"
            exit(1)

        loop_dev = m.group(1)

        # resize loop device
        retcode = subprocess.check_call(["losetup", "--set-capacity", loop_dev])

        retcode = subprocess.check_call([qvm_run_path, "-uroot", "--pass_io", vmname, 
                "while [ \"`blockdev --getsize64 /dev/xvdb`\" -lt {0} ]; do sleep 0.2; done; resize2fs /dev/xvdb".format(size_bytes) ])
    else:
        retcode = subprocess.check_call(["resize2fs", "-f", vm.private_img])
        
	exit (0)


main()