diff options
Diffstat (limited to 'scripts/lib/wic/plugins/imager/direct.py')
-rw-r--r-- | scripts/lib/wic/plugins/imager/direct.py | 174 |
1 files changed, 130 insertions, 44 deletions
diff --git a/scripts/lib/wic/plugins/imager/direct.py b/scripts/lib/wic/plugins/imager/direct.py index ea709e8c54..6e1f1c8cba 100644 --- a/scripts/lib/wic/plugins/imager/direct.py +++ b/scripts/lib/wic/plugins/imager/direct.py | |||
@@ -77,7 +77,8 @@ class DirectPlugin(ImagerPlugin): | |||
77 | 77 | ||
78 | image_path = self._full_path(self.workdir, self.parts[0].disk, "direct") | 78 | image_path = self._full_path(self.workdir, self.parts[0].disk, "direct") |
79 | self._image = PartitionedImage(image_path, self.ptable_format, | 79 | self._image = PartitionedImage(image_path, self.ptable_format, |
80 | self.parts, self.native_sysroot) | 80 | self.parts, self.native_sysroot, |
81 | options.extra_space) | ||
81 | 82 | ||
82 | def setup_workdir(self, workdir): | 83 | def setup_workdir(self, workdir): |
83 | if workdir: | 84 | if workdir: |
@@ -116,7 +117,7 @@ class DirectPlugin(ImagerPlugin): | |||
116 | updated = False | 117 | updated = False |
117 | for part in self.parts: | 118 | for part in self.parts: |
118 | if not part.realnum or not part.mountpoint \ | 119 | if not part.realnum or not part.mountpoint \ |
119 | or part.mountpoint == "/": | 120 | or part.mountpoint == "/" or not (part.mountpoint.startswith('/') or part.mountpoint == "swap"): |
120 | continue | 121 | continue |
121 | 122 | ||
122 | if part.use_uuid: | 123 | if part.use_uuid: |
@@ -137,8 +138,9 @@ class DirectPlugin(ImagerPlugin): | |||
137 | device_name = "/dev/%s%s%d" % (part.disk, prefix, part.realnum) | 138 | device_name = "/dev/%s%s%d" % (part.disk, prefix, part.realnum) |
138 | 139 | ||
139 | opts = part.fsopts if part.fsopts else "defaults" | 140 | opts = part.fsopts if part.fsopts else "defaults" |
141 | passno = part.fspassno if part.fspassno else "0" | ||
140 | line = "\t".join([device_name, part.mountpoint, part.fstype, | 142 | line = "\t".join([device_name, part.mountpoint, part.fstype, |
141 | opts, "0", "0"]) + "\n" | 143 | opts, "0", passno]) + "\n" |
142 | 144 | ||
143 | fstab_lines.append(line) | 145 | fstab_lines.append(line) |
144 | updated = True | 146 | updated = True |
@@ -147,6 +149,9 @@ class DirectPlugin(ImagerPlugin): | |||
147 | self.updated_fstab_path = os.path.join(self.workdir, "fstab") | 149 | self.updated_fstab_path = os.path.join(self.workdir, "fstab") |
148 | with open(self.updated_fstab_path, "w") as f: | 150 | with open(self.updated_fstab_path, "w") as f: |
149 | f.writelines(fstab_lines) | 151 | f.writelines(fstab_lines) |
152 | if os.getenv('SOURCE_DATE_EPOCH'): | ||
153 | fstab_time = int(os.getenv('SOURCE_DATE_EPOCH')) | ||
154 | os.utime(self.updated_fstab_path, (fstab_time, fstab_time)) | ||
150 | 155 | ||
151 | def _full_path(self, path, name, extention): | 156 | def _full_path(self, path, name, extention): |
152 | """ Construct full file path to a file we generate. """ | 157 | """ Construct full file path to a file we generate. """ |
@@ -198,6 +203,8 @@ class DirectPlugin(ImagerPlugin): | |||
198 | source_plugin = self.ks.bootloader.source | 203 | source_plugin = self.ks.bootloader.source |
199 | disk_name = self.parts[0].disk | 204 | disk_name = self.parts[0].disk |
200 | if source_plugin: | 205 | if source_plugin: |
206 | # Don't support '-' in plugin names | ||
207 | source_plugin = source_plugin.replace("-", "_") | ||
201 | plugin = PluginMgr.get_plugins('source')[source_plugin] | 208 | plugin = PluginMgr.get_plugins('source')[source_plugin] |
202 | plugin.do_install_disk(self._image, disk_name, self, self.workdir, | 209 | plugin.do_install_disk(self._image, disk_name, self, self.workdir, |
203 | self.oe_builddir, self.bootimg_dir, | 210 | self.oe_builddir, self.bootimg_dir, |
@@ -258,6 +265,8 @@ class DirectPlugin(ImagerPlugin): | |||
258 | if part.mountpoint == "/": | 265 | if part.mountpoint == "/": |
259 | if part.uuid: | 266 | if part.uuid: |
260 | return "PARTUUID=%s" % part.uuid | 267 | return "PARTUUID=%s" % part.uuid |
268 | elif part.label and self.ptable_format != 'msdos': | ||
269 | return "PARTLABEL=%s" % part.label | ||
261 | else: | 270 | else: |
262 | suffix = 'p' if part.disk.startswith('mmcblk') else '' | 271 | suffix = 'p' if part.disk.startswith('mmcblk') else '' |
263 | return "/dev/%s%s%-d" % (part.disk, suffix, part.realnum) | 272 | return "/dev/%s%s%-d" % (part.disk, suffix, part.realnum) |
@@ -293,7 +302,7 @@ class PartitionedImage(): | |||
293 | Partitioned image in a file. | 302 | Partitioned image in a file. |
294 | """ | 303 | """ |
295 | 304 | ||
296 | def __init__(self, path, ptable_format, partitions, native_sysroot=None): | 305 | def __init__(self, path, ptable_format, partitions, native_sysroot=None, extra_space=0): |
297 | self.path = path # Path to the image file | 306 | self.path = path # Path to the image file |
298 | self.numpart = 0 # Number of allocated partitions | 307 | self.numpart = 0 # Number of allocated partitions |
299 | self.realpart = 0 # Number of partitions in the partition table | 308 | self.realpart = 0 # Number of partitions in the partition table |
@@ -306,14 +315,26 @@ class PartitionedImage(): | |||
306 | # all partitions (in bytes) | 315 | # all partitions (in bytes) |
307 | self.ptable_format = ptable_format # Partition table format | 316 | self.ptable_format = ptable_format # Partition table format |
308 | # Disk system identifier | 317 | # Disk system identifier |
309 | self.identifier = random.SystemRandom().randint(1, 0xffffffff) | 318 | if os.getenv('SOURCE_DATE_EPOCH'): |
319 | self.identifier = random.Random(int(os.getenv('SOURCE_DATE_EPOCH'))).randint(1, 0xffffffff) | ||
320 | else: | ||
321 | self.identifier = random.SystemRandom().randint(1, 0xffffffff) | ||
310 | 322 | ||
311 | self.partitions = partitions | 323 | self.partitions = partitions |
312 | self.partimages = [] | 324 | self.partimages = [] |
313 | # Size of a sector used in calculations | 325 | # Size of a sector used in calculations |
314 | self.sector_size = SECTOR_SIZE | 326 | sector_size_str = get_bitbake_var('WIC_SECTOR_SIZE') |
327 | if sector_size_str is not None: | ||
328 | try: | ||
329 | self.sector_size = int(sector_size_str) | ||
330 | except ValueError: | ||
331 | self.sector_size = SECTOR_SIZE | ||
332 | else: | ||
333 | self.sector_size = SECTOR_SIZE | ||
334 | |||
315 | self.native_sysroot = native_sysroot | 335 | self.native_sysroot = native_sysroot |
316 | num_real_partitions = len([p for p in self.partitions if not p.no_table]) | 336 | num_real_partitions = len([p for p in self.partitions if not p.no_table]) |
337 | self.extra_space = extra_space | ||
317 | 338 | ||
318 | # calculate the real partition number, accounting for partitions not | 339 | # calculate the real partition number, accounting for partitions not |
319 | # in the partition table and logical partitions | 340 | # in the partition table and logical partitions |
@@ -331,7 +352,7 @@ class PartitionedImage(): | |||
331 | # generate parition and filesystem UUIDs | 352 | # generate parition and filesystem UUIDs |
332 | for part in self.partitions: | 353 | for part in self.partitions: |
333 | if not part.uuid and part.use_uuid: | 354 | if not part.uuid and part.use_uuid: |
334 | if self.ptable_format == 'gpt': | 355 | if self.ptable_format in ('gpt', 'gpt-hybrid'): |
335 | part.uuid = str(uuid.uuid4()) | 356 | part.uuid = str(uuid.uuid4()) |
336 | else: # msdos partition table | 357 | else: # msdos partition table |
337 | part.uuid = '%08x-%02d' % (self.identifier, part.realnum) | 358 | part.uuid = '%08x-%02d' % (self.identifier, part.realnum) |
@@ -387,6 +408,10 @@ class PartitionedImage(): | |||
387 | raise WicError("setting custom partition type is not " \ | 408 | raise WicError("setting custom partition type is not " \ |
388 | "implemented for msdos partitions") | 409 | "implemented for msdos partitions") |
389 | 410 | ||
411 | if part.mbr and self.ptable_format != 'gpt-hybrid': | ||
412 | raise WicError("Partition may only be included in MBR with " \ | ||
413 | "a gpt-hybrid partition table") | ||
414 | |||
390 | # Get the disk where the partition is located | 415 | # Get the disk where the partition is located |
391 | self.numpart += 1 | 416 | self.numpart += 1 |
392 | if not part.no_table: | 417 | if not part.no_table: |
@@ -395,7 +420,7 @@ class PartitionedImage(): | |||
395 | if self.numpart == 1: | 420 | if self.numpart == 1: |
396 | if self.ptable_format == "msdos": | 421 | if self.ptable_format == "msdos": |
397 | overhead = MBR_OVERHEAD | 422 | overhead = MBR_OVERHEAD |
398 | elif self.ptable_format == "gpt": | 423 | elif self.ptable_format in ("gpt", "gpt-hybrid"): |
399 | overhead = GPT_OVERHEAD | 424 | overhead = GPT_OVERHEAD |
400 | 425 | ||
401 | # Skip one sector required for the partitioning scheme overhead | 426 | # Skip one sector required for the partitioning scheme overhead |
@@ -479,10 +504,11 @@ class PartitionedImage(): | |||
479 | # Once all the partitions have been layed out, we can calculate the | 504 | # Once all the partitions have been layed out, we can calculate the |
480 | # minumim disk size | 505 | # minumim disk size |
481 | self.min_size = self.offset | 506 | self.min_size = self.offset |
482 | if self.ptable_format == "gpt": | 507 | if self.ptable_format in ("gpt", "gpt-hybrid"): |
483 | self.min_size += GPT_OVERHEAD | 508 | self.min_size += GPT_OVERHEAD |
484 | 509 | ||
485 | self.min_size *= self.sector_size | 510 | self.min_size *= self.sector_size |
511 | self.min_size += self.extra_space | ||
486 | 512 | ||
487 | def _create_partition(self, device, parttype, fstype, start, size): | 513 | def _create_partition(self, device, parttype, fstype, start, size): |
488 | """ Create a partition on an image described by the 'device' object. """ | 514 | """ Create a partition on an image described by the 'device' object. """ |
@@ -492,29 +518,58 @@ class PartitionedImage(): | |||
492 | logger.debug("Added '%s' partition, sectors %d-%d, size %d sectors", | 518 | logger.debug("Added '%s' partition, sectors %d-%d, size %d sectors", |
493 | parttype, start, end, size) | 519 | parttype, start, end, size) |
494 | 520 | ||
495 | cmd = "parted -s %s unit s mkpart %s" % (device, parttype) | 521 | cmd = "export PARTED_SECTOR_SIZE=%d; parted -s %s unit s mkpart %s" % \ |
522 | (self.sector_size, device, parttype) | ||
496 | if fstype: | 523 | if fstype: |
497 | cmd += " %s" % fstype | 524 | cmd += " %s" % fstype |
498 | cmd += " %d %d" % (start, end) | 525 | cmd += " %d %d" % (start, end) |
499 | 526 | ||
500 | return exec_native_cmd(cmd, self.native_sysroot) | 527 | return exec_native_cmd(cmd, self.native_sysroot) |
501 | 528 | ||
529 | def _write_identifier(self, device, identifier): | ||
530 | logger.debug("Set disk identifier %x", identifier) | ||
531 | with open(device, 'r+b') as img: | ||
532 | img.seek(0x1B8) | ||
533 | img.write(identifier.to_bytes(4, 'little')) | ||
534 | |||
535 | def _make_disk(self, device, ptable_format, min_size): | ||
536 | logger.debug("Creating sparse file %s", device) | ||
537 | with open(device, 'w') as sparse: | ||
538 | os.ftruncate(sparse.fileno(), min_size) | ||
539 | |||
540 | logger.debug("Initializing partition table for %s", device) | ||
541 | exec_native_cmd("export PARTED_SECTOR_SIZE=%d; parted -s %s mklabel %s" % | ||
542 | (self.sector_size, device, ptable_format), self.native_sysroot) | ||
543 | |||
544 | def _write_disk_guid(self): | ||
545 | if self.ptable_format in ('gpt', 'gpt-hybrid'): | ||
546 | if os.getenv('SOURCE_DATE_EPOCH'): | ||
547 | self.disk_guid = uuid.UUID(int=int(os.getenv('SOURCE_DATE_EPOCH'))) | ||
548 | else: | ||
549 | self.disk_guid = uuid.uuid4() | ||
550 | |||
551 | logger.debug("Set disk guid %s", self.disk_guid) | ||
552 | sfdisk_cmd = "sfdisk --sector-size %s --disk-id %s %s" % \ | ||
553 | (self.sector_size, self.path, self.disk_guid) | ||
554 | exec_native_cmd(sfdisk_cmd, self.native_sysroot) | ||
555 | |||
502 | def create(self): | 556 | def create(self): |
503 | logger.debug("Creating sparse file %s", self.path) | 557 | self._make_disk(self.path, |
504 | with open(self.path, 'w') as sparse: | 558 | "gpt" if self.ptable_format == "gpt-hybrid" else self.ptable_format, |
505 | os.ftruncate(sparse.fileno(), self.min_size) | 559 | self.min_size) |
506 | 560 | ||
507 | logger.debug("Initializing partition table for %s", self.path) | 561 | self._write_identifier(self.path, self.identifier) |
508 | exec_native_cmd("parted -s %s mklabel %s" % | 562 | self._write_disk_guid() |
509 | (self.path, self.ptable_format), self.native_sysroot) | ||
510 | 563 | ||
511 | logger.debug("Set disk identifier %x", self.identifier) | 564 | if self.ptable_format == "gpt-hybrid": |
512 | with open(self.path, 'r+b') as img: | 565 | mbr_path = self.path + ".mbr" |
513 | img.seek(0x1B8) | 566 | self._make_disk(mbr_path, "msdos", self.min_size) |
514 | img.write(self.identifier.to_bytes(4, 'little')) | 567 | self._write_identifier(mbr_path, self.identifier) |
515 | 568 | ||
516 | logger.debug("Creating partitions") | 569 | logger.debug("Creating partitions") |
517 | 570 | ||
571 | hybrid_mbr_part_num = 0 | ||
572 | |||
518 | for part in self.partitions: | 573 | for part in self.partitions: |
519 | if part.num == 0: | 574 | if part.num == 0: |
520 | continue | 575 | continue |
@@ -559,46 +614,77 @@ class PartitionedImage(): | |||
559 | self._create_partition(self.path, part.type, | 614 | self._create_partition(self.path, part.type, |
560 | parted_fs_type, part.start, part.size_sec) | 615 | parted_fs_type, part.start, part.size_sec) |
561 | 616 | ||
562 | if part.part_name: | 617 | if self.ptable_format == "gpt-hybrid" and part.mbr: |
563 | logger.debug("partition %d: set name to %s", | 618 | hybrid_mbr_part_num += 1 |
564 | part.num, part.part_name) | 619 | if hybrid_mbr_part_num > 4: |
565 | exec_native_cmd("sgdisk --change-name=%d:%s %s" % \ | 620 | raise WicError("Extended MBR partitions are not supported in hybrid MBR") |
566 | (part.num, part.part_name, | 621 | self._create_partition(mbr_path, "primary", |
567 | self.path), self.native_sysroot) | 622 | parted_fs_type, part.start, part.size_sec) |
568 | 623 | ||
624 | if self.ptable_format in ("gpt", "gpt-hybrid") and (part.part_name or part.label): | ||
625 | partition_label = part.part_name if part.part_name else part.label | ||
626 | logger.debug("partition %d: set name to %s", | ||
627 | part.num, partition_label) | ||
628 | exec_native_cmd("sfdisk --sector-size %s --part-label %s %d %s" % \ | ||
629 | (self.sector_size, self.path, part.num, | ||
630 | partition_label), self.native_sysroot) | ||
569 | if part.part_type: | 631 | if part.part_type: |
570 | logger.debug("partition %d: set type UID to %s", | 632 | logger.debug("partition %d: set type UID to %s", |
571 | part.num, part.part_type) | 633 | part.num, part.part_type) |
572 | exec_native_cmd("sgdisk --typecode=%d:%s %s" % \ | 634 | exec_native_cmd("sfdisk --sector-size %s --part-type %s %d %s" % \ |
573 | (part.num, part.part_type, | 635 | (self.sector_size, self.path, part.num, |
574 | self.path), self.native_sysroot) | 636 | part.part_type), self.native_sysroot) |
575 | 637 | ||
576 | if part.uuid and self.ptable_format == "gpt": | 638 | if part.uuid and self.ptable_format in ("gpt", "gpt-hybrid"): |
577 | logger.debug("partition %d: set UUID to %s", | 639 | logger.debug("partition %d: set UUID to %s", |
578 | part.num, part.uuid) | 640 | part.num, part.uuid) |
579 | exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \ | 641 | exec_native_cmd("sfdisk --sector-size %s --part-uuid %s %d %s" % \ |
580 | (part.num, part.uuid, self.path), | 642 | (self.sector_size, self.path, part.num, part.uuid), |
581 | self.native_sysroot) | ||
582 | |||
583 | if part.label and self.ptable_format == "gpt": | ||
584 | logger.debug("partition %d: set name to %s", | ||
585 | part.num, part.label) | ||
586 | exec_native_cmd("parted -s %s name %d %s" % \ | ||
587 | (self.path, part.num, part.label), | ||
588 | self.native_sysroot) | 643 | self.native_sysroot) |
589 | 644 | ||
590 | if part.active: | 645 | if part.active: |
591 | flag_name = "legacy_boot" if self.ptable_format == 'gpt' else "boot" | 646 | flag_name = "legacy_boot" if self.ptable_format in ('gpt', 'gpt-hybrid') else "boot" |
592 | logger.debug("Set '%s' flag for partition '%s' on disk '%s'", | 647 | logger.debug("Set '%s' flag for partition '%s' on disk '%s'", |
593 | flag_name, part.num, self.path) | 648 | flag_name, part.num, self.path) |
594 | exec_native_cmd("parted -s %s set %d %s on" % \ | 649 | exec_native_cmd("export PARTED_SECTOR_SIZE=%d; parted -s %s set %d %s on" % \ |
595 | (self.path, part.num, flag_name), | 650 | (self.sector_size, self.path, part.num, flag_name), |
596 | self.native_sysroot) | 651 | self.native_sysroot) |
652 | if self.ptable_format == 'gpt-hybrid' and part.mbr: | ||
653 | exec_native_cmd("export PARTED_SECTOR_SIZE=%d; parted -s %s set %d %s on" % \ | ||
654 | (self.sector_size, mbr_path, hybrid_mbr_part_num, "boot"), | ||
655 | self.native_sysroot) | ||
597 | if part.system_id: | 656 | if part.system_id: |
598 | exec_native_cmd("sfdisk --part-type %s %s %s" % \ | 657 | exec_native_cmd("sfdisk --sector-size %s --part-type %s %s %s" % \ |
599 | (self.path, part.num, part.system_id), | 658 | (self.sector_size, self.path, part.num, part.system_id), |
600 | self.native_sysroot) | 659 | self.native_sysroot) |
601 | 660 | ||
661 | if part.hidden and self.ptable_format == "gpt": | ||
662 | logger.debug("Set hidden attribute for partition '%s' on disk '%s'", | ||
663 | part.num, self.path) | ||
664 | exec_native_cmd("sfdisk --sector-size %s --part-attrs %s %s RequiredPartition" % \ | ||
665 | (self.sector_size, self.path, part.num), | ||
666 | self.native_sysroot) | ||
667 | |||
668 | if self.ptable_format == "gpt-hybrid": | ||
669 | # Write a protective GPT partition | ||
670 | hybrid_mbr_part_num += 1 | ||
671 | if hybrid_mbr_part_num > 4: | ||
672 | raise WicError("Extended MBR partitions are not supported in hybrid MBR") | ||
673 | |||
674 | # parted cannot directly create a protective GPT partition, so | ||
675 | # create with an arbitrary type, then change it to the correct type | ||
676 | # with sfdisk | ||
677 | self._create_partition(mbr_path, "primary", "fat32", 1, GPT_OVERHEAD) | ||
678 | exec_native_cmd("sfdisk --sector-size %s --part-type %s %d 0xee" % \ | ||
679 | (self.sector_size, mbr_path, hybrid_mbr_part_num), | ||
680 | self.native_sysroot) | ||
681 | |||
682 | # Copy hybrid MBR | ||
683 | with open(mbr_path, "rb") as mbr_file: | ||
684 | with open(self.path, "r+b") as image_file: | ||
685 | mbr = mbr_file.read(512) | ||
686 | image_file.write(mbr) | ||
687 | |||
602 | def cleanup(self): | 688 | def cleanup(self): |
603 | pass | 689 | pass |
604 | 690 | ||