diff options
Diffstat (limited to 'scripts/lib/wic/plugins/imager/direct.py')
-rw-r--r-- | scripts/lib/wic/plugins/imager/direct.py | 167 |
1 files changed, 124 insertions, 43 deletions
diff --git a/scripts/lib/wic/plugins/imager/direct.py b/scripts/lib/wic/plugins/imager/direct.py index 35fff7c102..6e1f1c8cba 100644 --- a/scripts/lib/wic/plugins/imager/direct.py +++ b/scripts/lib/wic/plugins/imager/direct.py | |||
@@ -117,7 +117,7 @@ class DirectPlugin(ImagerPlugin): | |||
117 | updated = False | 117 | updated = False |
118 | for part in self.parts: | 118 | for part in self.parts: |
119 | if not part.realnum or not part.mountpoint \ | 119 | if not part.realnum or not part.mountpoint \ |
120 | or part.mountpoint == "/" or not part.mountpoint.startswith('/'): | 120 | or part.mountpoint == "/" or not (part.mountpoint.startswith('/') or part.mountpoint == "swap"): |
121 | continue | 121 | continue |
122 | 122 | ||
123 | if part.use_uuid: | 123 | if part.use_uuid: |
@@ -138,8 +138,9 @@ class DirectPlugin(ImagerPlugin): | |||
138 | device_name = "/dev/%s%s%d" % (part.disk, prefix, part.realnum) | 138 | device_name = "/dev/%s%s%d" % (part.disk, prefix, part.realnum) |
139 | 139 | ||
140 | 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" | ||
141 | line = "\t".join([device_name, part.mountpoint, part.fstype, | 142 | line = "\t".join([device_name, part.mountpoint, part.fstype, |
142 | opts, "0", "0"]) + "\n" | 143 | opts, "0", passno]) + "\n" |
143 | 144 | ||
144 | fstab_lines.append(line) | 145 | fstab_lines.append(line) |
145 | updated = True | 146 | updated = True |
@@ -148,6 +149,9 @@ class DirectPlugin(ImagerPlugin): | |||
148 | self.updated_fstab_path = os.path.join(self.workdir, "fstab") | 149 | self.updated_fstab_path = os.path.join(self.workdir, "fstab") |
149 | with open(self.updated_fstab_path, "w") as f: | 150 | with open(self.updated_fstab_path, "w") as f: |
150 | 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)) | ||
151 | 155 | ||
152 | def _full_path(self, path, name, extention): | 156 | def _full_path(self, path, name, extention): |
153 | """ Construct full file path to a file we generate. """ | 157 | """ Construct full file path to a file we generate. """ |
@@ -199,6 +203,8 @@ class DirectPlugin(ImagerPlugin): | |||
199 | source_plugin = self.ks.bootloader.source | 203 | source_plugin = self.ks.bootloader.source |
200 | disk_name = self.parts[0].disk | 204 | disk_name = self.parts[0].disk |
201 | if source_plugin: | 205 | if source_plugin: |
206 | # Don't support '-' in plugin names | ||
207 | source_plugin = source_plugin.replace("-", "_") | ||
202 | plugin = PluginMgr.get_plugins('source')[source_plugin] | 208 | plugin = PluginMgr.get_plugins('source')[source_plugin] |
203 | plugin.do_install_disk(self._image, disk_name, self, self.workdir, | 209 | plugin.do_install_disk(self._image, disk_name, self, self.workdir, |
204 | self.oe_builddir, self.bootimg_dir, | 210 | self.oe_builddir, self.bootimg_dir, |
@@ -259,7 +265,7 @@ class DirectPlugin(ImagerPlugin): | |||
259 | if part.mountpoint == "/": | 265 | if part.mountpoint == "/": |
260 | if part.uuid: | 266 | if part.uuid: |
261 | return "PARTUUID=%s" % part.uuid | 267 | return "PARTUUID=%s" % part.uuid |
262 | elif part.label: | 268 | elif part.label and self.ptable_format != 'msdos': |
263 | return "PARTLABEL=%s" % part.label | 269 | return "PARTLABEL=%s" % part.label |
264 | else: | 270 | else: |
265 | suffix = 'p' if part.disk.startswith('mmcblk') else '' | 271 | suffix = 'p' if part.disk.startswith('mmcblk') else '' |
@@ -309,12 +315,23 @@ class PartitionedImage(): | |||
309 | # all partitions (in bytes) | 315 | # all partitions (in bytes) |
310 | self.ptable_format = ptable_format # Partition table format | 316 | self.ptable_format = ptable_format # Partition table format |
311 | # Disk system identifier | 317 | # Disk system identifier |
312 | 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) | ||
313 | 322 | ||
314 | self.partitions = partitions | 323 | self.partitions = partitions |
315 | self.partimages = [] | 324 | self.partimages = [] |
316 | # Size of a sector used in calculations | 325 | # Size of a sector used in calculations |
317 | 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 | |||
318 | self.native_sysroot = native_sysroot | 335 | self.native_sysroot = native_sysroot |
319 | 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]) |
320 | self.extra_space = extra_space | 337 | self.extra_space = extra_space |
@@ -335,7 +352,7 @@ class PartitionedImage(): | |||
335 | # generate parition and filesystem UUIDs | 352 | # generate parition and filesystem UUIDs |
336 | for part in self.partitions: | 353 | for part in self.partitions: |
337 | if not part.uuid and part.use_uuid: | 354 | if not part.uuid and part.use_uuid: |
338 | if self.ptable_format == 'gpt': | 355 | if self.ptable_format in ('gpt', 'gpt-hybrid'): |
339 | part.uuid = str(uuid.uuid4()) | 356 | part.uuid = str(uuid.uuid4()) |
340 | else: # msdos partition table | 357 | else: # msdos partition table |
341 | part.uuid = '%08x-%02d' % (self.identifier, part.realnum) | 358 | part.uuid = '%08x-%02d' % (self.identifier, part.realnum) |
@@ -391,6 +408,10 @@ class PartitionedImage(): | |||
391 | raise WicError("setting custom partition type is not " \ | 408 | raise WicError("setting custom partition type is not " \ |
392 | "implemented for msdos partitions") | 409 | "implemented for msdos partitions") |
393 | 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 | |||
394 | # Get the disk where the partition is located | 415 | # Get the disk where the partition is located |
395 | self.numpart += 1 | 416 | self.numpart += 1 |
396 | if not part.no_table: | 417 | if not part.no_table: |
@@ -399,7 +420,7 @@ class PartitionedImage(): | |||
399 | if self.numpart == 1: | 420 | if self.numpart == 1: |
400 | if self.ptable_format == "msdos": | 421 | if self.ptable_format == "msdos": |
401 | overhead = MBR_OVERHEAD | 422 | overhead = MBR_OVERHEAD |
402 | elif self.ptable_format == "gpt": | 423 | elif self.ptable_format in ("gpt", "gpt-hybrid"): |
403 | overhead = GPT_OVERHEAD | 424 | overhead = GPT_OVERHEAD |
404 | 425 | ||
405 | # Skip one sector required for the partitioning scheme overhead | 426 | # Skip one sector required for the partitioning scheme overhead |
@@ -483,7 +504,7 @@ class PartitionedImage(): | |||
483 | # 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 |
484 | # minumim disk size | 505 | # minumim disk size |
485 | self.min_size = self.offset | 506 | self.min_size = self.offset |
486 | if self.ptable_format == "gpt": | 507 | if self.ptable_format in ("gpt", "gpt-hybrid"): |
487 | self.min_size += GPT_OVERHEAD | 508 | self.min_size += GPT_OVERHEAD |
488 | 509 | ||
489 | self.min_size *= self.sector_size | 510 | self.min_size *= self.sector_size |
@@ -497,29 +518,58 @@ class PartitionedImage(): | |||
497 | logger.debug("Added '%s' partition, sectors %d-%d, size %d sectors", | 518 | logger.debug("Added '%s' partition, sectors %d-%d, size %d sectors", |
498 | parttype, start, end, size) | 519 | parttype, start, end, size) |
499 | 520 | ||
500 | 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) | ||
501 | if fstype: | 523 | if fstype: |
502 | cmd += " %s" % fstype | 524 | cmd += " %s" % fstype |
503 | cmd += " %d %d" % (start, end) | 525 | cmd += " %d %d" % (start, end) |
504 | 526 | ||
505 | return exec_native_cmd(cmd, self.native_sysroot) | 527 | return exec_native_cmd(cmd, self.native_sysroot) |
506 | 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 | |||
507 | def create(self): | 556 | def create(self): |
508 | logger.debug("Creating sparse file %s", self.path) | 557 | self._make_disk(self.path, |
509 | with open(self.path, 'w') as sparse: | 558 | "gpt" if self.ptable_format == "gpt-hybrid" else self.ptable_format, |
510 | os.ftruncate(sparse.fileno(), self.min_size) | 559 | self.min_size) |
511 | 560 | ||
512 | logger.debug("Initializing partition table for %s", self.path) | 561 | self._write_identifier(self.path, self.identifier) |
513 | exec_native_cmd("parted -s %s mklabel %s" % | 562 | self._write_disk_guid() |
514 | (self.path, self.ptable_format), self.native_sysroot) | ||
515 | 563 | ||
516 | logger.debug("Set disk identifier %x", self.identifier) | 564 | if self.ptable_format == "gpt-hybrid": |
517 | with open(self.path, 'r+b') as img: | 565 | mbr_path = self.path + ".mbr" |
518 | img.seek(0x1B8) | 566 | self._make_disk(mbr_path, "msdos", self.min_size) |
519 | img.write(self.identifier.to_bytes(4, 'little')) | 567 | self._write_identifier(mbr_path, self.identifier) |
520 | 568 | ||
521 | logger.debug("Creating partitions") | 569 | logger.debug("Creating partitions") |
522 | 570 | ||
571 | hybrid_mbr_part_num = 0 | ||
572 | |||
523 | for part in self.partitions: | 573 | for part in self.partitions: |
524 | if part.num == 0: | 574 | if part.num == 0: |
525 | continue | 575 | continue |
@@ -564,46 +614,77 @@ class PartitionedImage(): | |||
564 | self._create_partition(self.path, part.type, | 614 | self._create_partition(self.path, part.type, |
565 | parted_fs_type, part.start, part.size_sec) | 615 | parted_fs_type, part.start, part.size_sec) |
566 | 616 | ||
567 | if part.part_name: | 617 | if self.ptable_format == "gpt-hybrid" and part.mbr: |
568 | logger.debug("partition %d: set name to %s", | 618 | hybrid_mbr_part_num += 1 |
569 | part.num, part.part_name) | 619 | if hybrid_mbr_part_num > 4: |
570 | exec_native_cmd("sgdisk --change-name=%d:%s %s" % \ | 620 | raise WicError("Extended MBR partitions are not supported in hybrid MBR") |
571 | (part.num, part.part_name, | 621 | self._create_partition(mbr_path, "primary", |
572 | self.path), self.native_sysroot) | 622 | parted_fs_type, part.start, part.size_sec) |
573 | 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) | ||
574 | if part.part_type: | 631 | if part.part_type: |
575 | logger.debug("partition %d: set type UID to %s", | 632 | logger.debug("partition %d: set type UID to %s", |
576 | part.num, part.part_type) | 633 | part.num, part.part_type) |
577 | exec_native_cmd("sgdisk --typecode=%d:%s %s" % \ | 634 | exec_native_cmd("sfdisk --sector-size %s --part-type %s %d %s" % \ |
578 | (part.num, part.part_type, | 635 | (self.sector_size, self.path, part.num, |
579 | self.path), self.native_sysroot) | 636 | part.part_type), self.native_sysroot) |
580 | 637 | ||
581 | if part.uuid and self.ptable_format == "gpt": | 638 | if part.uuid and self.ptable_format in ("gpt", "gpt-hybrid"): |
582 | logger.debug("partition %d: set UUID to %s", | 639 | logger.debug("partition %d: set UUID to %s", |
583 | part.num, part.uuid) | 640 | part.num, part.uuid) |
584 | exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \ | 641 | exec_native_cmd("sfdisk --sector-size %s --part-uuid %s %d %s" % \ |
585 | (part.num, part.uuid, self.path), | 642 | (self.sector_size, self.path, part.num, part.uuid), |
586 | self.native_sysroot) | ||
587 | |||
588 | if part.label and self.ptable_format == "gpt": | ||
589 | logger.debug("partition %d: set name to %s", | ||
590 | part.num, part.label) | ||
591 | exec_native_cmd("parted -s %s name %d %s" % \ | ||
592 | (self.path, part.num, part.label), | ||
593 | self.native_sysroot) | 643 | self.native_sysroot) |
594 | 644 | ||
595 | if part.active: | 645 | if part.active: |
596 | 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" |
597 | logger.debug("Set '%s' flag for partition '%s' on disk '%s'", | 647 | logger.debug("Set '%s' flag for partition '%s' on disk '%s'", |
598 | flag_name, part.num, self.path) | 648 | flag_name, part.num, self.path) |
599 | 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" % \ |
600 | (self.path, part.num, flag_name), | 650 | (self.sector_size, self.path, part.num, flag_name), |
601 | 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) | ||
602 | if part.system_id: | 656 | if part.system_id: |
603 | exec_native_cmd("sfdisk --part-type %s %s %s" % \ | 657 | exec_native_cmd("sfdisk --sector-size %s --part-type %s %s %s" % \ |
604 | (self.path, part.num, part.system_id), | 658 | (self.sector_size, self.path, part.num, part.system_id), |
605 | self.native_sysroot) | 659 | self.native_sysroot) |
606 | 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 | |||
607 | def cleanup(self): | 688 | def cleanup(self): |
608 | pass | 689 | pass |
609 | 690 | ||