kernels.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #
  2. # The Qubes OS Project, http://www.qubes-os.org
  3. #
  4. # Copyright (C) 2010-2015 Joanna Rutkowska <joanna@invisiblethingslab.com>
  5. # Copyright (C) 2015 Wojtek Porczyk <woju@invisiblethingslab.com>
  6. # Copyright (C) 2016 Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
  7. #
  8. # This library is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU Lesser General Public
  10. # License as published by the Free Software Foundation; either
  11. # version 2.1 of the License, or (at your option) any later version.
  12. #
  13. # This library is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. # Lesser General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU Lesser General Public
  19. # License along with this library; if not, see <https://www.gnu.org/licenses/>.
  20. #
  21. ''' This module contains pool implementations for different OS kernels. '''
  22. import os
  23. from qubes.storage import Pool, StoragePoolException, Volume
  24. class LinuxModules(Volume):
  25. ''' A volume representing a ro linux kernel '''
  26. rw = False
  27. def __init__(self, target_dir, kernel_version, **kwargs):
  28. kwargs['vid'] = ''
  29. super(LinuxModules, self).__init__(**kwargs)
  30. self._kernel_version = kernel_version
  31. self.target_dir = target_dir
  32. @property
  33. def vid(self):
  34. if callable(self._kernel_version):
  35. return self._kernel_version()
  36. return self._kernel_version
  37. @vid.setter
  38. def vid(self, value):
  39. # ignore
  40. pass
  41. @property
  42. def kernels_dir(self):
  43. kernel_version = self.vid
  44. if not kernel_version:
  45. return None
  46. return os.path.join(self.target_dir, kernel_version)
  47. @property
  48. def path(self):
  49. kernels_dir = self.kernels_dir
  50. if not kernels_dir:
  51. return None
  52. return os.path.join(kernels_dir, 'modules.img')
  53. @property
  54. def vmlinuz(self):
  55. kernels_dir = self.kernels_dir
  56. if not kernels_dir:
  57. return None
  58. return os.path.join(kernels_dir, 'vmlinuz')
  59. @property
  60. def initramfs(self):
  61. kernels_dir = self.kernels_dir
  62. if not kernels_dir:
  63. return None
  64. return os.path.join(kernels_dir, 'initramfs')
  65. @property
  66. def revisions(self):
  67. return {}
  68. def is_dirty(self):
  69. return False
  70. def import_volume(self, src_volume):
  71. if isinstance(src_volume, LinuxModules):
  72. # do nothing
  73. return self
  74. raise StoragePoolException('clone of LinuxModules volume from '
  75. 'different volume type is not supported')
  76. def create(self):
  77. return self
  78. def remove(self):
  79. pass
  80. def commit(self):
  81. return self
  82. def export(self):
  83. return self.path
  84. def is_outdated(self):
  85. return False
  86. def start(self):
  87. return self
  88. def stop(self):
  89. pass
  90. def verify(self):
  91. if self.vid:
  92. _check_path(self.vmlinuz)
  93. _check_path(self.initramfs)
  94. def block_device(self):
  95. path = self.path
  96. # create block device for modules.img only if:
  97. # - there is kernel set for the VM
  98. # - that kernel directory contains modules.img file
  99. if path and os.path.exists(path):
  100. return super().block_device()
  101. return None
  102. class LinuxKernel(Pool):
  103. ''' Provides linux kernels '''
  104. driver = 'linux-kernel'
  105. def __init__(self, name=None, dir_path=None):
  106. assert dir_path, 'Missing dir_path'
  107. super(LinuxKernel, self).__init__(name=name)
  108. self.dir_path = dir_path
  109. def init_volume(self, vm, volume_config):
  110. assert not volume_config['rw']
  111. # migrate old config
  112. if volume_config.get('snap_on_start', False) and not \
  113. volume_config.get('source', None):
  114. volume_config['snap_on_start'] = False
  115. if volume_config.get('save_on_stop', False):
  116. raise NotImplementedError(
  117. 'LinuxKernel pool does not support save_on_stop=True')
  118. volume_config['pool'] = self
  119. volume = LinuxModules(self.dir_path, lambda: vm.kernel, **volume_config)
  120. return volume
  121. @property
  122. def config(self):
  123. return {
  124. 'name': self.name,
  125. 'dir_path': self.dir_path,
  126. 'driver': LinuxKernel.driver,
  127. }
  128. def destroy(self):
  129. pass
  130. def import_volume(self, dst_pool, dst_volume, src_pool, src_volume):
  131. pass
  132. def setup(self):
  133. pass
  134. @property
  135. def volumes(self):
  136. ''' Return all known kernel volumes '''
  137. return [LinuxModules(self.dir_path,
  138. kernel_version,
  139. pool=self,
  140. name=kernel_version,
  141. rw=False
  142. )
  143. for kernel_version in os.listdir(self.dir_path)]
  144. def _check_path(path):
  145. ''' Raise an :py:class:`qubes.storage.StoragePoolException` if ``path`` does
  146. not exist.
  147. '''
  148. if not os.path.exists(path):
  149. raise StoragePoolException('Missing file: %s' % path)