summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/plugins/source
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/plugins/source')
-rw-r--r--scripts/lib/wic/plugins/source/bootimg_biosplusefi.py213
-rw-r--r--scripts/lib/wic/plugins/source/bootimg_efi.py435
-rw-r--r--scripts/lib/wic/plugins/source/bootimg_partition.py162
-rw-r--r--scripts/lib/wic/plugins/source/bootimg_pcbios.py483
-rw-r--r--scripts/lib/wic/plugins/source/empty.py89
-rw-r--r--scripts/lib/wic/plugins/source/extra_partition.py134
-rw-r--r--scripts/lib/wic/plugins/source/isoimage_isohybrid.py463
-rw-r--r--scripts/lib/wic/plugins/source/rawcopy.py115
-rw-r--r--scripts/lib/wic/plugins/source/rootfs.py236
9 files changed, 0 insertions, 2330 deletions
diff --git a/scripts/lib/wic/plugins/source/bootimg_biosplusefi.py b/scripts/lib/wic/plugins/source/bootimg_biosplusefi.py
deleted file mode 100644
index 4279ddded8..0000000000
--- a/scripts/lib/wic/plugins/source/bootimg_biosplusefi.py
+++ /dev/null
@@ -1,213 +0,0 @@
1#
2# This program is free software; you can redistribute it and/or modify
3# it under the terms of the GNU General Public License version 2 as
4# published by the Free Software Foundation.
5#
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9# GNU General Public License for more details.
10#
11# You should have received a copy of the GNU General Public License along
12# with this program; if not, write to the Free Software Foundation, Inc.,
13# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
14#
15# DESCRIPTION
16# This implements the 'bootimg_biosplusefi' source plugin class for 'wic'
17#
18# AUTHORS
19# William Bourque <wbourque [at) gmail.com>
20
21import types
22
23from wic.pluginbase import SourcePlugin
24from importlib.machinery import SourceFileLoader
25
26class BootimgBiosPlusEFIPlugin(SourcePlugin):
27 """
28 Create MBR + EFI boot partition
29
30 This plugin creates a boot partition that contains both
31 legacy BIOS and EFI content. It will be able to boot from both.
32 This is useful when managing PC fleet with some older machines
33 without EFI support.
34
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
37 --source bootimg_efi and another one with --source bootimg_pcbios.
38 However, this method has the obvious downside that it requires TWO
39 partitions to be created on the storage device.
40 Both partitions will also be marked as "bootable" which does not work on
41 most BIOS, has BIOS often uses the "bootable" flag to determine
42 what to boot. If you have such a BIOS, you need to manually remove the
43 "bootable" flag from the EFI partition for the drive to be bootable.
44 Having two partitions also seems to confuse wic : the content of
45 the first partition will be duplicated into the second, even though it
46 will not be used at all.
47
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
50 not turn the rootfs into an initramfs RAM image.
51
52 This plugin is made to put everything into a single /boot partition so it
53 does not have the limitations listed above.
54
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"
57 and "bootimg_efi".
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
60 requires a --sourceparams argument to know which loader to use; refer
61 to "bootimg_efi" code/documentation for the list of loader.
62
63 Imports are handled with "SourceFileLoader" from importlib as it is
64 otherwise very difficult to import module that has hyphen "-" in their
65 filename.
66 The SourcePlugin() methods used in the plugins (do_install_disk,
67 do_configure_partition, do_prepare_partition) are then called on both,
68 beginning by "bootimg_efi".
69
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.
72
73 Example wic configuration:
74 part /boot --source bootimg_biosplusefi --sourceparams="loader=grub-efi"\\
75 --ondisk sda --label os_boot --active --align 1024 --use-uuid
76 """
77
78 name = 'bootimg_biosplusefi'
79
80 __PCBIOS_MODULE_NAME = "bootimg_pcbios"
81 __EFI_MODULE_NAME = "bootimg_efi"
82
83 __imgEFIObj = None
84 __imgBiosObj = None
85
86 @classmethod
87 def __init__(cls):
88 """
89 Constructor (init)
90 """
91
92 # XXX
93 # For some reasons, __init__ constructor is never called.
94 # Something to do with how pluginbase works?
95 cls.__instanciateSubClasses()
96
97 @classmethod
98 def __instanciateSubClasses(cls):
99 """
100
101 """
102
103 # Import bootimg_pcbios (class name "BootimgPcbiosPlugin")
104 modulePath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
105 cls.__PCBIOS_MODULE_NAME + ".py")
106 loader = SourceFileLoader(cls.__PCBIOS_MODULE_NAME, modulePath)
107 mod = types.ModuleType(loader.name)
108 loader.exec_module(mod)
109 cls.__imgBiosObj = mod.BootimgPcbiosPlugin()
110
111 # Import bootimg_efi (class name "BootimgEFIPlugin")
112 modulePath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
113 cls.__EFI_MODULE_NAME + ".py")
114 loader = SourceFileLoader(cls.__EFI_MODULE_NAME, modulePath)
115 mod = types.ModuleType(loader.name)
116 loader.exec_module(mod)
117 cls.__imgEFIObj = mod.BootimgEFIPlugin()
118
119 @classmethod
120 def do_install_disk(cls, disk, disk_name, creator, workdir, oe_builddir,
121 bootimg_dir, kernel_dir, native_sysroot):
122 """
123 Called after all partitions have been prepared and assembled into a
124 disk image.
125 """
126
127 if ( (not cls.__imgEFIObj) or (not cls.__imgBiosObj) ):
128 cls.__instanciateSubClasses()
129
130 cls.__imgEFIObj.do_install_disk(
131 disk,
132 disk_name,
133 creator,
134 workdir,
135 oe_builddir,
136 bootimg_dir,
137 kernel_dir,
138 native_sysroot)
139
140 cls.__imgBiosObj.do_install_disk(
141 disk,
142 disk_name,
143 creator,
144 workdir,
145 oe_builddir,
146 bootimg_dir,
147 kernel_dir,
148 native_sysroot)
149
150 @classmethod
151 def do_configure_partition(cls, part, source_params, creator, cr_workdir,
152 oe_builddir, bootimg_dir, kernel_dir,
153 native_sysroot):
154 """
155 Called before do_prepare_partition()
156 """
157
158 if ( (not cls.__imgEFIObj) or (not cls.__imgBiosObj) ):
159 cls.__instanciateSubClasses()
160
161 cls.__imgEFIObj.do_configure_partition(
162 part,
163 source_params,
164 creator,
165 cr_workdir,
166 oe_builddir,
167 bootimg_dir,
168 kernel_dir,
169 native_sysroot)
170
171 cls.__imgBiosObj.do_configure_partition(
172 part,
173 source_params,
174 creator,
175 cr_workdir,
176 oe_builddir,
177 bootimg_dir,
178 kernel_dir,
179 native_sysroot)
180
181 @classmethod
182 def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
183 oe_builddir, bootimg_dir, kernel_dir,
184 rootfs_dir, native_sysroot):
185 """
186 Called to do the actual content population for a partition i.e. it
187 'prepares' the partition to be incorporated into the image.
188 """
189
190 if ( (not cls.__imgEFIObj) or (not cls.__imgBiosObj) ):
191 cls.__instanciateSubClasses()
192
193 cls.__imgEFIObj.do_prepare_partition(
194 part,
195 source_params,
196 creator,
197 cr_workdir,
198 oe_builddir,
199 bootimg_dir,
200 kernel_dir,
201 rootfs_dir,
202 native_sysroot)
203
204 cls.__imgBiosObj.do_prepare_partition(
205 part,
206 source_params,
207 creator,
208 cr_workdir,
209 oe_builddir,
210 bootimg_dir,
211 kernel_dir,
212 rootfs_dir,
213 native_sysroot)
diff --git a/scripts/lib/wic/plugins/source/bootimg_efi.py b/scripts/lib/wic/plugins/source/bootimg_efi.py
deleted file mode 100644
index cf16705a28..0000000000
--- a/scripts/lib/wic/plugins/source/bootimg_efi.py
+++ /dev/null
@@ -1,435 +0,0 @@
1#
2# Copyright (c) 2014, Intel Corporation.
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6# DESCRIPTION
7# This implements the 'bootimg_efi' source plugin class for 'wic'
8#
9# AUTHORS
10# Tom Zanussi <tom.zanussi (at] linux.intel.com>
11#
12
13import logging
14import os
15import tempfile
16import shutil
17import re
18
19from glob import glob
20
21from wic import WicError
22from wic.engine import get_custom_config
23from wic.pluginbase import SourcePlugin
24from wic.misc import (exec_cmd, exec_native_cmd,
25 get_bitbake_var, BOOTDD_EXTRA_SPACE)
26
27logger = logging.getLogger('wic')
28
29class BootimgEFIPlugin(SourcePlugin):
30 """
31 Create EFI boot partition.
32 This plugin supports GRUB 2 and systemd-boot bootloaders.
33 """
34
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))
58
59 @classmethod
60 def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params):
61 """
62 Create loader-specific (grub-efi) config
63 """
64 configfile = creator.ks.bootloader.configfile
65 custom_cfg = None
66 if configfile:
67 custom_cfg = get_custom_config(configfile)
68 if custom_cfg:
69 # Use a custom configuration for grub
70 grubefi_conf = custom_cfg
71 logger.debug("Using custom configuration file "
72 "%s for grub.cfg", configfile)
73 else:
74 raise WicError("configfile is specified but failed to "
75 "get it from %s." % configfile)
76
77 initrd = source_params.get('initrd')
78 dtb = source_params.get('dtb')
79
80 cls._copy_additional_files(hdddir, initrd, dtb)
81
82 if not custom_cfg:
83 # Create grub configuration using parameters from wks file
84 bootloader = creator.ks.bootloader
85 title = source_params.get('title')
86
87 grubefi_conf = ""
88 grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n"
89 grubefi_conf += "default=boot\n"
90 grubefi_conf += "timeout=%s\n" % bootloader.timeout
91 grubefi_conf += "menuentry '%s'{\n" % (title if title else "boot")
92
93 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
94 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
95 if get_bitbake_var("INITRAMFS_IMAGE"):
96 kernel = "%s-%s.bin" % \
97 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
98
99 label = source_params.get('label')
100 label_conf = "root=%s" % creator.rootdev
101 if label:
102 label_conf = "LABEL=%s" % label
103
104 grubefi_conf += "linux /%s %s rootwait %s\n" \
105 % (kernel, label_conf, bootloader.append)
106
107 if initrd:
108 initrds = initrd.split(';')
109 grubefi_conf += "initrd"
110 for rd in initrds:
111 grubefi_conf += " /%s" % rd
112 grubefi_conf += "\n"
113
114 if dtb:
115 grubefi_conf += "devicetree /%s\n" % dtb
116
117 grubefi_conf += "}\n"
118
119 logger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg",
120 cr_workdir)
121 cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, "w")
122 cfg.write(grubefi_conf)
123 cfg.close()
124
125 @classmethod
126 def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params):
127 """
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.
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
138 install_cmd = "install -d %s/loader" % hdddir
139 exec_cmd(install_cmd)
140
141 install_cmd = "install -d %s/loader/entries" % hdddir
142 exec_cmd(install_cmd)
143
144 bootloader = creator.ks.bootloader
145 loader_conf = ""
146
147 # 5 seconds is a sensible default timeout
148 loader_conf += "timeout %d\n" % (bootloader.timeout or 5)
149
150 logger.debug("Writing systemd-boot config "
151 "%s/hdd/boot/loader/loader.conf", cr_workdir)
152 cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w")
153 cfg.write(loader_conf)
154 logger.debug("loader.conf:\n%s" % (loader_conf))
155 cfg.close()
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
162 configfile = creator.ks.bootloader.configfile
163 custom_cfg = None
164 boot_conf = ""
165 if configfile:
166 custom_cfg = get_custom_config(configfile)
167 if custom_cfg:
168 # Use a custom configuration for systemd-boot
169 boot_conf = custom_cfg
170 logger.debug("Using custom configuration file "
171 "%s for systemd-boots's boot.conf", configfile)
172 else:
173 raise WicError("configfile is specified but failed to "
174 "get it from %s.", configfile)
175 else:
176 # Create systemd-boot configuration using parameters from wks file
177 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
178 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
179 if get_bitbake_var("INITRAMFS_IMAGE"):
180 kernel = "%s-%s.bin" % \
181 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
182
183 title = source_params.get('title')
184
185 boot_conf += "title %s\n" % (title if title else "boot")
186 boot_conf += "linux /%s\n" % kernel
187
188 label = source_params.get('label')
189 label_conf = "LABEL=Boot root=%s" % creator.rootdev
190 if label:
191 label_conf = "LABEL=%s" % label
192
193 boot_conf += "options %s %s\n" % \
194 (label_conf, bootloader.append)
195
196 if initrd:
197 initrds = initrd.split(';')
198 for rd in initrds:
199 boot_conf += "initrd /%s\n" % rd
200
201 if dtb:
202 boot_conf += "devicetree /%s\n" % dtb
203
204 if not unified_image:
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()
211
212
213 @classmethod
214 def do_configure_partition(cls, part, source_params, creator, cr_workdir,
215 oe_builddir, bootimg_dir, kernel_dir,
216 native_sysroot):
217 """
218 Called before do_prepare_partition(), creates loader-specific config
219 """
220 hdddir = "%s/hdd/boot" % cr_workdir
221
222 install_cmd = "install -d %s/EFI/BOOT" % hdddir
223 exec_cmd(install_cmd)
224
225 try:
226 if source_params['loader'] == 'grub-efi':
227 cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params)
228 elif source_params['loader'] == 'systemd-boot':
229 cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params)
230 elif source_params['loader'] == 'uefi-kernel':
231 pass
232 else:
233 raise WicError("unrecognized bootimg_efi loader: %s" % source_params['loader'])
234 except KeyError:
235 raise WicError("bootimg_efi requires a loader, none specified")
236
237 if get_bitbake_var("IMAGE_EFI_BOOT_FILES") is None:
238 logger.debug('No boot files defined in IMAGE_EFI_BOOT_FILES')
239 else:
240 boot_files = None
241 for (fmt, id) in (("_uuid-%s", part.uuid), ("_label-%s", part.label), (None, None)):
242 if fmt:
243 var = fmt % id
244 else:
245 var = ""
246
247 boot_files = get_bitbake_var("IMAGE_EFI_BOOT_FILES" + var)
248 if boot_files:
249 break
250
251 logger.debug('Boot files: %s', boot_files)
252
253 # list of tuples (src_name, dst_name)
254 deploy_files = []
255 for src_entry in re.findall(r'[\w;\-\.\+/\*]+', boot_files):
256 if ';' in src_entry:
257 dst_entry = tuple(src_entry.split(';'))
258 if not dst_entry[0] or not dst_entry[1]:
259 raise WicError('Malformed boot file entry: %s' % src_entry)
260 else:
261 dst_entry = (src_entry, src_entry)
262
263 logger.debug('Destination entry: %r', dst_entry)
264 deploy_files.append(dst_entry)
265
266 cls.install_task = [];
267 for deploy_entry in deploy_files:
268 src, dst = deploy_entry
269 if '*' in src:
270 # by default install files under their basename
271 entry_name_fn = os.path.basename
272 if dst != src:
273 # unless a target name was given, then treat name
274 # as a directory and append a basename
275 entry_name_fn = lambda name: \
276 os.path.join(dst,
277 os.path.basename(name))
278
279 srcs = glob(os.path.join(kernel_dir, src))
280
281 logger.debug('Globbed sources: %s', ', '.join(srcs))
282 for entry in srcs:
283 src = os.path.relpath(entry, kernel_dir)
284 entry_dst_name = entry_name_fn(entry)
285 cls.install_task.append((src, entry_dst_name))
286 else:
287 cls.install_task.append((src, dst))
288
289 @classmethod
290 def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
291 oe_builddir, bootimg_dir, kernel_dir,
292 rootfs_dir, native_sysroot):
293 """
294 Called to do the actual content population for a partition i.e. it
295 'prepares' the partition to be incorporated into the image.
296 In this case, prepare content for an EFI (grub) boot partition.
297 """
298 if not kernel_dir:
299 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
300 if not kernel_dir:
301 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
302
303 staging_kernel_dir = kernel_dir
304
305 hdddir = "%s/hdd/boot" % cr_workdir
306
307 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
308 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
309 if get_bitbake_var("INITRAMFS_IMAGE"):
310 kernel = "%s-%s.bin" % \
311 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
312
313 if source_params.get('create-unified-kernel-image') == "true":
314 raise WicError("create-unified-kernel-image is no longer supported. Please use uki.bbclass.")
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)
321
322 if get_bitbake_var("IMAGE_EFI_BOOT_FILES"):
323 for src_path, dst_path in cls.install_task:
324 install_cmd = "install -v -p -m 0644 -D %s %s" \
325 % (os.path.join(kernel_dir, src_path),
326 os.path.join(hdddir, dst_path))
327 out = exec_cmd(install_cmd)
328 logger.debug("Installed IMAGE_EFI_BOOT_FILES:\n%s" % out)
329
330 try:
331 if source_params['loader'] == 'grub-efi':
332 shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir,
333 "%s/grub.cfg" % cr_workdir)
334 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("grub-efi-")]:
335 cp_cmd = "cp -v -p %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[9:])
336 exec_cmd(cp_cmd, True)
337 shutil.move("%s/grub.cfg" % cr_workdir,
338 "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir)
339 elif source_params['loader'] == 'systemd-boot':
340 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("systemd-")]:
341 cp_cmd = "cp -v -p %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[8:])
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)
367 else:
368 raise WicError("unrecognized bootimg_efi loader: %s" %
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
377 except KeyError:
378 raise WicError("bootimg_efi requires a loader, none specified")
379
380 startup = os.path.join(kernel_dir, "startup.nsh")
381 if os.path.exists(startup):
382 cp_cmd = "cp -v -p %s %s/" % (startup, hdddir)
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)
391
392 du_cmd = "du -bks %s" % hdddir
393 out = exec_cmd(du_cmd)
394 blocks = int(out.split()[0])
395
396 extra_blocks = part.get_extra_block_count(blocks)
397
398 if extra_blocks < BOOTDD_EXTRA_SPACE:
399 extra_blocks = BOOTDD_EXTRA_SPACE
400
401 blocks += extra_blocks
402
403 logger.debug("Added %d extra blocks to %s to get to %d total blocks",
404 extra_blocks, part.mountpoint, blocks)
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
413 # dosfs image, created by mkdosfs
414 bootimg = "%s/boot.img" % cr_workdir
415
416 label = part.label if part.label else "ESP"
417
418 dosfs_cmd = "mkdosfs -v -n %s -i %s -C %s %d" % \
419 (label, part.fsuuid, bootimg, blocks)
420 exec_native_cmd(dosfs_cmd, native_sysroot)
421 logger.debug("mkdosfs:\n%s" % (str(out)))
422
423 mcopy_cmd = "mcopy -v -p -i %s -s %s/* ::/" % (bootimg, hdddir)
424 out = exec_native_cmd(mcopy_cmd, native_sysroot)
425 logger.debug("mcopy:\n%s" % (str(out)))
426
427 chmod_cmd = "chmod 644 %s" % bootimg
428 exec_cmd(chmod_cmd)
429
430 du_cmd = "du -Lbks %s" % bootimg
431 out = exec_cmd(du_cmd)
432 bootimg_size = out.split()[0]
433
434 part.size = int(bootimg_size)
435 part.source_file = bootimg
diff --git a/scripts/lib/wic/plugins/source/bootimg_partition.py b/scripts/lib/wic/plugins/source/bootimg_partition.py
deleted file mode 100644
index cc121a78f0..0000000000
--- a/scripts/lib/wic/plugins/source/bootimg_partition.py
+++ /dev/null
@@ -1,162 +0,0 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6# DESCRIPTION
7# This implements the 'bootimg_partition' source plugin class for
8# 'wic'. The plugin creates an image of boot partition, copying over
9# files listed in IMAGE_BOOT_FILES bitbake variable.
10#
11# AUTHORS
12# Maciej Borzecki <maciej.borzecki (at] open-rnd.pl>
13#
14
15import logging
16import os
17import re
18
19from oe.bootfiles import get_boot_files
20
21from wic import WicError
22from wic.engine import get_custom_config
23from wic.pluginbase import SourcePlugin
24from wic.misc import exec_cmd, get_bitbake_var
25
26logger = logging.getLogger('wic')
27
28class BootimgPartitionPlugin(SourcePlugin):
29 """
30 Create an image of boot partition, copying over files
31 listed in IMAGE_BOOT_FILES bitbake variable.
32 """
33
34 name = 'bootimg_partition'
35 image_boot_files_var_name = 'IMAGE_BOOT_FILES'
36
37 @classmethod
38 def do_configure_partition(cls, part, source_params, cr, cr_workdir,
39 oe_builddir, bootimg_dir, kernel_dir,
40 native_sysroot):
41 """
42 Called before do_prepare_partition(), create u-boot specific boot config
43 """
44 hdddir = "%s/boot.%d" % (cr_workdir, part.lineno)
45 install_cmd = "install -d %s" % hdddir
46 exec_cmd(install_cmd)
47
48 if not kernel_dir:
49 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
50 if not kernel_dir:
51 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
52
53 boot_files = None
54 for (fmt, id) in (("_uuid-%s", part.uuid), ("_label-%s", part.label), (None, None)):
55 if fmt:
56 var = fmt % id
57 else:
58 var = ""
59
60 boot_files = get_bitbake_var(cls.image_boot_files_var_name + var)
61 if boot_files is not None:
62 break
63
64 if boot_files is None:
65 raise WicError('No boot files defined, %s unset for entry #%d' % (cls.image_boot_files_var_name, part.lineno))
66
67 logger.debug('Boot files: %s', boot_files)
68
69 cls.install_task = get_boot_files(kernel_dir, boot_files)
70 if source_params.get('loader') != "u-boot":
71 return
72
73 configfile = cr.ks.bootloader.configfile
74 custom_cfg = None
75 if configfile:
76 custom_cfg = get_custom_config(configfile)
77 if custom_cfg:
78 # Use a custom configuration for extlinux.conf
79 extlinux_conf = custom_cfg
80 logger.debug("Using custom configuration file "
81 "%s for extlinux.conf", configfile)
82 else:
83 raise WicError("configfile is specified but failed to "
84 "get it from %s." % configfile)
85
86 if not custom_cfg:
87 # The kernel types supported by the sysboot of u-boot
88 kernel_types = ["zImage", "Image", "fitImage", "uImage", "vmlinux"]
89 has_dtb = False
90 fdt_dir = '/'
91 kernel_name = None
92
93 # Find the kernel image name, from the highest precedence to lowest
94 for image in kernel_types:
95 for task in cls.install_task:
96 src, dst = task
97 if re.match(image, src):
98 kernel_name = os.path.join('/', dst)
99 break
100 if kernel_name:
101 break
102
103 for task in cls.install_task:
104 src, dst = task
105 # We suppose that all the dtb are in the same directory
106 if re.search(r'\.dtb', src) and fdt_dir == '/':
107 has_dtb = True
108 fdt_dir = os.path.join(fdt_dir, os.path.dirname(dst))
109 break
110
111 if not kernel_name:
112 raise WicError('No kernel file found')
113
114 # Compose the extlinux.conf
115 extlinux_conf = "default Yocto\n"
116 extlinux_conf += "label Yocto\n"
117 extlinux_conf += " kernel %s\n" % kernel_name
118 if has_dtb:
119 extlinux_conf += " fdtdir %s\n" % fdt_dir
120 bootloader = cr.ks.bootloader
121 extlinux_conf += "append root=%s rootwait %s\n" \
122 % (cr.rootdev, bootloader.append if bootloader.append else '')
123
124 install_cmd = "install -d %s/extlinux/" % hdddir
125 exec_cmd(install_cmd)
126 cfg = open("%s/extlinux/extlinux.conf" % hdddir, "w")
127 cfg.write(extlinux_conf)
128 cfg.close()
129
130
131 @classmethod
132 def do_prepare_partition(cls, part, source_params, cr, cr_workdir,
133 oe_builddir, bootimg_dir, kernel_dir,
134 rootfs_dir, native_sysroot):
135 """
136 Called to do the actual content population for a partition i.e. it
137 'prepares' the partition to be incorporated into the image.
138 In this case, does the following:
139 - sets up a vfat partition
140 - copies all files listed in IMAGE_BOOT_FILES variable
141 """
142 hdddir = "%s/boot.%d" % (cr_workdir, part.lineno)
143
144 if not kernel_dir:
145 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
146 if not kernel_dir:
147 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
148
149 logger.debug('Kernel dir: %s', bootimg_dir)
150
151
152 for task in cls.install_task:
153 src_path, dst_path = task
154 logger.debug('Install %s as %s', src_path, dst_path)
155 install_cmd = "install -m 0644 -D %s %s" \
156 % (os.path.join(kernel_dir, src_path),
157 os.path.join(hdddir, dst_path))
158 exec_cmd(install_cmd)
159
160 logger.debug('Prepare boot partition using rootfs in %s', hdddir)
161 part.prepare_rootfs(cr_workdir, oe_builddir, hdddir,
162 native_sysroot, False)
diff --git a/scripts/lib/wic/plugins/source/bootimg_pcbios.py b/scripts/lib/wic/plugins/source/bootimg_pcbios.py
deleted file mode 100644
index caabda6318..0000000000
--- a/scripts/lib/wic/plugins/source/bootimg_pcbios.py
+++ /dev/null
@@ -1,483 +0,0 @@
1#
2# Copyright (c) 2014, Intel Corporation.
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6# DESCRIPTION
7# This implements the 'bootimg_pcbios' source plugin class for 'wic'
8#
9# AUTHORS
10# Tom Zanussi <tom.zanussi (at] linux.intel.com>
11#
12
13import logging
14import os
15import re
16import shutil
17
18from glob import glob
19from wic import WicError
20from wic.engine import get_custom_config
21from wic.pluginbase import SourcePlugin
22from wic.misc import (exec_cmd, exec_native_cmd,
23 get_bitbake_var, BOOTDD_EXTRA_SPACE)
24
25logger = logging.getLogger('wic')
26
27class BootimgPcbiosPlugin(SourcePlugin):
28 """
29 Creates boot partition that is legacy BIOS firmare bootable with
30 MBR/MSDOS as partition table format. Plugin will install caller
31 selected bootloader directly to resulting wic image.
32
33 Supported Bootloaders:
34 * syslinux (default)
35 * grub
36
37 ****************** Wic Plugin Depends/Vars ******************
38 WKS_FILE_DEPENDS = "grub-native grub"
39 WKS_FILE_DEPENDS = "syslinux-native syslinux"
40
41 # Optional variables
42 # GRUB_MKIMAGE_FORMAT_PC - Used to define target platform.
43 # GRUB_PREFIX_PATH - Used to define which directory
44 # grub config and modules are going
45 # to reside in.
46 GRUB_PREFIX_PATH = '/boot/grub2' # Default: /boot/grub
47 GRUB_MKIMAGE_FORMAT_PC = 'i386-pc' # Default: i386-pc
48
49 WICVARS:append = "\
50 GRUB_PREFIX_PATH \
51 GRUB_MKIMAGE_FORMAT_PC \
52 "
53 ****************** Wic Plugin Depends/Vars ******************
54
55
56 **************** Example kickstart Legacy Bios Grub Boot ****************
57 part boot --label bios_boot --fstype ext4 --offset 1024 --fixed-size 78M
58 --source bootimg_pcbios --sourceparams="loader-bios=grub" --active
59
60 part roots --label rootfs --fstype ext4 --source rootfs --use-uuid
61 bootloader --ptable msdos --source bootimg_pcbios
62 **************** Example kickstart Legacy Bios Grub Boot ****************
63
64
65 *************** Example kickstart Legacy Bios Syslinux Boot ****************
66 part /boot --source bootimg_pcbios --sourceparams="loader-bios=syslinux"
67 --ondisk sda --label boot --fstype vfat --align 1024 --active
68
69 part roots --label rootfs --fstype ext4 --source rootfs --use-uuid
70 bootloader --ptable msdos --source bootimg_pcbios
71 """
72
73 name = 'bootimg_pcbios'
74
75 # Variable required for do_install_disk
76 loader = ''
77
78 @classmethod
79 def _get_bootimg_dir(cls, bootimg_dir, dirname):
80 """
81 Check if dirname exists in default bootimg_dir or in STAGING_DIR.
82 """
83 staging_datadir = get_bitbake_var("STAGING_DATADIR")
84 for result in (bootimg_dir, staging_datadir):
85 if os.path.exists("%s/%s" % (result, dirname)):
86 return result
87
88 # STAGING_DATADIR is expanded with MLPREFIX if multilib is enabled
89 # but dependency syslinux is still populated to original STAGING_DATADIR
90 nonarch_datadir = re.sub('/[^/]*recipe-sysroot', '/recipe-sysroot', staging_datadir)
91 if os.path.exists(os.path.join(nonarch_datadir, dirname)):
92 return nonarch_datadir
93
94 raise WicError("Couldn't find correct bootimg_dir, exiting")
95
96 @classmethod
97 def do_install_disk(cls, disk, disk_name, creator, workdir, oe_builddir,
98 bootimg_dir, kernel_dir, native_sysroot):
99 full_path = creator._full_path(workdir, disk_name, "direct")
100 logger.debug("Installing MBR on disk %s as %s with size %s bytes",
101 disk_name, full_path, disk.min_size)
102
103 if cls.loader == 'grub':
104 cls._do_install_grub(creator, kernel_dir,
105 native_sysroot, full_path)
106 elif cls.loader == 'syslinux':
107 cls._do_install_syslinux(creator, bootimg_dir,
108 native_sysroot, full_path)
109 else:
110 raise WicError("boot loader some how not specified check do_prepare_partition")
111
112 @classmethod
113 def do_configure_partition(cls, part, source_params, creator, cr_workdir,
114 oe_builddir, bootimg_dir, kernel_dir,
115 native_sysroot):
116 try:
117 if source_params['loader-bios'] == 'grub':
118 cls._do_configure_grub(part, creator, cr_workdir)
119 elif source_params['loader-bios'] == 'syslinux':
120 cls._do_configure_syslinux(part, creator, cr_workdir)
121 else:
122 raise WicError("unrecognized bootimg_pcbios loader: %s" % source_params['loader-bios'])
123 except KeyError:
124 cls._do_configure_syslinux(part, creator, cr_workdir)
125
126 @classmethod
127 def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
128 oe_builddir, bootimg_dir, kernel_dir,
129 rootfs_dir, native_sysroot):
130 try:
131 if source_params['loader-bios'] == 'grub':
132 cls._do_prepare_grub(part, cr_workdir, oe_builddir,
133 kernel_dir, rootfs_dir, native_sysroot)
134 elif source_params['loader-bios'] == 'syslinux':
135 cls._do_prepare_syslinux(part, cr_workdir, bootimg_dir,
136 kernel_dir, native_sysroot)
137 else:
138 raise WicError("unrecognized bootimg_pcbios loader: %s" % source_params['loader-bios'])
139
140 # Required by do_install_disk
141 cls.loader = source_params['loader-bios']
142 except KeyError:
143 # Required by do_install_disk
144 cls.loader = 'syslinux'
145 cls._do_prepare_syslinux(part, cr_workdir, bootimg_dir,
146 kernel_dir, native_sysroot)
147
148 @classmethod
149 def _get_staging_libdir(cls):
150 """
151 For unknown reasons when running test with poky
152 STAGING_LIBDIR gets unset when wic create is executed.
153 Bellow is a hack to determine what STAGING_LIBDIR should
154 be if not specified.
155 """
156
157 staging_libdir = get_bitbake_var('STAGING_LIBDIR')
158 staging_dir_target = get_bitbake_var('STAGING_DIR_TARGET')
159
160 if not staging_libdir:
161 staging_libdir = '%s/usr/lib64' % staging_dir_target
162 if not os.path.isdir(staging_libdir):
163 staging_libdir = '%s/usr/lib32' % staging_dir_target
164 if not os.path.isdir(staging_libdir):
165 staging_libdir = '%s/usr/lib' % staging_dir_target
166
167 return staging_libdir
168
169 @classmethod
170 def _get_bootloader_config(cls, bootloader, loader):
171 custom_cfg = None
172
173 if bootloader.configfile:
174 custom_cfg = get_custom_config(bootloader.configfile)
175 if custom_cfg:
176 logger.debug("Using custom configuration file %s "
177 "for %s.cfg", bootloader.configfile,
178 loader)
179 return custom_cfg
180 else:
181 raise WicError("configfile is specified but failed to "
182 "get it from %s." % bootloader.configfile)
183 return custom_cfg
184
185 @classmethod
186 def _do_configure_syslinux(cls, part, creator, cr_workdir):
187 """
188 Called before do_prepare_partition(), creates syslinux config
189 """
190
191 hdddir = "%s/hdd/boot" % cr_workdir
192
193 install_cmd = "install -d %s" % hdddir
194 exec_cmd(install_cmd)
195
196 bootloader = creator.ks.bootloader
197 syslinux_conf = cls._get_bootloader_config(bootloader, 'syslinux')
198
199 if not syslinux_conf:
200 # Create syslinux configuration using parameters from wks file
201 splash = os.path.join(hdddir, "/splash.jpg")
202 if os.path.exists(splash):
203 splashline = "menu background splash.jpg"
204 else:
205 splashline = ""
206
207 # Set a default timeout if none specified to avoid
208 # 'None' being the value placed within the configuration
209 # file.
210 if not bootloader.timeout:
211 bootloader.timeout = 500
212
213 # Set a default kernel params string if none specified
214 # to avoid 'None' being the value placed within the
215 # configuration file.
216 if not bootloader.append:
217 bootloader.append = "rootwait console=ttyS0,115200 console=tty0"
218
219 syslinux_conf = ""
220 syslinux_conf += "PROMPT 0\n"
221 syslinux_conf += "TIMEOUT " + str(bootloader.timeout) + "\n"
222 syslinux_conf += "\n"
223 syslinux_conf += "ALLOWOPTIONS 1\n"
224 syslinux_conf += "SERIAL 0 115200\n"
225 syslinux_conf += "\n"
226 if splashline:
227 syslinux_conf += "%s\n" % splashline
228 syslinux_conf += "DEFAULT boot\n"
229 syslinux_conf += "LABEL boot\n"
230
231 kernel = "/" + get_bitbake_var("KERNEL_IMAGETYPE")
232 syslinux_conf += "KERNEL " + kernel + "\n"
233
234 syslinux_conf += "APPEND label=boot root=%s %s\n" % \
235 (creator.rootdev, bootloader.append)
236
237 logger.debug("Writing syslinux config %s/syslinux.cfg", hdddir)
238 cfg = open("%s/hdd/boot/syslinux.cfg" % cr_workdir, "w")
239 cfg.write(syslinux_conf)
240 cfg.close()
241
242 @classmethod
243 def _do_prepare_syslinux(cls, part, cr_workdir, bootimg_dir,
244 kernel_dir, native_sysroot):
245 """
246 Called to do the actual content population for a partition i.e. it
247 'prepares' the partition to be incorporated into the image.
248 In this case, prepare content for legacy bios boot partition.
249 """
250 bootimg_dir = cls._get_bootimg_dir(bootimg_dir, 'syslinux')
251
252 staging_kernel_dir = kernel_dir
253
254 hdddir = "%s/hdd/boot" % cr_workdir
255
256 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
257 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
258 if get_bitbake_var("INITRAMFS_IMAGE"):
259 kernel = "%s-%s.bin" % \
260 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
261
262 cmds = ("install -m 0644 %s/%s %s/%s" %
263 (staging_kernel_dir, kernel, hdddir, get_bitbake_var("KERNEL_IMAGETYPE")),
264 "install -m 444 %s/syslinux/ldlinux.sys %s/ldlinux.sys" %
265 (bootimg_dir, hdddir),
266 "install -m 0644 %s/syslinux/vesamenu.c32 %s/vesamenu.c32" %
267 (bootimg_dir, hdddir),
268 "install -m 444 %s/syslinux/libcom32.c32 %s/libcom32.c32" %
269 (bootimg_dir, hdddir),
270 "install -m 444 %s/syslinux/libutil.c32 %s/libutil.c32" %
271 (bootimg_dir, hdddir))
272
273 for install_cmd in cmds:
274 exec_cmd(install_cmd)
275
276 du_cmd = "du -bks %s" % hdddir
277 out = exec_cmd(du_cmd)
278 blocks = int(out.split()[0])
279
280 extra_blocks = part.get_extra_block_count(blocks)
281
282 if extra_blocks < BOOTDD_EXTRA_SPACE:
283 extra_blocks = BOOTDD_EXTRA_SPACE
284
285 blocks += extra_blocks
286
287 logger.debug("Added %d extra blocks to %s to get to %d total blocks",
288 extra_blocks, part.mountpoint, blocks)
289
290 # dosfs image, created by mkdosfs
291 bootimg = "%s/boot%s.img" % (cr_workdir, part.lineno)
292
293 label = part.label if part.label else "boot"
294
295 dosfs_cmd = "mkdosfs -n %s -i %s -S 512 -C %s %d" % \
296 (label, part.fsuuid, bootimg, blocks)
297 exec_native_cmd(dosfs_cmd, native_sysroot)
298
299 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir)
300 exec_native_cmd(mcopy_cmd, native_sysroot)
301
302 syslinux_cmd = "syslinux %s" % bootimg
303 exec_native_cmd(syslinux_cmd, native_sysroot)
304
305 chmod_cmd = "chmod 644 %s" % bootimg
306 exec_cmd(chmod_cmd)
307
308 du_cmd = "du -Lbks %s" % bootimg
309 out = exec_cmd(du_cmd)
310 bootimg_size = out.split()[0]
311
312 part.size = int(bootimg_size)
313 part.source_file = bootimg
314
315 @classmethod
316 def _do_install_syslinux(cls, creator, bootimg_dir,
317 native_sysroot, full_path):
318 """
319 Called after all partitions have been prepared and assembled into a
320 disk image. In this case, we install the MBR.
321 """
322
323 bootimg_dir = cls._get_bootimg_dir(bootimg_dir, 'syslinux')
324 mbrfile = "%s/syslinux/" % bootimg_dir
325 if creator.ptable_format == 'msdos':
326 mbrfile += "mbr.bin"
327 elif creator.ptable_format == 'gpt':
328 mbrfile += "gptmbr.bin"
329 else:
330 raise WicError("Unsupported partition table: %s" %
331 creator.ptable_format)
332
333 if not os.path.exists(mbrfile):
334 raise WicError("Couldn't find %s. If using the -e option, do you "
335 "have the right MACHINE set in local.conf? If not, "
336 "is the bootimg_dir path correct?" % mbrfile)
337
338 dd_cmd = "dd if=%s of=%s conv=notrunc" % (mbrfile, full_path)
339 exec_cmd(dd_cmd, native_sysroot)
340
341 @classmethod
342 def _do_configure_grub(cls, part, creator, cr_workdir):
343 hdddir = "%s/hdd" % cr_workdir
344 bootloader = creator.ks.bootloader
345
346 grub_conf = cls._get_bootloader_config(bootloader, 'grub')
347
348 grub_prefix_path = get_bitbake_var('GRUB_PREFIX_PATH')
349 if not grub_prefix_path:
350 grub_prefix_path = '/boot/grub'
351
352 grub_path = "%s/%s" %(hdddir, grub_prefix_path)
353 install_cmd = "install -d %s" % grub_path
354 exec_cmd(install_cmd)
355
356 if not grub_conf:
357 # Set a default timeout if none specified to avoid
358 # 'None' being the value placed within the configuration
359 # file.
360 if not bootloader.timeout:
361 bootloader.timeout = 500
362
363 # Set a default kernel params string if none specified
364 # to avoid 'None' being the value placed within the
365 # configuration file.
366 if not bootloader.append:
367 bootloader.append = "rootwait rootfstype=%s " % (part.fstype)
368 bootloader.append += "console=ttyS0,115200 console=tty0"
369
370 kernel = "/boot/" + get_bitbake_var("KERNEL_IMAGETYPE")
371
372 grub_conf = 'serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n'
373 grub_conf += 'set gfxmode=auto\n'
374 grub_conf += 'set gfxpayload=keep\n\n'
375 grub_conf += 'set default=0\n\n'
376 grub_conf += '# Boot automatically after %d secs.\n' % (bootloader.timeout)
377 grub_conf += 'set timeout=%d\n\n' % (bootloader.timeout)
378 grub_conf += 'menuentry \'default\' {\n'
379 grub_conf += '\tsearch --no-floppy --set=root --file %s\n' % (kernel)
380 grub_conf += '\tprobe --set partuuid --part-uuid ($root)\n'
381 grub_conf += '\tlinux %s root=PARTUUID=$partuuid %s\n}\n' % \
382 (kernel, bootloader.append)
383
384 logger.debug("Writing grub config %s/grub.cfg", grub_path)
385 cfg = open("%s/grub.cfg" % grub_path, "w")
386 cfg.write(grub_conf)
387 cfg.close()
388
389 @classmethod
390 def _do_prepare_grub(cls, part, cr_workdir, oe_builddir,
391 kernel_dir, rootfs_dir, native_sysroot):
392 """
393 1. Generate embed.cfg that'll later be embedded into core.img.
394 So, that core.img knows where to search for grub.cfg.
395 2. Generate core.img or grub stage 1.5.
396 3. Copy modules into partition.
397 4. Create partition rootfs file.
398 """
399
400 hdddir = "%s/hdd" % cr_workdir
401
402 copy_types = [ '*.mod', '*.o', '*.lst' ]
403
404 builtin_modules = 'boot linux ext2 fat serial part_msdos part_gpt \
405 normal multiboot probe biosdisk msdospart configfile search loadenv test'
406
407 staging_libdir = cls._get_staging_libdir()
408
409 grub_format = get_bitbake_var('GRUB_MKIMAGE_FORMAT_PC')
410 if not grub_format:
411 grub_format = 'i386-pc'
412
413 grub_prefix_path = get_bitbake_var('GRUB_PREFIX_PATH')
414 if not grub_prefix_path:
415 grub_prefix_path = '/boot/grub'
416
417 grub_path = "%s/%s" %(hdddir, grub_prefix_path)
418 core_img = '%s/grub-bios-core.img' % (kernel_dir)
419 grub_mods_path = '%s/grub/%s' % (staging_libdir, grub_format)
420
421 # Generate embedded grub config
422 embed_cfg_str = 'search.file %s/grub.cfg root\n' % (grub_prefix_path)
423 embed_cfg_str += 'set prefix=($root)%s\n' % (grub_prefix_path)
424 embed_cfg_str += 'configfile ($root)%s/grub.cfg\n' % (grub_prefix_path)
425 cfg = open('%s/embed.cfg' % (kernel_dir), 'w+')
426 cfg.write(embed_cfg_str)
427 cfg.close()
428
429 # core.img doesn't get included into boot partition
430 # it's later dd onto the resulting wic image.
431 grub_mkimage = 'grub-mkimage \
432 --prefix=%s \
433 --format=%s \
434 --config=%s/embed.cfg \
435 --directory=%s \
436 --output=%s %s' % \
437 (grub_prefix_path, grub_format, kernel_dir,
438 grub_mods_path, core_img, builtin_modules)
439 exec_native_cmd(grub_mkimage, native_sysroot)
440
441 # Copy grub modules
442 install_dir = '%s/%s/%s' % (hdddir, grub_prefix_path, grub_format)
443 os.makedirs(install_dir, exist_ok=True)
444
445 for ctype in copy_types:
446 files = glob('%s/grub/%s/%s' % \
447 (staging_libdir, grub_format, ctype))
448 for file in files:
449 shutil.copy2(file, install_dir, follow_symlinks=True)
450
451 # Create boot partition
452 logger.debug('Prepare partition using rootfs in %s', hdddir)
453 part.prepare_rootfs(cr_workdir, oe_builddir, hdddir,
454 native_sysroot, False)
455
456 @classmethod
457 def _do_install_grub(cls, creator, kernel_dir,
458 native_sysroot, full_path):
459 core_img = '%s/grub-bios-core.img' % (kernel_dir)
460
461 staging_libdir = cls._get_staging_libdir()
462
463 grub_format = get_bitbake_var('GRUB_MKIMAGE_FORMAT_PC')
464 if not grub_format:
465 grub_format = 'i386-pc'
466
467 boot_img = '%s/grub/%s/boot.img' % (staging_libdir, grub_format)
468 if not os.path.exists(boot_img):
469 raise WicError("Couldn't find %s. Did you include "
470 "do_image_wic[depends] += \"grub:do_populate_sysroot\" "
471 "in your image recipe" % boot_img)
472
473 # Install boot.img or grub stage 1
474 dd_cmd = "dd if=%s of=%s conv=notrunc bs=1 seek=0 count=440" % (boot_img, full_path)
475 exec_cmd(dd_cmd, native_sysroot)
476
477 if creator.ptable_format == 'msdos':
478 # Install core.img or grub stage 1.5
479 dd_cmd = "dd if=%s of=%s conv=notrunc bs=1 seek=512" % (core_img, full_path)
480 exec_cmd(dd_cmd, native_sysroot)
481 else:
482 raise WicError("Unsupported partition table: %s" %
483 creator.ptable_format)
diff --git a/scripts/lib/wic/plugins/source/empty.py b/scripts/lib/wic/plugins/source/empty.py
deleted file mode 100644
index 4178912377..0000000000
--- a/scripts/lib/wic/plugins/source/empty.py
+++ /dev/null
@@ -1,89 +0,0 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
7# The empty wic plugin is used to create unformatted empty partitions for wic
8# images.
9# To use it you must pass "empty" as argument for the "--source" parameter in
10# the wks file. For example:
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.
19
20import logging
21import os
22
23from wic import WicError
24from wic.ksparser import sizetype
25from wic.pluginbase import SourcePlugin
26
27logger = logging.getLogger('wic')
28
29class EmptyPartitionPlugin(SourcePlugin):
30 """
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'.
42 """
43
44 name = 'empty'
45
46 @classmethod
47 def do_prepare_partition(cls, part, source_params, cr, cr_workdir,
48 oe_builddir, bootimg_dir, kernel_dir,
49 rootfs_dir, native_sysroot):
50 """
51 Called to do the actual content population for a partition i.e. it
52 'prepares' the partition to be incorporated into the image.
53 """
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/extra_partition.py b/scripts/lib/wic/plugins/source/extra_partition.py
deleted file mode 100644
index d370b0107e..0000000000
--- a/scripts/lib/wic/plugins/source/extra_partition.py
+++ /dev/null
@@ -1,134 +0,0 @@
1import logging
2import os
3import re
4
5from glob import glob
6
7from wic import WicError
8from wic.pluginbase import SourcePlugin
9from wic.misc import exec_cmd, get_bitbake_var
10
11logger = logging.getLogger('wic')
12
13class ExtraPartitionPlugin(SourcePlugin):
14 """
15 Populates an extra partition with files listed in the IMAGE_EXTRA_PARTITION_FILES
16 BitBake variable. Files should be deployed to the DEPLOY_DIR_IMAGE directory.
17
18 The plugin supports:
19 - Glob pattern matching for file selection.
20 - File renaming.
21 - Suffixes to specify the target partition (by label, UUID, or partname),
22 enabling multiple extra partitions to coexist.
23
24 For example:
25
26 IMAGE_EXTRA_PARTITION_FILES_label-foo = "bar.conf;foo.conf"
27 IMAGE_EXTRA_PARTITION_FILES_uuid-e7d0824e-cda3-4bed-9f54-9ef5312d105d = "bar.conf;foobar.conf"
28 IMAGE_EXTRA_PARTITION_FILES = "foo/*"
29 WICVARS:append = "\
30 IMAGE_EXTRA_PARTITION_FILES_label-foo \
31 IMAGE_EXTRA_PARTITION_FILES_uuid-e7d0824e-cda3-4bed-9f54-9ef5312d105d \
32 "
33
34 """
35
36 name = 'extra_partition'
37 image_extra_partition_files_var_name = 'IMAGE_EXTRA_PARTITION_FILES'
38
39 @classmethod
40 def do_configure_partition(cls, part, source_params, cr, cr_workdir,
41 oe_builddir, bootimg_dir, kernel_dir,
42 native_sysroot):
43 """
44 Called before do_prepare_partition(), list the files to copy
45 """
46 extradir = "%s/extra.%d" % (cr_workdir, part.lineno)
47 install_cmd = "install -d %s" % extradir
48 exec_cmd(install_cmd)
49
50 if not kernel_dir:
51 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
52 if not kernel_dir:
53 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
54
55 extra_files = None
56 for (fmt, id) in (("_uuid-%s", part.uuid), ("_label-%s", part.label), ("_part-name-%s", part.part_name), (None, None)):
57 if fmt:
58 var = fmt % id
59 else:
60 var = ""
61 extra_files = get_bitbake_var(cls.image_extra_partition_files_var_name + var)
62 if extra_files is not None:
63 break
64
65 if extra_files is None:
66 raise WicError('No extra files defined, %s unset for entry #%d' % (cls.image_extra_partition_files_var_name, part.lineno))
67
68 logger.info('Extra files: %s', extra_files)
69
70 # list of tuples (src_name, dst_name)
71 deploy_files = []
72 for src_entry in re.findall(r'[\w;\-\./\*]+', extra_files):
73 if ';' in src_entry:
74 dst_entry = tuple(src_entry.split(';'))
75 if not dst_entry[0] or not dst_entry[1]:
76 raise WicError('Malformed extra file entry: %s' % src_entry)
77 else:
78 dst_entry = (src_entry, src_entry)
79
80 logger.debug('Destination entry: %r', dst_entry)
81 deploy_files.append(dst_entry)
82
83 cls.install_task = [];
84 for deploy_entry in deploy_files:
85 src, dst = deploy_entry
86 if '*' in src:
87 # by default install files under their basename
88 entry_name_fn = os.path.basename
89 if dst != src:
90 # unless a target name was given, then treat name
91 # as a directory and append a basename
92 entry_name_fn = lambda name: \
93 os.path.join(dst,
94 os.path.basename(name))
95
96 srcs = glob(os.path.join(kernel_dir, src))
97
98 logger.debug('Globbed sources: %s', ', '.join(srcs))
99 for entry in srcs:
100 src = os.path.relpath(entry, kernel_dir)
101 entry_dst_name = entry_name_fn(entry)
102 cls.install_task.append((src, entry_dst_name))
103 else:
104 cls.install_task.append((src, dst))
105
106
107 @classmethod
108 def do_prepare_partition(cls, part, source_params, cr, cr_workdir,
109 oe_builddir, bootimg_dir, kernel_dir,
110 rootfs_dir, native_sysroot):
111 """
112 Called to do the actual content population for a partition i.e. it
113 'prepares' the partition to be incorporated into the image.
114 In this case, we copies all files listed in IMAGE_EXTRA_PARTITION_FILES variable.
115 """
116 extradir = "%s/extra.%d" % (cr_workdir, part.lineno)
117
118 if not kernel_dir:
119 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
120 if not kernel_dir:
121 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
122
123 for task in cls.install_task:
124 src_path, dst_path = task
125 logger.debug('Install %s as %s', src_path, dst_path)
126 install_cmd = "install -m 0644 -D %s %s" \
127 % (os.path.join(kernel_dir, src_path),
128 os.path.join(extradir, dst_path))
129 exec_cmd(install_cmd)
130
131 logger.debug('Prepare extra partition using rootfs in %s', extradir)
132 part.prepare_rootfs(cr_workdir, oe_builddir, extradir,
133 native_sysroot, False)
134
diff --git a/scripts/lib/wic/plugins/source/isoimage_isohybrid.py b/scripts/lib/wic/plugins/source/isoimage_isohybrid.py
deleted file mode 100644
index 5d42eb5d3e..0000000000
--- a/scripts/lib/wic/plugins/source/isoimage_isohybrid.py
+++ /dev/null
@@ -1,463 +0,0 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6# DESCRIPTION
7# This implements the 'isoimage_isohybrid' source plugin class for 'wic'
8#
9# AUTHORS
10# Mihaly Varga <mihaly.varga (at] ni.com>
11
12import glob
13import logging
14import os
15import re
16import shutil
17
18from wic import WicError
19from wic.engine import get_custom_config
20from wic.pluginbase import SourcePlugin
21from wic.misc import exec_cmd, exec_native_cmd, get_bitbake_var
22
23logger = logging.getLogger('wic')
24
25class IsoImagePlugin(SourcePlugin):
26 """
27 Create a bootable ISO image
28
29 This plugin creates a hybrid, legacy and EFI bootable ISO image. The
30 generated image can be used on optical media as well as USB media.
31
32 Legacy boot uses syslinux and EFI boot uses grub or gummiboot (not
33 implemented yet) as bootloader. The plugin creates the directories required
34 by bootloaders and populates them by creating and configuring the
35 bootloader files.
36
37 Example kickstart file:
38 part /boot --source isoimage_isohybrid --sourceparams="loader=grub-efi, \\
39 image_name= IsoImage" --ondisk cd --label LIVECD
40 bootloader --timeout=10 --append=" "
41
42 In --sourceparams "loader" specifies the bootloader used for booting in EFI
43 mode, while "image_name" specifies the name of the generated image. In the
44 example above, wic creates an ISO image named IsoImage-cd.direct (default
45 extension added by direct imeger plugin) and a file named IsoImage-cd.iso
46 """
47
48 name = 'isoimage_isohybrid'
49
50 @classmethod
51 def do_configure_syslinux(cls, creator, cr_workdir):
52 """
53 Create loader-specific (syslinux) config
54 """
55 splash = os.path.join(cr_workdir, "ISO/boot/splash.jpg")
56 if os.path.exists(splash):
57 splashline = "menu background splash.jpg"
58 else:
59 splashline = ""
60
61 bootloader = creator.ks.bootloader
62
63 syslinux_conf = ""
64 syslinux_conf += "PROMPT 0\n"
65 syslinux_conf += "TIMEOUT %s \n" % (bootloader.timeout or 10)
66 syslinux_conf += "\n"
67 syslinux_conf += "ALLOWOPTIONS 1\n"
68 syslinux_conf += "SERIAL 0 115200\n"
69 syslinux_conf += "\n"
70 if splashline:
71 syslinux_conf += "%s\n" % splashline
72 syslinux_conf += "DEFAULT boot\n"
73 syslinux_conf += "LABEL boot\n"
74
75 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
76 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
77 if get_bitbake_var("INITRAMFS_IMAGE"):
78 kernel = "%s-%s.bin" % \
79 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
80
81 syslinux_conf += "KERNEL /" + kernel + "\n"
82 syslinux_conf += "APPEND initrd=/initrd LABEL=boot %s\n" \
83 % bootloader.append
84
85 logger.debug("Writing syslinux config %s/ISO/isolinux/isolinux.cfg",
86 cr_workdir)
87
88 with open("%s/ISO/isolinux/isolinux.cfg" % cr_workdir, "w") as cfg:
89 cfg.write(syslinux_conf)
90
91 @classmethod
92 def do_configure_grubefi(cls, part, creator, target_dir):
93 """
94 Create loader-specific (grub-efi) config
95 """
96 configfile = creator.ks.bootloader.configfile
97 if configfile:
98 grubefi_conf = get_custom_config(configfile)
99 if grubefi_conf:
100 logger.debug("Using custom configuration file %s for grub.cfg",
101 configfile)
102 else:
103 raise WicError("configfile is specified "
104 "but failed to get it from %s", configfile)
105 else:
106 splash = os.path.join(target_dir, "splash.jpg")
107 if os.path.exists(splash):
108 splashline = "menu background splash.jpg"
109 else:
110 splashline = ""
111
112 bootloader = creator.ks.bootloader
113
114 grubefi_conf = ""
115 grubefi_conf += "serial --unit=0 --speed=115200 --word=8 "
116 grubefi_conf += "--parity=no --stop=1\n"
117 grubefi_conf += "default=boot\n"
118 grubefi_conf += "timeout=%s\n" % (bootloader.timeout or 10)
119 grubefi_conf += "\n"
120 grubefi_conf += "search --set=root --label %s " % part.label
121 grubefi_conf += "\n"
122 grubefi_conf += "menuentry 'boot'{\n"
123
124 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
125 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
126 if get_bitbake_var("INITRAMFS_IMAGE"):
127 kernel = "%s-%s.bin" % \
128 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
129
130 grubefi_conf += "linux /%s rootwait %s\n" \
131 % (kernel, bootloader.append)
132 grubefi_conf += "initrd /initrd \n"
133 grubefi_conf += "}\n"
134
135 if splashline:
136 grubefi_conf += "%s\n" % splashline
137
138 cfg_path = os.path.join(target_dir, "grub.cfg")
139 logger.debug("Writing grubefi config %s", cfg_path)
140
141 with open(cfg_path, "w") as cfg:
142 cfg.write(grubefi_conf)
143
144 @staticmethod
145 def _build_initramfs_path(rootfs_dir, cr_workdir):
146 """
147 Create path for initramfs image
148 """
149
150 initrd = get_bitbake_var("INITRD_LIVE") or get_bitbake_var("INITRD")
151 if not initrd:
152 initrd_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
153 if not initrd_dir:
154 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting.")
155
156 image_name = get_bitbake_var("IMAGE_BASENAME")
157 if not image_name:
158 raise WicError("Couldn't find IMAGE_BASENAME, exiting.")
159
160 image_type = get_bitbake_var("INITRAMFS_FSTYPES")
161 if not image_type:
162 raise WicError("Couldn't find INITRAMFS_FSTYPES, exiting.")
163
164 machine = os.path.basename(initrd_dir)
165
166 pattern = '%s/%s*%s.%s' % (initrd_dir, image_name, machine, image_type)
167 files = glob.glob(pattern)
168 if files:
169 initrd = files[0]
170
171 if not initrd or not os.path.exists(initrd):
172 # Create initrd from rootfs directory
173 initrd = "%s/initrd.cpio.gz" % cr_workdir
174 initrd_dir = "%s/INITRD" % cr_workdir
175 shutil.copytree("%s" % rootfs_dir, \
176 "%s" % initrd_dir, symlinks=True)
177
178 if os.path.isfile("%s/init" % rootfs_dir):
179 shutil.copy2("%s/init" % rootfs_dir, "%s/init" % initrd_dir)
180 elif os.path.lexists("%s/init" % rootfs_dir):
181 os.symlink(os.readlink("%s/init" % rootfs_dir), \
182 "%s/init" % initrd_dir)
183 elif os.path.isfile("%s/sbin/init" % rootfs_dir):
184 shutil.copy2("%s/sbin/init" % rootfs_dir, \
185 "%s" % initrd_dir)
186 elif os.path.lexists("%s/sbin/init" % rootfs_dir):
187 os.symlink(os.readlink("%s/sbin/init" % rootfs_dir), \
188 "%s/init" % initrd_dir)
189 else:
190 raise WicError("Couldn't find or build initrd, exiting.")
191
192 exec_cmd("cd %s && find . | cpio -o -H newc -R root:root >%s/initrd.cpio " \
193 % (initrd_dir, cr_workdir), as_shell=True)
194 exec_cmd("gzip -f -9 %s/initrd.cpio" % cr_workdir, as_shell=True)
195 shutil.rmtree(initrd_dir)
196
197 return initrd
198
199 @classmethod
200 def do_configure_partition(cls, part, source_params, creator, cr_workdir,
201 oe_builddir, bootimg_dir, kernel_dir,
202 native_sysroot):
203 """
204 Called before do_prepare_partition(), creates loader-specific config
205 """
206 isodir = "%s/ISO/" % cr_workdir
207
208 if os.path.exists(isodir):
209 shutil.rmtree(isodir)
210
211 install_cmd = "install -d %s " % isodir
212 exec_cmd(install_cmd)
213
214 # Overwrite the name of the created image
215 logger.debug(source_params)
216 if 'image_name' in source_params and \
217 source_params['image_name'].strip():
218 creator.name = source_params['image_name'].strip()
219 logger.debug("The name of the image is: %s", creator.name)
220
221 @staticmethod
222 def _install_payload(source_params, iso_dir):
223 """
224 Copies contents of payload directory (as specified in 'payload_dir' param) into iso_dir
225 """
226
227 if source_params.get('payload_dir'):
228 payload_dir = source_params['payload_dir']
229
230 logger.debug("Payload directory: %s", payload_dir)
231 shutil.copytree(payload_dir, iso_dir, symlinks=True, dirs_exist_ok=True)
232
233 @classmethod
234 def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
235 oe_builddir, bootimg_dir, kernel_dir,
236 rootfs_dir, native_sysroot):
237 """
238 Called to do the actual content population for a partition i.e. it
239 'prepares' the partition to be incorporated into the image.
240 In this case, prepare content for a bootable ISO image.
241 """
242
243 isodir = "%s/ISO" % cr_workdir
244
245 cls._install_payload(source_params, isodir)
246
247 if part.rootfs_dir is None:
248 if not 'ROOTFS_DIR' in rootfs_dir:
249 raise WicError("Couldn't find --rootfs-dir, exiting.")
250 rootfs_dir = rootfs_dir['ROOTFS_DIR']
251 else:
252 if part.rootfs_dir in rootfs_dir:
253 rootfs_dir = rootfs_dir[part.rootfs_dir]
254 elif part.rootfs_dir:
255 rootfs_dir = part.rootfs_dir
256 else:
257 raise WicError("Couldn't find --rootfs-dir=%s connection "
258 "or it is not a valid path, exiting." %
259 part.rootfs_dir)
260
261 if not os.path.isdir(rootfs_dir):
262 rootfs_dir = get_bitbake_var("IMAGE_ROOTFS")
263 if not os.path.isdir(rootfs_dir):
264 raise WicError("Couldn't find IMAGE_ROOTFS, exiting.")
265
266 part.rootfs_dir = rootfs_dir
267 deploy_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
268 img_iso_dir = get_bitbake_var("ISODIR")
269
270 # Remove the temporary file created by part.prepare_rootfs()
271 if os.path.isfile(part.source_file):
272 os.remove(part.source_file)
273
274 # Support using a different initrd other than default
275 if source_params.get('initrd'):
276 initrd = source_params['initrd']
277 if not deploy_dir:
278 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
279 cp_cmd = "cp %s/%s %s" % (deploy_dir, initrd, cr_workdir)
280 exec_cmd(cp_cmd)
281 else:
282 # Prepare initial ramdisk
283 initrd = "%s/initrd" % deploy_dir
284 if not os.path.isfile(initrd):
285 initrd = "%s/initrd" % img_iso_dir
286 if not os.path.isfile(initrd):
287 initrd = cls._build_initramfs_path(rootfs_dir, cr_workdir)
288
289 install_cmd = "install -m 0644 %s %s/initrd" % (initrd, isodir)
290 exec_cmd(install_cmd)
291
292 # Remove the temporary file created by _build_initramfs_path function
293 if os.path.isfile("%s/initrd.cpio.gz" % cr_workdir):
294 os.remove("%s/initrd.cpio.gz" % cr_workdir)
295
296 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
297 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
298 if get_bitbake_var("INITRAMFS_IMAGE"):
299 kernel = "%s-%s.bin" % \
300 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
301
302 install_cmd = "install -m 0644 %s/%s %s/%s" % \
303 (kernel_dir, kernel, isodir, kernel)
304 exec_cmd(install_cmd)
305
306 #Create bootloader for efi boot
307 try:
308 target_dir = "%s/EFI/BOOT" % isodir
309 if os.path.exists(target_dir):
310 shutil.rmtree(target_dir)
311
312 os.makedirs(target_dir)
313
314 if source_params['loader'] == 'grub-efi':
315 # Builds bootx64.efi/bootia32.efi if ISODIR didn't exist or
316 # didn't contains it
317 target_arch = get_bitbake_var("TARGET_SYS")
318 if not target_arch:
319 raise WicError("Coludn't find target architecture")
320
321 if re.match("x86_64", target_arch):
322 grub_src_image = "grub-efi-bootx64.efi"
323 grub_dest_image = "bootx64.efi"
324 elif re.match('i.86', target_arch):
325 grub_src_image = "grub-efi-bootia32.efi"
326 grub_dest_image = "bootia32.efi"
327 else:
328 raise WicError("grub-efi is incompatible with target %s" %
329 target_arch)
330
331 grub_target = os.path.join(target_dir, grub_dest_image)
332 if not os.path.isfile(grub_target):
333 grub_src = os.path.join(deploy_dir, grub_src_image)
334 if not os.path.exists(grub_src):
335 raise WicError("Grub loader %s is not found in %s. "
336 "Please build grub-efi first" % (grub_src_image, deploy_dir))
337 shutil.copy(grub_src, grub_target)
338
339 if not os.path.isfile(os.path.join(target_dir, "boot.cfg")):
340 cls.do_configure_grubefi(part, creator, target_dir)
341
342 else:
343 raise WicError("unrecognized bootimg_efi loader: %s" %
344 source_params['loader'])
345 except KeyError:
346 raise WicError("bootimg_efi requires a loader, none specified")
347
348 # Create efi.img that contains bootloader files for EFI booting
349 # if ISODIR didn't exist or didn't contains it
350 if os.path.isfile("%s/efi.img" % img_iso_dir):
351 install_cmd = "install -m 0644 %s/efi.img %s/efi.img" % \
352 (img_iso_dir, isodir)
353 exec_cmd(install_cmd)
354 else:
355 # Default to 100 blocks of extra space for file system overhead
356 esp_extra_blocks = int(source_params.get('esp_extra_blocks', '100'))
357
358 du_cmd = "du -bks %s/EFI" % isodir
359 out = exec_cmd(du_cmd)
360 blocks = int(out.split()[0])
361 blocks += esp_extra_blocks
362 logger.debug("Added 100 extra blocks to %s to get to %d "
363 "total blocks", part.mountpoint, blocks)
364
365 # dosfs image for EFI boot
366 bootimg = "%s/efi.img" % isodir
367
368 esp_label = source_params.get('esp_label', 'EFIimg')
369
370 dosfs_cmd = 'mkfs.vfat -n \'%s\' -S 512 -C %s %d' \
371 % (esp_label, bootimg, blocks)
372 exec_native_cmd(dosfs_cmd, native_sysroot)
373
374 mmd_cmd = "mmd -i %s ::/EFI" % bootimg
375 exec_native_cmd(mmd_cmd, native_sysroot)
376
377 mcopy_cmd = "mcopy -i %s -s %s/EFI/* ::/EFI/" \
378 % (bootimg, isodir)
379 exec_native_cmd(mcopy_cmd, native_sysroot)
380
381 chmod_cmd = "chmod 644 %s" % bootimg
382 exec_cmd(chmod_cmd)
383
384 # Prepare files for legacy boot
385 syslinux_dir = get_bitbake_var("STAGING_DATADIR")
386 if not syslinux_dir:
387 raise WicError("Couldn't find STAGING_DATADIR, exiting.")
388
389 if os.path.exists("%s/isolinux" % isodir):
390 shutil.rmtree("%s/isolinux" % isodir)
391
392 install_cmd = "install -d %s/isolinux" % isodir
393 exec_cmd(install_cmd)
394
395 cls.do_configure_syslinux(creator, cr_workdir)
396
397 install_cmd = "install -m 444 %s/syslinux/ldlinux.sys " % syslinux_dir
398 install_cmd += "%s/isolinux/ldlinux.sys" % isodir
399 exec_cmd(install_cmd)
400
401 install_cmd = "install -m 444 %s/syslinux/isohdpfx.bin " % syslinux_dir
402 install_cmd += "%s/isolinux/isohdpfx.bin" % isodir
403 exec_cmd(install_cmd)
404
405 install_cmd = "install -m 644 %s/syslinux/isolinux.bin " % syslinux_dir
406 install_cmd += "%s/isolinux/isolinux.bin" % isodir
407 exec_cmd(install_cmd)
408
409 install_cmd = "install -m 644 %s/syslinux/ldlinux.c32 " % syslinux_dir
410 install_cmd += "%s/isolinux/ldlinux.c32" % isodir
411 exec_cmd(install_cmd)
412
413 #create ISO image
414 iso_img = "%s/tempiso_img.iso" % cr_workdir
415 iso_bootimg = "isolinux/isolinux.bin"
416 iso_bootcat = "isolinux/boot.cat"
417 efi_img = "efi.img"
418
419 mkisofs_cmd = "mkisofs -V %s " % part.label
420 mkisofs_cmd += "-o %s -U " % iso_img
421 mkisofs_cmd += "-J -joliet-long -r -iso-level 2 -b %s " % iso_bootimg
422 mkisofs_cmd += "-c %s -no-emul-boot -boot-load-size 4 " % iso_bootcat
423 mkisofs_cmd += "-boot-info-table -eltorito-alt-boot "
424 mkisofs_cmd += "-eltorito-platform 0xEF -eltorito-boot %s " % efi_img
425 mkisofs_cmd += "-no-emul-boot %s " % isodir
426
427 logger.debug("running command: %s", mkisofs_cmd)
428 exec_native_cmd(mkisofs_cmd, native_sysroot)
429
430 shutil.rmtree(isodir)
431
432 du_cmd = "du -Lbks %s" % iso_img
433 out = exec_cmd(du_cmd)
434 isoimg_size = int(out.split()[0])
435
436 part.size = isoimg_size
437 part.source_file = iso_img
438
439 @classmethod
440 def do_install_disk(cls, disk, disk_name, creator, workdir, oe_builddir,
441 bootimg_dir, kernel_dir, native_sysroot):
442 """
443 Called after all partitions have been prepared and assembled into a
444 disk image. In this case, we insert/modify the MBR using isohybrid
445 utility for booting via BIOS from disk storage devices.
446 """
447
448 iso_img = "%s.p1" % disk.path
449 full_path = creator._full_path(workdir, disk_name, "direct")
450 full_path_iso = creator._full_path(workdir, disk_name, "iso")
451
452 isohybrid_cmd = "isohybrid -u %s" % iso_img
453 logger.debug("running command: %s", isohybrid_cmd)
454 exec_native_cmd(isohybrid_cmd, native_sysroot)
455
456 # Replace the image created by direct plugin with the one created by
457 # mkisofs command. This is necessary because the iso image created by
458 # mkisofs has a very specific MBR is system area of the ISO image, and
459 # direct plugin adds and configures an another MBR.
460 logger.debug("Replaceing the image created by direct plugin\n")
461 os.remove(disk.path)
462 shutil.copy2(iso_img, full_path_iso)
463 shutil.copy2(full_path_iso, full_path)
diff --git a/scripts/lib/wic/plugins/source/rawcopy.py b/scripts/lib/wic/plugins/source/rawcopy.py
deleted file mode 100644
index 21903c2f23..0000000000
--- a/scripts/lib/wic/plugins/source/rawcopy.py
+++ /dev/null
@@ -1,115 +0,0 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7import logging
8import os
9import signal
10import subprocess
11
12from wic import WicError
13from wic.pluginbase import SourcePlugin
14from wic.misc import exec_cmd, get_bitbake_var
15from wic.filemap import sparse_copy
16
17logger = logging.getLogger('wic')
18
19class RawCopyPlugin(SourcePlugin):
20 """
21 Populate partition content from raw image file.
22 """
23
24 name = 'rawcopy'
25
26 @staticmethod
27 def do_image_label(fstype, dst, label):
28 # don't create label when fstype is none
29 if fstype == 'none':
30 return
31
32 if fstype.startswith('ext'):
33 cmd = 'tune2fs -L %s %s' % (label, dst)
34 elif fstype in ('msdos', 'vfat'):
35 cmd = 'dosfslabel %s %s' % (dst, label)
36 elif fstype == 'btrfs':
37 cmd = 'btrfs filesystem label %s %s' % (dst, label)
38 elif fstype == 'swap':
39 cmd = 'mkswap -L %s %s' % (label, dst)
40 elif fstype in ('squashfs', 'erofs'):
41 raise WicError("It's not possible to update a %s "
42 "filesystem label '%s'" % (fstype, label))
43 else:
44 raise WicError("Cannot update filesystem label: "
45 "Unknown fstype: '%s'" % (fstype))
46
47 exec_cmd(cmd)
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
69 @classmethod
70 def do_prepare_partition(cls, part, source_params, cr, cr_workdir,
71 oe_builddir, bootimg_dir, kernel_dir,
72 rootfs_dir, native_sysroot):
73 """
74 Called to do the actual content population for a partition i.e. it
75 'prepares' the partition to be incorporated into the image.
76 """
77 if not kernel_dir:
78 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
79 if not kernel_dir:
80 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
81
82 logger.debug('Kernel dir: %s', kernel_dir)
83
84 if 'file' not in source_params:
85 raise WicError("No file specified")
86
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
94 dst = os.path.join(cr_workdir, "%s.%s" % (os.path.basename(source_params['file']), part.lineno))
95
96 if not os.path.exists(os.path.dirname(dst)):
97 os.makedirs(os.path.dirname(dst))
98
99 if 'skip' in source_params:
100 sparse_copy(src, dst, skip=int(source_params['skip']))
101 else:
102 sparse_copy(src, dst)
103
104 # get the size in the right units for kickstart (kB)
105 du_cmd = "du -Lbks %s" % dst
106 out = exec_cmd(du_cmd)
107 filesize = int(out.split()[0])
108
109 if filesize > part.size:
110 part.size = filesize
111
112 if part.label:
113 RawCopyPlugin.do_image_label(part.fstype, dst, part.label)
114
115 part.source_file = dst
diff --git a/scripts/lib/wic/plugins/source/rootfs.py b/scripts/lib/wic/plugins/source/rootfs.py
deleted file mode 100644
index 06fce06bb1..0000000000
--- a/scripts/lib/wic/plugins/source/rootfs.py
+++ /dev/null
@@ -1,236 +0,0 @@
1#
2# Copyright (c) 2014, Intel Corporation.
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6# DESCRIPTION
7# This implements the 'rootfs' source plugin class for 'wic'
8#
9# AUTHORS
10# Tom Zanussi <tom.zanussi (at] linux.intel.com>
11# Joao Henrique Ferreira de Freitas <joaohf (at] gmail.com>
12#
13
14import logging
15import os
16import shutil
17import sys
18
19from oe.path import copyhardlinktree
20from pathlib import Path
21
22from wic import WicError
23from wic.pluginbase import SourcePlugin
24from wic.misc import get_bitbake_var, exec_native_cmd
25
26logger = logging.getLogger('wic')
27
28class RootfsPlugin(SourcePlugin):
29 """
30 Populate partition content from a rootfs directory.
31 """
32
33 name = 'rootfs'
34
35 @staticmethod
36 def __validate_path(cmd, rootfs_dir, path):
37 if os.path.isabs(path):
38 logger.error("%s: Must be relative: %s" % (cmd, path))
39 sys.exit(1)
40
41 # Disallow climbing outside of parent directory using '..',
42 # because doing so could be quite disastrous (we will delete the
43 # directory, or modify a directory outside OpenEmbedded).
44 full_path = os.path.abspath(os.path.join(rootfs_dir, path))
45 if not full_path.startswith(os.path.realpath(rootfs_dir)):
46 logger.error("%s: Must point inside the rootfs: %s" % (cmd, path))
47 sys.exit(1)
48
49 return full_path
50
51 @staticmethod
52 def __get_rootfs_dir(rootfs_dir):
53 if rootfs_dir and os.path.isdir(rootfs_dir):
54 return os.path.realpath(rootfs_dir)
55
56 image_rootfs_dir = get_bitbake_var("IMAGE_ROOTFS", rootfs_dir)
57 if not os.path.isdir(image_rootfs_dir):
58 raise WicError("No valid artifact IMAGE_ROOTFS from image "
59 "named %s has been found at %s, exiting." %
60 (rootfs_dir, image_rootfs_dir))
61
62 return os.path.realpath(image_rootfs_dir)
63
64 @staticmethod
65 def __get_pseudo(native_sysroot, rootfs, pseudo_dir):
66 pseudo = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot
67 pseudo += "export PSEUDO_LOCALSTATEDIR=%s;" % pseudo_dir
68 pseudo += "export PSEUDO_PASSWD=%s;" % rootfs
69 pseudo += "export PSEUDO_NOSYMLINKEXP=1;"
70 pseudo += "%s " % get_bitbake_var("FAKEROOTCMD")
71 return pseudo
72
73 @classmethod
74 def do_prepare_partition(cls, part, source_params, cr, cr_workdir,
75 oe_builddir, bootimg_dir, kernel_dir,
76 krootfs_dir, native_sysroot):
77 """
78 Called to do the actual content population for a partition i.e. it
79 'prepares' the partition to be incorporated into the image.
80 In this case, prepare content for legacy bios boot partition.
81 """
82 if part.rootfs_dir is None:
83 if not 'ROOTFS_DIR' in krootfs_dir:
84 raise WicError("Couldn't find --rootfs-dir, exiting")
85
86 rootfs_dir = krootfs_dir['ROOTFS_DIR']
87 else:
88 if part.rootfs_dir in krootfs_dir:
89 rootfs_dir = krootfs_dir[part.rootfs_dir]
90 elif part.rootfs_dir:
91 rootfs_dir = part.rootfs_dir
92 else:
93 raise WicError("Couldn't find --rootfs-dir=%s connection or "
94 "it is not a valid path, exiting" % part.rootfs_dir)
95
96 part.rootfs_dir = cls.__get_rootfs_dir(rootfs_dir)
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")
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):
103 logger.warn("%s folder does not exist. "
104 "Usernames and permissions will be invalid " % pseudo_dir)
105 pseudo_dir = None
106
107 new_rootfs = None
108 new_pseudo = None
109 # Handle excluded paths.
110 if part.exclude_path or part.include_path or part.change_directory or part.update_fstab_in_rootfs:
111 # We need a new rootfs directory we can safely modify without
112 # interfering with other tasks. Copy to workdir.
113 new_rootfs = os.path.realpath(os.path.join(cr_workdir, "rootfs%d" % part.lineno))
114
115 if os.path.lexists(new_rootfs):
116 shutil.rmtree(os.path.join(new_rootfs))
117
118 if part.change_directory:
119 cd = part.change_directory
120 if cd[-1] == '/':
121 cd = cd[:-1]
122 orig_dir = cls.__validate_path("--change-directory", part.rootfs_dir, cd)
123 else:
124 orig_dir = part.rootfs_dir
125 copyhardlinktree(orig_dir, new_rootfs)
126
127 # Convert the pseudo directory to its new location
128 if (pseudo_dir):
129 new_pseudo = os.path.realpath(
130 os.path.join(cr_workdir, "pseudo%d" % part.lineno))
131 if os.path.lexists(new_pseudo):
132 shutil.rmtree(new_pseudo)
133 os.mkdir(new_pseudo)
134 shutil.copy(os.path.join(pseudo_dir, "files.db"),
135 os.path.join(new_pseudo, "files.db"))
136
137 pseudo_cmd = "%s -B -m %s -M %s" % (cls.__get_pseudo(native_sysroot,
138 new_rootfs,
139 new_pseudo),
140 orig_dir, new_rootfs)
141 exec_native_cmd(pseudo_cmd, native_sysroot)
142
143 for in_path in part.include_path or []:
144 #parse arguments
145 include_path = in_path[0]
146 if len(in_path) > 2:
147 logger.error("'Invalid number of arguments for include-path")
148 sys.exit(1)
149 if len(in_path) == 2:
150 path = in_path[1]
151 else:
152 path = None
153
154 # Pack files to be included into a tar file.
155 # We need to create a tar file, because that way we can keep the
156 # permissions from the files even when they belong to different
157 # pseudo enviroments.
158 # If we simply copy files using copyhardlinktree/copytree... the
159 # copied files will belong to the user running wic.
160 tar_file = os.path.realpath(
161 os.path.join(cr_workdir, "include-path%d.tar" % part.lineno))
162 if os.path.isfile(include_path):
163 parent = os.path.dirname(os.path.realpath(include_path))
164 tar_cmd = "tar c --owner=root --group=root -f %s -C %s %s" % (
165 tar_file, parent, os.path.relpath(include_path, parent))
166 exec_native_cmd(tar_cmd, native_sysroot)
167 else:
168 if include_path in krootfs_dir:
169 include_path = krootfs_dir[include_path]
170 include_path = cls.__get_rootfs_dir(include_path)
171 include_pseudo = os.path.join(include_path, "../pseudo")
172 if os.path.lexists(include_pseudo):
173 pseudo = cls.__get_pseudo(native_sysroot, include_path,
174 include_pseudo)
175 tar_cmd = "tar cf %s -C %s ." % (tar_file, include_path)
176 else:
177 pseudo = None
178 tar_cmd = "tar c --owner=root --group=root -f %s -C %s ." % (
179 tar_file, include_path)
180 exec_native_cmd(tar_cmd, native_sysroot, pseudo)
181
182 #create destination
183 if path:
184 destination = cls.__validate_path("--include-path", new_rootfs, path)
185 Path(destination).mkdir(parents=True, exist_ok=True)
186 else:
187 destination = new_rootfs
188
189 #extract destination
190 untar_cmd = "tar xf %s -C %s" % (tar_file, destination)
191 if new_pseudo:
192 pseudo = cls.__get_pseudo(native_sysroot, new_rootfs, new_pseudo)
193 else:
194 pseudo = None
195 exec_native_cmd(untar_cmd, native_sysroot, pseudo)
196 os.remove(tar_file)
197
198 for orig_path in part.exclude_path or []:
199 path = orig_path
200
201 full_path = cls.__validate_path("--exclude-path", new_rootfs, path)
202
203 if not os.path.lexists(full_path):
204 continue
205
206 if new_pseudo:
207 pseudo = cls.__get_pseudo(native_sysroot, new_rootfs, new_pseudo)
208 else:
209 pseudo = None
210 if path.endswith(os.sep):
211 # Delete content only.
212 for entry in os.listdir(full_path):
213 full_entry = os.path.join(full_path, entry)
214 rm_cmd = "rm -rf %s" % (full_entry)
215 exec_native_cmd(rm_cmd, native_sysroot, pseudo)
216 else:
217 # Delete whole directory.
218 rm_cmd = "rm -rf %s" % (full_path)
219 exec_native_cmd(rm_cmd, native_sysroot, pseudo)
220
221 # Update part.has_fstab here as fstab may have been added or
222 # removed by the above modifications.
223 part.has_fstab = os.path.exists(os.path.join(new_rootfs, "etc/fstab"))
224 if part.update_fstab_in_rootfs and part.has_fstab and not part.no_fstab_update:
225 fstab_path = os.path.join(new_rootfs, "etc/fstab")
226 # Assume that fstab should always be owned by root with fixed permissions
227 install_cmd = "install -m 0644 -p %s %s" % (part.updated_fstab_path, fstab_path)
228 if new_pseudo:
229 pseudo = cls.__get_pseudo(native_sysroot, new_rootfs, new_pseudo)
230 else:
231 pseudo = None
232 exec_native_cmd(install_cmd, native_sysroot, pseudo)
233
234 part.prepare_rootfs(cr_workdir, oe_builddir,
235 new_rootfs or part.rootfs_dir, native_sysroot,
236 pseudo_dir = new_pseudo or pseudo_dir)