diff --git a/linux/system-config/tmpfiles-qubes.conf b/linux/system-config/tmpfiles-qubes.conf index 834541f8..c3ca33b0 100644 --- a/linux/system-config/tmpfiles-qubes.conf +++ b/linux/system-config/tmpfiles-qubes.conf @@ -1,3 +1,4 @@ d /var/run/qubes 2770 root qubes f /var/run/qubes/xl-lock 0660 root qubes +f /var/run/qubes/empty 0444 root qubes d /var/run/xen-hotplug 0755 root root diff --git a/qubes/api/admin.py b/qubes/api/admin.py index 8b1f6596..b42d6479 100644 --- a/qubes/api/admin.py +++ b/qubes/api/admin.py @@ -1293,8 +1293,9 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI): dest_vm = profile_data['destination_vm'] dest_path = profile_data['destination_path'] include_vms = profile_data['include'] - # convert old keywords to new keywords - include_vms = [vm.replace('$', '@') for vm in include_vms] + if include_vms is not None: + # convert old keywords to new keywords + include_vms = [vm.replace('$', '@') for vm in include_vms] exclude_vms = profile_data.get('exclude', []) # convert old keywords to new keywords exclude_vms = [vm.replace('$', '@') for vm in exclude_vms] @@ -1339,14 +1340,17 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI): 'specify passphrase_text or passphrase_vm') # handle include - vms_to_backup = set(vm for vm in self.app.domains - if any(qubes.utils.match_vm_name_with_special(vm, name) - for name in include_vms)) + if include_vms is None: + vms_to_backup = None + else: + vms_to_backup = set(vm for vm in self.app.domains + if any(qubes.utils.match_vm_name_with_special(vm, name) + for name in include_vms)) - # handle exclude - vms_to_backup.difference_update(vm for vm in self.app.domains - if any(qubes.utils.match_vm_name_with_special(vm, name) - for name in exclude_vms)) + # handle exclude + vms_to_backup.difference_update(vm for vm in self.app.domains + if any(qubes.utils.match_vm_name_with_special(vm, name) + for name in exclude_vms)) kwargs = { 'target_vm': dest_vm, diff --git a/qubes/backup.py b/qubes/backup.py index a3b4f7aa..e3e6f1ec 100644 --- a/qubes/backup.py +++ b/qubes/backup.py @@ -381,6 +381,15 @@ class Backup(object): if os.path.exists(firewall_conf): vm_files.append(self.FileToBackup(firewall_conf, subdir)) + if not vm_files: + # subdir/ is needed in the tar file, otherwise restore + # of a (Disp)VM without any backed up files is going + # to fail. Adding a zero-sized file here happens to be + # more straightforward than adding an empty directory. + empty = self.FileToBackup("/var/run/qubes/empty", subdir) + assert empty.size == 0 + vm_files.append(empty) + files_to_backup[vm.qid] = self.VMToBackup(vm, vm_files, subdir) # Dom0 user home diff --git a/qubes/vm/adminvm.py b/qubes/vm/adminvm.py index 39c174d2..2d044f67 100644 --- a/qubes/vm/adminvm.py +++ b/qubes/vm/adminvm.py @@ -50,6 +50,10 @@ class AdminVM(qubes.vm.BaseVM): default=(lambda self: self.app.default_dispvm), doc='Default VM to be used as Disposable VM for service calls.') + include_in_backups = qubes.property('include_in_backups', + default=True, type=bool, + doc='If this domain is to be included in default backup.') + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/qubes/vm/dispvm.py b/qubes/vm/dispvm.py index b60279fb..4554998e 100644 --- a/qubes/vm/dispvm.py +++ b/qubes/vm/dispvm.py @@ -41,6 +41,10 @@ class DispVM(qubes.vm.qubesvm.QubesVM): auto_cleanup = qubes.property('auto_cleanup', type=bool, default=False, doc='automatically remove this VM upon shutdown') + include_in_backups = qubes.property('include_in_backups', type=bool, + default=(lambda self: not self.auto_cleanup), + doc='If this domain is to be included in default backup.') + def __init__(self, app, xml, *args, **kwargs): self.volume_config = { 'root': {