@@ -9,6 +9,7 @@ RDEPENDS:${PN} = "nativesdk-qemu nativesdk-unfs3 nativesdk-pseudo \
LIC_FILES_CHKSUM = "file://${COREBASE}/scripts/runqemu;beginline=5;endline=10;md5=ac2b489a58739c7628a2604698db5e7f"
SRC_URI = "file://${COREBASE}/scripts/runqemu \
+ file://${COREBASE}/scripts/lib/pseudo_rootfs_utils.py \
file://${COREBASE}/scripts/runqemu-addptable2image \
file://${COREBASE}/scripts/runqemu-gen-tapdevs \
file://${COREBASE}/scripts/runqemu-ifup \
@@ -30,4 +31,6 @@ do_install() {
install -d ${D}${bindir}
install -m 0755 ${S}${COREBASE}/scripts/oe-* ${D}${bindir}/
install -m 0755 ${S}${COREBASE}/scripts/runqemu* ${D}${bindir}/
+ # The runqemu-* wrappers import this module from their own directory.
+ install -m 0644 ${S}${COREBASE}/scripts/lib/pseudo_rootfs_utils.py ${D}${bindir}/
}
new file mode 100644
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+#
+# Helpers for preparing pseudo-managed rootfs trees (NFS booting, SDK/rootfs
+# extraction, target deploy).
+#
+# SPDX-License-Identifier: GPL-2.0-only
+
+"""Extract rootfs tarballs and locate their pseudo state for NFS booting."""
+
+import os
+import subprocess
+from pathlib import Path
+
+
+class PseudoRootfsError(Exception):
+ """Raised when a pseudo-managed rootfs cannot be prepared or exported."""
+
+
+def pseudo_native_environment():
+ """Return the pseudo native environment (PSEUDO and OECORE_NATIVE_SYSROOT), from the
+ qemu-helper-native recipe which provides a pseudo binary usable outside a recipe sysroot."""
+ native_sysroot = os.environ.get('OECORE_NATIVE_SYSROOT')
+ if not native_sysroot:
+ try:
+ import bb.tinfoil
+ except ImportError as exc:
+ raise PseudoRootfsError(
+ 'Unable to import bitbake.\n'
+ 'Did you forget to source your build system environment setup script?') from exc
+ try:
+ with bb.tinfoil.Tinfoil() as tinfoil:
+ tinfoil.prepare(quiet=2)
+ native_sysroot = tinfoil.parse_recipe('qemu-helper-native').getVar('STAGING_DIR_NATIVE')
+ except Exception as exc:
+ raise PseudoRootfsError('Unable to set up the qemu-helper-native sysroot') from exc
+
+ if not native_sysroot or not os.path.exists(native_sysroot):
+ raise PseudoRootfsError("%s doesn't exist" % native_sysroot)
+
+ environment = {'OECORE_NATIVE_SYSROOT': native_sysroot}
+ environment['PSEUDO'] = os.path.join(native_sysroot, 'usr', 'bin', 'pseudo')
+ return environment
+
+
+def _tar_options(rootfs_tarball):
+ tar_extract_options = {
+ '.tar.xz': '-xJf',
+ '.tar.bz2': '-xjf',
+ '.tar.gz': '-xzf',
+ '.tar.zst': '--zstd -xf',
+ '.tar': '-xf',
+ }
+ for extension, option in tar_extract_options.items():
+ if rootfs_tarball.endswith(extension):
+ return ['--numeric-owner', *option.split()]
+ raise PseudoRootfsError(
+ 'Unable to determine sdk tarball format\n'
+ 'Accepted types: .tar / .tar.gz / .tar.bz2 / .tar.xz / .tar.zst')
+
+
+def pseudo_state_dir(rootfs_dir):
+ """Return the pseudo database location associated with an extracted rootfs."""
+ return os.path.realpath(rootfs_dir) + '.pseudo_state'
+
+
+def extract_sdk_rootfs(rootfs_tarball, rootfs_dir, pseudo_cmd, environment):
+ """Extract a rootfs tarball under pseudo and return its absolute directory.
+
+ pseudo_cmd is the pseudo invocation prefix, e.g. a recipe's own
+ [FAKEROOTCMD] or [pseudo, '-P', native_sysroot_usr] from
+ pseudo_native_environment(). environment supplies the matching pseudo
+ database/env vars (e.g. a parsed FAKEROOTENV, or pseudo_native_environment()
+ itself); PSEUDO_LOCALSTATEDIR/PSEUDO_INCLUDE_PATHS are always overridden
+ here to point at rootfs_dir's own pseudo state, regardless of what's
+ already set in environment.
+ """
+ if not os.path.exists(rootfs_tarball):
+ raise PseudoRootfsError("sdk tarball '%s' does not exist" % rootfs_tarball)
+
+ rootfs_tarball = os.path.realpath(rootfs_tarball)
+ rootfs_dir = os.path.realpath(rootfs_dir)
+ tar_options = _tar_options(rootfs_tarball)
+ state_dir = pseudo_state_dir(rootfs_dir)
+ debug_image = '-dbg' in os.path.basename(rootfs_tarball)
+
+ if os.path.exists(state_dir) and not debug_image:
+ raise PseudoRootfsError(
+ '%s already exists!\n'
+ 'Please delete the rootfs tree and pseudo directory manually\n'
+ 'if this is really what you want.' % state_dir)
+
+ os.makedirs(rootfs_dir, exist_ok=True)
+ os.makedirs(state_dir, exist_ok=True)
+ Path(state_dir, 'pseudo.pid').touch()
+
+ environment = dict(environment)
+ environment['PSEUDO_LOCALSTATEDIR'] = state_dir
+ environment['PSEUDO_INCLUDE_PATHS'] = rootfs_dir
+
+ command = list(pseudo_cmd) + ['tar', '-C', rootfs_dir] + tar_options + [rootfs_tarball]
+ print('Extracting rootfs tarball using pseudo...')
+ print(' '.join(command))
+ try:
+ subprocess.run(command, env=environment, check=True)
+ except subprocess.CalledProcessError as exc:
+ raise PseudoRootfsError('Failed to extract rootfs tarball') from exc
+
+ if len(os.listdir(rootfs_dir)) < 4:
+ print("Warning: I don't see many files in %s" % rootfs_dir)
+ print('Please double-check the extraction worked as intended')
+ else:
+ print('SDK image successfully extracted to %s' % rootfs_dir)
+ return rootfs_dir
@@ -1,104 +1,30 @@
-#!/bin/bash
-#
-# This utility extracts an SDK image tarball using pseudo, and stores
-# the pseudo database in var/pseudo within the rootfs. If you want to
-# boot QEMU using an nfsroot, you *must* use this script to create the
-# rootfs to ensure it is done correctly with pseudo.
-#
-# Copyright (c) 2010 Intel Corp.
+#!/usr/bin/env python3
#
# SPDX-License-Identifier: GPL-2.0-only
-#
-function usage() {
- echo "Usage: $0 <image-tarball> <extract-dir>"
-}
+import os
+import sys
-if [ $# -ne 2 ]; then
- usage
- exit 1
-fi
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib'))
-SYSROOT_SETUP_SCRIPT=`which oe-find-native-sysroot 2> /dev/null`
-if [ -z "$SYSROOT_SETUP_SCRIPT" ]; then
- echo "Error: Unable to find the oe-find-native-sysroot script"
- echo "Did you forget to source your build system environment setup script?"
- exit 1
-fi
-. $SYSROOT_SETUP_SCRIPT qemu-helper-native
-PSEUDO_OPTS="-P $OECORE_NATIVE_SYSROOT/usr"
+from pseudo_rootfs_utils import PseudoRootfsError, extract_sdk_rootfs, pseudo_native_environment
-ROOTFS_TARBALL=$1
-SDK_ROOTFS_DIR=$2
-if [ ! -e "$ROOTFS_TARBALL" ]; then
- echo "Error: sdk tarball '$ROOTFS_TARBALL' does not exist"
- usage
- exit 1
-fi
+def main():
+ argv = sys.argv[1:]
+ if len(argv) != 2:
+ print('Usage: %s <image-tarball> <extract-dir>' % sys.argv[0])
+ return 1
+ try:
+ environment = pseudo_native_environment()
+ pseudo_cmd = [environment['PSEUDO'], '-P',
+ os.path.join(environment['OECORE_NATIVE_SYSROOT'], 'usr')]
+ extract_sdk_rootfs(*argv, pseudo_cmd, environment)
+ except PseudoRootfsError as exc:
+ print('Error: %s' % exc)
+ return 1
+ return 0
-# Convert SDK_ROOTFS_DIR to a full pathname
-if [[ ${SDK_ROOTFS_DIR:0:1} != "/" ]]; then
- SDK_ROOTFS_DIR=$(readlink -f $(pwd)/$SDK_ROOTFS_DIR)
-fi
-TAR_OPTS=""
-if [[ "$ROOTFS_TARBALL" =~ tar\.xz$ ]]; then
- TAR_OPTS="--numeric-owner -xJf"
-fi
-if [[ "$ROOTFS_TARBALL" =~ tar\.bz2$ ]]; then
- TAR_OPTS="--numeric-owner -xjf"
-fi
-if [[ "$ROOTFS_TARBALL" =~ tar\.gz$ ]]; then
- TAR_OPTS="--numeric-owner -xzf"
-fi
-if [[ "$ROOTFS_TARBALL" =~ tar\.zst$ ]]; then
- TAR_OPTS="--numeric-owner --zstd -xf"
-fi
-if [[ "$ROOTFS_TARBALL" =~ \.tar$ ]]; then
- TAR_OPTS="--numeric-owner -xf"
-fi
-if [ -z "$TAR_OPTS" ]; then
- echo "Error: Unable to determine sdk tarball format"
- echo "Accepted types: .tar / .tar.gz / .tar.bz2 / .tar.xz / tar.zst"
- exit 1
-fi
-
-if [ ! -d "$SDK_ROOTFS_DIR" ]; then
- echo "Creating directory $SDK_ROOTFS_DIR"
- mkdir -p "$SDK_ROOTFS_DIR"
-fi
-
-pseudo_state_dir="$SDK_ROOTFS_DIR/../$(basename "$SDK_ROOTFS_DIR").pseudo_state"
-pseudo_state_dir="$(readlink -f $pseudo_state_dir)"
-
-debug_image="`echo $ROOTFS_TARBALL | grep '\-dbg\.rootfs\.tar'`"
-
-if [ -e "$pseudo_state_dir" -a -z "$debug_image" ]; then
- echo "Error: $pseudo_state_dir already exists!"
- echo "Please delete the rootfs tree and pseudo directory manually"
- echo "if this is really what you want."
- exit 1
-fi
-
-mkdir -p "$pseudo_state_dir"
-touch "$pseudo_state_dir/pseudo.pid"
-PSEUDO_LOCALSTATEDIR="$pseudo_state_dir"
-export PSEUDO_LOCALSTATEDIR
-PSEUDO_INCLUDE_PATHS="$SDK_ROOTFS_DIR"
-export PSEUDO_INCLUDE_PATHS
-
-echo "Extracting rootfs tarball using pseudo..."
-echo "$PSEUDO $PSEUDO_OPTS tar -C \"$SDK_ROOTFS_DIR\" $TAR_OPTS \"$ROOTFS_TARBALL\""
-$PSEUDO $PSEUDO_OPTS tar -C "$SDK_ROOTFS_DIR" $TAR_OPTS "$ROOTFS_TARBALL"
-
-DIRCHECK=`ls -l "$SDK_ROOTFS_DIR" | wc -l`
-if [ "$DIRCHECK" -lt 5 ]; then
- echo "Warning: I don't see many files in $SDK_ROOTFS_DIR"
- echo "Please double-check the extraction worked as intended"
- exit 0
-fi
-
-echo "SDK image successfully extracted to $SDK_ROOTFS_DIR"
-
-exit 0
+if __name__ == "__main__":
+ sys.exit(main())