xref: /OK3568_Linux_fs/yocto/poky/meta/lib/oe/rootfs.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#
2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
3*4882a593Smuzhiyun#
4*4882a593Smuzhiyunfrom abc import ABCMeta, abstractmethod
5*4882a593Smuzhiyunfrom oe.utils import execute_pre_post_process
6*4882a593Smuzhiyunfrom oe.package_manager import *
7*4882a593Smuzhiyunfrom oe.manifest import *
8*4882a593Smuzhiyunimport oe.path
9*4882a593Smuzhiyunimport shutil
10*4882a593Smuzhiyunimport os
11*4882a593Smuzhiyunimport subprocess
12*4882a593Smuzhiyunimport re
13*4882a593Smuzhiyun
14*4882a593Smuzhiyunclass Rootfs(object, metaclass=ABCMeta):
15*4882a593Smuzhiyun    """
16*4882a593Smuzhiyun    This is an abstract class. Do not instantiate this directly.
17*4882a593Smuzhiyun    """
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun    def __init__(self, d, progress_reporter=None, logcatcher=None):
20*4882a593Smuzhiyun        self.d = d
21*4882a593Smuzhiyun        self.pm = None
22*4882a593Smuzhiyun        self.image_rootfs = self.d.getVar('IMAGE_ROOTFS')
23*4882a593Smuzhiyun        self.deploydir = self.d.getVar('IMGDEPLOYDIR')
24*4882a593Smuzhiyun        self.progress_reporter = progress_reporter
25*4882a593Smuzhiyun        self.logcatcher = logcatcher
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun        self.install_order = Manifest.INSTALL_ORDER
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun    @abstractmethod
30*4882a593Smuzhiyun    def _create(self):
31*4882a593Smuzhiyun        pass
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun    @abstractmethod
34*4882a593Smuzhiyun    def _get_delayed_postinsts(self):
35*4882a593Smuzhiyun        pass
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun    @abstractmethod
38*4882a593Smuzhiyun    def _save_postinsts(self):
39*4882a593Smuzhiyun        pass
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun    @abstractmethod
42*4882a593Smuzhiyun    def _log_check(self):
43*4882a593Smuzhiyun        pass
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun    def _log_check_common(self, type, match):
46*4882a593Smuzhiyun        # Ignore any lines containing log_check to avoid recursion, and ignore
47*4882a593Smuzhiyun        # lines beginning with a + since sh -x may emit code which isn't
48*4882a593Smuzhiyun        # actually executed, but may contain error messages
49*4882a593Smuzhiyun        excludes = [ 'log_check', r'^\+' ]
50*4882a593Smuzhiyun        if hasattr(self, 'log_check_expected_regexes'):
51*4882a593Smuzhiyun            excludes.extend(self.log_check_expected_regexes)
52*4882a593Smuzhiyun        # Insert custom log_check excludes
53*4882a593Smuzhiyun        excludes += [x for x in (self.d.getVar("IMAGE_LOG_CHECK_EXCLUDES") or "").split(" ") if x]
54*4882a593Smuzhiyun        excludes = [re.compile(x) for x in excludes]
55*4882a593Smuzhiyun        r = re.compile(match)
56*4882a593Smuzhiyun        log_path = self.d.expand("${T}/log.do_rootfs")
57*4882a593Smuzhiyun        messages = []
58*4882a593Smuzhiyun        with open(log_path, 'r') as log:
59*4882a593Smuzhiyun            for line in log:
60*4882a593Smuzhiyun                if self.logcatcher and self.logcatcher.contains(line.rstrip()):
61*4882a593Smuzhiyun                    continue
62*4882a593Smuzhiyun                for ee in excludes:
63*4882a593Smuzhiyun                    m = ee.search(line)
64*4882a593Smuzhiyun                    if m:
65*4882a593Smuzhiyun                        break
66*4882a593Smuzhiyun                if m:
67*4882a593Smuzhiyun                    continue
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun                m = r.search(line)
70*4882a593Smuzhiyun                if m:
71*4882a593Smuzhiyun                    messages.append('[log_check] %s' % line)
72*4882a593Smuzhiyun        if messages:
73*4882a593Smuzhiyun            if len(messages) == 1:
74*4882a593Smuzhiyun                msg = '1 %s message' % type
75*4882a593Smuzhiyun            else:
76*4882a593Smuzhiyun                msg = '%d %s messages' % (len(messages), type)
77*4882a593Smuzhiyun            msg = '[log_check] %s: found %s in the logfile:\n%s' % \
78*4882a593Smuzhiyun                (self.d.getVar('PN'), msg, ''.join(messages))
79*4882a593Smuzhiyun            if type == 'error':
80*4882a593Smuzhiyun                bb.fatal(msg)
81*4882a593Smuzhiyun            else:
82*4882a593Smuzhiyun                bb.warn(msg)
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun    def _log_check_warn(self):
85*4882a593Smuzhiyun        self._log_check_common('warning', '^(warn|Warn|WARNING:)')
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun    def _log_check_error(self):
88*4882a593Smuzhiyun        self._log_check_common('error', self.log_check_regex)
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun    def _insert_feed_uris(self):
91*4882a593Smuzhiyun        if bb.utils.contains("IMAGE_FEATURES", "package-management",
92*4882a593Smuzhiyun                         True, False, self.d):
93*4882a593Smuzhiyun            self.pm.insert_feeds_uris(self.d.getVar('PACKAGE_FEED_URIS') or "",
94*4882a593Smuzhiyun                self.d.getVar('PACKAGE_FEED_BASE_PATHS') or "",
95*4882a593Smuzhiyun                self.d.getVar('PACKAGE_FEED_ARCHS'))
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun    """
99*4882a593Smuzhiyun    The _cleanup() method should be used to clean-up stuff that we don't really
100*4882a593Smuzhiyun    want to end up on target. For example, in the case of RPM, the DB locks.
101*4882a593Smuzhiyun    The method is called, once, at the end of create() method.
102*4882a593Smuzhiyun    """
103*4882a593Smuzhiyun    @abstractmethod
104*4882a593Smuzhiyun    def _cleanup(self):
105*4882a593Smuzhiyun        pass
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun    def _setup_dbg_rootfs(self, dirs):
108*4882a593Smuzhiyun        gen_debugfs = self.d.getVar('IMAGE_GEN_DEBUGFS') or '0'
109*4882a593Smuzhiyun        if gen_debugfs != '1':
110*4882a593Smuzhiyun           return
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun        bb.note("  Renaming the original rootfs...")
113*4882a593Smuzhiyun        try:
114*4882a593Smuzhiyun            shutil.rmtree(self.image_rootfs + '-orig')
115*4882a593Smuzhiyun        except:
116*4882a593Smuzhiyun            pass
117*4882a593Smuzhiyun        bb.utils.rename(self.image_rootfs, self.image_rootfs + '-orig')
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun        bb.note("  Creating debug rootfs...")
120*4882a593Smuzhiyun        bb.utils.mkdirhier(self.image_rootfs)
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun        bb.note("  Copying back package database...")
123*4882a593Smuzhiyun        for dir in dirs:
124*4882a593Smuzhiyun            if not os.path.isdir(self.image_rootfs + '-orig' + dir):
125*4882a593Smuzhiyun                continue
126*4882a593Smuzhiyun            bb.utils.mkdirhier(self.image_rootfs + os.path.dirname(dir))
127*4882a593Smuzhiyun            shutil.copytree(self.image_rootfs + '-orig' + dir, self.image_rootfs + dir, symlinks=True)
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun        # Copy files located in /usr/lib/debug or /usr/src/debug
130*4882a593Smuzhiyun        for dir in ["/usr/lib/debug", "/usr/src/debug"]:
131*4882a593Smuzhiyun            src = self.image_rootfs + '-orig' + dir
132*4882a593Smuzhiyun            if os.path.exists(src):
133*4882a593Smuzhiyun                dst = self.image_rootfs + dir
134*4882a593Smuzhiyun                bb.utils.mkdirhier(os.path.dirname(dst))
135*4882a593Smuzhiyun                shutil.copytree(src, dst)
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun        # Copy files with suffix '.debug' or located in '.debug' dir.
138*4882a593Smuzhiyun        for root, dirs, files in os.walk(self.image_rootfs + '-orig'):
139*4882a593Smuzhiyun            relative_dir = root[len(self.image_rootfs + '-orig'):]
140*4882a593Smuzhiyun            for f in files:
141*4882a593Smuzhiyun                if f.endswith('.debug') or '/.debug' in relative_dir:
142*4882a593Smuzhiyun                    bb.utils.mkdirhier(self.image_rootfs + relative_dir)
143*4882a593Smuzhiyun                    shutil.copy(os.path.join(root, f),
144*4882a593Smuzhiyun                                self.image_rootfs + relative_dir)
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun        bb.note("  Install complementary '*-dbg' packages...")
147*4882a593Smuzhiyun        self.pm.install_complementary('*-dbg')
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun        if self.d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-with-srcpkg':
150*4882a593Smuzhiyun            bb.note("  Install complementary '*-src' packages...")
151*4882a593Smuzhiyun            self.pm.install_complementary('*-src')
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun        """
154*4882a593Smuzhiyun        Install additional debug packages. Possibility to install additional packages,
155*4882a593Smuzhiyun        which are not automatically installed as complementary package of
156*4882a593Smuzhiyun        standard one, e.g. debug package of static libraries.
157*4882a593Smuzhiyun        """
158*4882a593Smuzhiyun        extra_debug_pkgs = self.d.getVar('IMAGE_INSTALL_DEBUGFS')
159*4882a593Smuzhiyun        if extra_debug_pkgs:
160*4882a593Smuzhiyun            bb.note("  Install extra debug packages...")
161*4882a593Smuzhiyun            self.pm.install(extra_debug_pkgs.split(), True)
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun        bb.note("  Rename debug rootfs...")
164*4882a593Smuzhiyun        try:
165*4882a593Smuzhiyun            shutil.rmtree(self.image_rootfs + '-dbg')
166*4882a593Smuzhiyun        except:
167*4882a593Smuzhiyun            pass
168*4882a593Smuzhiyun        bb.utils.rename(self.image_rootfs, self.image_rootfs + '-dbg')
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun        bb.note("  Restoring original rootfs...")
171*4882a593Smuzhiyun        bb.utils.rename(self.image_rootfs + '-orig', self.image_rootfs)
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun    def _exec_shell_cmd(self, cmd):
174*4882a593Smuzhiyun        fakerootcmd = self.d.getVar('FAKEROOT')
175*4882a593Smuzhiyun        if fakerootcmd is not None:
176*4882a593Smuzhiyun            exec_cmd = [fakerootcmd, cmd]
177*4882a593Smuzhiyun        else:
178*4882a593Smuzhiyun            exec_cmd = cmd
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun        try:
181*4882a593Smuzhiyun            subprocess.check_output(exec_cmd, stderr=subprocess.STDOUT)
182*4882a593Smuzhiyun        except subprocess.CalledProcessError as e:
183*4882a593Smuzhiyun            return("Command '%s' returned %d:\n%s" % (e.cmd, e.returncode, e.output))
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun        return None
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun    def create(self):
188*4882a593Smuzhiyun        bb.note("###### Generate rootfs #######")
189*4882a593Smuzhiyun        pre_process_cmds = self.d.getVar("ROOTFS_PREPROCESS_COMMAND")
190*4882a593Smuzhiyun        post_process_cmds = self.d.getVar("ROOTFS_POSTPROCESS_COMMAND")
191*4882a593Smuzhiyun        rootfs_post_install_cmds = self.d.getVar('ROOTFS_POSTINSTALL_COMMAND')
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun        execute_pre_post_process(self.d, pre_process_cmds)
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun        if self.progress_reporter:
196*4882a593Smuzhiyun            self.progress_reporter.next_stage()
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun        # call the package manager dependent create method
199*4882a593Smuzhiyun        self._create()
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun        sysconfdir = self.image_rootfs + self.d.getVar('sysconfdir')
202*4882a593Smuzhiyun        bb.utils.mkdirhier(sysconfdir)
203*4882a593Smuzhiyun        with open(sysconfdir + "/version", "w+") as ver:
204*4882a593Smuzhiyun            ver.write(self.d.getVar('BUILDNAME') + "\n")
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun        execute_pre_post_process(self.d, rootfs_post_install_cmds)
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun        self.pm.run_intercepts()
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun        execute_pre_post_process(self.d, post_process_cmds)
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun        if self.progress_reporter:
213*4882a593Smuzhiyun            self.progress_reporter.next_stage()
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun        if bb.utils.contains("IMAGE_FEATURES", "read-only-rootfs",
216*4882a593Smuzhiyun                         True, False, self.d) and \
217*4882a593Smuzhiyun           not bb.utils.contains("IMAGE_FEATURES",
218*4882a593Smuzhiyun                         "read-only-rootfs-delayed-postinsts",
219*4882a593Smuzhiyun                         True, False, self.d):
220*4882a593Smuzhiyun            delayed_postinsts = self._get_delayed_postinsts()
221*4882a593Smuzhiyun            if delayed_postinsts is not None:
222*4882a593Smuzhiyun                bb.fatal("The following packages could not be configured "
223*4882a593Smuzhiyun                         "offline and rootfs is read-only: %s" %
224*4882a593Smuzhiyun                         delayed_postinsts)
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun        if self.d.getVar('USE_DEVFS') != "1":
227*4882a593Smuzhiyun            self._create_devfs()
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun        self._uninstall_unneeded()
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun        if self.progress_reporter:
232*4882a593Smuzhiyun            self.progress_reporter.next_stage()
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun        self._insert_feed_uris()
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun        self._run_ldconfig()
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun        if self.d.getVar('USE_DEPMOD') != "0":
239*4882a593Smuzhiyun            self._generate_kernel_module_deps()
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun        self._cleanup()
242*4882a593Smuzhiyun        self._log_check()
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun        if self.progress_reporter:
245*4882a593Smuzhiyun            self.progress_reporter.next_stage()
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun    def _uninstall_unneeded(self):
249*4882a593Smuzhiyun        # Remove the run-postinsts package if no delayed postinsts are found
250*4882a593Smuzhiyun        delayed_postinsts = self._get_delayed_postinsts()
251*4882a593Smuzhiyun        if delayed_postinsts is None:
252*4882a593Smuzhiyun            if os.path.exists(self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/init.d/run-postinsts")) or os.path.exists(self.d.expand("${IMAGE_ROOTFS}${systemd_system_unitdir}/run-postinsts.service")):
253*4882a593Smuzhiyun                self.pm.remove(["run-postinsts"])
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun        image_rorfs = bb.utils.contains("IMAGE_FEATURES", "read-only-rootfs",
256*4882a593Smuzhiyun                                        True, False, self.d)
257*4882a593Smuzhiyun        image_rorfs_force = self.d.getVar('FORCE_RO_REMOVE')
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun        if image_rorfs or image_rorfs_force == "1":
260*4882a593Smuzhiyun            # Remove components that we don't need if it's a read-only rootfs
261*4882a593Smuzhiyun            unneeded_pkgs = self.d.getVar("ROOTFS_RO_UNNEEDED").split()
262*4882a593Smuzhiyun            pkgs_installed = image_list_installed_packages(self.d)
263*4882a593Smuzhiyun            # Make sure update-alternatives is removed last. This is
264*4882a593Smuzhiyun            # because its database has to available while uninstalling
265*4882a593Smuzhiyun            # other packages, allowing alternative symlinks of packages
266*4882a593Smuzhiyun            # to be uninstalled or to be managed correctly otherwise.
267*4882a593Smuzhiyun            provider = self.d.getVar("VIRTUAL-RUNTIME_update-alternatives")
268*4882a593Smuzhiyun            pkgs_to_remove = sorted([pkg for pkg in pkgs_installed if pkg in unneeded_pkgs], key=lambda x: x == provider)
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun            # update-alternatives provider is removed in its own remove()
271*4882a593Smuzhiyun            # call because all package managers do not guarantee the packages
272*4882a593Smuzhiyun            # are removed in the order they given in the list (which is
273*4882a593Smuzhiyun            # passed to the command line). The sorting done earlier is
274*4882a593Smuzhiyun            # utilized to implement the 2-stage removal.
275*4882a593Smuzhiyun            if len(pkgs_to_remove) > 1:
276*4882a593Smuzhiyun                self.pm.remove(pkgs_to_remove[:-1], False)
277*4882a593Smuzhiyun            if len(pkgs_to_remove) > 0:
278*4882a593Smuzhiyun                self.pm.remove([pkgs_to_remove[-1]], False)
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun        if delayed_postinsts:
281*4882a593Smuzhiyun            self._save_postinsts()
282*4882a593Smuzhiyun            if image_rorfs:
283*4882a593Smuzhiyun                bb.warn("There are post install scripts "
284*4882a593Smuzhiyun                        "in a read-only rootfs")
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun        post_uninstall_cmds = self.d.getVar("ROOTFS_POSTUNINSTALL_COMMAND")
287*4882a593Smuzhiyun        execute_pre_post_process(self.d, post_uninstall_cmds)
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun        runtime_pkgmanage = bb.utils.contains("IMAGE_FEATURES", "package-management",
290*4882a593Smuzhiyun                                              True, False, self.d)
291*4882a593Smuzhiyun        if not runtime_pkgmanage:
292*4882a593Smuzhiyun            # Remove the package manager data files
293*4882a593Smuzhiyun            self.pm.remove_packaging_data()
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun    def _run_ldconfig(self):
296*4882a593Smuzhiyun        if self.d.getVar('LDCONFIGDEPEND'):
297*4882a593Smuzhiyun            bb.note("Executing: ldconfig -r " + self.image_rootfs + " -c new -v -X")
298*4882a593Smuzhiyun            self._exec_shell_cmd(['ldconfig', '-r', self.image_rootfs, '-c',
299*4882a593Smuzhiyun                                  'new', '-v', '-X'])
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun        image_rorfs = bb.utils.contains("IMAGE_FEATURES", "read-only-rootfs",
302*4882a593Smuzhiyun                                        True, False, self.d)
303*4882a593Smuzhiyun        ldconfig_in_features = bb.utils.contains("DISTRO_FEATURES", "ldconfig",
304*4882a593Smuzhiyun                                                 True, False, self.d)
305*4882a593Smuzhiyun        if image_rorfs or not ldconfig_in_features:
306*4882a593Smuzhiyun            ldconfig_cache_dir = os.path.join(self.image_rootfs, "var/cache/ldconfig")
307*4882a593Smuzhiyun            if os.path.exists(ldconfig_cache_dir):
308*4882a593Smuzhiyun                bb.note("Removing ldconfig auxiliary cache...")
309*4882a593Smuzhiyun                shutil.rmtree(ldconfig_cache_dir)
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun    def _check_for_kernel_modules(self, modules_dir):
312*4882a593Smuzhiyun        for root, dirs, files in os.walk(modules_dir, topdown=True):
313*4882a593Smuzhiyun            for name in files:
314*4882a593Smuzhiyun                found_ko = name.endswith((".ko", ".ko.gz", ".ko.xz", ".ko.zst"))
315*4882a593Smuzhiyun                if found_ko:
316*4882a593Smuzhiyun                    return found_ko
317*4882a593Smuzhiyun        return False
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun    def _generate_kernel_module_deps(self):
320*4882a593Smuzhiyun        modules_dir = os.path.join(self.image_rootfs, 'lib', 'modules')
321*4882a593Smuzhiyun        # if we don't have any modules don't bother to do the depmod
322*4882a593Smuzhiyun        if not self._check_for_kernel_modules(modules_dir):
323*4882a593Smuzhiyun            bb.note("No Kernel Modules found, not running depmod")
324*4882a593Smuzhiyun            return
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun        kernel_abi_ver_file = oe.path.join(self.d.getVar('PKGDATA_DIR'), "kernel-depmod",
327*4882a593Smuzhiyun                                           'kernel-abiversion')
328*4882a593Smuzhiyun        if not os.path.exists(kernel_abi_ver_file):
329*4882a593Smuzhiyun            bb.fatal("No kernel-abiversion file found (%s), cannot run depmod, aborting" % kernel_abi_ver_file)
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun        with open(kernel_abi_ver_file) as f:
332*4882a593Smuzhiyun            kernel_ver = f.read().strip(' \n')
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun        versioned_modules_dir = os.path.join(self.image_rootfs, modules_dir, kernel_ver)
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun        bb.utils.mkdirhier(versioned_modules_dir)
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun        self._exec_shell_cmd(['depmodwrapper', '-a', '-b', self.image_rootfs, kernel_ver])
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun    """
341*4882a593Smuzhiyun    Create devfs:
342*4882a593Smuzhiyun    * IMAGE_DEVICE_TABLE is the old name to an absolute path to a device table file
343*4882a593Smuzhiyun    * IMAGE_DEVICE_TABLES is a new name for a file, or list of files, seached
344*4882a593Smuzhiyun      for in the BBPATH
345*4882a593Smuzhiyun    If neither are specified then the default name of files/device_table-minimal.txt
346*4882a593Smuzhiyun    is searched for in the BBPATH (same as the old version.)
347*4882a593Smuzhiyun    """
348*4882a593Smuzhiyun    def _create_devfs(self):
349*4882a593Smuzhiyun        devtable_list = []
350*4882a593Smuzhiyun        devtable = self.d.getVar('IMAGE_DEVICE_TABLE')
351*4882a593Smuzhiyun        if devtable is not None:
352*4882a593Smuzhiyun            devtable_list.append(devtable)
353*4882a593Smuzhiyun        else:
354*4882a593Smuzhiyun            devtables = self.d.getVar('IMAGE_DEVICE_TABLES')
355*4882a593Smuzhiyun            if devtables is None:
356*4882a593Smuzhiyun                devtables = 'files/device_table-minimal.txt'
357*4882a593Smuzhiyun            for devtable in devtables.split():
358*4882a593Smuzhiyun                devtable_list.append("%s" % bb.utils.which(self.d.getVar('BBPATH'), devtable))
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun        for devtable in devtable_list:
361*4882a593Smuzhiyun            self._exec_shell_cmd(["makedevs", "-r",
362*4882a593Smuzhiyun                                  self.image_rootfs, "-D", devtable])
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun
365*4882a593Smuzhiyundef get_class_for_type(imgtype):
366*4882a593Smuzhiyun    import importlib
367*4882a593Smuzhiyun    mod = importlib.import_module('oe.package_manager.' + imgtype + '.rootfs')
368*4882a593Smuzhiyun    return mod.PkgRootfs
369*4882a593Smuzhiyun
370*4882a593Smuzhiyundef variable_depends(d, manifest_dir=None):
371*4882a593Smuzhiyun    img_type = d.getVar('IMAGE_PKGTYPE')
372*4882a593Smuzhiyun    cls = get_class_for_type(img_type)
373*4882a593Smuzhiyun    return cls._depends_list()
374*4882a593Smuzhiyun
375*4882a593Smuzhiyundef create_rootfs(d, manifest_dir=None, progress_reporter=None, logcatcher=None):
376*4882a593Smuzhiyun    env_bkp = os.environ.copy()
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun    img_type = d.getVar('IMAGE_PKGTYPE')
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun    cls = get_class_for_type(img_type)
381*4882a593Smuzhiyun    cls(d, manifest_dir, progress_reporter, logcatcher).create()
382*4882a593Smuzhiyun    os.environ.clear()
383*4882a593Smuzhiyun    os.environ.update(env_bkp)
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun
386*4882a593Smuzhiyundef image_list_installed_packages(d, rootfs_dir=None):
387*4882a593Smuzhiyun    # Theres no rootfs for baremetal images
388*4882a593Smuzhiyun    if bb.data.inherits_class('baremetal-image', d):
389*4882a593Smuzhiyun        return ""
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun    if not rootfs_dir:
392*4882a593Smuzhiyun        rootfs_dir = d.getVar('IMAGE_ROOTFS')
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun    img_type = d.getVar('IMAGE_PKGTYPE')
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun    import importlib
397*4882a593Smuzhiyun    cls = importlib.import_module('oe.package_manager.' + img_type)
398*4882a593Smuzhiyun    return cls.PMPkgsList(d, rootfs_dir).list_pkgs()
399*4882a593Smuzhiyun
400*4882a593Smuzhiyunif __name__ == "__main__":
401*4882a593Smuzhiyun    """
402*4882a593Smuzhiyun    We should be able to run this as a standalone script, from outside bitbake
403*4882a593Smuzhiyun    environment.
404*4882a593Smuzhiyun    """
405*4882a593Smuzhiyun    """
406*4882a593Smuzhiyun    TBD
407*4882a593Smuzhiyun    """
408