ba4dec5383
Libvirt do not show actual block device (loop*) choosen for the device - only original (file) path. But file path is available in device description. Please note that VM can provide any description (withing allowed limits), effectively breaking this check again (hidding the attachment status). But even without this bug it could do that - by hidding the whole device from QubesDB. Fixes QubesOS/qubes-issues#2453
153 lines
6.5 KiB
Python
Executable File
153 lines
6.5 KiB
Python
Executable File
#!/usr/bin/python2
|
|
# -*- encoding: utf8 -*-
|
|
#
|
|
# 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, QubesException
|
|
from qubes.qubesutils import block_list,block_attach,block_detach,block_detach_all,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] <vm-name> <device-vm-name>:<device>\n"\
|
|
"usage: %prog -A [options] <vm-name> <file-vm-name>:<file>\n"\
|
|
"usage: %prog -d [options] <device-vm-name>:<device>\n"\
|
|
"usage: %prog -d [options] <vm-name>\n"\
|
|
"List/set VM block 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_true", dest="do_file_attach", default=False,
|
|
help="Attach specified file instead of physical device")
|
|
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")
|
|
parser.add_option ("--show-system-disks", dest="system_disks", action="store_true", default=False,
|
|
help="List also system disks")
|
|
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
|
|
help="Force to run, even with root privileges")
|
|
|
|
(options, args) = parser.parse_args ()
|
|
|
|
if hasattr(os, "geteuid") and os.geteuid() == 0:
|
|
if not options.force_root:
|
|
print >> sys.stderr, "*** Running this tool as root is strongly discouraged, this will lead you in permissions problems."
|
|
print >> sys.stderr, "Retry as unprivileged user."
|
|
print >> sys.stderr, "... or use --force-root to continue anyway."
|
|
exit(1)
|
|
|
|
if options.do_file_attach:
|
|
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)
|
|
|
|
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 vm name and device!")
|
|
vm = qvm_collection.get_vm_by_name(args[0])
|
|
if vm is None:
|
|
parser.error ("Invalid VM name: %s" % args[0])
|
|
# FIXME: here we assume that device is always in form "domain:dev", which can be changed in the future
|
|
if args[1].find(":") < 0:
|
|
parser.error ("Invalid device syntax (missing VM name): %s" % args[1])
|
|
if options.do_file_attach:
|
|
dev = {}
|
|
(dev['vm'], dev['device']) = args[1].split(":")
|
|
dev['desc'] = dev['device']
|
|
dev['mode'] = 'w'
|
|
else:
|
|
dev_list = block_list(qvm_collection)
|
|
if not args[1] in dev_list.keys():
|
|
parser.error ("Invalid device name: %s" % args[1])
|
|
dev = dev_list[args[1]]
|
|
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
|
|
try:
|
|
block_attach(qvm_collection, vm, dev, **kwargs)
|
|
except QubesException as e:
|
|
print >> sys.stderr, "ERROR: %s" % str(e)
|
|
sys.exit(1)
|
|
elif options.do_detach:
|
|
if (len (args) < 1):
|
|
parser.error ("You must provide device or vm name!")
|
|
if len(args) > 1:
|
|
parser.error ("Too many parameters")
|
|
# 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:
|
|
block_detach_all(vm)
|
|
else:
|
|
# Maybe device?
|
|
dev_list = block_list(qvm_collection)
|
|
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(qvm_collection, dev)
|
|
if attached_to is None:
|
|
print >> sys.stderr, "WARNING: Device not connected to any VM"
|
|
exit(0)
|
|
block_detach(attached_to['vm'], attached_to['frontend'])
|
|
else:
|
|
# do_list
|
|
if len(args) > 0:
|
|
parser.error ("Too many parameters")
|
|
kwargs = {}
|
|
kwargs['qvmc'] = qvm_collection
|
|
kwargs['system_disks'] = options.system_disks
|
|
for dev in block_list(**kwargs).values():
|
|
attached_to = block_check_attached(qvm_collection, dev)
|
|
attached_to_str = ""
|
|
if attached_to:
|
|
attached_to_str = " (attached to '%s' as '%s')" % (
|
|
attached_to['vm'].name, 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()
|