diff options
Diffstat (limited to 'scripts/lib')
| -rw-r--r-- | scripts/lib/wic/plugins/imager/direct.py | 97 | ||||
| -rw-r--r-- | scripts/lib/wic/plugins/source/bootimg-pcbios.py | 2 | ||||
| -rw-r--r-- | scripts/lib/wic/plugins/source/isoimage-isohybrid.py | 10 | ||||
| -rw-r--r-- | scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py | 4 | ||||
| -rw-r--r-- | scripts/lib/wic/utils/partitionedfs.py | 194 |
5 files changed, 111 insertions, 196 deletions
diff --git a/scripts/lib/wic/plugins/imager/direct.py b/scripts/lib/wic/plugins/imager/direct.py index a9144e2f4b..fefe88e0df 100644 --- a/scripts/lib/wic/plugins/imager/direct.py +++ b/scripts/lib/wic/plugins/imager/direct.py | |||
| @@ -36,25 +36,8 @@ from wic.plugin import pluginmgr | |||
| 36 | from wic.pluginbase import ImagerPlugin | 36 | from wic.pluginbase import ImagerPlugin |
| 37 | from wic.utils.errors import CreatorError, ImageError | 37 | from wic.utils.errors import CreatorError, ImageError |
| 38 | from wic.utils.misc import get_bitbake_var, exec_cmd, exec_native_cmd | 38 | from wic.utils.misc import get_bitbake_var, exec_cmd, exec_native_cmd |
| 39 | from wic.utils.partitionedfs import Image | 39 | from wic.utils.partitionedfs import PartitionedImage |
| 40 | 40 | ||
| 41 | class DiskImage(): | ||
| 42 | """ | ||
| 43 | A Disk backed by a file. | ||
| 44 | """ | ||
| 45 | def __init__(self, device, size): | ||
| 46 | self.size = size | ||
| 47 | self.device = device | ||
| 48 | self.created = False | ||
| 49 | |||
| 50 | def create(self): | ||
| 51 | if self.created: | ||
| 52 | return | ||
| 53 | # create sparse disk image | ||
| 54 | with open(self.device, 'w') as sparse: | ||
| 55 | os.ftruncate(sparse.fileno(), self.size) | ||
| 56 | |||
| 57 | self.created = True | ||
| 58 | 41 | ||
| 59 | class DirectPlugin(ImagerPlugin): | 42 | class DirectPlugin(ImagerPlugin): |
| 60 | """ | 43 | """ |
| @@ -189,9 +172,10 @@ class DirectPlugin(ImagerPlugin): | |||
| 189 | filesystems from the artifacts directly and combine them into | 172 | filesystems from the artifacts directly and combine them into |
| 190 | a partitioned image. | 173 | a partitioned image. |
| 191 | """ | 174 | """ |
| 192 | self._image = Image(self.native_sysroot) | 175 | image_path = self._full_path(self.workdir, self.parts[0].disk, "direct") |
| 176 | self._image = PartitionedImage(image_path, self.ptable_format, | ||
| 177 | self.native_sysroot) | ||
| 193 | 178 | ||
| 194 | disk_ids = {} | ||
| 195 | for num, part in enumerate(self.parts, 1): | 179 | for num, part in enumerate(self.parts, 1): |
| 196 | # as a convenience, set source to the boot partition source | 180 | # as a convenience, set source to the boot partition source |
| 197 | # instead of forcing it to be set via bootloader --source | 181 | # instead of forcing it to be set via bootloader --source |
| @@ -203,10 +187,8 @@ class DirectPlugin(ImagerPlugin): | |||
| 203 | if self.ptable_format == 'gpt': | 187 | if self.ptable_format == 'gpt': |
| 204 | part.uuid = str(uuid.uuid4()) | 188 | part.uuid = str(uuid.uuid4()) |
| 205 | else: # msdos partition table | 189 | else: # msdos partition table |
| 206 | if part.disk not in disk_ids: | 190 | part.uuid = '%0x-%02d' % (self._image.identifier, |
| 207 | disk_ids[part.disk] = int.from_bytes(os.urandom(4), 'little') | 191 | self._get_part_num(num, self.parts)) |
| 208 | disk_id = disk_ids[part.disk] | ||
| 209 | part.uuid = '%0x-%02d' % (disk_id, self._get_part_num(num, self.parts)) | ||
| 210 | 192 | ||
| 211 | fstab_path = self._write_fstab(self.rootfs_dir.get("ROOTFS_DIR")) | 193 | fstab_path = self._write_fstab(self.rootfs_dir.get("ROOTFS_DIR")) |
| 212 | 194 | ||
| @@ -225,11 +207,6 @@ class DirectPlugin(ImagerPlugin): | |||
| 225 | part.size = int(round(float(rsize_bb))) | 207 | part.size = int(round(float(rsize_bb))) |
| 226 | # need to create the filesystems in order to get their | 208 | # need to create the filesystems in order to get their |
| 227 | # sizes before we can add them and do the layout. | 209 | # sizes before we can add them and do the layout. |
| 228 | # Image.create() actually calls __format_disks() to create | ||
| 229 | # the disk images and carve out the partitions, then | ||
| 230 | # self.assemble() calls Image.assemble() which calls | ||
| 231 | # __write_partitition() for each partition to dd the fs | ||
| 232 | # into the partitions. | ||
| 233 | part.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir, | 210 | part.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir, |
| 234 | self.bootimg_dir, self.kernel_dir, self.native_sysroot) | 211 | self.bootimg_dir, self.kernel_dir, self.native_sysroot) |
| 235 | 212 | ||
| @@ -238,26 +215,14 @@ class DirectPlugin(ImagerPlugin): | |||
| 238 | if fstab_path: | 215 | if fstab_path: |
| 239 | shutil.move(fstab_path + ".orig", fstab_path) | 216 | shutil.move(fstab_path + ".orig", fstab_path) |
| 240 | 217 | ||
| 241 | self._image.layout_partitions(self.ptable_format) | 218 | self._image.layout_partitions() |
| 242 | |||
| 243 | for disk_name, disk in self._image.disks.items(): | ||
| 244 | full_path = self._full_path(self.workdir, disk_name, "direct") | ||
| 245 | msger.debug("Adding disk %s as %s with size %s bytes" \ | ||
| 246 | % (disk_name, full_path, disk['min_size'])) | ||
| 247 | disk_obj = DiskImage(full_path, disk['min_size']) | ||
| 248 | self._image.add_disk(disk_name, disk_obj, disk_ids.get(disk_name)) | ||
| 249 | |||
| 250 | self._image.create() | 219 | self._image.create() |
| 251 | 220 | ||
| 252 | def assemble(self): | 221 | def assemble(self): |
| 253 | """ | 222 | """ |
| 254 | Assemble partitions into disk image(s) | 223 | Assemble partitions into disk image |
| 255 | """ | 224 | """ |
| 256 | for disk_name, disk in self._image.disks.items(): | 225 | self._image.assemble() |
| 257 | full_path = self._full_path(self.workdir, disk_name, "direct") | ||
| 258 | msger.debug("Assembling disk %s as %s with size %s bytes" \ | ||
| 259 | % (disk_name, full_path, disk['min_size'])) | ||
| 260 | self._image.assemble(full_path) | ||
| 261 | 226 | ||
| 262 | def finalize(self): | 227 | def finalize(self): |
| 263 | """ | 228 | """ |
| @@ -267,26 +232,25 @@ class DirectPlugin(ImagerPlugin): | |||
| 267 | creating and installing a bootloader configuration. | 232 | creating and installing a bootloader configuration. |
| 268 | """ | 233 | """ |
| 269 | source_plugin = self.ks.bootloader.source | 234 | source_plugin = self.ks.bootloader.source |
| 235 | disk_name = self.parts[0].disk | ||
| 270 | if source_plugin: | 236 | if source_plugin: |
| 271 | name = "do_install_disk" | 237 | name = "do_install_disk" |
| 272 | methods = pluginmgr.get_source_plugin_methods(source_plugin, | 238 | methods = pluginmgr.get_source_plugin_methods(source_plugin, |
| 273 | {name: None}) | 239 | {name: None}) |
| 274 | for disk_name, disk in self._image.disks.items(): | 240 | methods["do_install_disk"](self._image, disk_name, self, self.workdir, |
| 275 | methods["do_install_disk"](disk, disk_name, self, self.workdir, | 241 | self.oe_builddir, self.bootimg_dir, |
| 276 | self.oe_builddir, self.bootimg_dir, | 242 | self.kernel_dir, self.native_sysroot) |
| 277 | self.kernel_dir, self.native_sysroot) | 243 | |
| 278 | 244 | full_path = self._image.path | |
| 279 | for disk_name, disk in self._image.disks.items(): | 245 | # Generate .bmap |
| 280 | full_path = self._full_path(self.workdir, disk_name, "direct") | 246 | if self.bmap: |
| 281 | # Generate .bmap | 247 | msger.debug("Generating bmap file for %s" % disk_name) |
| 282 | if self.bmap: | 248 | exec_native_cmd("bmaptool create %s -o %s.bmap" % (full_path, full_path), |
| 283 | msger.debug("Generating bmap file for %s" % disk_name) | 249 | self.native_sysroot) |
| 284 | exec_native_cmd("bmaptool create %s -o %s.bmap" % (full_path, full_path), | 250 | # Compress the image |
| 285 | self.native_sysroot) | 251 | if self.compressor: |
| 286 | # Compress the image | 252 | msger.debug("Compressing disk %s with %s" % (disk_name, self.compressor)) |
| 287 | if self.compressor: | 253 | exec_cmd("%s %s" % (self.compressor, full_path)) |
| 288 | msger.debug("Compressing disk %s with %s" % (disk_name, self.compressor)) | ||
| 289 | exec_cmd("%s %s" % (self.compressor, full_path)) | ||
| 290 | 254 | ||
| 291 | def print_info(self): | 255 | def print_info(self): |
| 292 | """ | 256 | """ |
| @@ -294,13 +258,12 @@ class DirectPlugin(ImagerPlugin): | |||
| 294 | """ | 258 | """ |
| 295 | msg = "The new image(s) can be found here:\n" | 259 | msg = "The new image(s) can be found here:\n" |
| 296 | 260 | ||
| 297 | for disk_name in self._image.disks: | 261 | extension = "direct" + {"gzip": ".gz", |
| 298 | extension = "direct" + {"gzip": ".gz", | 262 | "bzip2": ".bz2", |
| 299 | "bzip2": ".bz2", | 263 | "xz": ".xz", |
| 300 | "xz": ".xz", | 264 | None: ""}.get(self.compressor) |
| 301 | None: ""}.get(self.compressor) | 265 | full_path = self._full_path(self.outdir, self.parts[0].disk, extension) |
| 302 | full_path = self._full_path(self.outdir, disk_name, extension) | 266 | msg += ' %s\n\n' % full_path |
| 303 | msg += ' %s\n\n' % full_path | ||
| 304 | 267 | ||
| 305 | msg += 'The following build artifacts were used to create the image(s):\n' | 268 | msg += 'The following build artifacts were used to create the image(s):\n' |
| 306 | for part in self.parts: | 269 | for part in self.parts: |
diff --git a/scripts/lib/wic/plugins/source/bootimg-pcbios.py b/scripts/lib/wic/plugins/source/bootimg-pcbios.py index 4b9b26552a..0be2b78e51 100644 --- a/scripts/lib/wic/plugins/source/bootimg-pcbios.py +++ b/scripts/lib/wic/plugins/source/bootimg-pcbios.py | |||
| @@ -63,7 +63,7 @@ class BootimgPcbiosPlugin(SourcePlugin): | |||
| 63 | 63 | ||
| 64 | full_path = creator._full_path(workdir, disk_name, "direct") | 64 | full_path = creator._full_path(workdir, disk_name, "direct") |
| 65 | msger.debug("Installing MBR on disk %s as %s with size %s bytes" \ | 65 | msger.debug("Installing MBR on disk %s as %s with size %s bytes" \ |
| 66 | % (disk_name, full_path, disk['min_size'])) | 66 | % (disk_name, full_path, disk.min_size)) |
| 67 | 67 | ||
| 68 | rcode = runner.show(['dd', 'if=%s' % mbrfile, | 68 | rcode = runner.show(['dd', 'if=%s' % mbrfile, |
| 69 | 'of=%s' % full_path, 'conv=notrunc']) | 69 | 'of=%s' % full_path, 'conv=notrunc']) |
diff --git a/scripts/lib/wic/plugins/source/isoimage-isohybrid.py b/scripts/lib/wic/plugins/source/isoimage-isohybrid.py index ca28bc0fa3..fb34235631 100644 --- a/scripts/lib/wic/plugins/source/isoimage-isohybrid.py +++ b/scripts/lib/wic/plugins/source/isoimage-isohybrid.py | |||
| @@ -473,13 +473,12 @@ class IsoImagePlugin(SourcePlugin): | |||
| 473 | utility for booting via BIOS from disk storage devices. | 473 | utility for booting via BIOS from disk storage devices. |
| 474 | """ | 474 | """ |
| 475 | 475 | ||
| 476 | iso_img = "%s.p1" % disk.path | ||
| 476 | full_path = creator._full_path(workdir, disk_name, "direct") | 477 | full_path = creator._full_path(workdir, disk_name, "direct") |
| 477 | iso_img = "%s.p1" % full_path | ||
| 478 | full_path_iso = creator._full_path(workdir, disk_name, "iso") | 478 | full_path_iso = creator._full_path(workdir, disk_name, "iso") |
| 479 | 479 | ||
| 480 | isohybrid_cmd = "isohybrid -u %s" % iso_img | 480 | isohybrid_cmd = "isohybrid -u %s" % iso_img |
| 481 | msger.debug("running command: %s" % \ | 481 | msger.debug("running command: %s" % isohybrid_cmd) |
| 482 | isohybrid_cmd) | ||
| 483 | exec_native_cmd(isohybrid_cmd, native_sysroot) | 482 | exec_native_cmd(isohybrid_cmd, native_sysroot) |
| 484 | 483 | ||
| 485 | # Replace the image created by direct plugin with the one created by | 484 | # Replace the image created by direct plugin with the one created by |
| @@ -487,9 +486,6 @@ class IsoImagePlugin(SourcePlugin): | |||
| 487 | # mkisofs has a very specific MBR is system area of the ISO image, and | 486 | # mkisofs has a very specific MBR is system area of the ISO image, and |
| 488 | # direct plugin adds and configures an another MBR. | 487 | # direct plugin adds and configures an another MBR. |
| 489 | msger.debug("Replaceing the image created by direct plugin\n") | 488 | msger.debug("Replaceing the image created by direct plugin\n") |
| 490 | os.remove(full_path) | 489 | os.remove(disk.path) |
| 491 | shutil.copy2(iso_img, full_path_iso) | 490 | shutil.copy2(iso_img, full_path_iso) |
| 492 | shutil.copy2(full_path_iso, full_path) | 491 | shutil.copy2(full_path_iso, full_path) |
| 493 | |||
| 494 | # Remove temporary ISO file | ||
| 495 | os.remove(iso_img) | ||
diff --git a/scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py b/scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py index cb1da93d30..9e79a139da 100644 --- a/scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py +++ b/scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py | |||
| @@ -204,9 +204,9 @@ class RootfsPlugin(SourcePlugin): | |||
| 204 | if not os.path.exists(mbrfile): | 204 | if not os.path.exists(mbrfile): |
| 205 | msger.error("Couldn't find %s. Has syslinux-native been baked?" % mbrfile) | 205 | msger.error("Couldn't find %s. Has syslinux-native been baked?" % mbrfile) |
| 206 | 206 | ||
| 207 | full_path = disk['disk'].device | 207 | full_path = disk.path |
| 208 | msger.debug("Installing MBR on disk %s as %s with size %s bytes" \ | 208 | msger.debug("Installing MBR on disk %s as %s with size %s bytes" \ |
| 209 | % (disk_name, full_path, disk['min_size'])) | 209 | % (disk_name, full_path, disk.min_size)) |
| 210 | 210 | ||
| 211 | ret_code = runner.show(['dd', 'if=%s' % mbrfile, 'of=%s' % full_path, 'conv=notrunc']) | 211 | ret_code = runner.show(['dd', 'if=%s' % mbrfile, 'of=%s' % full_path, 'conv=notrunc']) |
| 212 | if ret_code != 0: | 212 | if ret_code != 0: |
diff --git a/scripts/lib/wic/utils/partitionedfs.py b/scripts/lib/wic/utils/partitionedfs.py index 5397bb704c..cdf8f08015 100644 --- a/scripts/lib/wic/utils/partitionedfs.py +++ b/scripts/lib/wic/utils/partitionedfs.py | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 19 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 20 | 20 | ||
| 21 | import os | 21 | import os |
| 22 | |||
| 22 | from wic import msger | 23 | from wic import msger |
| 23 | from wic.utils.errors import ImageError | 24 | from wic.utils.errors import ImageError |
| 24 | from wic.utils.misc import exec_native_cmd | 25 | from wic.utils.misc import exec_native_cmd |
| @@ -33,50 +34,28 @@ GPT_OVERHEAD = 34 | |||
| 33 | # Size of a sector in bytes | 34 | # Size of a sector in bytes |
| 34 | SECTOR_SIZE = 512 | 35 | SECTOR_SIZE = 512 |
| 35 | 36 | ||
| 36 | class Image(): | 37 | class PartitionedImage(): |
| 37 | """ | 38 | """ |
| 38 | Generic base object for an image. | 39 | Partitioned image in a file. |
| 39 | |||
| 40 | An Image is a container for a set of DiskImages and associated | ||
| 41 | partitions. | ||
| 42 | """ | 40 | """ |
| 43 | def __init__(self, native_sysroot=None): | 41 | |
| 44 | self.disks = {} | 42 | def __init__(self, path, ptable_format, native_sysroot=None): |
| 43 | self.path = path # Path to the image file | ||
| 44 | self.numpart = 0 # Number of allocated partitions | ||
| 45 | self.realpart = 0 # Number of partitions in the partition table | ||
| 46 | self.offset = 0 # Offset of next partition (in sectors) | ||
| 47 | self.min_size = 0 # Minimum required disk size to fit | ||
| 48 | # all partitions (in bytes) | ||
| 49 | self.ptable_format = ptable_format # Partition table format | ||
| 50 | # Disk system identifier | ||
| 51 | self.identifier = int.from_bytes(os.urandom(4), 'little') | ||
| 52 | |||
| 45 | self.partitions = [] | 53 | self.partitions = [] |
| 46 | self.partimages = [] | 54 | self.partimages = [] |
| 47 | # Size of a sector used in calculations | 55 | # Size of a sector used in calculations |
| 48 | self.sector_size = SECTOR_SIZE | 56 | self.sector_size = SECTOR_SIZE |
| 49 | self.native_sysroot = native_sysroot | 57 | self.native_sysroot = native_sysroot |
| 50 | 58 | ||
| 51 | def _add_disk(self, disk_name): | ||
| 52 | """ Add a disk 'disk_name' to the internal list of disks. Note, | ||
| 53 | 'disk_name' is the name of the disk in the target system | ||
| 54 | (e.g., sdb). """ | ||
| 55 | |||
| 56 | if disk_name in self.disks: | ||
| 57 | # We already have this disk | ||
| 58 | return | ||
| 59 | |||
| 60 | self.disks[disk_name] = \ | ||
| 61 | {'disk': None, # Disk object | ||
| 62 | 'numpart': 0, # Number of allocate partitions | ||
| 63 | 'realpart': 0, # Number of partitions in the partition table | ||
| 64 | 'partitions': [], # Indexes to self.partitions | ||
| 65 | 'offset': 0, # Offset of next partition (in sectors) | ||
| 66 | # Minimum required disk size to fit all partitions (in bytes) | ||
| 67 | 'min_size': 0, | ||
| 68 | 'ptable_format': "msdos", # Partition table format | ||
| 69 | 'identifier': None} # Disk system identifier | ||
| 70 | |||
| 71 | def add_disk(self, name, disk_obj, identifier): | ||
| 72 | """ Add a disk object which have to be partitioned. More than one disk | ||
| 73 | can be added. In case of multiple disks, disk partitions have to be | ||
| 74 | added for each disk separately with 'add_partition()". """ | ||
| 75 | |||
| 76 | self._add_disk(name) | ||
| 77 | self.disks[name]['disk'] = disk_obj | ||
| 78 | self.disks[name]['identifier'] = identifier | ||
| 79 | |||
| 80 | def add_partition(self, part): | 59 | def add_partition(self, part): |
| 81 | """ | 60 | """ |
| 82 | Add the next partition. Partitions have to be added in the | 61 | Add the next partition. Partitions have to be added in the |
| @@ -88,24 +67,19 @@ class Image(): | |||
| 88 | part.size_sec = part.disk_size * 1024 // self.sector_size | 67 | part.size_sec = part.disk_size * 1024 // self.sector_size |
| 89 | 68 | ||
| 90 | self.partitions.append(part) | 69 | self.partitions.append(part) |
| 91 | self._add_disk(part.disk) | ||
| 92 | 70 | ||
| 93 | def layout_partitions(self, ptable_format="msdos"): | 71 | def layout_partitions(self): |
| 94 | """ Layout the partitions, meaning calculate the position of every | 72 | """ Layout the partitions, meaning calculate the position of every |
| 95 | partition on the disk. The 'ptable_format' parameter defines the | 73 | partition on the disk. The 'ptable_format' parameter defines the |
| 96 | partition table format and may be "msdos". """ | 74 | partition table format and may be "msdos". """ |
| 97 | 75 | ||
| 98 | msger.debug("Assigning %s partitions to disks" % ptable_format) | 76 | msger.debug("Assigning %s partitions to disks" % self.ptable_format) |
| 99 | 77 | ||
| 100 | # Go through partitions in the order they are added in .ks file | 78 | # Go through partitions in the order they are added in .ks file |
| 101 | for num in range(len(self.partitions)): | 79 | for num in range(len(self.partitions)): |
| 102 | part = self.partitions[num] | 80 | part = self.partitions[num] |
| 103 | 81 | ||
| 104 | if part.disk not in self.disks: | 82 | if self.ptable_format == 'msdos' and part.part_type: |
| 105 | raise ImageError("No disk %s for partition %s" \ | ||
| 106 | % (part.disk, part.mountpoint)) | ||
| 107 | |||
| 108 | if ptable_format == 'msdos' and part.part_type: | ||
| 109 | # The --part-type can also be implemented for MBR partitions, | 83 | # The --part-type can also be implemented for MBR partitions, |
| 110 | # in which case it would map to the 1-byte "partition type" | 84 | # in which case it would map to the 1-byte "partition type" |
| 111 | # filed at offset 3 of the partition entry. | 85 | # filed at offset 3 of the partition entry. |
| @@ -113,27 +87,24 @@ class Image(): | |||
| 113 | "implemented for msdos partitions") | 87 | "implemented for msdos partitions") |
| 114 | 88 | ||
| 115 | # Get the disk where the partition is located | 89 | # Get the disk where the partition is located |
| 116 | disk = self.disks[part.disk] | 90 | self.numpart += 1 |
| 117 | disk['numpart'] += 1 | ||
| 118 | if not part.no_table: | 91 | if not part.no_table: |
| 119 | disk['realpart'] += 1 | 92 | self.realpart += 1 |
| 120 | disk['ptable_format'] = ptable_format | ||
| 121 | 93 | ||
| 122 | if disk['numpart'] == 1: | 94 | if self.numpart == 1: |
| 123 | if ptable_format == "msdos": | 95 | if self.ptable_format == "msdos": |
| 124 | overhead = MBR_OVERHEAD | 96 | overhead = MBR_OVERHEAD |
| 125 | elif ptable_format == "gpt": | 97 | elif self.ptable_format == "gpt": |
| 126 | overhead = GPT_OVERHEAD | 98 | overhead = GPT_OVERHEAD |
| 127 | 99 | ||
| 128 | # Skip one sector required for the partitioning scheme overhead | 100 | # Skip one sector required for the partitioning scheme overhead |
| 129 | disk['offset'] += overhead | 101 | self.offset += overhead |
| 130 | 102 | ||
| 131 | if disk['realpart'] > 3: | 103 | if self.realpart > 3: |
| 132 | # Reserve a sector for EBR for every logical partition | 104 | # Reserve a sector for EBR for every logical partition |
| 133 | # before alignment is performed. | 105 | # before alignment is performed. |
| 134 | if ptable_format == "msdos": | 106 | if self.ptable_format == "msdos": |
| 135 | disk['offset'] += 1 | 107 | self.offset += 1 |
| 136 | |||
| 137 | 108 | ||
| 138 | if part.align: | 109 | if part.align: |
| 139 | # If not first partition and we do have alignment set we need | 110 | # If not first partition and we do have alignment set we need |
| @@ -142,7 +113,7 @@ class Image(): | |||
| 142 | # gaps we could enlargea the previous partition? | 113 | # gaps we could enlargea the previous partition? |
| 143 | 114 | ||
| 144 | # Calc how much the alignment is off. | 115 | # Calc how much the alignment is off. |
| 145 | align_sectors = disk['offset'] % (part.align * 1024 // self.sector_size) | 116 | align_sectors = self.offset % (part.align * 1024 // self.sector_size) |
| 146 | 117 | ||
| 147 | if align_sectors: | 118 | if align_sectors: |
| 148 | # If partition is not aligned as required, we need | 119 | # If partition is not aligned as required, we need |
| @@ -151,43 +122,41 @@ class Image(): | |||
| 151 | 122 | ||
| 152 | msger.debug("Realignment for %s%s with %s sectors, original" | 123 | msger.debug("Realignment for %s%s with %s sectors, original" |
| 153 | " offset %s, target alignment is %sK." % | 124 | " offset %s, target alignment is %sK." % |
| 154 | (part.disk, disk['numpart'], align_sectors, | 125 | (part.disk, self.numpart, align_sectors, |
| 155 | disk['offset'], part.align)) | 126 | self.offset, part.align)) |
| 156 | 127 | ||
| 157 | # increase the offset so we actually start the partition on right alignment | 128 | # increase the offset so we actually start the partition on right alignment |
| 158 | disk['offset'] += align_sectors | 129 | self.offset += align_sectors |
| 159 | 130 | ||
| 160 | part.start = disk['offset'] | 131 | part.start = self.offset |
| 161 | disk['offset'] += part.size_sec | 132 | self.offset += part.size_sec |
| 162 | 133 | ||
| 163 | part.type = 'primary' | 134 | part.type = 'primary' |
| 164 | if not part.no_table: | 135 | if not part.no_table: |
| 165 | part.num = disk['realpart'] | 136 | part.num = self.realpart |
| 166 | else: | 137 | else: |
| 167 | part.num = 0 | 138 | part.num = 0 |
| 168 | 139 | ||
| 169 | if disk['ptable_format'] == "msdos": | 140 | if self.ptable_format == "msdos": |
| 170 | # only count the partitions that are in partition table | 141 | # only count the partitions that are in partition table |
| 171 | if len([p for p in self.partitions if not p.no_table]) > 4: | 142 | if len([p for p in self.partitions if not p.no_table]) > 4: |
| 172 | if disk['realpart'] > 3: | 143 | if self.realpart > 3: |
| 173 | part.type = 'logical' | 144 | part.type = 'logical' |
| 174 | part.num = disk['realpart'] + 1 | 145 | part.num = self.realpart + 1 |
| 175 | 146 | ||
| 176 | disk['partitions'].append(num) | ||
| 177 | msger.debug("Assigned %s to %s%d, sectors range %d-%d size %d " | 147 | msger.debug("Assigned %s to %s%d, sectors range %d-%d size %d " |
| 178 | "sectors (%d bytes)." \ | 148 | "sectors (%d bytes)." \ |
| 179 | % (part.mountpoint, part.disk, part.num, | 149 | % (part.mountpoint, part.disk, part.num, |
| 180 | part.start, disk['offset'] - 1, | 150 | part.start, self.offset - 1, |
| 181 | part.size_sec, part.size_sec * self.sector_size)) | 151 | part.size_sec, part.size_sec * self.sector_size)) |
| 182 | 152 | ||
| 183 | # Once all the partitions have been layed out, we can calculate the | 153 | # Once all the partitions have been layed out, we can calculate the |
| 184 | # minumim disk sizes. | 154 | # minumim disk size |
| 185 | for disk in self.disks.values(): | 155 | self.min_size = self.offset |
| 186 | disk['min_size'] = disk['offset'] | 156 | if self.ptable_format == "gpt": |
| 187 | if disk['ptable_format'] == "gpt": | 157 | self.min_size += GPT_OVERHEAD |
| 188 | disk['min_size'] += GPT_OVERHEAD | ||
| 189 | 158 | ||
| 190 | disk['min_size'] *= self.sector_size | 159 | self.min_size *= self.sector_size |
| 191 | 160 | ||
| 192 | def _create_partition(self, device, parttype, fstype, start, size): | 161 | def _create_partition(self, device, parttype, fstype, start, size): |
| 193 | """ Create a partition on an image described by the 'device' object. """ | 162 | """ Create a partition on an image described by the 'device' object. """ |
| @@ -205,23 +174,18 @@ class Image(): | |||
| 205 | return exec_native_cmd(cmd, self.native_sysroot) | 174 | return exec_native_cmd(cmd, self.native_sysroot) |
| 206 | 175 | ||
| 207 | def create(self): | 176 | def create(self): |
| 208 | for dev in self.disks: | 177 | msger.debug("Creating sparse file %s" % self.path) |
| 209 | disk = self.disks[dev] | 178 | with open(self.path, 'w') as sparse: |
| 210 | disk['disk'].create() | 179 | os.ftruncate(sparse.fileno(), self.min_size) |
| 211 | 180 | ||
| 212 | for dev in self.disks: | 181 | msger.debug("Initializing partition table for %s" % self.path) |
| 213 | disk = self.disks[dev] | 182 | exec_native_cmd("parted -s %s mklabel %s" % |
| 214 | msger.debug("Initializing partition table for %s" % \ | 183 | (self.path, self.ptable_format), self.native_sysroot) |
| 215 | (disk['disk'].device)) | 184 | |
| 216 | exec_native_cmd("parted -s %s mklabel %s" % \ | 185 | msger.debug("Set disk identifier %x" % self.identifier) |
| 217 | (disk['disk'].device, disk['ptable_format']), | 186 | with open(self.path, 'r+b') as img: |
| 218 | self.native_sysroot) | 187 | img.seek(0x1B8) |
| 219 | 188 | img.write(self.identifier.to_bytes(4, 'little')) | |
| 220 | if disk['identifier']: | ||
| 221 | msger.debug("Set disk identifier %x" % disk['identifier']) | ||
| 222 | with open(disk['disk'].device, 'r+b') as img: | ||
| 223 | img.seek(0x1B8) | ||
| 224 | img.write(disk['identifier'].to_bytes(4, 'little')) | ||
| 225 | 189 | ||
| 226 | msger.debug("Creating partitions") | 190 | msger.debug("Creating partitions") |
| 227 | 191 | ||
| @@ -229,8 +193,7 @@ class Image(): | |||
| 229 | if part.num == 0: | 193 | if part.num == 0: |
| 230 | continue | 194 | continue |
| 231 | 195 | ||
| 232 | disk = self.disks[part.disk] | 196 | if self.ptable_format == "msdos" and part.num == 5: |
| 233 | if disk['ptable_format'] == "msdos" and part.num == 5: | ||
| 234 | # Create an extended partition (note: extended | 197 | # Create an extended partition (note: extended |
| 235 | # partition is described in MBR and contains all | 198 | # partition is described in MBR and contains all |
| 236 | # logical partitions). The logical partitions save a | 199 | # logical partitions). The logical partitions save a |
| @@ -242,9 +205,9 @@ class Image(): | |||
| 242 | # starts a sector before the first logical partition, | 205 | # starts a sector before the first logical partition, |
| 243 | # add a sector at the back, so that there is enough | 206 | # add a sector at the back, so that there is enough |
| 244 | # room for all logical partitions. | 207 | # room for all logical partitions. |
| 245 | self._create_partition(disk['disk'].device, "extended", | 208 | self._create_partition(self.path, "extended", |
| 246 | None, part.start - 1, | 209 | None, part.start - 1, |
| 247 | disk['offset'] - part.start + 1) | 210 | self.offset - part.start + 1) |
| 248 | 211 | ||
| 249 | if part.fstype == "swap": | 212 | if part.fstype == "swap": |
| 250 | parted_fs_type = "linux-swap" | 213 | parted_fs_type = "linux-swap" |
| @@ -267,7 +230,7 @@ class Image(): | |||
| 267 | part.mountpoint) | 230 | part.mountpoint) |
| 268 | part.size_sec -= 1 | 231 | part.size_sec -= 1 |
| 269 | 232 | ||
| 270 | self._create_partition(disk['disk'].device, part.type, | 233 | self._create_partition(self.path, part.type, |
| 271 | parted_fs_type, part.start, part.size_sec) | 234 | parted_fs_type, part.start, part.size_sec) |
| 272 | 235 | ||
| 273 | if part.part_type: | 236 | if part.part_type: |
| @@ -275,71 +238,64 @@ class Image(): | |||
| 275 | (part.num, part.part_type)) | 238 | (part.num, part.part_type)) |
| 276 | exec_native_cmd("sgdisk --typecode=%d:%s %s" % \ | 239 | exec_native_cmd("sgdisk --typecode=%d:%s %s" % \ |
| 277 | (part.num, part.part_type, | 240 | (part.num, part.part_type, |
| 278 | disk['disk'].device), self.native_sysroot) | 241 | self.path), self.native_sysroot) |
| 279 | 242 | ||
| 280 | if part.uuid and disk['ptable_format'] == "gpt": | 243 | if part.uuid and self.ptable_format == "gpt": |
| 281 | msger.debug("partition %d: set UUID to %s" % \ | 244 | msger.debug("partition %d: set UUID to %s" % \ |
| 282 | (part.num, part.uuid)) | 245 | (part.num, part.uuid)) |
| 283 | exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \ | 246 | exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \ |
| 284 | (part.num, part.uuid, disk['disk'].device), | 247 | (part.num, part.uuid, self.path), |
| 285 | self.native_sysroot) | 248 | self.native_sysroot) |
| 286 | 249 | ||
| 287 | if part.label and disk['ptable_format'] == "gpt": | 250 | if part.label and self.ptable_format == "gpt": |
| 288 | msger.debug("partition %d: set name to %s" % \ | 251 | msger.debug("partition %d: set name to %s" % \ |
| 289 | (part.num, part.label)) | 252 | (part.num, part.label)) |
| 290 | exec_native_cmd("parted -s %s name %d %s" % \ | 253 | exec_native_cmd("parted -s %s name %d %s" % \ |
| 291 | (disk['disk'].device, part.num, part.label), | 254 | (self.path, part.num, part.label), |
| 292 | self.native_sysroot) | 255 | self.native_sysroot) |
| 293 | 256 | ||
| 294 | if part.active: | 257 | if part.active: |
| 295 | flag_name = "legacy_boot" if disk['ptable_format'] == 'gpt' else "boot" | 258 | flag_name = "legacy_boot" if self.ptable_format == 'gpt' else "boot" |
| 296 | msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \ | 259 | msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \ |
| 297 | (flag_name, part.num, disk['disk'].device)) | 260 | (flag_name, part.num, self.path)) |
| 298 | exec_native_cmd("parted -s %s set %d %s on" % \ | 261 | exec_native_cmd("parted -s %s set %d %s on" % \ |
| 299 | (disk['disk'].device, part.num, flag_name), | 262 | (self.path, part.num, flag_name), |
| 300 | self.native_sysroot) | 263 | self.native_sysroot) |
| 301 | if part.system_id: | 264 | if part.system_id: |
| 302 | exec_native_cmd("sfdisk --part-type %s %s %s" % \ | 265 | exec_native_cmd("sfdisk --part-type %s %s %s" % \ |
| 303 | (disk['disk'].device, part.num, part.system_id), | 266 | (self.path, part.num, part.system_id), |
| 304 | self.native_sysroot) | 267 | self.native_sysroot) |
| 305 | 268 | ||
| 306 | # Parted defaults to enabling the lba flag for fat16 partitions, | 269 | # Parted defaults to enabling the lba flag for fat16 partitions, |
| 307 | # which causes compatibility issues with some firmware (and really | 270 | # which causes compatibility issues with some firmware (and really |
| 308 | # isn't necessary). | 271 | # isn't necessary). |
| 309 | if parted_fs_type == "fat16": | 272 | if parted_fs_type == "fat16": |
| 310 | if disk['ptable_format'] == 'msdos': | 273 | if self.ptable_format == 'msdos': |
| 311 | msger.debug("Disable 'lba' flag for partition '%s' on disk '%s'" % \ | 274 | msger.debug("Disable 'lba' flag for partition '%s' on disk '%s'" % \ |
| 312 | (part.num, disk['disk'].device)) | 275 | (part.num, self.path)) |
| 313 | exec_native_cmd("parted -s %s set %d lba off" % \ | 276 | exec_native_cmd("parted -s %s set %d lba off" % \ |
| 314 | (disk['disk'].device, part.num), | 277 | (self.path, part.num), |
| 315 | self.native_sysroot) | 278 | self.native_sysroot) |
| 316 | 279 | ||
| 317 | def cleanup(self): | 280 | def cleanup(self): |
| 318 | if self.disks: | ||
| 319 | for dev in self.disks: | ||
| 320 | disk = self.disks[dev] | ||
| 321 | if hasattr(disk['disk'], 'cleanup'): | ||
| 322 | disk['disk'].cleanup() | ||
| 323 | |||
| 324 | # remove partition images | 281 | # remove partition images |
| 325 | for image in self.partimages: | 282 | for image in self.partimages: |
| 326 | if os.path.isfile(image): | 283 | os.remove(image) |
| 327 | os.remove(image) | ||
| 328 | 284 | ||
| 329 | def assemble(self, image_file): | 285 | def assemble(self): |
| 330 | msger.debug("Installing partitions") | 286 | msger.debug("Installing partitions") |
| 331 | 287 | ||
| 332 | for part in self.partitions: | 288 | for part in self.partitions: |
| 333 | source = part.source_file | 289 | source = part.source_file |
| 334 | if source: | 290 | if source: |
| 335 | # install source_file contents into a partition | 291 | # install source_file contents into a partition |
| 336 | sparse_copy(source, image_file, part.start * self.sector_size) | 292 | sparse_copy(source, self.path, part.start * self.sector_size) |
| 337 | 293 | ||
| 338 | msger.debug("Installed %s in partition %d, sectors %d-%d, " | 294 | msger.debug("Installed %s in partition %d, sectors %d-%d, " |
| 339 | "size %d sectors" % \ | 295 | "size %d sectors" % \ |
| 340 | (source, part.num, part.start, | 296 | (source, part.num, part.start, |
| 341 | part.start + part.size_sec - 1, part.size_sec)) | 297 | part.start + part.size_sec - 1, part.size_sec)) |
| 342 | 298 | ||
| 343 | partimage = image_file + '.p%d' % part.num | 299 | partimage = self.path + '.p%d' % part.num |
| 344 | os.rename(source, partimage) | 300 | os.rename(source, partimage) |
| 345 | self.partimages.append(partimage) | 301 | self.partimages.append(partimage) |
