diff --git a/common/fstab b/common/fstab index 3bd34745..37b23a9e 100644 --- a/common/fstab +++ b/common/fstab @@ -9,6 +9,7 @@ /dev/mapper/dmroot / ext4 defaults,noatime 1 1 /dev/xvdb /rw ext4 noauto,defaults 0 0 /dev/xvdc1 swap swap defaults 0 0 +/dev/xvdd /lib/modules ext3 defaults,ro 0 0 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 diff --git a/dom0/misc/vm-template.conf b/dom0/misc/vm-template.conf index df138c85..e9f929e4 100644 --- a/dom0/misc/vm-template.conf +++ b/dom0/misc/vm-template.conf @@ -15,6 +15,7 @@ name = "{name}" disk = [ {rootdev} {privatedev} {volatiledev} + {otherdevs} ] vif = [ {netdev} ] diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index 8e92b0fb..2deeab95 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -56,6 +56,7 @@ qubes_appvms_dir = qubes_base_dir + "/appvms" qubes_templates_dir = qubes_base_dir + "/vm-templates" qubes_servicevms_dir = qubes_base_dir + "/servicevms" qubes_store_filename = qubes_base_dir + "/qubes.xml" +qubes_kernels_base_dir = qubes_base_dir + "/vm-kernels" qubes_max_xid = 1024 qubes_max_qid = 254 @@ -194,7 +195,9 @@ class QubesVm(object): volatile_img = None, pcidevs = None, internal = False, - vcpus = None): + vcpus = None, + kernel = None, + uses_default_kernel = True): assert qid < qubes_max_qid, "VM id out of bounds!" @@ -277,11 +280,18 @@ class QubesVm(object): else: assert self.root_img is not None, "Missing root_img for standalone VM!" + self.kernel = kernel + if template_vm is not None: self.kernels_dir = template_vm.kernels_dir + elif self.kernel is not None: + self.kernels_dir = qubes_kernels_base_dir + "/" + self.kernel else: + # for backward compatibility (or another rare case): kernel=None -> kernel in VM dir self.kernels_dir = self.dir_path + "/" + default_kernels_subdir + self.uses_default_kernel = uses_default_kernel + if updateable: self.appmenus_templates_dir = self.dir_path + "/" + default_appmenus_templates_subdir @@ -644,6 +654,7 @@ class QubesVm(object): args['rootdev'] = self.get_rootdev(source_template=source_template) args['privatedev'] = "'script:file:{dir}/private.img,xvdb,w',".format(dir=self.dir_path) args['volatiledev'] = "'script:file:{dir}/volatile.img,xvdc,w',".format(dir=self.dir_path) + args['otherdevs'] = "'script:file:{dir}/modules.img,xvdd,r',".format(dir=self.kernels_dir) args['kernelopts'] = '' return args @@ -708,13 +719,6 @@ class QubesVm(object): raise IOError ("Error while copying {0} to {1}".\ format(template_root, self.root_img)) - kernels_dir = self.dir_path + '/' + default_kernels_subdir - if verbose: - print "--> Copying the template's kernel dir: {0}".\ - format(source_template.kernels_dir) - shutil.copytree (source_template.kernels_dir, kernels_dir) - - # Create volatile.img self.reset_volatile_storage(source_template = source_template) @@ -749,6 +753,21 @@ class QubesVm(object): raise QubesException ( "VM private image file doesn't exist: {0}".\ format(self.private_img)) + + if not os.path.exists (self.kernels_dir + '/vmlinuz'): + raise QubesException ( + "VM kernel does not exists: {0}".\ + format(self.kernels_dir + '/vmlinuz')) + + if not os.path.exists (self.kernels_dir + '/initramfs'): + raise QubesException ( + "VM initramfs does not exists: {0}".\ + format(self.kernels_dir + '/initramfs')) + + if not os.path.exists (self.kernels_dir + '/modules.img'): + raise QubesException ( + "VM kernel modules image does not exists: {0}".\ + format(self.kernels_dir + '/modules.img')) return True def reset_volatile_storage(self, source_template = None): @@ -986,6 +1005,8 @@ class QubesVm(object): attrs["pcidevs"] = str(self.pcidevs) attrs["vcpus"] = str(self.vcpus) attrs["internal"] = str(self.internal) + attrs["uses_default_kernel"] = str(self.uses_default_kernel) + attrs["kernel"] = str(self.kernel) return attrs def create_xml_element(self): @@ -1020,7 +1041,7 @@ class QubesTemplateVm(QubesVm): # Clean image for root-cow and swap (AppVM side) self.clean_volatile_img = self.dir_path + "/" + default_clean_volatile_img - + # Image for template changes self.rootcow_img = self.dir_path + "/" + default_rootcow_img @@ -1097,11 +1118,6 @@ class QubesTemplateVm(QubesVm): if retcode != 0: raise IOError ("Error while copying {0} to {1}".\ format(self.clean_volatile_img, self.volatile_img)) - if verbose: - print "--> Copying the template's kernel dir:\n{0} ==>\n{1}".\ - format(src_template_vm.kernels_dir, self.kernels_dir) - shutil.copytree (src_template_vm.kernels_dir, self.kernels_dir) - if verbose: print "--> Copying the template's appmenus templates dir:\n{0} ==>\n{1}".\ format(src_template_vm.appmenus_templates_dir, self.appmenus_templates_dir) @@ -1766,6 +1782,13 @@ class QubesVmCollection(dict): else: return self[self.default_netvm_qid] + def set_default_kernel(self, kernel): + assert os.path.exists(qubes_kernels_base_dir + '/' + kernel), "Kerel {0} not installed!".format(kernel) + self.default_kernel = kernel + + def get_default_kernel(self): + return self.default_kernel + def set_default_fw_netvm_vm(self, vm): assert vm.is_netvm(), "VM {0} does not provide network!".format(vm.name) self.default_fw_netvm_qid = vm.qid @@ -1891,7 +1914,10 @@ class QubesVmCollection(dict): if self.default_fw_netvm_qid is not None else "None", updatevm=str(self.updatevm_qid) \ - if self.updatevm_qid is not None else "None" + if self.updatevm_qid is not None else "None", + + default_kernel=str(self.default_kernel) \ + if self.default_kernel is not None else "None", ) for vm in self.values(): @@ -1919,7 +1945,7 @@ class QubesVmCollection(dict): "private_img", "root_img", "template_qid", "installed_by_rpm", "updateable", "internal", "uses_default_netvm", "label", "memory", "vcpus", "pcidevs", - "maxmem" ) + "maxmem", "kernel", "uses_default_kernel" ) for attribute in common_attr_list: kwargs[attribute] = element.get(attribute) @@ -1953,6 +1979,20 @@ class QubesVmCollection(dict): else: kwargs["label"] = QubesVmLabels[kwargs["label"]] + if "kernel" in kwargs and kwargs["kernel"] == "None": + kwargs["kernel"] = None + if "uses_default_kernel" in kwargs: + kwargs["uses_default_kernel"] = True if kwargs["uses_default_kernel"] == "True" else False + else: + # For backward compatibility + kwargs["uses_default_kernel"] = False + if kwargs["uses_default_kernel"]: + kwargs["kernel"] = self.get_default_kernel() + else: + if "kernel" in kwargs and kwargs["kernel"]=="None": + kwargs["kernel"]=None + # for other cases - generic assigment is ok + return kwargs def set_netvm_dependency(self, element): @@ -2027,6 +2067,7 @@ class QubesVmCollection(dict): if updatevm != "None" else None #assert self.default_netvm_qid is not None + self.default_kernel = element.get("default_kernel") # Then, read in the TemplateVMs, because a reference to template VM # is needed to create each AppVM diff --git a/dom0/qvm-tools/qvm-prefs b/dom0/qvm-tools/qvm-prefs index 6f22f9a4..10cf066a 100755 --- a/dom0/qvm-tools/qvm-prefs +++ b/dom0/qvm-tools/qvm-prefs @@ -22,8 +22,10 @@ from qubes.qubes import QubesVmCollection from qubes.qubes import QubesVmLabels +from qubes.qubes import qubes_kernels_base_dir from optparse import OptionParser import subprocess +import os def do_list(vm): label_width = 18 @@ -52,6 +54,10 @@ def do_list(vm): print fmt.format ("private img", vm.private_img) print fmt.format ("memory", vm.memory) print fmt.format ("maxmem", vm.maxmem) + if vm.uses_default_kernel: + print fmt.format ("kernel", "%s (default)" % vm.kernel) + else: + print fmt.format ("kernel", vm.kernel) def set_label(vms, vm, args): @@ -168,6 +174,33 @@ def set_nonupdateable(vms, vm, args): vm.set_nonupdateable() return True +def set_kernel(vms, vm, args): + if len (args) != 1: + print "Missing kernel version argument!" + print "Possible values:" + print "1) default" + print "2) none (kernels subdir in VM)" + print "3) , one of:" + for k in os.listdir(qubes_kernels_base_dir): + print " -", k + return + + 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(qubes_kernels_base_dir + '/' + kernel): + print "Kernel version {0} not installed.".format(kernel) + exit(1) + vm.uses_default_kernel = False + + vm.kernel = kernel + + properties = { "updateable": set_updateable, "nonupdateable": set_nonupdateable, @@ -176,6 +209,7 @@ properties = { "netvm" : set_netvm, "maxmem" : set_maxmem, "memory" : set_memory, + "kernel" : set_kernel, } diff --git a/dom0/qvm-tools/qvm-set-default-kernel b/dom0/qvm-tools/qvm-set-default-kernel new file mode 100755 index 00000000..37f85f54 --- /dev/null +++ b/dom0/qvm-tools/qvm-set-default-kernel @@ -0,0 +1,48 @@ +#!/usr/bin/python2.6 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2011 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, qubes_kernels_base_dir +from optparse import OptionParser; +import os + +def main(): + usage = "usage: %prog " + parser = OptionParser (usage) + (options, args) = parser.parse_args () + if (len (args) != 1): + parser.error ("Missing argument!") + kernel = args[0] + + if not os.path.exists(qubes_kernels_base_dir + "/" + kernel): + print "Kernel {0} not installed".format(kernel) + exit(1) + + qvm_collection = QubesVmCollection() + qvm_collection.lock_db_for_writing() + qvm_collection.load() + + qvm_collection.set_default_kernel(kernel) + + qvm_collection.save() + qvm_collection.unlock_db() + +main() diff --git a/rpm_spec/core-commonvm.spec b/rpm_spec/core-commonvm.spec index d754c361..26d89b11 100644 --- a/rpm_spec/core-commonvm.spec +++ b/rpm_spec/core-commonvm.spec @@ -86,6 +86,9 @@ mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes cp qubes_trigger_sync_appmenus.sh $RPM_BUILD_ROOT/usr/lib/qubes/ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/dom0-updates +mkdir -p $RPM_BUILD_ROOT/lib/firmware +ln -s /lib/modules/firmware $RPM_BUILD_ROOT/lib/firmware/updates + %triggerin -- initscripts cp /var/lib/qubes/serial.conf /etc/init/serial.conf @@ -236,3 +239,4 @@ rm -rf $RPM_BUILD_ROOT /etc/yum/post-actions/qubes_trigger_sync_appmenus.action /usr/lib/qubes/qubes_trigger_sync_appmenus.sh /usr/lib/qubes/qubes_download_dom0_updates.sh +/lib/firmware/updates diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index 3759e4e2..4f13fd4d 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -115,6 +115,7 @@ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/vm-templates mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/appvms mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/servicevms +mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/vm-kernels mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/backup mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/dvmdata @@ -295,6 +296,7 @@ fi %attr(770,root,qubes) %dir /var/lib/qubes/backup %attr(770,root,qubes) %dir /var/lib/qubes/dvmdata %attr(770,root,qubes) %dir /var/lib/qubes/updates +%attr(770,root,qubes) %dir /var/lib/qubes/vm-kernels %dir /usr/share/qubes/icons/*.png /usr/share/qubes/qubes-vm.directory.template /usr/share/qubes/qubes-templatevm.directory.template