8105fad646
Allow to attach disk image from different VM as block device. File attached with qvm-block -A will be visible as loopX device and as such can be detached. File path will be in device description.
126 lines
5.2 KiB
Python
Executable File
126 lines
5.2 KiB
Python
Executable File
#!/usr/bin/python2
|
|
#
|
|
# The Qubes OS Project, http://www.qubes-os.org
|
|
#
|
|
# Copyright (C) 2010 Marek Marczykowski <marmarek@invisiblethingslab.com>
|
|
#
|
|
# 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.qubesutils import block_list,block_attach,block_detach,block_check_attached
|
|
from qubes.qubesutils import kbytes_to_kmg, bytes_to_kmg
|
|
from optparse import OptionParser
|
|
import subprocess
|
|
import sys
|
|
import os
|
|
|
|
def main():
|
|
usage = "usage: %prog -l [options]\n"\
|
|
"usage: %prog -a [options] <device> <vm-name>\n"\
|
|
"usage: %prog -d [options] <device>\n"\
|
|
"usage: %prog -d [options] <vm-name>\n"\
|
|
"List/set VM PCI devices."
|
|
|
|
parser = OptionParser (usage)
|
|
parser.add_option ("-l", "--list", action="store_true", dest="do_list", default=False)
|
|
parser.add_option ("-A", "--attach-file", action="store", dest="file_path", default=None,
|
|
help="Attach specified file instead of physical device (syntax: qvm-block -A file backend-VM frontend-VM)")
|
|
parser.add_option ("-a", "--attach", action="store_true", dest="do_attach", default=False)
|
|
parser.add_option ("-d", "--detach", action="store_true", dest="do_detach", default=False)
|
|
parser.add_option ("-f", "--frontend", dest="frontend",
|
|
help="Specify device name at destination VM [default: xvdi]")
|
|
parser.add_option ("--ro", dest="ro", action="store_true", default=False,
|
|
help="Force read-only mode")
|
|
parser.add_option ("--no-auto-detach", dest="auto_detach", action="store_false", default=True,
|
|
help="Fail when device already connected to other VM")
|
|
|
|
(options, args) = parser.parse_args ()
|
|
|
|
if options.file_path:
|
|
options.do_attach = True
|
|
|
|
if options.do_list + options.do_attach + options.do_detach > 1:
|
|
print >> sys.stderr, "Only one of -l -a/-A -d is allowed!"
|
|
exit (1)
|
|
|
|
if options.do_attach or options.do_detach:
|
|
qvm_collection = QubesVmCollection()
|
|
qvm_collection.lock_db_for_reading()
|
|
qvm_collection.load()
|
|
qvm_collection.unlock_db()
|
|
|
|
if options.do_attach:
|
|
if (len (args) < 2):
|
|
parser.error ("You must provide device and vm name!")
|
|
vm = qvm_collection.get_vm_by_name(args[1])
|
|
if vm is None:
|
|
parser.error ("Invalid VM name: %s" % args[1])
|
|
if options.file_path:
|
|
dev = {}
|
|
dev['vm'] = args[0]
|
|
dev['device'] = options.file_path
|
|
dev['mode'] = 'w'
|
|
else:
|
|
dev_list = block_list()
|
|
if not args[0] in dev_list.keys():
|
|
parser.error ("Invalid device name: %s" % args[0])
|
|
dev = dev_list[args[0]]
|
|
backend_vm = qvm_collection.get_vm_by_name(dev['vm'])
|
|
assert backend_vm is not None
|
|
kwargs = {}
|
|
if options.frontend:
|
|
kwargs['frontend'] = options.frontend
|
|
if options.ro:
|
|
kwargs['mode'] = "r"
|
|
else:
|
|
kwargs['mode'] = dev['mode']
|
|
kwargs['auto_detach'] = options.auto_detach
|
|
block_attach(vm, backend_vm, dev['device'], **kwargs)
|
|
elif options.do_detach:
|
|
if (len (args) < 1):
|
|
parser.error ("You must provide device or vm name!")
|
|
# Check if provided name is VM
|
|
vm = qvm_collection.get_vm_by_name(args[0])
|
|
if vm is not None:
|
|
kwargs = {}
|
|
if options.frontend:
|
|
kwargs['frontend'] = options.frontend
|
|
block_detach(vm, **kwargs)
|
|
else:
|
|
# Maybe device?
|
|
dev_list = block_list()
|
|
if not args[0] in dev_list.keys():
|
|
parser.error ("Invalid VM or device name: %s" % args[0])
|
|
dev = dev_list[args[0]]
|
|
attached_to = block_check_attached(None, dev['device'], backend_xid = dev['xid'])
|
|
if attached_to is None:
|
|
print >> sys.stderr, "WARNING: Device not connected to any VM"
|
|
exit(0)
|
|
block_detach(None, attached_to['devid'], vm_xid=attached_to['xid'])
|
|
else:
|
|
# do_list
|
|
for dev in block_list().values():
|
|
attached_to = block_check_attached(None, dev['device'], backend_xid = dev['xid'])
|
|
attached_to_str = ""
|
|
if attached_to:
|
|
attached_to_str = " (attached to '%s' as '%s')" % (attached_to['vm'], attached_to['frontend'])
|
|
size_str = bytes_to_kmg(dev['size'])
|
|
print "%s\t%s %s%s" % (dev['name'], dev['desc'], size_str, attached_to_str)
|
|
exit (0)
|
|
|
|
main()
|