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