#!/usr/bin/python2 # -*- encoding: utf8 -*- # # The Qubes OS Project, http://www.qubes-os.org # # Copyright (C) 2010 Marek Marczykowski # # 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 optparse import OptionParser import subprocess import os import sys from qubes.qubes import vmm import re def find_devices_of_class(klass): p = subprocess.Popen(["/sbin/lspci", "-mm", "-n"], stdout=subprocess.PIPE) result = p.communicate() retcode = p.returncode if retcode != 0: print "ERROR when executing lspci!" raise IOError rx_netdev = re.compile(r"^([0-9a-f]{2}:[0-9a-f]{2}.[0-9a-f]) \"" + klass) for dev in str(result[0]).splitlines(): match = rx_netdev.match(dev) if match is not None: dev_bdf = match.group(1) assert dev_bdf is not None yield dev_bdf def main(): usage = "usage: %prog -l [options] \n"\ "usage: %prog -a [options] \n"\ "usage: %prog -d [options] \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", "--add", action="store_true", dest="do_add", default=False) parser.add_option ("-d", "--delete", action="store_true", dest="do_delete", default=False) parser.add_option("-C", "--add-class", action="store_true", dest="do_add_class", default=False, help="Add all devices of given class (net, usb)") parser.add_option ("--offline-mode", dest="offline_mode", action="store_true", default=False, help="Offline mode") (options, args) = parser.parse_args () if (len (args) < 1): parser.error ("You must provide at least the vmname!") vmname = args[0] if options.do_list + options.do_add + options.do_delete + \ options.do_add_class > 1: print >> sys.stderr, "Only one of -l -a -d -C is allowed!" exit(1) if options.offline_mode: vmm.offline_mode = True if options.do_add or options.do_delete or options.do_add_class: qvm_collection = QubesVmCollection() qvm_collection.lock_db_for_writing() qvm_collection.load() else: 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 or vm.qid not in qvm_collection: print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname) exit(1) if options.do_add: if len (args) < 2: print >> sys.stderr, "You must specify the PCI device to add" exit (1) pci = args[1] vm.pci_add(pci) qvm_collection.save() qvm_collection.unlock_db() elif options.do_add_class: if len(args) < 2: print >> sys.stderr, "You must specify the PCI device class to add" exit(1) klass = args[1] if klass == 'net': devs = find_devices_of_class("02") elif klass == 'usb': devs = find_devices_of_class("0c03") else: print >> sys.stderr, "Supported classes: net, usb" exit(1) for dev in devs: vm.pci_add(dev) qvm_collection.save() qvm_collection.unlock_db() elif options.do_delete: if len (args) < 2: print >> sys.stderr, "You must specify the PCI device to delete" exit (1) pci = args[1] vm.pci_remove(pci) qvm_collection.save() qvm_collection.unlock_db() else: # do_list print str(vm.pcidevs) main()