summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/plugins')
-rw-r--r--scripts/lib/wic/plugins/imager/direct.py167
-rw-r--r--scripts/lib/wic/plugins/source/bootimg_biosplusefi.py (renamed from scripts/lib/wic/plugins/source/bootimg-biosplusefi.py)30
-rw-r--r--scripts/lib/wic/plugins/source/bootimg_efi.py (renamed from scripts/lib/wic/plugins/source/bootimg-efi.py)225
-rw-r--r--scripts/lib/wic/plugins/source/bootimg_partition.py (renamed from scripts/lib/wic/plugins/source/bootimg-partition.py)52
-rw-r--r--scripts/lib/wic/plugins/source/bootimg_pcbios.py (renamed from scripts/lib/wic/plugins/source/bootimg-pcbios.py)10
-rw-r--r--scripts/lib/wic/plugins/source/empty.py59
-rw-r--r--scripts/lib/wic/plugins/source/isoimage_isohybrid.py (renamed from scripts/lib/wic/plugins/source/isoimage-isohybrid.py)12
-rw-r--r--scripts/lib/wic/plugins/source/rawcopy.py36
-rw-r--r--scripts/lib/wic/plugins/source/rootfs.py13
9 files changed, 385 insertions, 219 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
diff --git a/scripts/lib/wic/plugins/source/bootimg-biosplusefi.py b/scripts/lib/wic/plugins/source/bootimg_biosplusefi.py
index 5bd7390680..4279ddded8 100644
--- a/scripts/lib/wic/plugins/source/bootimg-biosplusefi.py
+++ b/scripts/lib/wic/plugins/source/bootimg_biosplusefi.py
@@ -13,7 +13,7 @@
13# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 13# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
14# 14#
15# DESCRIPTION 15# DESCRIPTION
16# This implements the 'bootimg-biosplusefi' source plugin class for 'wic' 16# This implements the 'bootimg_biosplusefi' source plugin class for 'wic'
17# 17#
18# AUTHORS 18# AUTHORS
19# William Bourque <wbourque [at) gmail.com> 19# William Bourque <wbourque [at) gmail.com>
@@ -34,7 +34,7 @@ class BootimgBiosPlusEFIPlugin(SourcePlugin):
34 34
35 Note it is possible to create an image that can boot from both 35 Note it is possible to create an image that can boot from both
36 legacy BIOS and EFI by defining two partitions : one with arg 36 legacy BIOS and EFI by defining two partitions : one with arg
37 --source bootimg-efi and another one with --source bootimg-pcbios. 37 --source bootimg_efi and another one with --source bootimg_pcbios.
38 However, this method has the obvious downside that it requires TWO 38 However, this method has the obvious downside that it requires TWO
39 partitions to be created on the storage device. 39 partitions to be created on the storage device.
40 Both partitions will also be marked as "bootable" which does not work on 40 Both partitions will also be marked as "bootable" which does not work on
@@ -45,7 +45,7 @@ class BootimgBiosPlusEFIPlugin(SourcePlugin):
45 the first partition will be duplicated into the second, even though it 45 the first partition will be duplicated into the second, even though it
46 will not be used at all. 46 will not be used at all.
47 47
48 Also, unlike "isoimage-isohybrid" that also does BIOS and EFI, this plugin 48 Also, unlike "isoimage_isohybrid" that also does BIOS and EFI, this plugin
49 allows you to have more than only a single rootfs partitions and does 49 allows you to have more than only a single rootfs partitions and does
50 not turn the rootfs into an initramfs RAM image. 50 not turn the rootfs into an initramfs RAM image.
51 51
@@ -53,32 +53,32 @@ class BootimgBiosPlusEFIPlugin(SourcePlugin):
53 does not have the limitations listed above. 53 does not have the limitations listed above.
54 54
55 The plugin is made so it does tries not to reimplement what's already 55 The plugin is made so it does tries not to reimplement what's already
56 been done in other plugins; as such it imports "bootimg-pcbios" 56 been done in other plugins; as such it imports "bootimg_pcbios"
57 and "bootimg-efi". 57 and "bootimg_efi".
58 Plugin "bootimg-pcbios" is used to generate legacy BIOS boot. 58 Plugin "bootimg_pcbios" is used to generate legacy BIOS boot.
59 Plugin "bootimg-efi" is used to generate the UEFI boot. Note that it 59 Plugin "bootimg_efi" is used to generate the UEFI boot. Note that it
60 requires a --sourceparams argument to know which loader to use; refer 60 requires a --sourceparams argument to know which loader to use; refer
61 to "bootimg-efi" code/documentation for the list of loader. 61 to "bootimg_efi" code/documentation for the list of loader.
62 62
63 Imports are handled with "SourceFileLoader" from importlib as it is 63 Imports are handled with "SourceFileLoader" from importlib as it is
64 otherwise very difficult to import module that has hyphen "-" in their 64 otherwise very difficult to import module that has hyphen "-" in their
65 filename. 65 filename.
66 The SourcePlugin() methods used in the plugins (do_install_disk, 66 The SourcePlugin() methods used in the plugins (do_install_disk,
67 do_configure_partition, do_prepare_partition) are then called on both, 67 do_configure_partition, do_prepare_partition) are then called on both,
68 beginning by "bootimg-efi". 68 beginning by "bootimg_efi".
69 69
70 Plugin options, such as "--sourceparams" can still be passed to a 70 Plugin options, such as "--sourceparams" can still be passed to a
71 plugin, as long they does not cause issue in the other plugin. 71 plugin, as long they does not cause issue in the other plugin.
72 72
73 Example wic configuration: 73 Example wic configuration:
74 part /boot --source bootimg-biosplusefi --sourceparams="loader=grub-efi"\\ 74 part /boot --source bootimg_biosplusefi --sourceparams="loader=grub-efi"\\
75 --ondisk sda --label os_boot --active --align 1024 --use-uuid 75 --ondisk sda --label os_boot --active --align 1024 --use-uuid
76 """ 76 """
77 77
78 name = 'bootimg-biosplusefi' 78 name = 'bootimg_biosplusefi'
79 79
80 __PCBIOS_MODULE_NAME = "bootimg-pcbios" 80 __PCBIOS_MODULE_NAME = "bootimg_pcbios"
81 __EFI_MODULE_NAME = "bootimg-efi" 81 __EFI_MODULE_NAME = "bootimg_efi"
82 82
83 __imgEFIObj = None 83 __imgEFIObj = None
84 __imgBiosObj = None 84 __imgBiosObj = None
@@ -100,7 +100,7 @@ class BootimgBiosPlusEFIPlugin(SourcePlugin):
100 100
101 """ 101 """
102 102
103 # Import bootimg-pcbios (class name "BootimgPcbiosPlugin") 103 # Import bootimg_pcbios (class name "BootimgPcbiosPlugin")
104 modulePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 104 modulePath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
105 cls.__PCBIOS_MODULE_NAME + ".py") 105 cls.__PCBIOS_MODULE_NAME + ".py")
106 loader = SourceFileLoader(cls.__PCBIOS_MODULE_NAME, modulePath) 106 loader = SourceFileLoader(cls.__PCBIOS_MODULE_NAME, modulePath)
@@ -108,7 +108,7 @@ class BootimgBiosPlusEFIPlugin(SourcePlugin):
108 loader.exec_module(mod) 108 loader.exec_module(mod)
109 cls.__imgBiosObj = mod.BootimgPcbiosPlugin() 109 cls.__imgBiosObj = mod.BootimgPcbiosPlugin()
110 110
111 # Import bootimg-efi (class name "BootimgEFIPlugin") 111 # Import bootimg_efi (class name "BootimgEFIPlugin")
112 modulePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 112 modulePath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
113 cls.__EFI_MODULE_NAME + ".py") 113 cls.__EFI_MODULE_NAME + ".py")
114 loader = SourceFileLoader(cls.__EFI_MODULE_NAME, modulePath) 114 loader = SourceFileLoader(cls.__EFI_MODULE_NAME, modulePath)
diff --git a/scripts/lib/wic/plugins/source/bootimg-efi.py b/scripts/lib/wic/plugins/source/bootimg_efi.py
index 0391aebdc8..cf16705a28 100644
--- a/scripts/lib/wic/plugins/source/bootimg-efi.py
+++ b/scripts/lib/wic/plugins/source/bootimg_efi.py
@@ -4,7 +4,7 @@
4# SPDX-License-Identifier: GPL-2.0-only 4# SPDX-License-Identifier: GPL-2.0-only
5# 5#
6# DESCRIPTION 6# DESCRIPTION
7# This implements the 'bootimg-efi' source plugin class for 'wic' 7# This implements the 'bootimg_efi' source plugin class for 'wic'
8# 8#
9# AUTHORS 9# AUTHORS
10# Tom Zanussi <tom.zanussi (at] linux.intel.com> 10# Tom Zanussi <tom.zanussi (at] linux.intel.com>
@@ -32,7 +32,29 @@ class BootimgEFIPlugin(SourcePlugin):
32 This plugin supports GRUB 2 and systemd-boot bootloaders. 32 This plugin supports GRUB 2 and systemd-boot bootloaders.
33 """ 33 """
34 34
35 name = 'bootimg-efi' 35 name = 'bootimg_efi'
36
37 @classmethod
38 def _copy_additional_files(cls, hdddir, initrd, dtb):
39 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
40 if not bootimg_dir:
41 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
42
43 if initrd:
44 initrds = initrd.split(';')
45 for rd in initrds:
46 cp_cmd = "cp -v -p %s/%s %s" % (bootimg_dir, rd, hdddir)
47 out = exec_cmd(cp_cmd, True)
48 logger.debug("initrd files:\n%s" % (out))
49 else:
50 logger.debug("Ignoring missing initrd")
51
52 if dtb:
53 if ';' in dtb:
54 raise WicError("Only one DTB supported, exiting")
55 cp_cmd = "cp -v -p %s/%s %s" % (bootimg_dir, dtb, hdddir)
56 out = exec_cmd(cp_cmd, True)
57 logger.debug("dtb files:\n%s" % (out))
36 58
37 @classmethod 59 @classmethod
38 def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params): 60 def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params):
@@ -53,18 +75,9 @@ class BootimgEFIPlugin(SourcePlugin):
53 "get it from %s." % configfile) 75 "get it from %s." % configfile)
54 76
55 initrd = source_params.get('initrd') 77 initrd = source_params.get('initrd')
78 dtb = source_params.get('dtb')
56 79
57 if initrd: 80 cls._copy_additional_files(hdddir, initrd, dtb)
58 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
59 if not bootimg_dir:
60 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
61
62 initrds = initrd.split(';')
63 for rd in initrds:
64 cp_cmd = "cp %s/%s %s" % (bootimg_dir, rd, hdddir)
65 exec_cmd(cp_cmd, True)
66 else:
67 logger.debug("Ignoring missing initrd")
68 81
69 if not custom_cfg: 82 if not custom_cfg:
70 # Create grub configuration using parameters from wks file 83 # Create grub configuration using parameters from wks file
@@ -98,6 +111,9 @@ class BootimgEFIPlugin(SourcePlugin):
98 grubefi_conf += " /%s" % rd 111 grubefi_conf += " /%s" % rd
99 grubefi_conf += "\n" 112 grubefi_conf += "\n"
100 113
114 if dtb:
115 grubefi_conf += "devicetree /%s\n" % dtb
116
101 grubefi_conf += "}\n" 117 grubefi_conf += "}\n"
102 118
103 logger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg", 119 logger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg",
@@ -109,8 +125,16 @@ class BootimgEFIPlugin(SourcePlugin):
109 @classmethod 125 @classmethod
110 def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params): 126 def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params):
111 """ 127 """
112 Create loader-specific systemd-boot/gummiboot config 128 Create loader-specific systemd-boot/gummiboot config. Unified Kernel Image (uki)
129 support is done in image recipe with uki.bbclass and only systemd-boot loader config
130 and ESP partition structure is created here.
113 """ 131 """
132 # detect uki.bbclass usage
133 image_classes = get_bitbake_var("IMAGE_CLASSES").split()
134 unified_image = False
135 if "uki" in image_classes:
136 unified_image = True
137
114 install_cmd = "install -d %s/loader" % hdddir 138 install_cmd = "install -d %s/loader" % hdddir
115 exec_cmd(install_cmd) 139 exec_cmd(install_cmd)
116 140
@@ -118,35 +142,26 @@ class BootimgEFIPlugin(SourcePlugin):
118 exec_cmd(install_cmd) 142 exec_cmd(install_cmd)
119 143
120 bootloader = creator.ks.bootloader 144 bootloader = creator.ks.bootloader
121
122 loader_conf = "" 145 loader_conf = ""
123 if source_params.get('create-unified-kernel-image') != "true":
124 loader_conf += "default boot\n"
125 loader_conf += "timeout %d\n" % bootloader.timeout
126 146
127 initrd = source_params.get('initrd') 147 # 5 seconds is a sensible default timeout
128 148 loader_conf += "timeout %d\n" % (bootloader.timeout or 5)
129 if initrd and source_params.get('create-unified-kernel-image') != "true":
130 # obviously we need to have a common common deploy var
131 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
132 if not bootimg_dir:
133 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
134
135 initrds = initrd.split(';')
136 for rd in initrds:
137 cp_cmd = "cp %s/%s %s" % (bootimg_dir, rd, hdddir)
138 exec_cmd(cp_cmd, True)
139 else:
140 logger.debug("Ignoring missing initrd")
141 149
142 logger.debug("Writing systemd-boot config " 150 logger.debug("Writing systemd-boot config "
143 "%s/hdd/boot/loader/loader.conf", cr_workdir) 151 "%s/hdd/boot/loader/loader.conf", cr_workdir)
144 cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w") 152 cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w")
145 cfg.write(loader_conf) 153 cfg.write(loader_conf)
154 logger.debug("loader.conf:\n%s" % (loader_conf))
146 cfg.close() 155 cfg.close()
147 156
157 initrd = source_params.get('initrd')
158 dtb = source_params.get('dtb')
159 if not unified_image:
160 cls._copy_additional_files(hdddir, initrd, dtb)
161
148 configfile = creator.ks.bootloader.configfile 162 configfile = creator.ks.bootloader.configfile
149 custom_cfg = None 163 custom_cfg = None
164 boot_conf = ""
150 if configfile: 165 if configfile:
151 custom_cfg = get_custom_config(configfile) 166 custom_cfg = get_custom_config(configfile)
152 if custom_cfg: 167 if custom_cfg:
@@ -157,8 +172,7 @@ class BootimgEFIPlugin(SourcePlugin):
157 else: 172 else:
158 raise WicError("configfile is specified but failed to " 173 raise WicError("configfile is specified but failed to "
159 "get it from %s.", configfile) 174 "get it from %s.", configfile)
160 175 else:
161 if not custom_cfg:
162 # Create systemd-boot configuration using parameters from wks file 176 # Create systemd-boot configuration using parameters from wks file
163 kernel = get_bitbake_var("KERNEL_IMAGETYPE") 177 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
164 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1": 178 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
@@ -168,7 +182,6 @@ class BootimgEFIPlugin(SourcePlugin):
168 182
169 title = source_params.get('title') 183 title = source_params.get('title')
170 184
171 boot_conf = ""
172 boot_conf += "title %s\n" % (title if title else "boot") 185 boot_conf += "title %s\n" % (title if title else "boot")
173 boot_conf += "linux /%s\n" % kernel 186 boot_conf += "linux /%s\n" % kernel
174 187
@@ -185,11 +198,15 @@ class BootimgEFIPlugin(SourcePlugin):
185 for rd in initrds: 198 for rd in initrds:
186 boot_conf += "initrd /%s\n" % rd 199 boot_conf += "initrd /%s\n" % rd
187 200
188 if source_params.get('create-unified-kernel-image') != "true": 201 if dtb:
202 boot_conf += "devicetree /%s\n" % dtb
203
204 if not unified_image:
189 logger.debug("Writing systemd-boot config " 205 logger.debug("Writing systemd-boot config "
190 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir) 206 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir)
191 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w") 207 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w")
192 cfg.write(boot_conf) 208 cfg.write(boot_conf)
209 logger.debug("boot.conf:\n%s" % (boot_conf))
193 cfg.close() 210 cfg.close()
194 211
195 212
@@ -210,10 +227,12 @@ class BootimgEFIPlugin(SourcePlugin):
210 cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params) 227 cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params)
211 elif source_params['loader'] == 'systemd-boot': 228 elif source_params['loader'] == 'systemd-boot':
212 cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params) 229 cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params)
230 elif source_params['loader'] == 'uefi-kernel':
231 pass
213 else: 232 else:
214 raise WicError("unrecognized bootimg-efi loader: %s" % source_params['loader']) 233 raise WicError("unrecognized bootimg_efi loader: %s" % source_params['loader'])
215 except KeyError: 234 except KeyError:
216 raise WicError("bootimg-efi requires a loader, none specified") 235 raise WicError("bootimg_efi requires a loader, none specified")
217 236
218 if get_bitbake_var("IMAGE_EFI_BOOT_FILES") is None: 237 if get_bitbake_var("IMAGE_EFI_BOOT_FILES") is None:
219 logger.debug('No boot files defined in IMAGE_EFI_BOOT_FILES') 238 logger.debug('No boot files defined in IMAGE_EFI_BOOT_FILES')
@@ -233,7 +252,7 @@ class BootimgEFIPlugin(SourcePlugin):
233 252
234 # list of tuples (src_name, dst_name) 253 # list of tuples (src_name, dst_name)
235 deploy_files = [] 254 deploy_files = []
236 for src_entry in re.findall(r'[\w;\-\./\*]+', boot_files): 255 for src_entry in re.findall(r'[\w;\-\.\+/\*]+', boot_files):
237 if ';' in src_entry: 256 if ';' in src_entry:
238 dst_entry = tuple(src_entry.split(';')) 257 dst_entry = tuple(src_entry.split(';'))
239 if not dst_entry[0] or not dst_entry[1]: 258 if not dst_entry[0] or not dst_entry[1]:
@@ -292,90 +311,83 @@ class BootimgEFIPlugin(SourcePlugin):
292 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME")) 311 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
293 312
294 if source_params.get('create-unified-kernel-image') == "true": 313 if source_params.get('create-unified-kernel-image') == "true":
295 initrd = source_params.get('initrd') 314 raise WicError("create-unified-kernel-image is no longer supported. Please use uki.bbclass.")
296 if not initrd:
297 raise WicError("initrd= must be specified when create-unified-kernel-image=true, exiting")
298
299 deploy_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
300 efi_stub = glob("%s/%s" % (deploy_dir, "linux*.efi.stub"))
301 if len(efi_stub) == 0:
302 raise WicError("Unified Kernel Image EFI stub not found, exiting")
303 efi_stub = efi_stub[0]
304
305 with tempfile.TemporaryDirectory() as tmp_dir:
306 label = source_params.get('label')
307 label_conf = "root=%s" % creator.rootdev
308 if label:
309 label_conf = "LABEL=%s" % label
310
311 bootloader = creator.ks.bootloader
312 cmdline = open("%s/cmdline" % tmp_dir, "w")
313 cmdline.write("%s %s" % (label_conf, bootloader.append))
314 cmdline.close()
315 315
316 initrds = initrd.split(';') 316 if source_params.get('install-kernel-into-boot-dir') != 'false':
317 initrd = open("%s/initrd" % tmp_dir, "wb") 317 install_cmd = "install -v -p -m 0644 %s/%s %s/%s" % \
318 for f in initrds:
319 with open("%s/%s" % (deploy_dir, f), 'rb') as in_file:
320 shutil.copyfileobj(in_file, initrd)
321 initrd.close()
322
323 # Searched by systemd-boot:
324 # https://systemd.io/BOOT_LOADER_SPECIFICATION/#type-2-efi-unified-kernel-images
325 install_cmd = "install -d %s/EFI/Linux" % hdddir
326 exec_cmd(install_cmd)
327
328 staging_dir_host = get_bitbake_var("STAGING_DIR_HOST")
329
330 # https://www.freedesktop.org/software/systemd/man/systemd-stub.html
331 objcopy_cmd = "objcopy \
332 --add-section .osrel=%s --change-section-vma .osrel=0x20000 \
333 --add-section .cmdline=%s --change-section-vma .cmdline=0x30000 \
334 --add-section .linux=%s --change-section-vma .linux=0x2000000 \
335 --add-section .initrd=%s --change-section-vma .initrd=0x3000000 \
336 %s %s" % \
337 ("%s/usr/lib/os-release" % staging_dir_host,
338 cmdline.name,
339 "%s/%s" % (staging_kernel_dir, kernel),
340 initrd.name,
341 efi_stub,
342 "%s/EFI/Linux/linux.efi" % hdddir)
343 exec_cmd(objcopy_cmd)
344 else:
345 install_cmd = "install -m 0644 %s/%s %s/%s" % \
346 (staging_kernel_dir, kernel, hdddir, kernel) 318 (staging_kernel_dir, kernel, hdddir, kernel)
347 exec_cmd(install_cmd) 319 out = exec_cmd(install_cmd)
320 logger.debug("Installed kernel files:\n%s" % out)
348 321
349 if get_bitbake_var("IMAGE_EFI_BOOT_FILES"): 322 if get_bitbake_var("IMAGE_EFI_BOOT_FILES"):
350 for src_path, dst_path in cls.install_task: 323 for src_path, dst_path in cls.install_task:
351 install_cmd = "install -m 0644 -D %s %s" \ 324 install_cmd = "install -v -p -m 0644 -D %s %s" \
352 % (os.path.join(kernel_dir, src_path), 325 % (os.path.join(kernel_dir, src_path),
353 os.path.join(hdddir, dst_path)) 326 os.path.join(hdddir, dst_path))
354 exec_cmd(install_cmd) 327 out = exec_cmd(install_cmd)
328 logger.debug("Installed IMAGE_EFI_BOOT_FILES:\n%s" % out)
355 329
356 try: 330 try:
357 if source_params['loader'] == 'grub-efi': 331 if source_params['loader'] == 'grub-efi':
358 shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, 332 shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir,
359 "%s/grub.cfg" % cr_workdir) 333 "%s/grub.cfg" % cr_workdir)
360 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("grub-efi-")]: 334 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("grub-efi-")]:
361 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[9:]) 335 cp_cmd = "cp -v -p %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[9:])
362 exec_cmd(cp_cmd, True) 336 exec_cmd(cp_cmd, True)
363 shutil.move("%s/grub.cfg" % cr_workdir, 337 shutil.move("%s/grub.cfg" % cr_workdir,
364 "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir) 338 "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir)
365 elif source_params['loader'] == 'systemd-boot': 339 elif source_params['loader'] == 'systemd-boot':
366 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("systemd-")]: 340 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("systemd-")]:
367 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[8:]) 341 cp_cmd = "cp -v -p %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[8:])
368 exec_cmd(cp_cmd, True) 342 out = exec_cmd(cp_cmd, True)
343 logger.debug("systemd-boot files:\n%s" % out)
344 elif source_params['loader'] == 'uefi-kernel':
345 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
346 if not kernel:
347 raise WicError("Empty KERNEL_IMAGETYPE")
348 target = get_bitbake_var("TARGET_SYS")
349 if not target:
350 raise WicError("Empty TARGET_SYS")
351
352 if re.match("x86_64", target):
353 kernel_efi_image = "bootx64.efi"
354 elif re.match('i.86', target):
355 kernel_efi_image = "bootia32.efi"
356 elif re.match('aarch64', target):
357 kernel_efi_image = "bootaa64.efi"
358 elif re.match('arm', target):
359 kernel_efi_image = "bootarm.efi"
360 else:
361 raise WicError("UEFI stub kernel is incompatible with target %s" % target)
362
363 for mod in [x for x in os.listdir(kernel_dir) if x.startswith(kernel)]:
364 cp_cmd = "cp -v -p %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, kernel_efi_image)
365 out = exec_cmd(cp_cmd, True)
366 logger.debug("uefi-kernel files:\n%s" % out)
369 else: 367 else:
370 raise WicError("unrecognized bootimg-efi loader: %s" % 368 raise WicError("unrecognized bootimg_efi loader: %s" %
371 source_params['loader']) 369 source_params['loader'])
370
371 # must have installed at least one EFI bootloader
372 out = glob(os.path.join(hdddir, 'EFI', 'BOOT', 'boot*.efi'))
373 logger.debug("Installed EFI loader files:\n%s" % out)
374 if not out:
375 raise WicError("No EFI loaders installed to ESP partition. Check that grub-efi, systemd-boot or similar is installed.")
376
372 except KeyError: 377 except KeyError:
373 raise WicError("bootimg-efi requires a loader, none specified") 378 raise WicError("bootimg_efi requires a loader, none specified")
374 379
375 startup = os.path.join(kernel_dir, "startup.nsh") 380 startup = os.path.join(kernel_dir, "startup.nsh")
376 if os.path.exists(startup): 381 if os.path.exists(startup):
377 cp_cmd = "cp %s %s/" % (startup, hdddir) 382 cp_cmd = "cp -v -p %s %s/" % (startup, hdddir)
378 exec_cmd(cp_cmd, True) 383 out = exec_cmd(cp_cmd, True)
384 logger.debug("startup files:\n%s" % out)
385
386 for paths in part.include_path or []:
387 for path in paths:
388 cp_cmd = "cp -v -p -r %s %s/" % (path, hdddir)
389 exec_cmd(cp_cmd, True)
390 logger.debug("include_path files:\n%s" % out)
379 391
380 du_cmd = "du -bks %s" % hdddir 392 du_cmd = "du -bks %s" % hdddir
381 out = exec_cmd(du_cmd) 393 out = exec_cmd(du_cmd)
@@ -391,17 +403,26 @@ class BootimgEFIPlugin(SourcePlugin):
391 logger.debug("Added %d extra blocks to %s to get to %d total blocks", 403 logger.debug("Added %d extra blocks to %s to get to %d total blocks",
392 extra_blocks, part.mountpoint, blocks) 404 extra_blocks, part.mountpoint, blocks)
393 405
406 # required for compatibility with certain devices expecting file system
407 # block count to be equal to partition block count
408 if blocks < part.fixed_size:
409 blocks = part.fixed_size
410 logger.debug("Overriding %s to %d total blocks for compatibility",
411 part.mountpoint, blocks)
412
394 # dosfs image, created by mkdosfs 413 # dosfs image, created by mkdosfs
395 bootimg = "%s/boot.img" % cr_workdir 414 bootimg = "%s/boot.img" % cr_workdir
396 415
397 label = part.label if part.label else "ESP" 416 label = part.label if part.label else "ESP"
398 417
399 dosfs_cmd = "mkdosfs -n %s -i %s -C %s %d" % \ 418 dosfs_cmd = "mkdosfs -v -n %s -i %s -C %s %d" % \
400 (label, part.fsuuid, bootimg, blocks) 419 (label, part.fsuuid, bootimg, blocks)
401 exec_native_cmd(dosfs_cmd, native_sysroot) 420 exec_native_cmd(dosfs_cmd, native_sysroot)
421 logger.debug("mkdosfs:\n%s" % (str(out)))
402 422
403 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) 423 mcopy_cmd = "mcopy -v -p -i %s -s %s/* ::/" % (bootimg, hdddir)
404 exec_native_cmd(mcopy_cmd, native_sysroot) 424 out = exec_native_cmd(mcopy_cmd, native_sysroot)
425 logger.debug("mcopy:\n%s" % (str(out)))
405 426
406 chmod_cmd = "chmod 644 %s" % bootimg 427 chmod_cmd = "chmod 644 %s" % bootimg
407 exec_cmd(chmod_cmd) 428 exec_cmd(chmod_cmd)
diff --git a/scripts/lib/wic/plugins/source/bootimg-partition.py b/scripts/lib/wic/plugins/source/bootimg_partition.py
index 5dbe2558d2..cc121a78f0 100644
--- a/scripts/lib/wic/plugins/source/bootimg-partition.py
+++ b/scripts/lib/wic/plugins/source/bootimg_partition.py
@@ -1,8 +1,10 @@
1# 1#
2# Copyright OpenEmbedded Contributors
3#
2# SPDX-License-Identifier: GPL-2.0-only 4# SPDX-License-Identifier: GPL-2.0-only
3# 5#
4# DESCRIPTION 6# DESCRIPTION
5# This implements the 'bootimg-partition' source plugin class for 7# This implements the 'bootimg_partition' source plugin class for
6# 'wic'. The plugin creates an image of boot partition, copying over 8# 'wic'. The plugin creates an image of boot partition, copying over
7# files listed in IMAGE_BOOT_FILES bitbake variable. 9# files listed in IMAGE_BOOT_FILES bitbake variable.
8# 10#
@@ -14,7 +16,7 @@ import logging
14import os 16import os
15import re 17import re
16 18
17from glob import glob 19from oe.bootfiles import get_boot_files
18 20
19from wic import WicError 21from wic import WicError
20from wic.engine import get_custom_config 22from wic.engine import get_custom_config
@@ -29,7 +31,8 @@ class BootimgPartitionPlugin(SourcePlugin):
29 listed in IMAGE_BOOT_FILES bitbake variable. 31 listed in IMAGE_BOOT_FILES bitbake variable.
30 """ 32 """
31 33
32 name = 'bootimg-partition' 34 name = 'bootimg_partition'
35 image_boot_files_var_name = 'IMAGE_BOOT_FILES'
33 36
34 @classmethod 37 @classmethod
35 def do_configure_partition(cls, part, source_params, cr, cr_workdir, 38 def do_configure_partition(cls, part, source_params, cr, cr_workdir,
@@ -54,51 +57,16 @@ class BootimgPartitionPlugin(SourcePlugin):
54 else: 57 else:
55 var = "" 58 var = ""
56 59
57 boot_files = get_bitbake_var("IMAGE_BOOT_FILES" + var) 60 boot_files = get_bitbake_var(cls.image_boot_files_var_name + var)
58 if boot_files is not None: 61 if boot_files is not None:
59 break 62 break
60 63
61 if boot_files is None: 64 if boot_files is None:
62 raise WicError('No boot files defined, IMAGE_BOOT_FILES unset for entry #%d' % part.lineno) 65 raise WicError('No boot files defined, %s unset for entry #%d' % (cls.image_boot_files_var_name, part.lineno))
63 66
64 logger.debug('Boot files: %s', boot_files) 67 logger.debug('Boot files: %s', boot_files)
65 68
66 # list of tuples (src_name, dst_name) 69 cls.install_task = get_boot_files(kernel_dir, boot_files)
67 deploy_files = []
68 for src_entry in re.findall(r'[\w;\-\./\*]+', boot_files):
69 if ';' in src_entry:
70 dst_entry = tuple(src_entry.split(';'))
71 if not dst_entry[0] or not dst_entry[1]:
72 raise WicError('Malformed boot file entry: %s' % src_entry)
73 else:
74 dst_entry = (src_entry, src_entry)
75
76 logger.debug('Destination entry: %r', dst_entry)
77 deploy_files.append(dst_entry)
78
79 cls.install_task = [];
80 for deploy_entry in deploy_files:
81 src, dst = deploy_entry
82 if '*' in src:
83 # by default install files under their basename
84 entry_name_fn = os.path.basename
85 if dst != src:
86 # unless a target name was given, then treat name
87 # as a directory and append a basename
88 entry_name_fn = lambda name: \
89 os.path.join(dst,
90 os.path.basename(name))
91
92 srcs = glob(os.path.join(kernel_dir, src))
93
94 logger.debug('Globbed sources: %s', ', '.join(srcs))
95 for entry in srcs:
96 src = os.path.relpath(entry, kernel_dir)
97 entry_dst_name = entry_name_fn(entry)
98 cls.install_task.append((src, entry_dst_name))
99 else:
100 cls.install_task.append((src, dst))
101
102 if source_params.get('loader') != "u-boot": 70 if source_params.get('loader') != "u-boot":
103 return 71 return
104 72
@@ -110,7 +78,7 @@ class BootimgPartitionPlugin(SourcePlugin):
110 # Use a custom configuration for extlinux.conf 78 # Use a custom configuration for extlinux.conf
111 extlinux_conf = custom_cfg 79 extlinux_conf = custom_cfg
112 logger.debug("Using custom configuration file " 80 logger.debug("Using custom configuration file "
113 "%s for extlinux.cfg", configfile) 81 "%s for extlinux.conf", configfile)
114 else: 82 else:
115 raise WicError("configfile is specified but failed to " 83 raise WicError("configfile is specified but failed to "
116 "get it from %s." % configfile) 84 "get it from %s." % configfile)
diff --git a/scripts/lib/wic/plugins/source/bootimg-pcbios.py b/scripts/lib/wic/plugins/source/bootimg_pcbios.py
index 32e47f1831..21f41e00bb 100644
--- a/scripts/lib/wic/plugins/source/bootimg-pcbios.py
+++ b/scripts/lib/wic/plugins/source/bootimg_pcbios.py
@@ -4,7 +4,7 @@
4# SPDX-License-Identifier: GPL-2.0-only 4# SPDX-License-Identifier: GPL-2.0-only
5# 5#
6# DESCRIPTION 6# DESCRIPTION
7# This implements the 'bootimg-pcbios' source plugin class for 'wic' 7# This implements the 'bootimg_pcbios' source plugin class for 'wic'
8# 8#
9# AUTHORS 9# AUTHORS
10# Tom Zanussi <tom.zanussi (at] linux.intel.com> 10# Tom Zanussi <tom.zanussi (at] linux.intel.com>
@@ -27,7 +27,7 @@ class BootimgPcbiosPlugin(SourcePlugin):
27 Create MBR boot partition and install syslinux on it. 27 Create MBR boot partition and install syslinux on it.
28 """ 28 """
29 29
30 name = 'bootimg-pcbios' 30 name = 'bootimg_pcbios'
31 31
32 @classmethod 32 @classmethod
33 def _get_bootimg_dir(cls, bootimg_dir, dirname): 33 def _get_bootimg_dir(cls, bootimg_dir, dirname):
@@ -122,7 +122,7 @@ class BootimgPcbiosPlugin(SourcePlugin):
122 syslinux_conf += "DEFAULT boot\n" 122 syslinux_conf += "DEFAULT boot\n"
123 syslinux_conf += "LABEL boot\n" 123 syslinux_conf += "LABEL boot\n"
124 124
125 kernel = "/vmlinuz" 125 kernel = "/" + get_bitbake_var("KERNEL_IMAGETYPE")
126 syslinux_conf += "KERNEL " + kernel + "\n" 126 syslinux_conf += "KERNEL " + kernel + "\n"
127 127
128 syslinux_conf += "APPEND label=boot root=%s %s\n" % \ 128 syslinux_conf += "APPEND label=boot root=%s %s\n" % \
@@ -155,8 +155,8 @@ class BootimgPcbiosPlugin(SourcePlugin):
155 kernel = "%s-%s.bin" % \ 155 kernel = "%s-%s.bin" % \
156 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME")) 156 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
157 157
158 cmds = ("install -m 0644 %s/%s %s/vmlinuz" % 158 cmds = ("install -m 0644 %s/%s %s/%s" %
159 (staging_kernel_dir, kernel, hdddir), 159 (staging_kernel_dir, kernel, hdddir, get_bitbake_var("KERNEL_IMAGETYPE")),
160 "install -m 444 %s/syslinux/ldlinux.sys %s/ldlinux.sys" % 160 "install -m 444 %s/syslinux/ldlinux.sys %s/ldlinux.sys" %
161 (bootimg_dir, hdddir), 161 (bootimg_dir, hdddir),
162 "install -m 0644 %s/syslinux/vesamenu.c32 %s/vesamenu.c32" % 162 "install -m 0644 %s/syslinux/vesamenu.c32 %s/vesamenu.c32" %
diff --git a/scripts/lib/wic/plugins/source/empty.py b/scripts/lib/wic/plugins/source/empty.py
index 041617d648..4178912377 100644
--- a/scripts/lib/wic/plugins/source/empty.py
+++ b/scripts/lib/wic/plugins/source/empty.py
@@ -1,4 +1,6 @@
1# 1#
2# Copyright OpenEmbedded Contributors
3#
2# SPDX-License-Identifier: MIT 4# SPDX-License-Identifier: MIT
3# 5#
4 6
@@ -7,9 +9,19 @@
7# To use it you must pass "empty" as argument for the "--source" parameter in 9# To use it you must pass "empty" as argument for the "--source" parameter in
8# the wks file. For example: 10# the wks file. For example:
9# part foo --source empty --ondisk sda --size="1024" --align 1024 11# part foo --source empty --ondisk sda --size="1024" --align 1024
12#
13# The plugin supports writing zeros to the start of the
14# partition. This is useful to overwrite old content like
15# filesystem signatures which may be re-recognized otherwise.
16# This feature can be enabled with
17# '--sourceparams="[fill|size=<N>[S|s|K|k|M|G]][,][bs=<N>[S|s|K|k|M|G]]"'
18# Conflicting or missing options throw errors.
10 19
11import logging 20import logging
21import os
12 22
23from wic import WicError
24from wic.ksparser import sizetype
13from wic.pluginbase import SourcePlugin 25from wic.pluginbase import SourcePlugin
14 26
15logger = logging.getLogger('wic') 27logger = logging.getLogger('wic')
@@ -17,6 +29,16 @@ logger = logging.getLogger('wic')
17class EmptyPartitionPlugin(SourcePlugin): 29class EmptyPartitionPlugin(SourcePlugin):
18 """ 30 """
19 Populate unformatted empty partition. 31 Populate unformatted empty partition.
32
33 The following sourceparams are supported:
34 - fill
35 Fill the entire partition with zeros. Requires '--fixed-size' option
36 to be set.
37 - size=<N>[S|s|K|k|M|G]
38 Set the first N bytes of the partition to zero. Default unit is 'K'.
39 - bs=<N>[S|s|K|k|M|G]
40 Write at most N bytes at a time during source file creation.
41 Defaults to '1M'. Default unit is 'K'.
20 """ 42 """
21 43
22 name = 'empty' 44 name = 'empty'
@@ -29,4 +51,39 @@ class EmptyPartitionPlugin(SourcePlugin):
29 Called to do the actual content population for a partition i.e. it 51 Called to do the actual content population for a partition i.e. it
30 'prepares' the partition to be incorporated into the image. 52 'prepares' the partition to be incorporated into the image.
31 """ 53 """
32 return 54 get_byte_count = sizetype('K', True)
55 size = 0
56
57 if 'fill' in source_params and 'size' in source_params:
58 raise WicError("Conflicting source parameters 'fill' and 'size' specified, exiting.")
59
60 # Set the size of the zeros to be written to the partition
61 if 'fill' in source_params:
62 if part.fixed_size == 0:
63 raise WicError("Source parameter 'fill' only works with the '--fixed-size' option, exiting.")
64 size = get_byte_count(part.fixed_size)
65 elif 'size' in source_params:
66 size = get_byte_count(source_params['size'])
67
68 if size == 0:
69 # Nothing to do, create empty partition
70 return
71
72 if 'bs' in source_params:
73 bs = get_byte_count(source_params['bs'])
74 else:
75 bs = get_byte_count('1M')
76
77 # Create a binary file of the requested size filled with zeros
78 source_file = os.path.join(cr_workdir, 'empty-plugin-zeros%s.bin' % part.lineno)
79 if not os.path.exists(os.path.dirname(source_file)):
80 os.makedirs(os.path.dirname(source_file))
81
82 quotient, remainder = divmod(size, bs)
83 with open(source_file, 'wb') as file:
84 for _ in range(quotient):
85 file.write(bytearray(bs))
86 file.write(bytearray(remainder))
87
88 part.size = (size + 1024 - 1) // 1024 # size in KB rounded up
89 part.source_file = source_file
diff --git a/scripts/lib/wic/plugins/source/isoimage-isohybrid.py b/scripts/lib/wic/plugins/source/isoimage_isohybrid.py
index afc9ea0f8f..5d42eb5d3e 100644
--- a/scripts/lib/wic/plugins/source/isoimage-isohybrid.py
+++ b/scripts/lib/wic/plugins/source/isoimage_isohybrid.py
@@ -1,8 +1,10 @@
1# 1#
2# Copyright OpenEmbedded Contributors
3#
2# SPDX-License-Identifier: GPL-2.0-only 4# SPDX-License-Identifier: GPL-2.0-only
3# 5#
4# DESCRIPTION 6# DESCRIPTION
5# This implements the 'isoimage-isohybrid' source plugin class for 'wic' 7# This implements the 'isoimage_isohybrid' source plugin class for 'wic'
6# 8#
7# AUTHORS 9# AUTHORS
8# Mihaly Varga <mihaly.varga (at] ni.com> 10# Mihaly Varga <mihaly.varga (at] ni.com>
@@ -33,7 +35,7 @@ class IsoImagePlugin(SourcePlugin):
33 bootloader files. 35 bootloader files.
34 36
35 Example kickstart file: 37 Example kickstart file:
36 part /boot --source isoimage-isohybrid --sourceparams="loader=grub-efi, \\ 38 part /boot --source isoimage_isohybrid --sourceparams="loader=grub-efi, \\
37 image_name= IsoImage" --ondisk cd --label LIVECD 39 image_name= IsoImage" --ondisk cd --label LIVECD
38 bootloader --timeout=10 --append=" " 40 bootloader --timeout=10 --append=" "
39 41
@@ -43,7 +45,7 @@ class IsoImagePlugin(SourcePlugin):
43 extension added by direct imeger plugin) and a file named IsoImage-cd.iso 45 extension added by direct imeger plugin) and a file named IsoImage-cd.iso
44 """ 46 """
45 47
46 name = 'isoimage-isohybrid' 48 name = 'isoimage_isohybrid'
47 49
48 @classmethod 50 @classmethod
49 def do_configure_syslinux(cls, creator, cr_workdir): 51 def do_configure_syslinux(cls, creator, cr_workdir):
@@ -338,10 +340,10 @@ class IsoImagePlugin(SourcePlugin):
338 cls.do_configure_grubefi(part, creator, target_dir) 340 cls.do_configure_grubefi(part, creator, target_dir)
339 341
340 else: 342 else:
341 raise WicError("unrecognized bootimg-efi loader: %s" % 343 raise WicError("unrecognized bootimg_efi loader: %s" %
342 source_params['loader']) 344 source_params['loader'])
343 except KeyError: 345 except KeyError:
344 raise WicError("bootimg-efi requires a loader, none specified") 346 raise WicError("bootimg_efi requires a loader, none specified")
345 347
346 # Create efi.img that contains bootloader files for EFI booting 348 # Create efi.img that contains bootloader files for EFI booting
347 # if ISODIR didn't exist or didn't contains it 349 # if ISODIR didn't exist or didn't contains it
diff --git a/scripts/lib/wic/plugins/source/rawcopy.py b/scripts/lib/wic/plugins/source/rawcopy.py
index fa7b1eb8ac..21903c2f23 100644
--- a/scripts/lib/wic/plugins/source/rawcopy.py
+++ b/scripts/lib/wic/plugins/source/rawcopy.py
@@ -1,9 +1,13 @@
1# 1#
2# Copyright OpenEmbedded Contributors
3#
2# SPDX-License-Identifier: GPL-2.0-only 4# SPDX-License-Identifier: GPL-2.0-only
3# 5#
4 6
5import logging 7import logging
6import os 8import os
9import signal
10import subprocess
7 11
8from wic import WicError 12from wic import WicError
9from wic.pluginbase import SourcePlugin 13from wic.pluginbase import SourcePlugin
@@ -21,6 +25,10 @@ class RawCopyPlugin(SourcePlugin):
21 25
22 @staticmethod 26 @staticmethod
23 def do_image_label(fstype, dst, label): 27 def do_image_label(fstype, dst, label):
28 # don't create label when fstype is none
29 if fstype == 'none':
30 return
31
24 if fstype.startswith('ext'): 32 if fstype.startswith('ext'):
25 cmd = 'tune2fs -L %s %s' % (label, dst) 33 cmd = 'tune2fs -L %s %s' % (label, dst)
26 elif fstype in ('msdos', 'vfat'): 34 elif fstype in ('msdos', 'vfat'):
@@ -38,6 +46,26 @@ class RawCopyPlugin(SourcePlugin):
38 46
39 exec_cmd(cmd) 47 exec_cmd(cmd)
40 48
49 @staticmethod
50 def do_image_uncompression(src, dst, workdir):
51 def subprocess_setup():
52 # Python installs a SIGPIPE handler by default. This is usually not what
53 # non-Python subprocesses expect.
54 # SIGPIPE errors are known issues with gzip/bash
55 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
56
57 extension = os.path.splitext(src)[1]
58 decompressor = {
59 ".bz2": "bzip2",
60 ".gz": "gzip",
61 ".xz": "xz",
62 ".zst": "zstd -f",
63 }.get(extension)
64 if not decompressor:
65 raise WicError("Not supported compressor filename extension: %s" % extension)
66 cmd = "%s -dc %s > %s" % (decompressor, src, dst)
67 subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True, cwd=workdir)
68
41 @classmethod 69 @classmethod
42 def do_prepare_partition(cls, part, source_params, cr, cr_workdir, 70 def do_prepare_partition(cls, part, source_params, cr, cr_workdir,
43 oe_builddir, bootimg_dir, kernel_dir, 71 oe_builddir, bootimg_dir, kernel_dir,
@@ -56,7 +84,13 @@ class RawCopyPlugin(SourcePlugin):
56 if 'file' not in source_params: 84 if 'file' not in source_params:
57 raise WicError("No file specified") 85 raise WicError("No file specified")
58 86
59 src = os.path.join(kernel_dir, source_params['file']) 87 if 'unpack' in source_params:
88 img = os.path.join(kernel_dir, source_params['file'])
89 src = os.path.join(cr_workdir, os.path.splitext(source_params['file'])[0])
90 RawCopyPlugin.do_image_uncompression(img, src, cr_workdir)
91 else:
92 src = os.path.join(kernel_dir, source_params['file'])
93
60 dst = os.path.join(cr_workdir, "%s.%s" % (os.path.basename(source_params['file']), part.lineno)) 94 dst = os.path.join(cr_workdir, "%s.%s" % (os.path.basename(source_params['file']), part.lineno))
61 95
62 if not os.path.exists(os.path.dirname(dst)): 96 if not os.path.exists(os.path.dirname(dst)):
diff --git a/scripts/lib/wic/plugins/source/rootfs.py b/scripts/lib/wic/plugins/source/rootfs.py
index 2e34e715ca..06fce06bb1 100644
--- a/scripts/lib/wic/plugins/source/rootfs.py
+++ b/scripts/lib/wic/plugins/source/rootfs.py
@@ -35,22 +35,22 @@ class RootfsPlugin(SourcePlugin):
35 @staticmethod 35 @staticmethod
36 def __validate_path(cmd, rootfs_dir, path): 36 def __validate_path(cmd, rootfs_dir, path):
37 if os.path.isabs(path): 37 if os.path.isabs(path):
38 logger.error("%s: Must be relative: %s" % (cmd, orig_path)) 38 logger.error("%s: Must be relative: %s" % (cmd, path))
39 sys.exit(1) 39 sys.exit(1)
40 40
41 # Disallow climbing outside of parent directory using '..', 41 # Disallow climbing outside of parent directory using '..',
42 # because doing so could be quite disastrous (we will delete the 42 # because doing so could be quite disastrous (we will delete the
43 # directory, or modify a directory outside OpenEmbedded). 43 # directory, or modify a directory outside OpenEmbedded).
44 full_path = os.path.realpath(os.path.join(rootfs_dir, path)) 44 full_path = os.path.abspath(os.path.join(rootfs_dir, path))
45 if not full_path.startswith(os.path.realpath(rootfs_dir)): 45 if not full_path.startswith(os.path.realpath(rootfs_dir)):
46 logger.error("%s: Must point inside the rootfs:" % (cmd, path)) 46 logger.error("%s: Must point inside the rootfs: %s" % (cmd, path))
47 sys.exit(1) 47 sys.exit(1)
48 48
49 return full_path 49 return full_path
50 50
51 @staticmethod 51 @staticmethod
52 def __get_rootfs_dir(rootfs_dir): 52 def __get_rootfs_dir(rootfs_dir):
53 if os.path.isdir(rootfs_dir): 53 if rootfs_dir and os.path.isdir(rootfs_dir):
54 return os.path.realpath(rootfs_dir) 54 return os.path.realpath(rootfs_dir)
55 55
56 image_rootfs_dir = get_bitbake_var("IMAGE_ROOTFS", rootfs_dir) 56 image_rootfs_dir = get_bitbake_var("IMAGE_ROOTFS", rootfs_dir)
@@ -97,6 +97,9 @@ class RootfsPlugin(SourcePlugin):
97 part.has_fstab = os.path.exists(os.path.join(part.rootfs_dir, "etc/fstab")) 97 part.has_fstab = os.path.exists(os.path.join(part.rootfs_dir, "etc/fstab"))
98 pseudo_dir = os.path.join(part.rootfs_dir, "../pseudo") 98 pseudo_dir = os.path.join(part.rootfs_dir, "../pseudo")
99 if not os.path.lexists(pseudo_dir): 99 if not os.path.lexists(pseudo_dir):
100 pseudo_dir = os.path.join(cls.__get_rootfs_dir(None), '../pseudo')
101
102 if not os.path.lexists(pseudo_dir):
100 logger.warn("%s folder does not exist. " 103 logger.warn("%s folder does not exist. "
101 "Usernames and permissions will be invalid " % pseudo_dir) 104 "Usernames and permissions will be invalid " % pseudo_dir)
102 pseudo_dir = None 105 pseudo_dir = None
@@ -221,7 +224,7 @@ class RootfsPlugin(SourcePlugin):
221 if part.update_fstab_in_rootfs and part.has_fstab and not part.no_fstab_update: 224 if part.update_fstab_in_rootfs and part.has_fstab and not part.no_fstab_update:
222 fstab_path = os.path.join(new_rootfs, "etc/fstab") 225 fstab_path = os.path.join(new_rootfs, "etc/fstab")
223 # Assume that fstab should always be owned by root with fixed permissions 226 # Assume that fstab should always be owned by root with fixed permissions
224 install_cmd = "install -m 0644 %s %s" % (part.updated_fstab_path, fstab_path) 227 install_cmd = "install -m 0644 -p %s %s" % (part.updated_fstab_path, fstab_path)
225 if new_pseudo: 228 if new_pseudo:
226 pseudo = cls.__get_pseudo(native_sysroot, new_rootfs, new_pseudo) 229 pseudo = cls.__get_pseudo(native_sysroot, new_rootfs, new_pseudo)
227 else: 230 else: