core-admin/qvm-tools/qvm-block
Marek Marczykowski-Górecki ba4dec5383
qvm-block: fix checking attached status of disk image files
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
2016-11-23 03:25:03 +01:00

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()