1eb8dc403SDave Cobbley#
2eb8dc403SDave Cobbley# Copyright (c) 2013-2016 Intel Corporation.
3eb8dc403SDave Cobbley#
4c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only
5eb8dc403SDave Cobbley#
6eb8dc403SDave Cobbley# DESCRIPTION
7eb8dc403SDave Cobbley# This module provides the OpenEmbedded partition object definitions.
8eb8dc403SDave Cobbley#
9eb8dc403SDave Cobbley# AUTHORS
10eb8dc403SDave Cobbley# Tom Zanussi <tom.zanussi (at] linux.intel.com>
11eb8dc403SDave Cobbley# Ed Bartosh <ed.bartosh> (at] linux.intel.com>
12eb8dc403SDave Cobbley
13eb8dc403SDave Cobbleyimport logging
14eb8dc403SDave Cobbleyimport os
15eb8dc403SDave Cobbleyimport uuid
16eb8dc403SDave Cobbley
17eb8dc403SDave Cobbleyfrom wic import WicError
18eb8dc403SDave Cobbleyfrom wic.misc import exec_cmd, exec_native_cmd, get_bitbake_var
19eb8dc403SDave Cobbleyfrom wic.pluginbase import PluginMgr
20eb8dc403SDave Cobbley
21eb8dc403SDave Cobbleylogger = logging.getLogger('wic')
22eb8dc403SDave Cobbley
23eb8dc403SDave Cobbleyclass Partition():
24eb8dc403SDave Cobbley
25eb8dc403SDave Cobbley    def __init__(self, args, lineno):
26eb8dc403SDave Cobbley        self.args = args
27eb8dc403SDave Cobbley        self.active = args.active
28eb8dc403SDave Cobbley        self.align = args.align
29eb8dc403SDave Cobbley        self.disk = args.disk
30eb8dc403SDave Cobbley        self.device = None
31eb8dc403SDave Cobbley        self.extra_space = args.extra_space
32eb8dc403SDave Cobbley        self.exclude_path = args.exclude_path
3382c905dcSAndrew Geissler        self.include_path = args.include_path
3482c905dcSAndrew Geissler        self.change_directory = args.change_directory
35eb8dc403SDave Cobbley        self.fsopts = args.fsopts
36d583833aSAndrew Geissler        self.fspassno = args.fspassno
37eb8dc403SDave Cobbley        self.fstype = args.fstype
38eb8dc403SDave Cobbley        self.label = args.label
391a4b7ee2SBrad Bishop        self.use_label = args.use_label
40eb8dc403SDave Cobbley        self.mkfs_extraopts = args.mkfs_extraopts
41eb8dc403SDave Cobbley        self.mountpoint = args.mountpoint
42eb8dc403SDave Cobbley        self.no_table = args.no_table
43eb8dc403SDave Cobbley        self.num = None
444ed12e16SAndrew Geissler        self.offset = args.offset
45eb8dc403SDave Cobbley        self.overhead_factor = args.overhead_factor
46eb8dc403SDave Cobbley        self.part_name = args.part_name
47eb8dc403SDave Cobbley        self.part_type = args.part_type
48eb8dc403SDave Cobbley        self.rootfs_dir = args.rootfs_dir
49eb8dc403SDave Cobbley        self.size = args.size
50eb8dc403SDave Cobbley        self.fixed_size = args.fixed_size
51eb8dc403SDave Cobbley        self.source = args.source
52eb8dc403SDave Cobbley        self.sourceparams = args.sourceparams
53eb8dc403SDave Cobbley        self.system_id = args.system_id
54eb8dc403SDave Cobbley        self.use_uuid = args.use_uuid
55eb8dc403SDave Cobbley        self.uuid = args.uuid
56eb8dc403SDave Cobbley        self.fsuuid = args.fsuuid
5708902b01SBrad Bishop        self.type = args.type
58d159c7fbSAndrew Geissler        self.no_fstab_update = args.no_fstab_update
59d1e89497SAndrew Geissler        self.updated_fstab_path = None
60d1e89497SAndrew Geissler        self.has_fstab = False
61d1e89497SAndrew Geissler        self.update_fstab_in_rootfs = False
62e760df85SPatrick Williams        self.hidden = args.hidden
635082cc7fSAndrew Geissler        self.mbr = args.mbr
64eb8dc403SDave Cobbley
65eb8dc403SDave Cobbley        self.lineno = lineno
66eb8dc403SDave Cobbley        self.source_file = ""
67eb8dc403SDave Cobbley
68eb8dc403SDave Cobbley    def get_extra_block_count(self, current_blocks):
69eb8dc403SDave Cobbley        """
70eb8dc403SDave Cobbley        The --size param is reflected in self.size (in kB), and we already
71eb8dc403SDave Cobbley        have current_blocks (1k) blocks, calculate and return the
72eb8dc403SDave Cobbley        number of (1k) blocks we need to add to get to --size, 0 if
73eb8dc403SDave Cobbley        we're already there or beyond.
74eb8dc403SDave Cobbley        """
75eb8dc403SDave Cobbley        logger.debug("Requested partition size for %s: %d",
76eb8dc403SDave Cobbley                     self.mountpoint, self.size)
77eb8dc403SDave Cobbley
78eb8dc403SDave Cobbley        if not self.size:
79eb8dc403SDave Cobbley            return 0
80eb8dc403SDave Cobbley
81eb8dc403SDave Cobbley        requested_blocks = self.size
82eb8dc403SDave Cobbley
83eb8dc403SDave Cobbley        logger.debug("Requested blocks %d, current_blocks %d",
84eb8dc403SDave Cobbley                     requested_blocks, current_blocks)
85eb8dc403SDave Cobbley
86eb8dc403SDave Cobbley        if requested_blocks > current_blocks:
87eb8dc403SDave Cobbley            return requested_blocks - current_blocks
88eb8dc403SDave Cobbley        else:
89eb8dc403SDave Cobbley            return 0
90eb8dc403SDave Cobbley
91eb8dc403SDave Cobbley    def get_rootfs_size(self, actual_rootfs_size=0):
92eb8dc403SDave Cobbley        """
93eb8dc403SDave Cobbley        Calculate the required size of rootfs taking into consideration
94eb8dc403SDave Cobbley        --size/--fixed-size flags as well as overhead and extra space, as
95eb8dc403SDave Cobbley        specified in kickstart file. Raises an error if the
96eb8dc403SDave Cobbley        `actual_rootfs_size` is larger than fixed-size rootfs.
97eb8dc403SDave Cobbley
98eb8dc403SDave Cobbley        """
99eb8dc403SDave Cobbley        if self.fixed_size:
100eb8dc403SDave Cobbley            rootfs_size = self.fixed_size
101eb8dc403SDave Cobbley            if actual_rootfs_size > rootfs_size:
102eb8dc403SDave Cobbley                raise WicError("Actual rootfs size (%d kB) is larger than "
103eb8dc403SDave Cobbley                               "allowed size %d kB" %
104eb8dc403SDave Cobbley                               (actual_rootfs_size, rootfs_size))
105eb8dc403SDave Cobbley        else:
106eb8dc403SDave Cobbley            extra_blocks = self.get_extra_block_count(actual_rootfs_size)
107eb8dc403SDave Cobbley            if extra_blocks < self.extra_space:
108eb8dc403SDave Cobbley                extra_blocks = self.extra_space
109eb8dc403SDave Cobbley
110eb8dc403SDave Cobbley            rootfs_size = actual_rootfs_size + extra_blocks
1115199d831SAndrew Geissler            rootfs_size = int(rootfs_size * self.overhead_factor)
112eb8dc403SDave Cobbley
113eb8dc403SDave Cobbley            logger.debug("Added %d extra blocks to %s to get to %d total blocks",
114eb8dc403SDave Cobbley                         extra_blocks, self.mountpoint, rootfs_size)
115eb8dc403SDave Cobbley
116eb8dc403SDave Cobbley        return rootfs_size
117eb8dc403SDave Cobbley
118eb8dc403SDave Cobbley    @property
119eb8dc403SDave Cobbley    def disk_size(self):
120eb8dc403SDave Cobbley        """
121eb8dc403SDave Cobbley        Obtain on-disk size of partition taking into consideration
122eb8dc403SDave Cobbley        --size/--fixed-size options.
123eb8dc403SDave Cobbley
124eb8dc403SDave Cobbley        """
125eb8dc403SDave Cobbley        return self.fixed_size if self.fixed_size else self.size
126eb8dc403SDave Cobbley
127eb8dc403SDave Cobbley    def prepare(self, creator, cr_workdir, oe_builddir, rootfs_dir,
128d1e89497SAndrew Geissler                bootimg_dir, kernel_dir, native_sysroot, updated_fstab_path):
129eb8dc403SDave Cobbley        """
130eb8dc403SDave Cobbley        Prepare content for individual partitions, depending on
131eb8dc403SDave Cobbley        partition command parameters.
132eb8dc403SDave Cobbley        """
133d1e89497SAndrew Geissler        self.updated_fstab_path = updated_fstab_path
134d1e89497SAndrew Geissler        if self.updated_fstab_path and not (self.fstype.startswith("ext") or self.fstype == "msdos"):
135d1e89497SAndrew Geissler            self.update_fstab_in_rootfs = True
136d1e89497SAndrew Geissler
137eb8dc403SDave Cobbley        if not self.source:
1385082cc7fSAndrew Geissler            if self.fstype == "none" or self.no_table:
1396aa7eec5SAndrew Geissler                return
140eb8dc403SDave Cobbley            if not self.size and not self.fixed_size:
141eb8dc403SDave Cobbley                raise WicError("The %s partition has a size of zero. Please "
142eb8dc403SDave Cobbley                               "specify a non-zero --size/--fixed-size for that "
143eb8dc403SDave Cobbley                               "partition." % self.mountpoint)
144eb8dc403SDave Cobbley
145eb8dc403SDave Cobbley            if self.fstype == "swap":
146eb8dc403SDave Cobbley                self.prepare_swap_partition(cr_workdir, oe_builddir,
147eb8dc403SDave Cobbley                                            native_sysroot)
148eb8dc403SDave Cobbley                self.source_file = "%s/fs.%s" % (cr_workdir, self.fstype)
149eb8dc403SDave Cobbley            else:
150ac69b488SWilliam A. Kennington III                if self.fstype in ('squashfs', 'erofs'):
151ac69b488SWilliam A. Kennington III                    raise WicError("It's not possible to create empty %s "
152ac69b488SWilliam A. Kennington III                                   "partition '%s'" % (self.fstype, self.mountpoint))
153eb8dc403SDave Cobbley
154eb8dc403SDave Cobbley                rootfs = "%s/fs_%s.%s.%s" % (cr_workdir, self.label,
155eb8dc403SDave Cobbley                                             self.lineno, self.fstype)
156eb8dc403SDave Cobbley                if os.path.isfile(rootfs):
157eb8dc403SDave Cobbley                    os.remove(rootfs)
158eb8dc403SDave Cobbley
159eb8dc403SDave Cobbley                prefix = "ext" if self.fstype.startswith("ext") else self.fstype
160eb8dc403SDave Cobbley                method = getattr(self, "prepare_empty_partition_" + prefix)
161eb8dc403SDave Cobbley                method(rootfs, oe_builddir, native_sysroot)
162eb8dc403SDave Cobbley                self.source_file = rootfs
163eb8dc403SDave Cobbley            return
164eb8dc403SDave Cobbley
165eb8dc403SDave Cobbley        plugins = PluginMgr.get_plugins('source')
166eb8dc403SDave Cobbley
167eb8dc403SDave Cobbley        if self.source not in plugins:
168eb8dc403SDave Cobbley            raise WicError("The '%s' --source specified for %s doesn't exist.\n\t"
169eb8dc403SDave Cobbley                           "See 'wic list source-plugins' for a list of available"
170eb8dc403SDave Cobbley                           " --sources.\n\tSee 'wic help source-plugins' for "
171eb8dc403SDave Cobbley                           "details on adding a new source plugin." %
172eb8dc403SDave Cobbley                           (self.source, self.mountpoint))
173eb8dc403SDave Cobbley
174eb8dc403SDave Cobbley        srcparams_dict = {}
175eb8dc403SDave Cobbley        if self.sourceparams:
176eb8dc403SDave Cobbley            # Split sourceparams string of the form key1=val1[,key2=val2,...]
177eb8dc403SDave Cobbley            # into a dict.  Also accepts valueless keys i.e. without =
178eb8dc403SDave Cobbley            splitted = self.sourceparams.split(',')
1797e0e3c0cSAndrew Geissler            srcparams_dict = dict((par.split('=', 1) + [None])[:2] for par in splitted if par)
180eb8dc403SDave Cobbley
181eb8dc403SDave Cobbley        plugin = PluginMgr.get_plugins('source')[self.source]
182eb8dc403SDave Cobbley        plugin.do_configure_partition(self, srcparams_dict, creator,
183eb8dc403SDave Cobbley                                      cr_workdir, oe_builddir, bootimg_dir,
184eb8dc403SDave Cobbley                                      kernel_dir, native_sysroot)
185eb8dc403SDave Cobbley        plugin.do_stage_partition(self, srcparams_dict, creator,
186eb8dc403SDave Cobbley                                  cr_workdir, oe_builddir, bootimg_dir,
187eb8dc403SDave Cobbley                                  kernel_dir, native_sysroot)
188eb8dc403SDave Cobbley        plugin.do_prepare_partition(self, srcparams_dict, creator,
189eb8dc403SDave Cobbley                                    cr_workdir, oe_builddir, bootimg_dir,
190eb8dc403SDave Cobbley                                    kernel_dir, rootfs_dir, native_sysroot)
191eb8dc403SDave Cobbley        plugin.do_post_partition(self, srcparams_dict, creator,
192eb8dc403SDave Cobbley                                    cr_workdir, oe_builddir, bootimg_dir,
193eb8dc403SDave Cobbley                                    kernel_dir, rootfs_dir, native_sysroot)
194eb8dc403SDave Cobbley
195eb8dc403SDave Cobbley        # further processing required Partition.size to be an integer, make
196eb8dc403SDave Cobbley        # sure that it is one
197eb8dc403SDave Cobbley        if not isinstance(self.size, int):
198eb8dc403SDave Cobbley            raise WicError("Partition %s internal size is not an integer. "
199eb8dc403SDave Cobbley                           "This a bug in source plugin %s and needs to be fixed." %
200eb8dc403SDave Cobbley                           (self.mountpoint, self.source))
201eb8dc403SDave Cobbley
202eb8dc403SDave Cobbley        if self.fixed_size and self.size > self.fixed_size:
203eb8dc403SDave Cobbley            raise WicError("File system image of partition %s is "
204eb8dc403SDave Cobbley                           "larger (%d kB) than its allowed size %d kB" %
205eb8dc403SDave Cobbley                           (self.mountpoint, self.size, self.fixed_size))
206eb8dc403SDave Cobbley
207eb8dc403SDave Cobbley    def prepare_rootfs(self, cr_workdir, oe_builddir, rootfs_dir,
20882c905dcSAndrew Geissler                       native_sysroot, real_rootfs = True, pseudo_dir = None):
209eb8dc403SDave Cobbley        """
210eb8dc403SDave Cobbley        Prepare content for a rootfs partition i.e. create a partition
211eb8dc403SDave Cobbley        and fill it from a /rootfs dir.
212eb8dc403SDave Cobbley
213eb8dc403SDave Cobbley        Currently handles ext2/3/4, btrfs, vfat and squashfs.
214eb8dc403SDave Cobbley        """
215f0343792SAndrew Geissler
216f0343792SAndrew Geissler        rootfs = "%s/rootfs_%s.%s.%s" % (cr_workdir, self.label,
217f0343792SAndrew Geissler                                         self.lineno, self.fstype)
218f0343792SAndrew Geissler        if os.path.isfile(rootfs):
219f0343792SAndrew Geissler            os.remove(rootfs)
220f0343792SAndrew Geissler
221eb8dc403SDave Cobbley        p_prefix = os.environ.get("PSEUDO_PREFIX", "%s/usr" % native_sysroot)
22282c905dcSAndrew Geissler        if (pseudo_dir):
223d1e89497SAndrew Geissler            # Canonicalize the ignore paths. This corresponds to
224d1e89497SAndrew Geissler            # calling oe.path.canonicalize(), which is used in bitbake.conf.
225d1e89497SAndrew Geissler            ignore_paths = [rootfs] + (get_bitbake_var("PSEUDO_IGNORE_PATHS") or "").split(",")
226d1e89497SAndrew Geissler            canonical_paths = []
227d1e89497SAndrew Geissler            for path in ignore_paths:
228d1e89497SAndrew Geissler                if "$" not in path:
229d1e89497SAndrew Geissler                    trailing_slash = path.endswith("/") and "/" or ""
230d1e89497SAndrew Geissler                    canonical_paths.append(os.path.realpath(path) + trailing_slash)
231d1e89497SAndrew Geissler            ignore_paths = ",".join(canonical_paths)
232d1e89497SAndrew Geissler
233eb8dc403SDave Cobbley            pseudo = "export PSEUDO_PREFIX=%s;" % p_prefix
23482c905dcSAndrew Geissler            pseudo += "export PSEUDO_LOCALSTATEDIR=%s;" % pseudo_dir
23582c905dcSAndrew Geissler            pseudo += "export PSEUDO_PASSWD=%s;" % rootfs_dir
23682c905dcSAndrew Geissler            pseudo += "export PSEUDO_NOSYMLINKEXP=1;"
237d1e89497SAndrew Geissler            pseudo += "export PSEUDO_IGNORE_PATHS=%s;" % ignore_paths
238eb8dc403SDave Cobbley            pseudo += "%s " % get_bitbake_var("FAKEROOTCMD")
23982c905dcSAndrew Geissler        else:
24082c905dcSAndrew Geissler            pseudo = None
241eb8dc403SDave Cobbley
242eb8dc403SDave Cobbley        if not self.size and real_rootfs:
24300e122a7SBrad Bishop            # The rootfs size is not set in .ks file so try to get it
24400e122a7SBrad Bishop            # from bitbake variable
24500e122a7SBrad Bishop            rsize_bb = get_bitbake_var('ROOTFS_SIZE')
24600e122a7SBrad Bishop            rdir = get_bitbake_var('IMAGE_ROOTFS')
24700e122a7SBrad Bishop            if rsize_bb and rdir == rootfs_dir:
24800e122a7SBrad Bishop                # Bitbake variable ROOTFS_SIZE is calculated in
24900e122a7SBrad Bishop                # Image._get_rootfs_size method from meta/lib/oe/image.py
25000e122a7SBrad Bishop                # using IMAGE_ROOTFS_SIZE, IMAGE_ROOTFS_ALIGNMENT,
25100e122a7SBrad Bishop                # IMAGE_OVERHEAD_FACTOR and IMAGE_ROOTFS_EXTRA_SPACE
25200e122a7SBrad Bishop                self.size = int(round(float(rsize_bb)))
25300e122a7SBrad Bishop            else:
25400e122a7SBrad Bishop                # Bitbake variable ROOTFS_SIZE is not defined so compute it
25500e122a7SBrad Bishop                # from the rootfs_dir size using the same logic found in
25600e122a7SBrad Bishop                # get_rootfs_size() from meta/classes/image.bbclass
25708902b01SBrad Bishop                du_cmd = "du -ks %s" % rootfs_dir
25808902b01SBrad Bishop                out = exec_cmd(du_cmd)
25908902b01SBrad Bishop                self.size = int(out.split()[0])
260eb8dc403SDave Cobbley
261eb8dc403SDave Cobbley        prefix = "ext" if self.fstype.startswith("ext") else self.fstype
262eb8dc403SDave Cobbley        method = getattr(self, "prepare_rootfs_" + prefix)
263d1e89497SAndrew Geissler        method(rootfs, cr_workdir, oe_builddir, rootfs_dir, native_sysroot, pseudo)
264eb8dc403SDave Cobbley        self.source_file = rootfs
265eb8dc403SDave Cobbley
266eb8dc403SDave Cobbley        # get the rootfs size in the right units for kickstart (kB)
267eb8dc403SDave Cobbley        du_cmd = "du -Lbks %s" % rootfs
268eb8dc403SDave Cobbley        out = exec_cmd(du_cmd)
269eb8dc403SDave Cobbley        self.size = int(out.split()[0])
270eb8dc403SDave Cobbley
271d1e89497SAndrew Geissler    def prepare_rootfs_ext(self, rootfs, cr_workdir, oe_builddir, rootfs_dir,
272eb8dc403SDave Cobbley                           native_sysroot, pseudo):
273eb8dc403SDave Cobbley        """
274eb8dc403SDave Cobbley        Prepare content for an ext2/3/4 rootfs partition.
275eb8dc403SDave Cobbley        """
276eb8dc403SDave Cobbley        du_cmd = "du -ks %s" % rootfs_dir
277eb8dc403SDave Cobbley        out = exec_cmd(du_cmd)
278eb8dc403SDave Cobbley        actual_rootfs_size = int(out.split()[0])
279eb8dc403SDave Cobbley
280eb8dc403SDave Cobbley        rootfs_size = self.get_rootfs_size(actual_rootfs_size)
281eb8dc403SDave Cobbley
282eb8dc403SDave Cobbley        with open(rootfs, 'w') as sparse:
283eb8dc403SDave Cobbley            os.ftruncate(sparse.fileno(), rootfs_size * 1024)
284eb8dc403SDave Cobbley
285eb8dc403SDave Cobbley        extraopts = self.mkfs_extraopts or "-F -i 8192"
286eb8dc403SDave Cobbley
287*169d7bccSPatrick Williams        if os.getenv('SOURCE_DATE_EPOCH'):
288*169d7bccSPatrick Williams            sde_time = int(os.getenv('SOURCE_DATE_EPOCH'))
289*169d7bccSPatrick Williams            if pseudo:
290*169d7bccSPatrick Williams                pseudo = "export E2FSPROGS_FAKE_TIME=%s;%s " % (sde_time, pseudo)
291*169d7bccSPatrick Williams            else:
292*169d7bccSPatrick Williams                pseudo = "export E2FSPROGS_FAKE_TIME=%s; " % sde_time
293*169d7bccSPatrick Williams
294*169d7bccSPatrick Williams            # Set hash_seed to generate deterministic directory indexes
295*169d7bccSPatrick Williams            namespace = uuid.UUID("e7429877-e7b3-4a68-a5c9-2f2fdf33d460")
296*169d7bccSPatrick Williams            if self.fsuuid:
297*169d7bccSPatrick Williams                namespace = uuid.UUID(self.fsuuid)
298*169d7bccSPatrick Williams            hash_seed = str(uuid.uuid5(namespace, str(sde_time)))
299*169d7bccSPatrick Williams            extraopts += " -E hash_seed=%s" % hash_seed
300*169d7bccSPatrick Williams
301eb8dc403SDave Cobbley        label_str = ""
302eb8dc403SDave Cobbley        if self.label:
303eb8dc403SDave Cobbley            label_str = "-L %s" % self.label
304eb8dc403SDave Cobbley
305eb8dc403SDave Cobbley        mkfs_cmd = "mkfs.%s %s %s %s -U %s -d %s" % \
306eb8dc403SDave Cobbley            (self.fstype, extraopts, rootfs, label_str, self.fsuuid, rootfs_dir)
307eb8dc403SDave Cobbley        exec_native_cmd(mkfs_cmd, native_sysroot, pseudo=pseudo)
308eb8dc403SDave Cobbley
309d159c7fbSAndrew Geissler        if self.updated_fstab_path and self.has_fstab and not self.no_fstab_update:
310d1e89497SAndrew Geissler            debugfs_script_path = os.path.join(cr_workdir, "debugfs_script")
311d1e89497SAndrew Geissler            with open(debugfs_script_path, "w") as f:
312d1e89497SAndrew Geissler                f.write("cd etc\n")
313d1e89497SAndrew Geissler                f.write("rm fstab\n")
314d1e89497SAndrew Geissler                f.write("write %s fstab\n" % (self.updated_fstab_path))
315d1e89497SAndrew Geissler            debugfs_cmd = "debugfs -w -f %s %s" % (debugfs_script_path, rootfs)
316d1e89497SAndrew Geissler            exec_native_cmd(debugfs_cmd, native_sysroot)
317d1e89497SAndrew Geissler
318eb8dc403SDave Cobbley        mkfs_cmd = "fsck.%s -pvfD %s" % (self.fstype, rootfs)
319eb8dc403SDave Cobbley        exec_native_cmd(mkfs_cmd, native_sysroot, pseudo=pseudo)
320eb8dc403SDave Cobbley
3217784c429SPatrick Williams        if os.getenv('SOURCE_DATE_EPOCH'):
3227784c429SPatrick Williams            sde_time = hex(int(os.getenv('SOURCE_DATE_EPOCH')))
3237784c429SPatrick Williams            debugfs_script_path = os.path.join(cr_workdir, "debugfs_script")
3247784c429SPatrick Williams            files = []
3257784c429SPatrick Williams            for root, dirs, others in os.walk(rootfs_dir):
3267784c429SPatrick Williams                base = root.replace(rootfs_dir, "").rstrip(os.sep)
3277784c429SPatrick Williams                files += [ "/" if base == "" else base ]
3287784c429SPatrick Williams                files += [ base + "/" + n for n in dirs + others ]
3297784c429SPatrick Williams            with open(debugfs_script_path, "w") as f:
3307784c429SPatrick Williams                f.write("set_current_time %s\n" % (sde_time))
3317784c429SPatrick Williams                if self.updated_fstab_path and self.has_fstab and not self.no_fstab_update:
3327784c429SPatrick Williams                    f.write("set_inode_field /etc/fstab mtime %s\n" % (sde_time))
3337784c429SPatrick Williams                    f.write("set_inode_field /etc/fstab mtime_extra 0\n")
3347784c429SPatrick Williams                for file in set(files):
3357784c429SPatrick Williams                    for time in ["atime", "ctime", "crtime"]:
3367784c429SPatrick Williams                        f.write("set_inode_field \"%s\" %s %s\n" % (file, time, sde_time))
3377784c429SPatrick Williams                        f.write("set_inode_field \"%s\" %s_extra 0\n" % (file, time))
3387784c429SPatrick Williams                for time in ["wtime", "mkfs_time", "lastcheck"]:
3397784c429SPatrick Williams                    f.write("set_super_value %s %s\n" % (time, sde_time))
3407784c429SPatrick Williams                for time in ["mtime", "first_error_time", "last_error_time"]:
3417784c429SPatrick Williams                    f.write("set_super_value %s 0\n" % (time))
3427784c429SPatrick Williams            debugfs_cmd = "debugfs -w -f %s %s" % (debugfs_script_path, rootfs)
3437784c429SPatrick Williams            exec_native_cmd(debugfs_cmd, native_sysroot)
3447784c429SPatrick Williams
34590fd73cbSAndrew Geissler        self.check_for_Y2038_problem(rootfs, native_sysroot)
34690fd73cbSAndrew Geissler
347d1e89497SAndrew Geissler    def prepare_rootfs_btrfs(self, rootfs, cr_workdir, oe_builddir, rootfs_dir,
348eb8dc403SDave Cobbley                             native_sysroot, pseudo):
349eb8dc403SDave Cobbley        """
350eb8dc403SDave Cobbley        Prepare content for a btrfs rootfs partition.
351eb8dc403SDave Cobbley        """
352eb8dc403SDave Cobbley        du_cmd = "du -ks %s" % rootfs_dir
353eb8dc403SDave Cobbley        out = exec_cmd(du_cmd)
354eb8dc403SDave Cobbley        actual_rootfs_size = int(out.split()[0])
355eb8dc403SDave Cobbley
356eb8dc403SDave Cobbley        rootfs_size = self.get_rootfs_size(actual_rootfs_size)
357eb8dc403SDave Cobbley
358eb8dc403SDave Cobbley        with open(rootfs, 'w') as sparse:
359eb8dc403SDave Cobbley            os.ftruncate(sparse.fileno(), rootfs_size * 1024)
360eb8dc403SDave Cobbley
361eb8dc403SDave Cobbley        label_str = ""
362eb8dc403SDave Cobbley        if self.label:
363eb8dc403SDave Cobbley            label_str = "-L %s" % self.label
364eb8dc403SDave Cobbley
365eb8dc403SDave Cobbley        mkfs_cmd = "mkfs.%s -b %d -r %s %s %s -U %s %s" % \
366eb8dc403SDave Cobbley            (self.fstype, rootfs_size * 1024, rootfs_dir, label_str,
367eb8dc403SDave Cobbley             self.mkfs_extraopts, self.fsuuid, rootfs)
368eb8dc403SDave Cobbley        exec_native_cmd(mkfs_cmd, native_sysroot, pseudo=pseudo)
369eb8dc403SDave Cobbley
370d1e89497SAndrew Geissler    def prepare_rootfs_msdos(self, rootfs, cr_workdir, oe_builddir, rootfs_dir,
371eb8dc403SDave Cobbley                             native_sysroot, pseudo):
372eb8dc403SDave Cobbley        """
373eb8dc403SDave Cobbley        Prepare content for a msdos/vfat rootfs partition.
374eb8dc403SDave Cobbley        """
375eb8dc403SDave Cobbley        du_cmd = "du -bks %s" % rootfs_dir
376eb8dc403SDave Cobbley        out = exec_cmd(du_cmd)
377eb8dc403SDave Cobbley        blocks = int(out.split()[0])
378eb8dc403SDave Cobbley
379eb8dc403SDave Cobbley        rootfs_size = self.get_rootfs_size(blocks)
380eb8dc403SDave Cobbley
381eb8dc403SDave Cobbley        label_str = "-n boot"
382eb8dc403SDave Cobbley        if self.label:
383eb8dc403SDave Cobbley            label_str = "-n %s" % self.label
384eb8dc403SDave Cobbley
385eb8dc403SDave Cobbley        size_str = ""
386eb8dc403SDave Cobbley
387eb8dc403SDave Cobbley        extraopts = self.mkfs_extraopts or '-S 512'
388eb8dc403SDave Cobbley
389eb8dc403SDave Cobbley        dosfs_cmd = "mkdosfs %s -i %s %s %s -C %s %d" % \
390eb8dc403SDave Cobbley                    (label_str, self.fsuuid, size_str, extraopts, rootfs,
391c342db35SBrad Bishop                     rootfs_size)
392eb8dc403SDave Cobbley        exec_native_cmd(dosfs_cmd, native_sysroot)
393eb8dc403SDave Cobbley
394eb8dc403SDave Cobbley        mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (rootfs, rootfs_dir)
395eb8dc403SDave Cobbley        exec_native_cmd(mcopy_cmd, native_sysroot)
396eb8dc403SDave Cobbley
397d159c7fbSAndrew Geissler        if self.updated_fstab_path and self.has_fstab and not self.no_fstab_update:
3982390b1b6SPatrick Williams            mcopy_cmd = "mcopy -m -i %s %s ::/etc/fstab" % (rootfs, self.updated_fstab_path)
399d1e89497SAndrew Geissler            exec_native_cmd(mcopy_cmd, native_sysroot)
400d1e89497SAndrew Geissler
401eb8dc403SDave Cobbley        chmod_cmd = "chmod 644 %s" % rootfs
402eb8dc403SDave Cobbley        exec_cmd(chmod_cmd)
403eb8dc403SDave Cobbley
404eb8dc403SDave Cobbley    prepare_rootfs_vfat = prepare_rootfs_msdos
405eb8dc403SDave Cobbley
406d1e89497SAndrew Geissler    def prepare_rootfs_squashfs(self, rootfs, cr_workdir, oe_builddir, rootfs_dir,
407eb8dc403SDave Cobbley                                native_sysroot, pseudo):
408eb8dc403SDave Cobbley        """
409eb8dc403SDave Cobbley        Prepare content for a squashfs rootfs partition.
410eb8dc403SDave Cobbley        """
411eb8dc403SDave Cobbley        extraopts = self.mkfs_extraopts or '-noappend'
412eb8dc403SDave Cobbley        squashfs_cmd = "mksquashfs %s %s %s" % \
413eb8dc403SDave Cobbley                       (rootfs_dir, rootfs, extraopts)
414eb8dc403SDave Cobbley        exec_native_cmd(squashfs_cmd, native_sysroot, pseudo=pseudo)
415eb8dc403SDave Cobbley
416ac69b488SWilliam A. Kennington III    def prepare_rootfs_erofs(self, rootfs, cr_workdir, oe_builddir, rootfs_dir,
417ac69b488SWilliam A. Kennington III                             native_sysroot, pseudo):
418ac69b488SWilliam A. Kennington III        """
419ac69b488SWilliam A. Kennington III        Prepare content for a erofs rootfs partition.
420ac69b488SWilliam A. Kennington III        """
421ac69b488SWilliam A. Kennington III        extraopts = self.mkfs_extraopts or ''
422ac69b488SWilliam A. Kennington III        erofs_cmd = "mkfs.erofs %s -U %s %s %s" % \
423ac69b488SWilliam A. Kennington III                       (extraopts, self.fsuuid, rootfs, rootfs_dir)
424ac69b488SWilliam A. Kennington III        exec_native_cmd(erofs_cmd, native_sysroot, pseudo=pseudo)
425ac69b488SWilliam A. Kennington III
4266aa7eec5SAndrew Geissler    def prepare_empty_partition_none(self, rootfs, oe_builddir, native_sysroot):
4276aa7eec5SAndrew Geissler        pass
4286aa7eec5SAndrew Geissler
429eb8dc403SDave Cobbley    def prepare_empty_partition_ext(self, rootfs, oe_builddir,
430eb8dc403SDave Cobbley                                    native_sysroot):
431eb8dc403SDave Cobbley        """
432eb8dc403SDave Cobbley        Prepare an empty ext2/3/4 partition.
433eb8dc403SDave Cobbley        """
434eb8dc403SDave Cobbley        size = self.disk_size
435eb8dc403SDave Cobbley        with open(rootfs, 'w') as sparse:
436eb8dc403SDave Cobbley            os.ftruncate(sparse.fileno(), size * 1024)
437eb8dc403SDave Cobbley
438eb8dc403SDave Cobbley        extraopts = self.mkfs_extraopts or "-i 8192"
439eb8dc403SDave Cobbley
440eb8dc403SDave Cobbley        label_str = ""
441eb8dc403SDave Cobbley        if self.label:
442eb8dc403SDave Cobbley            label_str = "-L %s" % self.label
443eb8dc403SDave Cobbley
444eb8dc403SDave Cobbley        mkfs_cmd = "mkfs.%s -F %s %s -U %s %s" % \
445eb8dc403SDave Cobbley            (self.fstype, extraopts, label_str, self.fsuuid, rootfs)
446eb8dc403SDave Cobbley        exec_native_cmd(mkfs_cmd, native_sysroot)
447eb8dc403SDave Cobbley
44890fd73cbSAndrew Geissler        self.check_for_Y2038_problem(rootfs, native_sysroot)
44990fd73cbSAndrew Geissler
450eb8dc403SDave Cobbley    def prepare_empty_partition_btrfs(self, rootfs, oe_builddir,
451eb8dc403SDave Cobbley                                      native_sysroot):
452eb8dc403SDave Cobbley        """
453eb8dc403SDave Cobbley        Prepare an empty btrfs partition.
454eb8dc403SDave Cobbley        """
455eb8dc403SDave Cobbley        size = self.disk_size
456eb8dc403SDave Cobbley        with open(rootfs, 'w') as sparse:
457eb8dc403SDave Cobbley            os.ftruncate(sparse.fileno(), size * 1024)
458eb8dc403SDave Cobbley
459eb8dc403SDave Cobbley        label_str = ""
460eb8dc403SDave Cobbley        if self.label:
461eb8dc403SDave Cobbley            label_str = "-L %s" % self.label
462eb8dc403SDave Cobbley
463eb8dc403SDave Cobbley        mkfs_cmd = "mkfs.%s -b %d %s -U %s %s %s" % \
464eb8dc403SDave Cobbley                   (self.fstype, self.size * 1024, label_str, self.fsuuid,
465eb8dc403SDave Cobbley                    self.mkfs_extraopts, rootfs)
466eb8dc403SDave Cobbley        exec_native_cmd(mkfs_cmd, native_sysroot)
467eb8dc403SDave Cobbley
468eb8dc403SDave Cobbley    def prepare_empty_partition_msdos(self, rootfs, oe_builddir,
469eb8dc403SDave Cobbley                                      native_sysroot):
470eb8dc403SDave Cobbley        """
471eb8dc403SDave Cobbley        Prepare an empty vfat partition.
472eb8dc403SDave Cobbley        """
473eb8dc403SDave Cobbley        blocks = self.disk_size
474eb8dc403SDave Cobbley
475eb8dc403SDave Cobbley        label_str = "-n boot"
476eb8dc403SDave Cobbley        if self.label:
477eb8dc403SDave Cobbley            label_str = "-n %s" % self.label
478eb8dc403SDave Cobbley
479eb8dc403SDave Cobbley        size_str = ""
480eb8dc403SDave Cobbley
481eb8dc403SDave Cobbley        extraopts = self.mkfs_extraopts or '-S 512'
482eb8dc403SDave Cobbley
483eb8dc403SDave Cobbley        dosfs_cmd = "mkdosfs %s -i %s %s %s -C %s %d" % \
484eb8dc403SDave Cobbley                    (label_str, self.fsuuid, extraopts, size_str, rootfs,
485eb8dc403SDave Cobbley                     blocks)
486eb8dc403SDave Cobbley
487eb8dc403SDave Cobbley        exec_native_cmd(dosfs_cmd, native_sysroot)
488eb8dc403SDave Cobbley
489eb8dc403SDave Cobbley        chmod_cmd = "chmod 644 %s" % rootfs
490eb8dc403SDave Cobbley        exec_cmd(chmod_cmd)
491eb8dc403SDave Cobbley
492eb8dc403SDave Cobbley    prepare_empty_partition_vfat = prepare_empty_partition_msdos
493eb8dc403SDave Cobbley
494eb8dc403SDave Cobbley    def prepare_swap_partition(self, cr_workdir, oe_builddir, native_sysroot):
495eb8dc403SDave Cobbley        """
496eb8dc403SDave Cobbley        Prepare a swap partition.
497eb8dc403SDave Cobbley        """
498eb8dc403SDave Cobbley        path = "%s/fs.%s" % (cr_workdir, self.fstype)
499eb8dc403SDave Cobbley
500eb8dc403SDave Cobbley        with open(path, 'w') as sparse:
501eb8dc403SDave Cobbley            os.ftruncate(sparse.fileno(), self.size * 1024)
502eb8dc403SDave Cobbley
503eb8dc403SDave Cobbley        label_str = ""
504eb8dc403SDave Cobbley        if self.label:
505eb8dc403SDave Cobbley            label_str = "-L %s" % self.label
506eb8dc403SDave Cobbley
507eb8dc403SDave Cobbley        mkswap_cmd = "mkswap %s -U %s %s" % (label_str, self.fsuuid, path)
508eb8dc403SDave Cobbley        exec_native_cmd(mkswap_cmd, native_sysroot)
50990fd73cbSAndrew Geissler
51090fd73cbSAndrew Geissler    def check_for_Y2038_problem(self, rootfs, native_sysroot):
51190fd73cbSAndrew Geissler        """
51290fd73cbSAndrew Geissler        Check if the filesystem is affected by the Y2038 problem
51390fd73cbSAndrew Geissler        (Y2038 problem = 32 bit time_t overflow in January 2038)
51490fd73cbSAndrew Geissler        """
51590fd73cbSAndrew Geissler        def get_err_str(part):
51690fd73cbSAndrew Geissler            err = "The {} filesystem {} has no Y2038 support."
51790fd73cbSAndrew Geissler            if part.mountpoint:
51890fd73cbSAndrew Geissler                args = [part.fstype, "mounted at %s" % part.mountpoint]
51990fd73cbSAndrew Geissler            elif part.label:
52090fd73cbSAndrew Geissler                args = [part.fstype, "labeled '%s'" % part.label]
52190fd73cbSAndrew Geissler            elif part.part_name:
52290fd73cbSAndrew Geissler                args = [part.fstype, "in partition '%s'" % part.part_name]
52390fd73cbSAndrew Geissler            else:
52490fd73cbSAndrew Geissler                args = [part.fstype, "in partition %s" % part.num]
52590fd73cbSAndrew Geissler            return err.format(*args)
52690fd73cbSAndrew Geissler
52790fd73cbSAndrew Geissler        # ext2 and ext3 are always affected by the Y2038 problem
52890fd73cbSAndrew Geissler        if self.fstype in ["ext2", "ext3"]:
52990fd73cbSAndrew Geissler            logger.warn(get_err_str(self))
53090fd73cbSAndrew Geissler            return
53190fd73cbSAndrew Geissler
53290fd73cbSAndrew Geissler        ret, out = exec_native_cmd("dumpe2fs %s" % rootfs, native_sysroot)
53390fd73cbSAndrew Geissler
53490fd73cbSAndrew Geissler        # if ext4 is affected by the Y2038 problem depends on the inode size
53590fd73cbSAndrew Geissler        for line in out.splitlines():
53690fd73cbSAndrew Geissler            if line.startswith("Inode size:"):
53790fd73cbSAndrew Geissler                size = int(line.split(":")[1].strip())
53890fd73cbSAndrew Geissler                if size < 256:
53990fd73cbSAndrew Geissler                    logger.warn("%s Inodes (of size %d) are too small." %
54090fd73cbSAndrew Geissler                                (get_err_str(self), size))
54190fd73cbSAndrew Geissler                break
54290fd73cbSAndrew Geissler
543