summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic')
-rw-r--r--scripts/lib/wic/canned-wks/common.wks.inc4
-rw-r--r--scripts/lib/wic/canned-wks/directdisk-gpt.wks4
-rw-r--r--scripts/lib/wic/canned-wks/directdisk-multi-rootfs.wks2
-rw-r--r--scripts/lib/wic/canned-wks/efi-bootdisk.wks.in2
-rw-r--r--scripts/lib/wic/canned-wks/efi-uki-bootdisk.wks.in3
-rw-r--r--scripts/lib/wic/canned-wks/mkefidisk.wks6
-rw-r--r--scripts/lib/wic/canned-wks/mkhybridiso.wks2
-rw-r--r--scripts/lib/wic/canned-wks/qemuloongarch.wks3
-rw-r--r--scripts/lib/wic/canned-wks/qemux86-directdisk.wks2
-rw-r--r--scripts/lib/wic/canned-wks/sdimage-bootpart.wks2
-rw-r--r--scripts/lib/wic/canned-wks/systemd-bootdisk.wks2
-rw-r--r--scripts/lib/wic/engine.py28
-rw-r--r--scripts/lib/wic/filemap.py7
-rw-r--r--scripts/lib/wic/help.py60
-rw-r--r--scripts/lib/wic/ksparser.py13
-rw-r--r--scripts/lib/wic/misc.py14
-rw-r--r--scripts/lib/wic/partition.py99
-rw-r--r--scripts/lib/wic/pluginbase.py10
-rw-r--r--scripts/lib/wic/plugins/imager/direct.py174
-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)189
-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)16
-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.py42
-rw-r--r--scripts/lib/wic/plugins/source/rootfs.py15
27 files changed, 618 insertions, 234 deletions
diff --git a/scripts/lib/wic/canned-wks/common.wks.inc b/scripts/lib/wic/canned-wks/common.wks.inc
index 4fd29fa8c1..4a440ddafe 100644
--- a/scripts/lib/wic/canned-wks/common.wks.inc
+++ b/scripts/lib/wic/canned-wks/common.wks.inc
@@ -1,3 +1,3 @@
1# This file is included into 3 canned wks files from this directory 1# This file is included into 3 canned wks files from this directory
2part /boot --source bootimg-pcbios --ondisk sda --label boot --active --align 1024 2part /boot --source bootimg_pcbios --ondisk sda --label boot --active --align 1024
3part / --source rootfs --use-uuid --fstype=ext4 --mkfs-extraopts "-T default" --label platform --align 1024 3part / --source rootfs --use-uuid --fstype=ext4 --label platform --align 1024
diff --git a/scripts/lib/wic/canned-wks/directdisk-gpt.wks b/scripts/lib/wic/canned-wks/directdisk-gpt.wks
index cf16c0c30b..cb640056f1 100644
--- a/scripts/lib/wic/canned-wks/directdisk-gpt.wks
+++ b/scripts/lib/wic/canned-wks/directdisk-gpt.wks
@@ -3,8 +3,8 @@
3# can directly dd to boot media. 3# can directly dd to boot media.
4 4
5 5
6part /boot --source bootimg-pcbios --ondisk sda --label boot --active --align 1024 6part /boot --source bootimg_pcbios --ondisk sda --label boot --active --align 1024
7part / --source rootfs --ondisk sda --fstype=ext4 --mkfs-extraopts "-T default" --label platform --align 1024 --use-uuid 7part / --source rootfs --ondisk sda --fstype=ext4 --label platform --align 1024 --use-uuid
8 8
9bootloader --ptable gpt --timeout=0 --append="rootwait rootfstype=ext4 video=vesafb vga=0x318 console=tty0 console=ttyS0,115200n8" 9bootloader --ptable gpt --timeout=0 --append="rootwait rootfstype=ext4 video=vesafb vga=0x318 console=tty0 console=ttyS0,115200n8"
10 10
diff --git a/scripts/lib/wic/canned-wks/directdisk-multi-rootfs.wks b/scripts/lib/wic/canned-wks/directdisk-multi-rootfs.wks
index f61d941d6d..4fd1999ffb 100644
--- a/scripts/lib/wic/canned-wks/directdisk-multi-rootfs.wks
+++ b/scripts/lib/wic/canned-wks/directdisk-multi-rootfs.wks
@@ -15,7 +15,7 @@
15# 15#
16# - or any combinations of -r and --rootfs command line options 16# - or any combinations of -r and --rootfs command line options
17 17
18part /boot --source bootimg-pcbios --ondisk sda --label boot --active --align 1024 18part /boot --source bootimg_pcbios --ondisk sda --label boot --active --align 1024
19part / --source rootfs --rootfs-dir=rootfs1 --ondisk sda --fstype=ext4 --label platform --align 1024 19part / --source rootfs --rootfs-dir=rootfs1 --ondisk sda --fstype=ext4 --label platform --align 1024
20part /rescue --source rootfs --rootfs-dir=rootfs2 --ondisk sda --fstype=ext4 --label secondary --align 1024 20part /rescue --source rootfs --rootfs-dir=rootfs2 --ondisk sda --fstype=ext4 --label secondary --align 1024
21 21
diff --git a/scripts/lib/wic/canned-wks/efi-bootdisk.wks.in b/scripts/lib/wic/canned-wks/efi-bootdisk.wks.in
index 7300e65e32..5211972955 100644
--- a/scripts/lib/wic/canned-wks/efi-bootdisk.wks.in
+++ b/scripts/lib/wic/canned-wks/efi-bootdisk.wks.in
@@ -1,3 +1,3 @@
1bootloader --ptable gpt 1bootloader --ptable gpt
2part /boot --source rootfs --rootfs-dir=${IMAGE_ROOTFS}/boot --fstype=vfat --label boot --active --align 1024 --use-uuid --overhead-factor 1.0 2part /boot --source rootfs --rootfs-dir=${IMAGE_ROOTFS}/boot --fstype=vfat --label boot --active --align 1024 --use-uuid --overhead-factor 1.2
3part / --source rootfs --fstype=ext4 --label root --align 1024 --exclude-path boot/ 3part / --source rootfs --fstype=ext4 --label root --align 1024 --exclude-path boot/
diff --git a/scripts/lib/wic/canned-wks/efi-uki-bootdisk.wks.in b/scripts/lib/wic/canned-wks/efi-uki-bootdisk.wks.in
new file mode 100644
index 0000000000..cac0fa32cd
--- /dev/null
+++ b/scripts/lib/wic/canned-wks/efi-uki-bootdisk.wks.in
@@ -0,0 +1,3 @@
1bootloader --ptable gpt --timeout=5
2part /boot --source bootimg_efi --sourceparams="loader=${EFI_PROVIDER}" --label boot --active --align 1024 --use-uuid --part-name="ESP" --part-type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B --overhead-factor=1
3part / --source rootfs --fstype=ext4 --label root --align 1024 --exclude-path boot/
diff --git a/scripts/lib/wic/canned-wks/mkefidisk.wks b/scripts/lib/wic/canned-wks/mkefidisk.wks
index d1878e23e5..16dfe76dfe 100644
--- a/scripts/lib/wic/canned-wks/mkefidisk.wks
+++ b/scripts/lib/wic/canned-wks/mkefidisk.wks
@@ -2,10 +2,10 @@
2# long-description: Creates a partitioned EFI disk image that the user 2# long-description: Creates a partitioned EFI disk image that the user
3# can directly dd to boot media. 3# can directly dd to boot media.
4 4
5part /boot --source bootimg-efi --sourceparams="loader=grub-efi" --ondisk sda --label msdos --active --align 1024 5part /boot --source bootimg_efi --sourceparams="loader=grub-efi" --ondisk sda --label msdos --active --align 1024
6 6
7part / --source rootfs --ondisk sda --fstype=ext4 --mkfs-extraopts "-T default" --label platform --align 1024 --use-uuid 7part / --source rootfs --ondisk sda --fstype=ext4 --label platform --align 1024 --use-uuid
8 8
9part swap --ondisk sda --size 44 --label swap1 --fstype=swap 9part swap --ondisk sda --size 44 --label swap1 --fstype=swap
10 10
11bootloader --ptable gpt --timeout=5 --append="rootfstype=ext4 console=ttyS0,115200 console=tty0" 11bootloader --ptable gpt --timeout=5 --append="rootfstype=ext4 console=${KERNEL_CONSOLE} console=tty0"
diff --git a/scripts/lib/wic/canned-wks/mkhybridiso.wks b/scripts/lib/wic/canned-wks/mkhybridiso.wks
index 48c5ac4791..c3a030e5b4 100644
--- a/scripts/lib/wic/canned-wks/mkhybridiso.wks
+++ b/scripts/lib/wic/canned-wks/mkhybridiso.wks
@@ -2,6 +2,6 @@
2# long-description: Creates an EFI and legacy bootable hybrid ISO image 2# long-description: Creates an EFI and legacy bootable hybrid ISO image
3# which can be used on optical media as well as USB media. 3# which can be used on optical media as well as USB media.
4 4
5part /boot --source isoimage-isohybrid --sourceparams="loader=grub-efi,image_name=HYBRID_ISO_IMG" --ondisk cd --label HYBRIDISO 5part /boot --source isoimage_isohybrid --sourceparams="loader=grub-efi,image_name=HYBRID_ISO_IMG" --ondisk cd --label HYBRIDISO
6 6
7bootloader --timeout=15 --append="" 7bootloader --timeout=15 --append=""
diff --git a/scripts/lib/wic/canned-wks/qemuloongarch.wks b/scripts/lib/wic/canned-wks/qemuloongarch.wks
new file mode 100644
index 0000000000..8465c7a8c0
--- /dev/null
+++ b/scripts/lib/wic/canned-wks/qemuloongarch.wks
@@ -0,0 +1,3 @@
1# short-description: Create qcow2 image for LoongArch QEMU machines
2
3part / --source rootfs --fstype=ext4 --label root --align 4096 --size 5G
diff --git a/scripts/lib/wic/canned-wks/qemux86-directdisk.wks b/scripts/lib/wic/canned-wks/qemux86-directdisk.wks
index 22b45217f1..808997611a 100644
--- a/scripts/lib/wic/canned-wks/qemux86-directdisk.wks
+++ b/scripts/lib/wic/canned-wks/qemux86-directdisk.wks
@@ -4,5 +4,5 @@
4 4
5include common.wks.inc 5include common.wks.inc
6 6
7bootloader --timeout=0 --append="rw oprofile.timer=1 rootfstype=ext4 " 7bootloader --timeout=0 --append="rw oprofile.timer=1 rootfstype=ext4 console=tty console=ttyS0 "
8 8
diff --git a/scripts/lib/wic/canned-wks/sdimage-bootpart.wks b/scripts/lib/wic/canned-wks/sdimage-bootpart.wks
index 63bc4dab6a..f9f8044f7d 100644
--- a/scripts/lib/wic/canned-wks/sdimage-bootpart.wks
+++ b/scripts/lib/wic/canned-wks/sdimage-bootpart.wks
@@ -2,5 +2,5 @@
2# long-description: Creates a partitioned SD card image. Boot files 2# long-description: Creates a partitioned SD card image. Boot files
3# are located in the first vfat partition. 3# are located in the first vfat partition.
4 4
5part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4 --size 16 5part /boot --source bootimg_partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4 --size 16
6part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4 6part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4
diff --git a/scripts/lib/wic/canned-wks/systemd-bootdisk.wks b/scripts/lib/wic/canned-wks/systemd-bootdisk.wks
index 95d7b97a60..3fb2c0e35f 100644
--- a/scripts/lib/wic/canned-wks/systemd-bootdisk.wks
+++ b/scripts/lib/wic/canned-wks/systemd-bootdisk.wks
@@ -2,7 +2,7 @@
2# long-description: Creates a partitioned EFI disk image that the user 2# long-description: Creates a partitioned EFI disk image that the user
3# can directly dd to boot media. The selected bootloader is systemd-boot. 3# can directly dd to boot media. The selected bootloader is systemd-boot.
4 4
5part /boot --source bootimg-efi --sourceparams="loader=systemd-boot" --ondisk sda --label msdos --active --align 1024 --use-uuid 5part /boot --source bootimg_efi --sourceparams="loader=systemd-boot" --ondisk sda --label msdos --active --align 1024 --use-uuid
6 6
7part / --source rootfs --ondisk sda --fstype=ext4 --label platform --align 1024 --use-uuid 7part / --source rootfs --ondisk sda --fstype=ext4 --label platform --align 1024 --use-uuid
8 8
diff --git a/scripts/lib/wic/engine.py b/scripts/lib/wic/engine.py
index 018815b966..b9e60cbe4e 100644
--- a/scripts/lib/wic/engine.py
+++ b/scripts/lib/wic/engine.py
@@ -19,10 +19,10 @@ import os
19import tempfile 19import tempfile
20import json 20import json
21import subprocess 21import subprocess
22import shutil
22import re 23import re
23 24
24from collections import namedtuple, OrderedDict 25from collections import namedtuple, OrderedDict
25from distutils.spawn import find_executable
26 26
27from wic import WicError 27from wic import WicError
28from wic.filemap import sparse_copy 28from wic.filemap import sparse_copy
@@ -180,6 +180,8 @@ def wic_create(wks_file, rootfs_dir, bootimg_dir, kernel_dir,
180 os.makedirs(options.outdir) 180 os.makedirs(options.outdir)
181 181
182 pname = options.imager 182 pname = options.imager
183 # Don't support '-' in plugin names
184 pname = pname.replace("-", "_")
183 plugin_class = PluginMgr.get_plugins('imager').get(pname) 185 plugin_class = PluginMgr.get_plugins('imager').get(pname)
184 if not plugin_class: 186 if not plugin_class:
185 raise WicError('Unknown plugin: %s' % pname) 187 raise WicError('Unknown plugin: %s' % pname)
@@ -232,6 +234,16 @@ class Disk:
232 self._psector_size = None 234 self._psector_size = None
233 self._ptable_format = None 235 self._ptable_format = None
234 236
237 # define sector size
238 sector_size_str = get_bitbake_var('WIC_SECTOR_SIZE')
239 if sector_size_str is not None:
240 try:
241 self.sector_size = int(sector_size_str)
242 except ValueError:
243 self.sector_size = None
244 else:
245 self.sector_size = None
246
235 # find parted 247 # find parted
236 # read paths from $PATH environment variable 248 # read paths from $PATH environment variable
237 # if it fails, use hardcoded paths 249 # if it fails, use hardcoded paths
@@ -245,7 +257,7 @@ class Disk:
245 for path in pathlist.split(':'): 257 for path in pathlist.split(':'):
246 self.paths = "%s%s:%s" % (native_sysroot, path, self.paths) 258 self.paths = "%s%s:%s" % (native_sysroot, path, self.paths)
247 259
248 self.parted = find_executable("parted", self.paths) 260 self.parted = shutil.which("parted", path=self.paths)
249 if not self.parted: 261 if not self.parted:
250 raise WicError("Can't find executable parted") 262 raise WicError("Can't find executable parted")
251 263
@@ -258,7 +270,13 @@ class Disk:
258 def get_partitions(self): 270 def get_partitions(self):
259 if self._partitions is None: 271 if self._partitions is None:
260 self._partitions = OrderedDict() 272 self._partitions = OrderedDict()
261 out = exec_cmd("%s -sm %s unit B print" % (self.parted, self.imagepath)) 273
274 if self.sector_size is not None:
275 out = exec_cmd("export PARTED_SECTOR_SIZE=%d; %s -sm %s unit B print" % \
276 (self.sector_size, self.parted, self.imagepath), True)
277 else:
278 out = exec_cmd("%s -sm %s unit B print" % (self.parted, self.imagepath))
279
262 parttype = namedtuple("Part", "pnum start end size fstype") 280 parttype = namedtuple("Part", "pnum start end size fstype")
263 splitted = out.splitlines() 281 splitted = out.splitlines()
264 # skip over possible errors in exec_cmd output 282 # skip over possible errors in exec_cmd output
@@ -283,7 +301,7 @@ class Disk:
283 "resize2fs", "mkswap", "mkdosfs", "debugfs","blkid"): 301 "resize2fs", "mkswap", "mkdosfs", "debugfs","blkid"):
284 aname = "_%s" % name 302 aname = "_%s" % name
285 if aname not in self.__dict__: 303 if aname not in self.__dict__:
286 setattr(self, aname, find_executable(name, self.paths)) 304 setattr(self, aname, shutil.which(name, path=self.paths))
287 if aname not in self.__dict__ or self.__dict__[aname] is None: 305 if aname not in self.__dict__ or self.__dict__[aname] is None:
288 raise WicError("Can't find executable '{}'".format(name)) 306 raise WicError("Can't find executable '{}'".format(name))
289 return self.__dict__[aname] 307 return self.__dict__[aname]
@@ -359,7 +377,7 @@ class Disk:
359 Remove files/dirs and their contents from the partition. 377 Remove files/dirs and their contents from the partition.
360 This only applies to ext* partition. 378 This only applies to ext* partition.
361 """ 379 """
362 abs_path = re.sub('\/\/+', '/', path) 380 abs_path = re.sub(r'\/\/+', '/', path)
363 cmd = "{} {} -wR 'rm \"{}\"'".format(self.debugfs, 381 cmd = "{} {} -wR 'rm \"{}\"'".format(self.debugfs,
364 self._get_part_image(pnum), 382 self._get_part_image(pnum),
365 abs_path) 383 abs_path)
diff --git a/scripts/lib/wic/filemap.py b/scripts/lib/wic/filemap.py
index 4d9da28172..85b39d5d74 100644
--- a/scripts/lib/wic/filemap.py
+++ b/scripts/lib/wic/filemap.py
@@ -46,6 +46,13 @@ def get_block_size(file_obj):
46 bsize = stat.st_blksize 46 bsize = stat.st_blksize
47 else: 47 else:
48 raise IOError("Unable to determine block size") 48 raise IOError("Unable to determine block size")
49
50 # The logic in this script only supports a maximum of a 4KB
51 # block size
52 max_block_size = 4 * 1024
53 if bsize > max_block_size:
54 bsize = max_block_size
55
49 return bsize 56 return bsize
50 57
51class ErrorNotSupp(Exception): 58class ErrorNotSupp(Exception):
diff --git a/scripts/lib/wic/help.py b/scripts/lib/wic/help.py
index bd3a2b97df..2e3061f343 100644
--- a/scripts/lib/wic/help.py
+++ b/scripts/lib/wic/help.py
@@ -544,18 +544,18 @@ DESCRIPTION
544 the --source param given to that partition. For example, if the 544 the --source param given to that partition. For example, if the
545 partition is set up like this: 545 partition is set up like this:
546 546
547 part /boot --source bootimg-pcbios ... 547 part /boot --source bootimg_pcbios ...
548 548
549 then the methods defined as class members of the plugin having the 549 then the methods defined as class members of the plugin having the
550 matching bootimg-pcbios .name class member would be used. 550 matching bootimg_pcbios .name class member would be used.
551 551
552 To be more concrete, here's the plugin definition that would match 552 To be more concrete, here's the plugin definition that would match
553 a '--source bootimg-pcbios' usage, along with an example method 553 a '--source bootimg_pcbios' usage, along with an example method
554 that would be called by the wic implementation when it needed to 554 that would be called by the wic implementation when it needed to
555 invoke an implementation-specific partition-preparation function: 555 invoke an implementation-specific partition-preparation function:
556 556
557 class BootimgPcbiosPlugin(SourcePlugin): 557 class BootimgPcbiosPlugin(SourcePlugin):
558 name = 'bootimg-pcbios' 558 name = 'bootimg_pcbios'
559 559
560 @classmethod 560 @classmethod
561 def do_prepare_partition(self, part, ...) 561 def do_prepare_partition(self, part, ...)
@@ -637,7 +637,7 @@ DESCRIPTION
637 oe-core: directdisk.bbclass and mkefidisk.sh. The difference 637 oe-core: directdisk.bbclass and mkefidisk.sh. The difference
638 between wic and those examples is that with wic the functionality 638 between wic and those examples is that with wic the functionality
639 of those scripts is implemented by a general-purpose partitioning 639 of those scripts is implemented by a general-purpose partitioning
640 'language' based on Redhat kickstart syntax). 640 'language' based on Red Hat kickstart syntax).
641 641
642 The initial motivation and design considerations that lead to the 642 The initial motivation and design considerations that lead to the
643 current tool are described exhaustively in Yocto Bug #3847 643 current tool are described exhaustively in Yocto Bug #3847
@@ -794,7 +794,7 @@ DESCRIPTION
794 794
795 Here is a content of test.wks: 795 Here is a content of test.wks:
796 796
797 part /boot --source bootimg-pcbios --ondisk sda --label boot --active --align 1024 797 part /boot --source bootimg_pcbios --ondisk sda --label boot --active --align 1024
798 part / --source rootfs --ondisk sda --fstype=ext3 --label platform --align 1024 798 part / --source rootfs --ondisk sda --fstype=ext3 --label platform --align 1024
799 799
800 bootloader --timeout=0 --append="rootwait rootfstype=ext3 video=vesafb vga=0x318 console=tty0" 800 bootloader --timeout=0 --append="rootwait rootfstype=ext3 video=vesafb vga=0x318 console=tty0"
@@ -840,8 +840,8 @@ DESCRIPTION
840 meanings. The commands are based on the Fedora kickstart 840 meanings. The commands are based on the Fedora kickstart
841 documentation but with modifications to reflect wic capabilities. 841 documentation but with modifications to reflect wic capabilities.
842 842
843 http://fedoraproject.org/wiki/Anaconda/Kickstart#part_or_partition 843 https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html#part-or-partition
844 http://fedoraproject.org/wiki/Anaconda/Kickstart#bootloader 844 https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html#bootloader
845 845
846 Commands 846 Commands
847 847
@@ -916,6 +916,10 @@ DESCRIPTION
916 will create empty partition. --size parameter has 916 will create empty partition. --size parameter has
917 to be used to specify size of empty partition. 917 to be used to specify size of empty partition.
918 918
919 --sourceparams: This option is specific to wic. Supply additional
920 parameters to the source plugin in
921 key1=value1,key2 format.
922
919 --ondisk or --ondrive: Forces the partition to be created on 923 --ondisk or --ondrive: Forces the partition to be created on
920 a particular disk. 924 a particular disk.
921 925
@@ -930,7 +934,9 @@ DESCRIPTION
930 ext4 934 ext4
931 btrfs 935 btrfs
932 squashfs 936 squashfs
937 erofs
933 swap 938 swap
939 none
934 940
935 --fsoptions: Specifies a free-form string of options to be 941 --fsoptions: Specifies a free-form string of options to be
936 used when mounting the filesystem. This string 942 used when mounting the filesystem. This string
@@ -939,6 +945,12 @@ DESCRIPTION
939 quotes. If not specified, the default string is 945 quotes. If not specified, the default string is
940 "defaults". 946 "defaults".
941 947
948 --fspassno: Specifies the order in which filesystem checks are done
949 at boot time by fsck. See fs_passno parameter of
950 fstab(5). This parameter will be copied into the
951 /etc/fstab file of the installed system. If not
952 specified the default value of "0" will be used.
953
942 --label label: Specifies the label to give to the filesystem 954 --label label: Specifies the label to give to the filesystem
943 to be made on the partition. If the given 955 to be made on the partition. If the given
944 label is already in use by another filesystem, 956 label is already in use by another filesystem,
@@ -958,6 +970,14 @@ DESCRIPTION
958 to start a partition on an x KBytes 970 to start a partition on an x KBytes
959 boundary. 971 boundary.
960 972
973 --offset: This option is specific to wic that says to place a partition
974 at exactly the specified offset. If the partition cannot be
975 placed at the specified offset, the image build will fail.
976 Specify as an integer value optionally followed by one of the
977 units s/S for 512 byte sector, k/K for kibibyte, M for
978 mebibyte and G for gibibyte. The default unit if none is
979 given is k.
980
961 --no-table: This option is specific to wic. Space will be 981 --no-table: This option is specific to wic. Space will be
962 reserved for the partition and it will be 982 reserved for the partition and it will be
963 populated but it will not be added to the 983 populated but it will not be added to the
@@ -990,6 +1010,9 @@ DESCRIPTION
990 multiple partitions and we want to keep the right 1010 multiple partitions and we want to keep the right
991 permissions and usernames in all the partitions. 1011 permissions and usernames in all the partitions.
992 1012
1013 --no-fstab-update: This option is specific to wic. It does not update the
1014 '/etc/fstab' stock file for the given partition.
1015
993 --extra-space: This option is specific to wic. It adds extra 1016 --extra-space: This option is specific to wic. It adds extra
994 space after the space filled by the content 1017 space after the space filled by the content
995 of the partition. The final size can go 1018 of the partition. The final size can go
@@ -1035,6 +1058,18 @@ DESCRIPTION
1035 not take effect when --mkfs-extraopts is used. This should be taken into 1058 not take effect when --mkfs-extraopts is used. This should be taken into
1036 account when using --mkfs-extraopts. 1059 account when using --mkfs-extraopts.
1037 1060
1061 --type: This option is specific to wic. Valid values are 'primary',
1062 'logical'. For msdos partition tables, this option specifies
1063 the partition type.
1064
1065 --hidden: This option is specific to wic. This option sets the
1066 RequiredPartition bit (bit 0) on GPT partitions.
1067
1068 --mbr: This option is specific to wic. This option is used with the
1069 gpt-hybrid partition type that uses both a GPT partition and
1070 an MBR header. Partitions with this flag will be included in
1071 this MBR header.
1072
1038 * bootloader 1073 * bootloader
1039 1074
1040 This command allows the user to specify various bootloader 1075 This command allows the user to specify various bootloader
@@ -1053,6 +1088,13 @@ DESCRIPTION
1053 file. Using this option will override any other 1088 file. Using this option will override any other
1054 bootloader option. 1089 bootloader option.
1055 1090
1091 --ptable: Specifies the partition table format. Valid values are
1092 'msdos', 'gpt', 'gpt-hybrid'.
1093
1094 --source: Specifies the source plugin. If not specified, the
1095 --source value will be copied from the partition that has
1096 /boot as mountpoint.
1097
1056 Note that bootloader functionality and boot partitions are 1098 Note that bootloader functionality and boot partitions are
1057 implemented by the various --source plugins that implement 1099 implemented by the various --source plugins that implement
1058 bootloader functionality; the bootloader command essentially 1100 bootloader functionality; the bootloader command essentially
@@ -1108,7 +1150,7 @@ COMMAND:
1108TOPIC: 1150TOPIC:
1109 overview - Presents an overall overview of Wic 1151 overview - Presents an overall overview of Wic
1110 plugins - Presents an overview and API for Wic plugins 1152 plugins - Presents an overview and API for Wic plugins
1111 kickstart - Presents a Wic kicstart file reference 1153 kickstart - Presents a Wic kickstart file reference
1112 1154
1113 1155
1114Examples: 1156Examples:
diff --git a/scripts/lib/wic/ksparser.py b/scripts/lib/wic/ksparser.py
index 3eb669da39..7ef3dc83dd 100644
--- a/scripts/lib/wic/ksparser.py
+++ b/scripts/lib/wic/ksparser.py
@@ -155,9 +155,11 @@ class KickStart():
155 part.add_argument('--change-directory') 155 part.add_argument('--change-directory')
156 part.add_argument("--extra-space", type=sizetype("M")) 156 part.add_argument("--extra-space", type=sizetype("M"))
157 part.add_argument('--fsoptions', dest='fsopts') 157 part.add_argument('--fsoptions', dest='fsopts')
158 part.add_argument('--fspassno', dest='fspassno')
158 part.add_argument('--fstype', default='vfat', 159 part.add_argument('--fstype', default='vfat',
159 choices=('ext2', 'ext3', 'ext4', 'btrfs', 160 choices=('ext2', 'ext3', 'ext4', 'btrfs',
160 'squashfs', 'vfat', 'msdos', 'swap')) 161 'squashfs', 'vfat', 'msdos', 'erofs',
162 'swap', 'none'))
161 part.add_argument('--mkfs-extraopts', default='') 163 part.add_argument('--mkfs-extraopts', default='')
162 part.add_argument('--label') 164 part.add_argument('--label')
163 part.add_argument('--use-label', action='store_true') 165 part.add_argument('--use-label', action='store_true')
@@ -169,6 +171,7 @@ class KickStart():
169 part.add_argument('--rootfs-dir') 171 part.add_argument('--rootfs-dir')
170 part.add_argument('--type', default='primary', 172 part.add_argument('--type', default='primary',
171 choices = ('primary', 'logical')) 173 choices = ('primary', 'logical'))
174 part.add_argument('--hidden', action='store_true')
172 175
173 # --size and --fixed-size cannot be specified together; options 176 # --size and --fixed-size cannot be specified together; options
174 # ----extra-space and --overhead-factor should also raise a parser 177 # ----extra-space and --overhead-factor should also raise a parser
@@ -184,11 +187,13 @@ class KickStart():
184 part.add_argument('--use-uuid', action='store_true') 187 part.add_argument('--use-uuid', action='store_true')
185 part.add_argument('--uuid') 188 part.add_argument('--uuid')
186 part.add_argument('--fsuuid') 189 part.add_argument('--fsuuid')
190 part.add_argument('--no-fstab-update', action='store_true')
191 part.add_argument('--mbr', action='store_true')
187 192
188 bootloader = subparsers.add_parser('bootloader') 193 bootloader = subparsers.add_parser('bootloader')
189 bootloader.add_argument('--append') 194 bootloader.add_argument('--append')
190 bootloader.add_argument('--configfile') 195 bootloader.add_argument('--configfile')
191 bootloader.add_argument('--ptable', choices=('msdos', 'gpt'), 196 bootloader.add_argument('--ptable', choices=('msdos', 'gpt', 'gpt-hybrid'),
192 default='msdos') 197 default='msdos')
193 bootloader.add_argument('--timeout', type=int) 198 bootloader.add_argument('--timeout', type=int)
194 bootloader.add_argument('--source') 199 bootloader.add_argument('--source')
@@ -229,6 +234,10 @@ class KickStart():
229 err = "%s:%d: SquashFS does not support LABEL" \ 234 err = "%s:%d: SquashFS does not support LABEL" \
230 % (confpath, lineno) 235 % (confpath, lineno)
231 raise KickStartError(err) 236 raise KickStartError(err)
237 # erofs does not support filesystem labels
238 if parsed.fstype == 'erofs' and parsed.label:
239 err = "%s:%d: erofs does not support LABEL" % (confpath, lineno)
240 raise KickStartError(err)
232 if parsed.fstype == 'msdos' or parsed.fstype == 'vfat': 241 if parsed.fstype == 'msdos' or parsed.fstype == 'vfat':
233 if parsed.fsuuid: 242 if parsed.fsuuid:
234 if parsed.fsuuid.upper().startswith('0X'): 243 if parsed.fsuuid.upper().startswith('0X'):
diff --git a/scripts/lib/wic/misc.py b/scripts/lib/wic/misc.py
index 57c042c503..1a7c140fa6 100644
--- a/scripts/lib/wic/misc.py
+++ b/scripts/lib/wic/misc.py
@@ -16,16 +16,16 @@ import logging
16import os 16import os
17import re 17import re
18import subprocess 18import subprocess
19import shutil
19 20
20from collections import defaultdict 21from collections import defaultdict
21from distutils import spawn
22 22
23from wic import WicError 23from wic import WicError
24 24
25logger = logging.getLogger('wic') 25logger = logging.getLogger('wic')
26 26
27# executable -> recipe pairs for exec_native_cmd 27# executable -> recipe pairs for exec_native_cmd
28NATIVE_RECIPES = {"bmaptool": "bmap-tools", 28NATIVE_RECIPES = {"bmaptool": "bmaptool",
29 "dumpe2fs": "e2fsprogs", 29 "dumpe2fs": "e2fsprogs",
30 "grub-mkimage": "grub-efi", 30 "grub-mkimage": "grub-efi",
31 "isohybrid": "syslinux", 31 "isohybrid": "syslinux",
@@ -36,6 +36,7 @@ NATIVE_RECIPES = {"bmaptool": "bmap-tools",
36 "mkdosfs": "dosfstools", 36 "mkdosfs": "dosfstools",
37 "mkisofs": "cdrtools", 37 "mkisofs": "cdrtools",
38 "mkfs.btrfs": "btrfs-tools", 38 "mkfs.btrfs": "btrfs-tools",
39 "mkfs.erofs": "erofs-utils",
39 "mkfs.ext2": "e2fsprogs", 40 "mkfs.ext2": "e2fsprogs",
40 "mkfs.ext3": "e2fsprogs", 41 "mkfs.ext3": "e2fsprogs",
41 "mkfs.ext4": "e2fsprogs", 42 "mkfs.ext4": "e2fsprogs",
@@ -122,7 +123,7 @@ def find_executable(cmd, paths):
122 if provided and "%s-native" % recipe in provided: 123 if provided and "%s-native" % recipe in provided:
123 return True 124 return True
124 125
125 return spawn.find_executable(cmd, paths) 126 return shutil.which(cmd, path=paths)
126 127
127def exec_native_cmd(cmd_and_args, native_sysroot, pseudo=""): 128def exec_native_cmd(cmd_and_args, native_sysroot, pseudo=""):
128 """ 129 """
@@ -140,11 +141,12 @@ def exec_native_cmd(cmd_and_args, native_sysroot, pseudo=""):
140 cmd_and_args = pseudo + cmd_and_args 141 cmd_and_args = pseudo + cmd_and_args
141 142
142 hosttools_dir = get_bitbake_var("HOSTTOOLS_DIR") 143 hosttools_dir = get_bitbake_var("HOSTTOOLS_DIR")
144 target_sys = get_bitbake_var("TARGET_SYS")
143 145
144 native_paths = "%s/sbin:%s/usr/sbin:%s/usr/bin:%s/bin:%s" % \ 146 native_paths = "%s/sbin:%s/usr/sbin:%s/usr/bin:%s/usr/bin/%s:%s/bin:%s" % \
145 (native_sysroot, native_sysroot, 147 (native_sysroot, native_sysroot,
146 native_sysroot, native_sysroot, 148 native_sysroot, native_sysroot, target_sys,
147 hosttools_dir) 149 native_sysroot, hosttools_dir)
148 150
149 native_cmd_and_args = "export PATH=%s:$PATH;%s" % \ 151 native_cmd_and_args = "export PATH=%s:$PATH;%s" % \
150 (native_paths, cmd_and_args) 152 (native_paths, cmd_and_args)
diff --git a/scripts/lib/wic/partition.py b/scripts/lib/wic/partition.py
index 76d144d12d..b34691d313 100644
--- a/scripts/lib/wic/partition.py
+++ b/scripts/lib/wic/partition.py
@@ -33,6 +33,7 @@ class Partition():
33 self.include_path = args.include_path 33 self.include_path = args.include_path
34 self.change_directory = args.change_directory 34 self.change_directory = args.change_directory
35 self.fsopts = args.fsopts 35 self.fsopts = args.fsopts
36 self.fspassno = args.fspassno
36 self.fstype = args.fstype 37 self.fstype = args.fstype
37 self.label = args.label 38 self.label = args.label
38 self.use_label = args.use_label 39 self.use_label = args.use_label
@@ -54,9 +55,12 @@ class Partition():
54 self.uuid = args.uuid 55 self.uuid = args.uuid
55 self.fsuuid = args.fsuuid 56 self.fsuuid = args.fsuuid
56 self.type = args.type 57 self.type = args.type
58 self.no_fstab_update = args.no_fstab_update
57 self.updated_fstab_path = None 59 self.updated_fstab_path = None
58 self.has_fstab = False 60 self.has_fstab = False
59 self.update_fstab_in_rootfs = False 61 self.update_fstab_in_rootfs = False
62 self.hidden = args.hidden
63 self.mbr = args.mbr
60 64
61 self.lineno = lineno 65 self.lineno = lineno
62 self.source_file = "" 66 self.source_file = ""
@@ -104,7 +108,7 @@ class Partition():
104 extra_blocks = self.extra_space 108 extra_blocks = self.extra_space
105 109
106 rootfs_size = actual_rootfs_size + extra_blocks 110 rootfs_size = actual_rootfs_size + extra_blocks
107 rootfs_size *= self.overhead_factor 111 rootfs_size = int(rootfs_size * self.overhead_factor)
108 112
109 logger.debug("Added %d extra blocks to %s to get to %d total blocks", 113 logger.debug("Added %d extra blocks to %s to get to %d total blocks",
110 extra_blocks, self.mountpoint, rootfs_size) 114 extra_blocks, self.mountpoint, rootfs_size)
@@ -131,6 +135,8 @@ class Partition():
131 self.update_fstab_in_rootfs = True 135 self.update_fstab_in_rootfs = True
132 136
133 if not self.source: 137 if not self.source:
138 if self.fstype == "none" or self.no_table:
139 return
134 if not self.size and not self.fixed_size: 140 if not self.size and not self.fixed_size:
135 raise WicError("The %s partition has a size of zero. Please " 141 raise WicError("The %s partition has a size of zero. Please "
136 "specify a non-zero --size/--fixed-size for that " 142 "specify a non-zero --size/--fixed-size for that "
@@ -141,9 +147,9 @@ class Partition():
141 native_sysroot) 147 native_sysroot)
142 self.source_file = "%s/fs.%s" % (cr_workdir, self.fstype) 148 self.source_file = "%s/fs.%s" % (cr_workdir, self.fstype)
143 else: 149 else:
144 if self.fstype == 'squashfs': 150 if self.fstype in ('squashfs', 'erofs'):
145 raise WicError("It's not possible to create empty squashfs " 151 raise WicError("It's not possible to create empty %s "
146 "partition '%s'" % (self.mountpoint)) 152 "partition '%s'" % (self.fstype, self.mountpoint))
147 153
148 rootfs = "%s/fs_%s.%s.%s" % (cr_workdir, self.label, 154 rootfs = "%s/fs_%s.%s.%s" % (cr_workdir, self.label,
149 self.lineno, self.fstype) 155 self.lineno, self.fstype)
@@ -158,6 +164,9 @@ class Partition():
158 164
159 plugins = PluginMgr.get_plugins('source') 165 plugins = PluginMgr.get_plugins('source')
160 166
167 # Don't support '-' in plugin names
168 self.source = self.source.replace("-", "_")
169
161 if self.source not in plugins: 170 if self.source not in plugins:
162 raise WicError("The '%s' --source specified for %s doesn't exist.\n\t" 171 raise WicError("The '%s' --source specified for %s doesn't exist.\n\t"
163 "See 'wic list source-plugins' for a list of available" 172 "See 'wic list source-plugins' for a list of available"
@@ -170,9 +179,9 @@ class Partition():
170 # Split sourceparams string of the form key1=val1[,key2=val2,...] 179 # Split sourceparams string of the form key1=val1[,key2=val2,...]
171 # into a dict. Also accepts valueless keys i.e. without = 180 # into a dict. Also accepts valueless keys i.e. without =
172 splitted = self.sourceparams.split(',') 181 splitted = self.sourceparams.split(',')
173 srcparams_dict = dict(par.split('=', 1) for par in splitted if par) 182 srcparams_dict = dict((par.split('=', 1) + [None])[:2] for par in splitted if par)
174 183
175 plugin = PluginMgr.get_plugins('source')[self.source] 184 plugin = plugins[self.source]
176 plugin.do_configure_partition(self, srcparams_dict, creator, 185 plugin.do_configure_partition(self, srcparams_dict, creator,
177 cr_workdir, oe_builddir, bootimg_dir, 186 cr_workdir, oe_builddir, bootimg_dir,
178 kernel_dir, native_sysroot) 187 kernel_dir, native_sysroot)
@@ -216,19 +225,19 @@ class Partition():
216 if (pseudo_dir): 225 if (pseudo_dir):
217 # Canonicalize the ignore paths. This corresponds to 226 # Canonicalize the ignore paths. This corresponds to
218 # calling oe.path.canonicalize(), which is used in bitbake.conf. 227 # calling oe.path.canonicalize(), which is used in bitbake.conf.
219 ignore_paths = [rootfs] + (get_bitbake_var("PSEUDO_IGNORE_PATHS") or "").split(",") 228 include_paths = [rootfs_dir] + (get_bitbake_var("PSEUDO_INCLUDE_PATHS") or "").split(",")
220 canonical_paths = [] 229 canonical_paths = []
221 for path in ignore_paths: 230 for path in include_paths:
222 if "$" not in path: 231 if "$" not in path:
223 trailing_slash = path.endswith("/") and "/" or "" 232 trailing_slash = path.endswith("/") and "/" or ""
224 canonical_paths.append(os.path.realpath(path) + trailing_slash) 233 canonical_paths.append(os.path.realpath(path) + trailing_slash)
225 ignore_paths = ",".join(canonical_paths) 234 include_paths = ",".join(canonical_paths)
226 235
227 pseudo = "export PSEUDO_PREFIX=%s;" % p_prefix 236 pseudo = "export PSEUDO_PREFIX=%s;" % p_prefix
228 pseudo += "export PSEUDO_LOCALSTATEDIR=%s;" % pseudo_dir 237 pseudo += "export PSEUDO_LOCALSTATEDIR=%s;" % pseudo_dir
229 pseudo += "export PSEUDO_PASSWD=%s;" % rootfs_dir 238 pseudo += "export PSEUDO_PASSWD=%s;" % rootfs_dir
230 pseudo += "export PSEUDO_NOSYMLINKEXP=1;" 239 pseudo += "export PSEUDO_NOSYMLINKEXP=1;"
231 pseudo += "export PSEUDO_IGNORE_PATHS=%s;" % ignore_paths 240 pseudo += "export PSEUDO_INCLUDE_PATHS=%s;" % include_paths
232 pseudo += "%s " % get_bitbake_var("FAKEROOTCMD") 241 pseudo += "%s " % get_bitbake_var("FAKEROOTCMD")
233 else: 242 else:
234 pseudo = None 243 pseudo = None
@@ -238,7 +247,7 @@ class Partition():
238 # from bitbake variable 247 # from bitbake variable
239 rsize_bb = get_bitbake_var('ROOTFS_SIZE') 248 rsize_bb = get_bitbake_var('ROOTFS_SIZE')
240 rdir = get_bitbake_var('IMAGE_ROOTFS') 249 rdir = get_bitbake_var('IMAGE_ROOTFS')
241 if rsize_bb and rdir == rootfs_dir: 250 if rsize_bb and (rdir == rootfs_dir or (rootfs_dir.split('/')[-2] == "tmp-wic" and rootfs_dir.split('/')[-1][:6] == "rootfs")):
242 # Bitbake variable ROOTFS_SIZE is calculated in 251 # Bitbake variable ROOTFS_SIZE is calculated in
243 # Image._get_rootfs_size method from meta/lib/oe/image.py 252 # Image._get_rootfs_size method from meta/lib/oe/image.py
244 # using IMAGE_ROOTFS_SIZE, IMAGE_ROOTFS_ALIGNMENT, 253 # using IMAGE_ROOTFS_SIZE, IMAGE_ROOTFS_ALIGNMENT,
@@ -278,6 +287,9 @@ class Partition():
278 287
279 extraopts = self.mkfs_extraopts or "-F -i 8192" 288 extraopts = self.mkfs_extraopts or "-F -i 8192"
280 289
290 # use hash_seed to generate reproducible ext4 images
291 (extraopts, pseudo) = self.get_hash_seed_ext4(extraopts, pseudo)
292
281 label_str = "" 293 label_str = ""
282 if self.label: 294 if self.label:
283 label_str = "-L %s" % self.label 295 label_str = "-L %s" % self.label
@@ -286,7 +298,7 @@ class Partition():
286 (self.fstype, extraopts, rootfs, label_str, self.fsuuid, rootfs_dir) 298 (self.fstype, extraopts, rootfs, label_str, self.fsuuid, rootfs_dir)
287 exec_native_cmd(mkfs_cmd, native_sysroot, pseudo=pseudo) 299 exec_native_cmd(mkfs_cmd, native_sysroot, pseudo=pseudo)
288 300
289 if self.updated_fstab_path and self.has_fstab: 301 if self.updated_fstab_path and self.has_fstab and not self.no_fstab_update:
290 debugfs_script_path = os.path.join(cr_workdir, "debugfs_script") 302 debugfs_script_path = os.path.join(cr_workdir, "debugfs_script")
291 with open(debugfs_script_path, "w") as f: 303 with open(debugfs_script_path, "w") as f:
292 f.write("cd etc\n") 304 f.write("cd etc\n")
@@ -298,8 +310,49 @@ class Partition():
298 mkfs_cmd = "fsck.%s -pvfD %s" % (self.fstype, rootfs) 310 mkfs_cmd = "fsck.%s -pvfD %s" % (self.fstype, rootfs)
299 exec_native_cmd(mkfs_cmd, native_sysroot, pseudo=pseudo) 311 exec_native_cmd(mkfs_cmd, native_sysroot, pseudo=pseudo)
300 312
313 if os.getenv('SOURCE_DATE_EPOCH'):
314 sde_time = hex(int(os.getenv('SOURCE_DATE_EPOCH')))
315 debugfs_script_path = os.path.join(cr_workdir, "debugfs_script")
316 files = []
317 for root, dirs, others in os.walk(rootfs_dir):
318 base = root.replace(rootfs_dir, "").rstrip(os.sep)
319 files += [ "/" if base == "" else base ]
320 files += [ base + "/" + n for n in dirs + others ]
321 with open(debugfs_script_path, "w") as f:
322 f.write("set_current_time %s\n" % (sde_time))
323 if self.updated_fstab_path and self.has_fstab and not self.no_fstab_update:
324 f.write("set_inode_field /etc/fstab mtime %s\n" % (sde_time))
325 f.write("set_inode_field /etc/fstab mtime_extra 0\n")
326 for file in set(files):
327 for time in ["atime", "ctime", "crtime"]:
328 f.write("set_inode_field \"%s\" %s %s\n" % (file, time, sde_time))
329 f.write("set_inode_field \"%s\" %s_extra 0\n" % (file, time))
330 for time in ["wtime", "mkfs_time", "lastcheck"]:
331 f.write("set_super_value %s %s\n" % (time, sde_time))
332 for time in ["mtime", "first_error_time", "last_error_time"]:
333 f.write("set_super_value %s 0\n" % (time))
334 debugfs_cmd = "debugfs -w -f %s %s" % (debugfs_script_path, rootfs)
335 exec_native_cmd(debugfs_cmd, native_sysroot)
336
301 self.check_for_Y2038_problem(rootfs, native_sysroot) 337 self.check_for_Y2038_problem(rootfs, native_sysroot)
302 338
339 def get_hash_seed_ext4(self, extraopts, pseudo):
340 if os.getenv('SOURCE_DATE_EPOCH'):
341 sde_time = int(os.getenv('SOURCE_DATE_EPOCH'))
342 if pseudo:
343 pseudo = "export E2FSPROGS_FAKE_TIME=%s;%s " % (sde_time, pseudo)
344 else:
345 pseudo = "export E2FSPROGS_FAKE_TIME=%s; " % sde_time
346
347 # Set hash_seed to generate deterministic directory indexes
348 namespace = uuid.UUID("e7429877-e7b3-4a68-a5c9-2f2fdf33d460")
349 if self.fsuuid:
350 namespace = uuid.UUID(self.fsuuid)
351 hash_seed = str(uuid.uuid5(namespace, str(sde_time)))
352 extraopts += " -E hash_seed=%s" % hash_seed
353
354 return (extraopts, pseudo)
355
303 def prepare_rootfs_btrfs(self, rootfs, cr_workdir, oe_builddir, rootfs_dir, 356 def prepare_rootfs_btrfs(self, rootfs, cr_workdir, oe_builddir, rootfs_dir,
304 native_sysroot, pseudo): 357 native_sysroot, pseudo):
305 """ 358 """
@@ -350,8 +403,8 @@ class Partition():
350 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (rootfs, rootfs_dir) 403 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (rootfs, rootfs_dir)
351 exec_native_cmd(mcopy_cmd, native_sysroot) 404 exec_native_cmd(mcopy_cmd, native_sysroot)
352 405
353 if self.updated_fstab_path and self.has_fstab: 406 if self.updated_fstab_path and self.has_fstab and not self.no_fstab_update:
354 mcopy_cmd = "mcopy -i %s %s ::/etc/fstab" % (rootfs, self.updated_fstab_path) 407 mcopy_cmd = "mcopy -m -i %s %s ::/etc/fstab" % (rootfs, self.updated_fstab_path)
355 exec_native_cmd(mcopy_cmd, native_sysroot) 408 exec_native_cmd(mcopy_cmd, native_sysroot)
356 409
357 chmod_cmd = "chmod 644 %s" % rootfs 410 chmod_cmd = "chmod 644 %s" % rootfs
@@ -369,6 +422,19 @@ class Partition():
369 (rootfs_dir, rootfs, extraopts) 422 (rootfs_dir, rootfs, extraopts)
370 exec_native_cmd(squashfs_cmd, native_sysroot, pseudo=pseudo) 423 exec_native_cmd(squashfs_cmd, native_sysroot, pseudo=pseudo)
371 424
425 def prepare_rootfs_erofs(self, rootfs, cr_workdir, oe_builddir, rootfs_dir,
426 native_sysroot, pseudo):
427 """
428 Prepare content for a erofs rootfs partition.
429 """
430 extraopts = self.mkfs_extraopts or ''
431 erofs_cmd = "mkfs.erofs %s -U %s %s %s" % \
432 (extraopts, self.fsuuid, rootfs, rootfs_dir)
433 exec_native_cmd(erofs_cmd, native_sysroot, pseudo=pseudo)
434
435 def prepare_empty_partition_none(self, rootfs, oe_builddir, native_sysroot):
436 pass
437
372 def prepare_empty_partition_ext(self, rootfs, oe_builddir, 438 def prepare_empty_partition_ext(self, rootfs, oe_builddir,
373 native_sysroot): 439 native_sysroot):
374 """ 440 """
@@ -380,13 +446,16 @@ class Partition():
380 446
381 extraopts = self.mkfs_extraopts or "-i 8192" 447 extraopts = self.mkfs_extraopts or "-i 8192"
382 448
449 # use hash_seed to generate reproducible ext4 images
450 (extraopts, pseudo) = self.get_hash_seed_ext4(extraopts, None)
451
383 label_str = "" 452 label_str = ""
384 if self.label: 453 if self.label:
385 label_str = "-L %s" % self.label 454 label_str = "-L %s" % self.label
386 455
387 mkfs_cmd = "mkfs.%s -F %s %s -U %s %s" % \ 456 mkfs_cmd = "mkfs.%s -F %s %s -U %s %s" % \
388 (self.fstype, extraopts, label_str, self.fsuuid, rootfs) 457 (self.fstype, extraopts, label_str, self.fsuuid, rootfs)
389 exec_native_cmd(mkfs_cmd, native_sysroot) 458 exec_native_cmd(mkfs_cmd, native_sysroot, pseudo=pseudo)
390 459
391 self.check_for_Y2038_problem(rootfs, native_sysroot) 460 self.check_for_Y2038_problem(rootfs, native_sysroot)
392 461
diff --git a/scripts/lib/wic/pluginbase.py b/scripts/lib/wic/pluginbase.py
index d9b4e57747..640da292d3 100644
--- a/scripts/lib/wic/pluginbase.py
+++ b/scripts/lib/wic/pluginbase.py
@@ -9,9 +9,11 @@ __all__ = ['ImagerPlugin', 'SourcePlugin']
9 9
10import os 10import os
11import logging 11import logging
12import types
12 13
13from collections import defaultdict 14from collections import defaultdict
14from importlib.machinery import SourceFileLoader 15import importlib
16import importlib.util
15 17
16from wic import WicError 18from wic import WicError
17from wic.misc import get_bitbake_var 19from wic.misc import get_bitbake_var
@@ -42,7 +44,7 @@ class PluginMgr:
42 path = os.path.join(layer_path, script_plugin_dir) 44 path = os.path.join(layer_path, script_plugin_dir)
43 path = os.path.abspath(os.path.expanduser(path)) 45 path = os.path.abspath(os.path.expanduser(path))
44 if path not in cls._plugin_dirs and os.path.isdir(path): 46 if path not in cls._plugin_dirs and os.path.isdir(path):
45 cls._plugin_dirs.insert(0, path) 47 cls._plugin_dirs.append(path)
46 48
47 if ptype not in PLUGINS: 49 if ptype not in PLUGINS:
48 # load all ptype plugins 50 # load all ptype plugins
@@ -54,7 +56,9 @@ class PluginMgr:
54 mname = fname[:-3] 56 mname = fname[:-3]
55 mpath = os.path.join(ppath, fname) 57 mpath = os.path.join(ppath, fname)
56 logger.debug("loading plugin module %s", mpath) 58 logger.debug("loading plugin module %s", mpath)
57 SourceFileLoader(mname, mpath).load_module() 59 spec = importlib.util.spec_from_file_location(mname, mpath)
60 module = importlib.util.module_from_spec(spec)
61 spec.loader.exec_module(module)
58 62
59 return PLUGINS.get(ptype) 63 return PLUGINS.get(ptype)
60 64
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
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 cdc72543c2..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>
@@ -12,6 +12,7 @@
12 12
13import logging 13import logging
14import os 14import os
15import tempfile
15import shutil 16import shutil
16import re 17import re
17 18
@@ -31,7 +32,29 @@ class BootimgEFIPlugin(SourcePlugin):
31 This plugin supports GRUB 2 and systemd-boot bootloaders. 32 This plugin supports GRUB 2 and systemd-boot bootloaders.
32 """ 33 """
33 34
34 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))
35 58
36 @classmethod 59 @classmethod
37 def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params): 60 def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params):
@@ -52,18 +75,9 @@ class BootimgEFIPlugin(SourcePlugin):
52 "get it from %s." % configfile) 75 "get it from %s." % configfile)
53 76
54 initrd = source_params.get('initrd') 77 initrd = source_params.get('initrd')
78 dtb = source_params.get('dtb')
55 79
56 if initrd: 80 cls._copy_additional_files(hdddir, initrd, dtb)
57 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
58 if not bootimg_dir:
59 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
60
61 initrds = initrd.split(';')
62 for rd in initrds:
63 cp_cmd = "cp %s/%s %s" % (bootimg_dir, rd, hdddir)
64 exec_cmd(cp_cmd, True)
65 else:
66 logger.debug("Ignoring missing initrd")
67 81
68 if not custom_cfg: 82 if not custom_cfg:
69 # Create grub configuration using parameters from wks file 83 # Create grub configuration using parameters from wks file
@@ -97,6 +111,9 @@ class BootimgEFIPlugin(SourcePlugin):
97 grubefi_conf += " /%s" % rd 111 grubefi_conf += " /%s" % rd
98 grubefi_conf += "\n" 112 grubefi_conf += "\n"
99 113
114 if dtb:
115 grubefi_conf += "devicetree /%s\n" % dtb
116
100 grubefi_conf += "}\n" 117 grubefi_conf += "}\n"
101 118
102 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",
@@ -108,8 +125,16 @@ class BootimgEFIPlugin(SourcePlugin):
108 @classmethod 125 @classmethod
109 def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params): 126 def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params):
110 """ 127 """
111 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.
112 """ 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
113 install_cmd = "install -d %s/loader" % hdddir 138 install_cmd = "install -d %s/loader" % hdddir
114 exec_cmd(install_cmd) 139 exec_cmd(install_cmd)
115 140
@@ -117,34 +142,26 @@ class BootimgEFIPlugin(SourcePlugin):
117 exec_cmd(install_cmd) 142 exec_cmd(install_cmd)
118 143
119 bootloader = creator.ks.bootloader 144 bootloader = creator.ks.bootloader
120
121 loader_conf = "" 145 loader_conf = ""
122 loader_conf += "default boot\n"
123 loader_conf += "timeout %d\n" % bootloader.timeout
124
125 initrd = source_params.get('initrd')
126
127 if initrd:
128 # obviously we need to have a common common deploy var
129 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
130 if not bootimg_dir:
131 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
132 146
133 initrds = initrd.split(';') 147 # 5 seconds is a sensible default timeout
134 for rd in initrds: 148 loader_conf += "timeout %d\n" % (bootloader.timeout or 5)
135 cp_cmd = "cp %s/%s %s" % (bootimg_dir, rd, hdddir)
136 exec_cmd(cp_cmd, True)
137 else:
138 logger.debug("Ignoring missing initrd")
139 149
140 logger.debug("Writing systemd-boot config " 150 logger.debug("Writing systemd-boot config "
141 "%s/hdd/boot/loader/loader.conf", cr_workdir) 151 "%s/hdd/boot/loader/loader.conf", cr_workdir)
142 cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w") 152 cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w")
143 cfg.write(loader_conf) 153 cfg.write(loader_conf)
154 logger.debug("loader.conf:\n%s" % (loader_conf))
144 cfg.close() 155 cfg.close()
145 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
146 configfile = creator.ks.bootloader.configfile 162 configfile = creator.ks.bootloader.configfile
147 custom_cfg = None 163 custom_cfg = None
164 boot_conf = ""
148 if configfile: 165 if configfile:
149 custom_cfg = get_custom_config(configfile) 166 custom_cfg = get_custom_config(configfile)
150 if custom_cfg: 167 if custom_cfg:
@@ -155,8 +172,7 @@ class BootimgEFIPlugin(SourcePlugin):
155 else: 172 else:
156 raise WicError("configfile is specified but failed to " 173 raise WicError("configfile is specified but failed to "
157 "get it from %s.", configfile) 174 "get it from %s.", configfile)
158 175 else:
159 if not custom_cfg:
160 # Create systemd-boot configuration using parameters from wks file 176 # Create systemd-boot configuration using parameters from wks file
161 kernel = get_bitbake_var("KERNEL_IMAGETYPE") 177 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
162 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1": 178 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
@@ -166,7 +182,6 @@ class BootimgEFIPlugin(SourcePlugin):
166 182
167 title = source_params.get('title') 183 title = source_params.get('title')
168 184
169 boot_conf = ""
170 boot_conf += "title %s\n" % (title if title else "boot") 185 boot_conf += "title %s\n" % (title if title else "boot")
171 boot_conf += "linux /%s\n" % kernel 186 boot_conf += "linux /%s\n" % kernel
172 187
@@ -183,11 +198,16 @@ class BootimgEFIPlugin(SourcePlugin):
183 for rd in initrds: 198 for rd in initrds:
184 boot_conf += "initrd /%s\n" % rd 199 boot_conf += "initrd /%s\n" % rd
185 200
186 logger.debug("Writing systemd-boot config " 201 if dtb:
187 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir) 202 boot_conf += "devicetree /%s\n" % dtb
188 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w") 203
189 cfg.write(boot_conf) 204 if not unified_image:
190 cfg.close() 205 logger.debug("Writing systemd-boot config "
206 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir)
207 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w")
208 cfg.write(boot_conf)
209 logger.debug("boot.conf:\n%s" % (boot_conf))
210 cfg.close()
191 211
192 212
193 @classmethod 213 @classmethod
@@ -207,10 +227,12 @@ class BootimgEFIPlugin(SourcePlugin):
207 cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params) 227 cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params)
208 elif source_params['loader'] == 'systemd-boot': 228 elif source_params['loader'] == 'systemd-boot':
209 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
210 else: 232 else:
211 raise WicError("unrecognized bootimg-efi loader: %s" % source_params['loader']) 233 raise WicError("unrecognized bootimg_efi loader: %s" % source_params['loader'])
212 except KeyError: 234 except KeyError:
213 raise WicError("bootimg-efi requires a loader, none specified") 235 raise WicError("bootimg_efi requires a loader, none specified")
214 236
215 if get_bitbake_var("IMAGE_EFI_BOOT_FILES") is None: 237 if get_bitbake_var("IMAGE_EFI_BOOT_FILES") is None:
216 logger.debug('No boot files defined in IMAGE_EFI_BOOT_FILES') 238 logger.debug('No boot files defined in IMAGE_EFI_BOOT_FILES')
@@ -230,7 +252,7 @@ class BootimgEFIPlugin(SourcePlugin):
230 252
231 # list of tuples (src_name, dst_name) 253 # list of tuples (src_name, dst_name)
232 deploy_files = [] 254 deploy_files = []
233 for src_entry in re.findall(r'[\w;\-\./\*]+', boot_files): 255 for src_entry in re.findall(r'[\w;\-\.\+/\*]+', boot_files):
234 if ';' in src_entry: 256 if ';' in src_entry:
235 dst_entry = tuple(src_entry.split(';')) 257 dst_entry = tuple(src_entry.split(';'))
236 if not dst_entry[0] or not dst_entry[1]: 258 if not dst_entry[0] or not dst_entry[1]:
@@ -288,40 +310,84 @@ class BootimgEFIPlugin(SourcePlugin):
288 kernel = "%s-%s.bin" % \ 310 kernel = "%s-%s.bin" % \
289 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME")) 311 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
290 312
291 install_cmd = "install -m 0644 %s/%s %s/%s" % \ 313 if source_params.get('create-unified-kernel-image') == "true":
292 (staging_kernel_dir, kernel, hdddir, kernel) 314 raise WicError("create-unified-kernel-image is no longer supported. Please use uki.bbclass.")
293 exec_cmd(install_cmd) 315
316 if source_params.get('install-kernel-into-boot-dir') != 'false':
317 install_cmd = "install -v -p -m 0644 %s/%s %s/%s" % \
318 (staging_kernel_dir, kernel, hdddir, kernel)
319 out = exec_cmd(install_cmd)
320 logger.debug("Installed kernel files:\n%s" % out)
294 321
295 if get_bitbake_var("IMAGE_EFI_BOOT_FILES"): 322 if get_bitbake_var("IMAGE_EFI_BOOT_FILES"):
296 for src_path, dst_path in cls.install_task: 323 for src_path, dst_path in cls.install_task:
297 install_cmd = "install -m 0644 -D %s %s" \ 324 install_cmd = "install -v -p -m 0644 -D %s %s" \
298 % (os.path.join(kernel_dir, src_path), 325 % (os.path.join(kernel_dir, src_path),
299 os.path.join(hdddir, dst_path)) 326 os.path.join(hdddir, dst_path))
300 exec_cmd(install_cmd) 327 out = exec_cmd(install_cmd)
328 logger.debug("Installed IMAGE_EFI_BOOT_FILES:\n%s" % out)
301 329
302 try: 330 try:
303 if source_params['loader'] == 'grub-efi': 331 if source_params['loader'] == 'grub-efi':
304 shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, 332 shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir,
305 "%s/grub.cfg" % cr_workdir) 333 "%s/grub.cfg" % cr_workdir)
306 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-")]:
307 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:])
308 exec_cmd(cp_cmd, True) 336 exec_cmd(cp_cmd, True)
309 shutil.move("%s/grub.cfg" % cr_workdir, 337 shutil.move("%s/grub.cfg" % cr_workdir,
310 "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir) 338 "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir)
311 elif source_params['loader'] == 'systemd-boot': 339 elif source_params['loader'] == 'systemd-boot':
312 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-")]:
313 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:])
314 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)
315 else: 367 else:
316 raise WicError("unrecognized bootimg-efi loader: %s" % 368 raise WicError("unrecognized bootimg_efi loader: %s" %
317 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
318 except KeyError: 377 except KeyError:
319 raise WicError("bootimg-efi requires a loader, none specified") 378 raise WicError("bootimg_efi requires a loader, none specified")
320 379
321 startup = os.path.join(kernel_dir, "startup.nsh") 380 startup = os.path.join(kernel_dir, "startup.nsh")
322 if os.path.exists(startup): 381 if os.path.exists(startup):
323 cp_cmd = "cp %s %s/" % (startup, hdddir) 382 cp_cmd = "cp -v -p %s %s/" % (startup, hdddir)
324 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)
325 391
326 du_cmd = "du -bks %s" % hdddir 392 du_cmd = "du -bks %s" % hdddir
327 out = exec_cmd(du_cmd) 393 out = exec_cmd(du_cmd)
@@ -337,17 +403,26 @@ class BootimgEFIPlugin(SourcePlugin):
337 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",
338 extra_blocks, part.mountpoint, blocks) 404 extra_blocks, part.mountpoint, blocks)
339 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
340 # dosfs image, created by mkdosfs 413 # dosfs image, created by mkdosfs
341 bootimg = "%s/boot.img" % cr_workdir 414 bootimg = "%s/boot.img" % cr_workdir
342 415
343 label = part.label if part.label else "ESP" 416 label = part.label if part.label else "ESP"
344 417
345 dosfs_cmd = "mkdosfs -n %s -i %s -C %s %d" % \ 418 dosfs_cmd = "mkdosfs -v -n %s -i %s -C %s %d" % \
346 (label, part.fsuuid, bootimg, blocks) 419 (label, part.fsuuid, bootimg, blocks)
347 exec_native_cmd(dosfs_cmd, native_sysroot) 420 exec_native_cmd(dosfs_cmd, native_sysroot)
421 logger.debug("mkdosfs:\n%s" % (str(out)))
348 422
349 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) 423 mcopy_cmd = "mcopy -v -p -i %s -s %s/* ::/" % (bootimg, hdddir)
350 exec_native_cmd(mcopy_cmd, native_sysroot) 424 out = exec_native_cmd(mcopy_cmd, native_sysroot)
425 logger.debug("mcopy:\n%s" % (str(out)))
351 426
352 chmod_cmd = "chmod 644 %s" % bootimg 427 chmod_cmd = "chmod 644 %s" % bootimg
353 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 f2639e7004..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" %
@@ -186,8 +186,10 @@ class BootimgPcbiosPlugin(SourcePlugin):
186 # dosfs image, created by mkdosfs 186 # dosfs image, created by mkdosfs
187 bootimg = "%s/boot%s.img" % (cr_workdir, part.lineno) 187 bootimg = "%s/boot%s.img" % (cr_workdir, part.lineno)
188 188
189 dosfs_cmd = "mkdosfs -n boot -i %s -S 512 -C %s %d" % \ 189 label = part.label if part.label else "boot"
190 (part.fsuuid, bootimg, blocks) 190
191 dosfs_cmd = "mkdosfs -n %s -i %s -S 512 -C %s %d" % \
192 (label, part.fsuuid, bootimg, blocks)
191 exec_native_cmd(dosfs_cmd, native_sysroot) 193 exec_native_cmd(dosfs_cmd, native_sysroot)
192 194
193 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) 195 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir)
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 3c4997d8ba..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'):
@@ -29,15 +37,35 @@ class RawCopyPlugin(SourcePlugin):
29 cmd = 'btrfs filesystem label %s %s' % (dst, label) 37 cmd = 'btrfs filesystem label %s %s' % (dst, label)
30 elif fstype == 'swap': 38 elif fstype == 'swap':
31 cmd = 'mkswap -L %s %s' % (label, dst) 39 cmd = 'mkswap -L %s %s' % (label, dst)
32 elif fstype == 'squashfs': 40 elif fstype in ('squashfs', 'erofs'):
33 raise WicError("It's not possible to update a squashfs " 41 raise WicError("It's not possible to update a %s "
34 "filesystem label '%s'" % (label)) 42 "filesystem label '%s'" % (fstype, label))
35 else: 43 else:
36 raise WicError("Cannot update filesystem label: " 44 raise WicError("Cannot update filesystem label: "
37 "Unknown fstype: '%s'" % (fstype)) 45 "Unknown fstype: '%s'" % (fstype))
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 96d940a91d..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
@@ -218,10 +221,10 @@ class RootfsPlugin(SourcePlugin):
218 # Update part.has_fstab here as fstab may have been added or 221 # Update part.has_fstab here as fstab may have been added or
219 # removed by the above modifications. 222 # removed by the above modifications.
220 part.has_fstab = os.path.exists(os.path.join(new_rootfs, "etc/fstab")) 223 part.has_fstab = os.path.exists(os.path.join(new_rootfs, "etc/fstab"))
221 if part.update_fstab_in_rootfs and part.has_fstab: 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: