Browse Source

qubes/tools: qvm-prefs

Wojtek Porczyk 8 years ago
parent
commit
e7cba0214f
5 changed files with 179 additions and 616 deletions
  1. 36 18
      doc/manpages/qvm-prefs.rst
  2. 1 0
      qubes/Makefile
  3. 137 0
      qubes/tools/qvm_prefs.py
  4. 4 598
      qvm-tools/qvm-prefs
  5. 1 0
      rpm_spec/core-dom0.spec

+ 36 - 18
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:: --help-properties
+
+   List available properties with short descriptions and exit.
+
+.. option:: --xml=XMLFILE
+
+   Qubes OS store file.
+
+.. option:: --verbose, -v
 
-.. option:: --list, -l
+   Increase verbosity.
 
-    List properties of a specified VM
+.. option:: --quiet, -q
 
-.. option:: --get, -g
+   Decrease verbosity.
 
-    Get a single property of a specified VM
+.. option:: --force-root
 
-.. option:: --set, -s
+   Force to run as root.
 
-    Set properties of a specified VM
 
-Properties
-==========
+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 <joanna at invisiblethingslab dot com>
 | Rafal Wojtczuk <rafal at invisiblethingslab dot com>
 | Marek Marczykowski <marmarek at invisiblethingslab dot com>
+| Wojtek Porczyk <woju at invisiblethingslab dot com>
+
+.. vim: ts=3 sw=3 et tw=80

+ 1 - 0
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

+ 137 - 0
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 <joanna@invisiblethingslab.com>
+# Copyright (C) 2015       Wojtek Porczyk <woju@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.
+#
+
+# 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())

+ 4 - 598
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 <joanna@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.
-#
-#
+#!/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) <vmaname>"
-        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) <vmaname>"
-        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) <kernel version>, 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) <opts>"
-        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] <vm-name>\n"\
-            "usage: %prog -g [options] <vm-name> <property>\n"\
-            "usage: %prog -s [options] <vm-name> <property> [...]\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())

+ 1 - 0
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*