summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/plugins/imager/direct.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/plugins/imager/direct.py')
-rw-r--r--scripts/lib/wic/plugins/imager/direct.py167
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