diff --git a/doc/manpages/qvm-prefs.rst b/doc/manpages/qvm-prefs.rst index 3ad952b7..c55c5b70 100644 --- a/doc/manpages/qvm-prefs.rst +++ b/doc/manpages/qvm-prefs.rst @@ -1,37 +1,51 @@ .. program:: qvm-prefs -========================================================== :program:`qvm-prefs` -- List/set various per-VM properties ========================================================== Synopsis -======== -| :command:`qvm-prefs` [*options*] -l <*vm-name*> -| :command:`qvm-prefs` [*options*] -g <*vm-name*> <*property*> -| :command:`qvm-prefs` [*options*] -s <*vm-name*> <*property*> [*...*] +-------- +:command:`qvm-prefs` qvm-prefs [-h] [--xml *XMLFILE*] [--verbose] [--quiet] [--force-root] [--help-properties] *VMNAME* [*PROPERTY* [*VALUE*]] Options -======= +------- .. option:: --help, -h - Show this help message and exit + Show help message and exit. -.. option:: --list, -l +.. option:: --help-properties - List properties of a specified VM + List available properties with short descriptions and exit. -.. option:: --get, -g +.. option:: --xml=XMLFILE - Get a single property of a specified VM + Qubes OS store file. -.. option:: --set, -s +.. option:: --verbose, -v - Set properties of a specified VM + Increase verbosity. -Properties -========== +.. option:: --quiet, -q + + Decrease verbosity. + +.. option:: --force-root + + Force to run as root. + + +Common properties +================= + +This list is non-exhaustive. For authoritative listing, see +:option:`--help-properties` and documentation of the source code. + +.. warning:: + + This list is from the core2. It is wrong in many cases, some of them obvious, + some of them not. include_in_backups Accepted values: ``True``, ``False`` @@ -40,11 +54,11 @@ include_in_backups works only in qubes-manager). You can always manually select or deselect any VM for backup. -pcidevs + pcidevs PCI devices assigned to the VM. Should be edited using :manpage:`qvm-pci(1)` tool. -pci_strictreset + pci_strictreset Accepted values: ``True``, ``False`` Control whether prevent assigning to VM a device which does not support any @@ -212,7 +226,11 @@ timezone proper timezone set). Authors -======= +------- + | Joanna Rutkowska | Rafal Wojtczuk | Marek Marczykowski +| Wojtek Porczyk + +.. vim: ts=3 sw=3 et tw=80 diff --git a/qubes/Makefile b/qubes/Makefile index 65365a65..eed1dc39 100644 --- a/qubes/Makefile +++ b/qubes/Makefile @@ -56,6 +56,7 @@ endif tools/qubes_create.py* \ tools/qvm_create.py* \ tools/qvm_ls.py* \ + tools/qvm_prefs.py* \ $(DESTDIR)$(PYTHON_QUBESPATH)/tools cp ext/__init__.py* $(DESTDIR)$(PYTHON_QUBESPATH)/ext diff --git a/qubes/tools/qvm_prefs.py b/qubes/tools/qvm_prefs.py new file mode 100644 index 00000000..287e76c1 --- /dev/null +++ b/qubes/tools/qvm_prefs.py @@ -0,0 +1,137 @@ +#!/usr/bin/python2 +# -*- encoding: utf8 -*- +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010-2015 Joanna Rutkowska +# Copyright (C) 2015 Wojtek Porczyk +# +# 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. +# + +# TODO list properties for all classes +# TODO indicate default values + +from __future__ import print_function + +import argparse +import os +import subprocess +import sys +import textwrap + +import qubes +import qubes.tools +import qubes.utils +import qubes.vm + + +class _HelpPropertiesAction(argparse.Action): + '''Action for argument parser that displays all properties and exits.''' + # pylint: disable=redefined-builtin + def __init__(self, + option_strings, + dest=argparse.SUPPRESS, + default=argparse.SUPPRESS, + help='list all available properties with short descriptions' + ' and exit'): + super(_HelpPropertiesAction, self).__init__( + option_strings=option_strings, + dest=dest, + default=default, + nargs=0, + help=help) + + def __call__(self, parser, namespace, values, option_string=None): + properties = qubes.vm.qubesvm.QubesVM.property_list() + width = max(len(prop.__name__) for prop in properties) + wrapper = textwrap.TextWrapper(width=80, + initial_indent=' ', subsequent_indent=' ' * (width + 6)) + + text = 'Common properties:\n' + '\n'.join( + wrapper.fill('{name:{width}s} {doc}'.format( + name=prop.__name__, + doc=qubes.utils.format_doc(prop.__doc__) if prop.__doc__ else'', + width=width)) + for prop in sorted(properties)) + parser.exit(message=text + + '\n\nThere may be more properties in specific domain classes.\n') + + +parser = qubes.tools.get_parser_base(want_force_root=True) + +#parser.add_argument('--property', '--prop', '-p', +# action=qubes.tools.PropertyAction, +# help='set domain\'s property (may be given multiple times)') + +parser.add_argument('name', metavar='VMNAME', + help='name of the domain to change') + +parser.add_argument('property', metavar='PROPERTY', + nargs='?', + help='name of the property to show or change') + +parser.add_argument('value', metavar='VALUE', + nargs='?', + help='new value of the property') + +parser.add_argument('--help-properties', action=_HelpPropertiesAction) + + +def main(): + args = parser.parse_args() + qubes.tools.set_verbosity(parser, args) + qubes.tools.dont_run_as_root(parser, args) + + app = qubes.Qubes(args.xml) + try: + domain = app.domains[args.name] + except KeyError: + parser.error('no such domain: {!r}'.format(args.name)) + + if args.property is None: + properties = domain.property_list() + width = max(len(prop.__name__) for prop in properties) + + for prop in sorted(properties): + try: + value = getattr(domain, prop.__name__) + except AttributeError: + print('{name:{width}s} U'.format( + name=prop.__name__, width=width)) + continue + + if domain.property_is_default(prop): + print('{name:{width}s} D {value!r}'.format( + name=prop.__name__, width=width, value=value)) + else: + print('{name:{width}s} - {value!r}'.format( + name=prop.__name__, width=width, value=value)) + + return True + + + if args.value is None: + print(str(getattr(domain, args.property))) + return True + + setattr(domain, args.property, args.value) + app.save() + + return True + + +if __name__ == '__main__': + sys.exit(not main()) diff --git a/qvm-tools/qvm-prefs b/qvm-tools/qvm-prefs index 8eac355d..a02f5768 100755 --- a/qvm-tools/qvm-prefs +++ b/qvm-tools/qvm-prefs @@ -1,601 +1,7 @@ -#!/usr/bin/python2 -# -*- encoding: utf8 -*- -# -# The Qubes OS Project, http://www.qubes-os.org -# -# Copyright (C) 2010 Joanna Rutkowska -# -# 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. -# -# +#!/usr/bin/python2 -O +# vim: fileencoding=utf-8 -from qubes.qubes import QubesVmCollection -from qubes.qubes import QubesVmLabels -from qubes.qubes import QubesHost -from qubes.qubes import system_path -from optparse import OptionParser -import subprocess -import os import sys -import re +import qubes.tools.qvm_prefs -def do_list(vm): - label_width = 19 - fmt="{{0:<{0}}}: {{1}}".format(label_width) - - print fmt.format ("name", vm.name) - print fmt.format ("label", vm.label.name) - print fmt.format ("type", vm.type) - if vm.template is not None: - print fmt.format ("template", vm.template.name) - if vm.netvm is not None: - print fmt.format ("netvm", vm.netvm.name) - if vm.qid != 0: - print fmt.format("dispvm_netvm", "%s%s" % ( - vm.dispvm_netvm.name if vm.dispvm_netvm - else "none", - " (default)" if vm.uses_default_dispvm_netvm else "")) - print fmt.format ("updateable", vm.updateable) - print fmt.format ("autostart", vm.autostart) - print fmt.format ("installed_by_rpm", vm.installed_by_rpm) - print fmt.format ("include_in_backups", vm.include_in_backups) - print fmt.format ("last_backup", vm.backup_timestamp) - print fmt.format ("dir", vm.dir_path) - print fmt.format ("config", vm.conf_file) - print fmt.format ("pcidevs", vm.pcidevs) - print fmt.format ("pci_strictreset", vm.pci_strictreset) - if vm.template is None: - print fmt.format ("root_img", vm.root_img) - if hasattr(vm, "rootcow_img") and vm.rootcow_img is not None: - print fmt.format ("root_cow_img", vm.rootcow_img) - if vm.template is not None: - print fmt.format ("root_img", vm.template.root_img) - if hasattr(vm, 'volatile_img') and vm.volatile_img is not None: - print fmt.format ("root_volatile_img", vm.volatile_img) - - if hasattr(vm, 'private_img') and vm.private_img is not None: - print fmt.format ("private_img", vm.private_img) - print fmt.format ("vcpus", str(vm.vcpus)) - print fmt.format ("memory", vm.memory) - if hasattr(vm, 'maxmem'): - print fmt.format ("maxmem", vm.maxmem) - print fmt.format ("MAC", "%s%s" % (vm.mac, " (auto)" if vm._mac is None else "")) - - if hasattr(vm, 'kernel'): - if vm.uses_default_kernel: - print fmt.format ("kernel", "%s (default)" % vm.kernel) - else: - print fmt.format ("kernel", vm.kernel) - - if hasattr(vm, 'kernelopts'): - if vm.uses_default_kernelopts: - print fmt.format ("kernelopts", "%s (default)" % vm.kernelopts) - else: - print fmt.format ("kernelopts", vm.kernelopts) - if hasattr(vm, 'debug'): - print fmt.format("debug", "on" if vm.debug else "off") - - if hasattr(vm, 'default_user'): - print fmt.format("default_user", str(vm.default_user)) - - if hasattr(vm, 'qrexec_installed'): - print fmt.format("qrexec_installed", str(vm.qrexec_installed)) - - if hasattr(vm, 'qrexec_timeout'): - print fmt.format("qrexec_timeout", str(vm.qrexec_timeout)) - - if hasattr(vm, 'guiagent_installed'): - print fmt.format("guiagent_installed", str(vm.guiagent_installed)) - - if hasattr(vm, 'seamless_gui_mode'): - print fmt.format("seamless_gui_mode", str(vm.seamless_gui_mode)) - - if hasattr(vm, 'drive'): - print fmt.format("drive", str(vm.drive)) - - if hasattr(vm, 'timezone'): - print fmt.format("timezone", str(vm.timezone)) - - print fmt.format ("internal", vm.internal) - - -def do_get(vms, vm, prop): - - if prop == 'config': - prop = 'conf_file' - elif prop == 'dir': - prop = 'dir_path' - elif prop == 'last_backup': - prop = 'backup_timestamp' - if not hasattr(vm, prop): - print >>sys.stderr, "VM '{}' has no attribute '{}'".format(vm.name, - prop) - return - if getattr(vm, prop, None) is None: - # not set or set to None - return - if prop in ['template', 'netvm', 'dispvm_netvm']: - print getattr(vm, prop).name - else: - print str(getattr(vm, prop)) - - -def set_label(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing label name argument!" - return False - - label = args[0] - if label not in QubesVmLabels: - print >> sys.stderr, "Wrong label name, supported values are the following:" - for l in QubesVmLabels.values(): - print >> sys.stderr, "* {0}".format(l.name) - return False - - vm.label = QubesVmLabels[label] - return True - -def set_memory(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing memory argument!" - return False - - new_memory = int(args[0]) - - if new_memory <= 0: - print >>sys.stderr, "Memory size must be positive" - return False - - qubes_host = QubesHost() - if new_memory > qubes_host.memory_total/1024: - print >> sys.stderr, "This host has only {0} MB of RAM".format(qubes_host.memory_total/1024) - return False - - vm.memory = new_memory - return True - -def set_maxmem(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing maxmem argument!" - exit (1) - - new_maxmem = int(args[0]) - - if new_maxmem <= 0: - print >>sys.stderr, "Memory size must be positive" - return False - - qubes_host = QubesHost() - if new_maxmem > qubes_host.memory_total/1024: - print >> sys.stderr, "This host has only {0} MB of RAM".format(qubes_host.memory_total/1024) - return False - - if new_maxmem < vm.memory: - print >> sys.stderr, "WARNING: new maxmem smaller than memory property - VM will be able to use only 'maxmem' memory amount" - - vm.maxmem = new_maxmem - return True - -def set_mac(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing MAC argument!" - return False - - if not re.match("[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}|auto", args[0]): - print >> sys.stderr, "Invalid MAC argument!" - print >> sys.stderr, "Possible values:" - print >> sys.stderr, "1) auto" - print >> sys.stderr, "2) MAC in format: XX:XX:XX:XX:XX:XX" - return False - - mac = args[0] - if mac == "auto": - mac = None - vm.mac = mac - return True - -def set_pcidevs(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing pcidevs argument!" - return False - - if vm.is_running(): - print >>sys.stderr, "Cannot modify PCI devices of running VM, " \ - "use qvm-pci instead" - return False - vm.pcidevs = list(eval(args[0])) - return True - -def set_pci_strictreset(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing value (True/False)!" - return False - - vm.pci_strictreset = bool(eval(args[0].capitalize())) - return True - -def set_netvm(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing netvm name argument!" - print >> sys.stderr, "Possible values:" - print >> sys.stderr, "1) default" - print >> sys.stderr, "2) none" - print >> sys.stderr, "3) " - return - - netvm = args[0] - if netvm == "none": - netvm = None - vm.uses_default_netvm = False - elif netvm == "default": - netvm = vms.get_default_netvm() - vm.uses_default_netvm = True - else: - netvm = vms.get_vm_by_name (netvm) - if netvm is None: - print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(netvm) - return False - if not netvm.is_netvm(): - print >> sys.stderr, "VM '{0}' is not a NetVM".format(netvm) - return False - vm.uses_default_netvm = False - - vm.netvm = netvm - return True - -def set_dispvm_netvm(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing netvm name argument!" - print >> sys.stderr, "Possible values:" - print >> sys.stderr, "1) default (the same as VM own netvm)" - print >> sys.stderr, "2) none" - print >> sys.stderr, "3) " - return - - netvm = args[0] - if netvm == "none": - vm.netvm = None - vm.uses_default_dispvm_netvm = False - elif netvm == "default": - vm.uses_default_dispvm_netvm = True - else: - netvm = vms.get_vm_by_name (netvm) - if netvm is None: - print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(netvm) - return False - if not netvm.is_netvm(): - print >> sys.stderr, "VM '{0}' is not a NetVM".format(netvm) - return False - vm.dispvm_netvm = netvm - vm.uses_default_dispvm_netvm = False - return True - -def set_kernel(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing kernel version argument!" - print >> sys.stderr, "Possible values:" - print >> sys.stderr, "1) default" - print >> sys.stderr, "2) none (kernels subdir in VM)" - print >> sys.stderr, "3) , one of:" - for k in os.listdir(system_path["qubes_kernels_base_dir"]): - print >> sys.stderr, " -", k - return False - - kernel = args[0] - if kernel == "default": - kernel = vms.get_default_kernel() - vm.uses_default_kernel = True - elif kernel == "none": - kernel = None - vm.uses_default_kernel = False - else: - if not os.path.exists(os.path.join(system_path["qubes_kernels_base_dir"], kernel)): - print >> sys.stderr, "Kernel version {0} not installed.".format(kernel) - return False - vm.uses_default_kernel = False - - vm.kernel = kernel - return True - -def set_template(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing template name argument!" - return False - - template_name = args[0]; - template = vms.get_vm_by_name(template_name) - if template is None or template.qid not in vms: - print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(template_name) - return False - - if not template.is_template(): - print >> sys.stderr, "VM '{0}' is not a TemplateVM".format(template_name) - return False - - print >> sys.stderr, "Setting template for VM '{0}' to '{1}'...".format (vm.name, template_name) - vm.template = template - return True - -def set_vcpus(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing vcpus count argument!" - return False - - vcpus = int(args[0]) - if vcpus <= 0: - print >> sys.stderr, "A vcpus count must be positive." - return False - - qubes_host = QubesHost() - if vcpus > qubes_host.no_cpus: - print >> sys.stderr, "This host has only {0} cpus".format( - qubes_host.no_cpus) - return False - - print >> sys.stderr, "Setting vcpus count for VM '{0}' to '{1}'...".format (vm.name, vcpus) - vm.vcpus = vcpus - return True - -def set_kernelopts(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing kernel opts argument!" - print >> sys.stderr, "Possible values:" - print >> sys.stderr, "1) default" - print >> sys.stderr, "2) " - return False - - if args[0] == 'default': - vm.uses_default_kernelopts = True - else: - vm.uses_default_kernelopts = False - vm.kernelopts = args[0] - - return True - -def set_name(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing new name!" - return False - - if args[0] == vm.name: - return False - vm.set_name(args[0]) - return True - -def set_drive(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing new drive content (file/device)!" - return False - - if args[0] == '' or args[0].lower() == 'none': - vm.drive = None - else: - vm.drive = args[0] - return True - -def set_debug(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing value (True/False or on/off)!" - return False - - if args[0].lower() == "on": - vm.debug = True - elif args[0].lower() == "off": - vm.debug = False - else: - vm.debug = bool(eval(args[0].capitalize())) - return True - -def set_default_user(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing user name!" - return False - - vm.default_user = args[0] - return True - -def set_include_in_backups(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing value (True/False)!" - return False - - vm.include_in_backups = bool(eval(args[0].capitalize())) - return True - -def set_qrexec_installed(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing value (True/False)!" - return False - - vm.qrexec_installed = bool(eval(args[0].capitalize())) - return True - -def set_internal(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing value (True/False)!" - return False - - vm.internal = bool(eval(args[0].capitalize())) - return True - -def set_guiagent_installed(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing value (True/False)!" - return False - - vm.guiagent_installed = bool(eval(args[0].capitalize())) - return True - -def set_seamless_gui_mode(vms, vm, args): - if len(args) != 1: - print >> sys.stderr, "Missing value (true/false)!" - return False - - if not args[0].lower() in ['true', 'false']: - print >> sys.stderr, "Invalid value, expected 'true' or 'false'" - return False - - if args[0].lower() == 'true': - vm.seamless_gui_mode = True - else: - vm.seamless_gui_mode = False - return True - -def set_autostart(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing value (True/False)!" - return False - - vm.autostart = bool(eval(args[0].capitalize())) - return True - -def set_qrexec_timeout(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing timeout value (seconds)!" - return False - - vm.qrexec_timeout = int(args[0]) - return True - -def set_timezone(vms, vm, args): - if len (args) != 1: - print >> sys.stderr, "Missing value ('localtime' or timeoffset in seconds)!" - return False - - if not args[0].isdigit() and args[0].lower() == 'localtime': - print >> sys.stderr, "Invalid timezone value!" - return False - - vm.timezone = args[0] - return True - -properties = { - "include_in_backups": set_include_in_backups, - "pcidevs": set_pcidevs, - "pci_strictreset": set_pci_strictreset, - "label" : set_label, - "netvm" : set_netvm, - "dispvm_netvm" : set_dispvm_netvm, - "maxmem" : set_maxmem, - "memory" : set_memory, - "kernel" : set_kernel, - "template" : set_template, - "vcpus" : set_vcpus, - "kernelopts": set_kernelopts, - "name": set_name, - "drive": set_drive, - "mac": set_mac, - "debug": set_debug, - "default_user": set_default_user, - "qrexec_installed": set_qrexec_installed, - "guiagent_installed": set_guiagent_installed, - "seamless_gui_mode": set_seamless_gui_mode, - "qrexec_timeout": set_qrexec_timeout, - "timezone": set_timezone, - "internal": set_internal, - "autostart": set_autostart, -} - - -def do_set(vms, vm, property, args): - if property not in properties.keys(): - print >> sys.stderr, "ERROR: Wrong property name: '{0}'".format(property) - return False - - if not hasattr(vm, property): - print >> sys.stderr, "ERROR: Property '{0}' not available for this VM".format(property) - return False - - try: - return properties[property](vms, vm, args) - except Exception as err: - print >> sys.stderr, "ERROR: %s" % str(err) - return False - - -def main(): - usage = "usage: %prog -l [options] \n"\ - "usage: %prog -g [options] \n"\ - "usage: %prog -s [options] [...]\n"\ - "List/set various per-VM properties." - - parser = OptionParser (usage) - parser.add_option("-l", "--list", action="store_true", dest="do_list", - default=False) - parser.add_option("-s", "--set", action="store_true", dest="do_set", - default=False) - parser.add_option ("-g", "--gry", action="store_true", dest="do_get", - default=False) - 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 (len (args) < 1): - parser.error ("You must provide at least the vmname!") - - vmname = args[0] - - 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_list + options.do_set + options.do_get > 1: - print >> sys.stderr, "You can provide at most one of -l, -g and -s at " \ - "the same time!" - exit(1) - - if options.do_set: - 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_set: - if len (args) < 2: - print >> sys.stderr, "You must specify the property you wish to set..." - print >> sys.stderr, "Available properties:" - for p in properties.keys(): - if hasattr(vm, p): - print >> sys.stderr, "--> '{0}'".format(p) - exit (1) - - property = args[1] - if do_set(qvm_collection, vm, property, args[2:]): - qvm_collection.save() - qvm_collection.unlock_db() - else: - qvm_collection.unlock_db() - exit(1) - - elif options.do_get or len(args) == 2: - do_get(qvm_collection, vm, args[1]) - else: - # do_list - do_list(vm) - -main() +sys.exit(not qubes.tools.qvm_prefs.main()) diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index 0f3b3bf7..695e62ec 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -219,6 +219,7 @@ fi %{python_sitearch}/qubes/tools/qubes_create.py* %{python_sitearch}/qubes/tools/qvm_create.py* %{python_sitearch}/qubes/tools/qvm_ls.py* +%{python_sitearch}/qubes/tools/qvm_prefs.py* %dir %{python_sitearch}/qubes/ext %{python_sitearch}/qubes/ext/__init__.py*