From: AdrianF <adrian.freihofer@siemens.com>
To: openembedded-core@lists.openembedded.org
Cc: Adrian Freihofer <adrian.freihofer@siemens.com>
Subject: [PATCH v2 15/25] runqemu-extract-sdk: refactor in Python
Date: Sun, 30 Aug 2026 23:48:37 +0200 [thread overview]
Message-ID: <20260830214912.1346063-16-adrian.freihofer@siemens.com> (raw)
In-Reply-To: <20260830214912.1346063-1-adrian.freihofer@siemens.com>
From: Adrian Freihofer <adrian.freihofer@siemens.com>
Move the pseudo-backed rootfs extraction logic into a reusable Python
module while preserving the existing command interface.
Install the module with qemu-helper so the wrapper also works from an SDK.
AI-Generated: Uses GitHub Copilot
Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com>
---
.../qemu/nativesdk-qemu-helper_1.0.bb | 3 +
scripts/lib/runqemu_utils.py | 124 ++++++++++++++++++
| 103 +--------------
3 files changed, 133 insertions(+), 97 deletions(-)
create mode 100644 scripts/lib/runqemu_utils.py
diff --git a/meta/recipes-devtools/qemu/nativesdk-qemu-helper_1.0.bb b/meta/recipes-devtools/qemu/nativesdk-qemu-helper_1.0.bb
index e1f343989a..16fc07fadf 100644
--- a/meta/recipes-devtools/qemu/nativesdk-qemu-helper_1.0.bb
+++ b/meta/recipes-devtools/qemu/nativesdk-qemu-helper_1.0.bb
@@ -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/runqemu_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/runqemu_utils.py ${D}${bindir}/
}
diff --git a/scripts/lib/runqemu_utils.py b/scripts/lib/runqemu_utils.py
new file mode 100644
index 0000000000..dff0ca8d3a
--- /dev/null
+++ b/scripts/lib/runqemu_utils.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+#
+# Helpers shared by runqemu and NFS-rootfs preparation tools.
+#
+# SPDX-License-Identifier: GPL-2.0-only
+
+"""Extract and export rootfs tarballs for NFS booting."""
+
+import os
+import subprocess
+import sys
+
+
+class RunQemuRootfsError(Exception):
+ """Raised when an NFS rootfs cannot be prepared or exported."""
+
+
+def native_environment():
+ """Return the qemu-helper-native environment set by oe-find-native-sysroot."""
+ command = '''
+ helper=$(command -v oe-find-native-sysroot) || exit 127
+ . "$helper" qemu-helper-native >/dev/null
+ env -0
+ printf 'PSEUDO=%s\\0OECORE_NATIVE_SYSROOT=%s\\0' "$PSEUDO" "$OECORE_NATIVE_SYSROOT"
+ '''
+ result = subprocess.run(['bash', '-c', command], capture_output=True)
+ if result.returncode:
+ if result.returncode == 127:
+ raise RunQemuRootfsError(
+ 'Unable to find the oe-find-native-sysroot script.\n'
+ 'Did you forget to source your build system environment setup script?')
+ raise RunQemuRootfsError(
+ result.stderr.decode(errors='replace').strip() or
+ 'Unable to set up the qemu-helper-native sysroot')
+
+ environment = {}
+ for entry in result.stdout.split(b'\0'):
+ if b'=' in entry:
+ key, value = entry.split(b'=', 1)
+ environment[key.decode()] = value.decode()
+ return environment
+
+
+def _tar_options(rootfs_tarball):
+ if rootfs_tarball.endswith('.tar.xz'):
+ return ['--numeric-owner', '-xJf']
+ if rootfs_tarball.endswith('.tar.bz2'):
+ return ['--numeric-owner', '-xjf']
+ if rootfs_tarball.endswith('.tar.gz'):
+ return ['--numeric-owner', '-xzf']
+ if rootfs_tarball.endswith('.tar.zst'):
+ return ['--numeric-owner', '--zstd', '-xf']
+ if rootfs_tarball.endswith('.tar'):
+ return ['--numeric-owner', '-xf']
+ raise RunQemuRootfsError(
+ '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."""
+ rootfs_dir = os.path.realpath(rootfs_dir)
+ return os.path.join(os.path.dirname(rootfs_dir),
+ os.path.basename(rootfs_dir) + '.pseudo_state')
+
+
+def extract_sdk_rootfs(rootfs_tarball, rootfs_dir):
+ """Extract a rootfs tarball under pseudo and return its absolute directory."""
+ if not os.path.exists(rootfs_tarball):
+ raise RunQemuRootfsError("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 RunQemuRootfsError(
+ '%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)
+ open(os.path.join(state_dir, 'pseudo.pid'), 'a').close()
+
+ environment = native_environment()
+ environment['PSEUDO_LOCALSTATEDIR'] = state_dir
+ environment['PSEUDO_INCLUDE_PATHS'] = rootfs_dir
+ pseudo = environment.get('PSEUDO')
+ native_sysroot = environment.get('OECORE_NATIVE_SYSROOT')
+ if not pseudo or not native_sysroot:
+ raise RunQemuRootfsError('qemu-helper-native did not provide pseudo')
+
+ command = [pseudo, '-P', os.path.join(native_sysroot, 'usr'), 'tar', '-C', rootfs_dir]
+ command.extend(tar_options)
+ command.append(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 RunQemuRootfsError('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
+
+
+def extract_sdk_main(argv=None):
+ argv = sys.argv[1:] if argv is None else argv
+ if len(argv) != 2:
+ print('Usage: %s <image-tarball> <extract-dir>' % sys.argv[0])
+ return 1
+ try:
+ extract_sdk_rootfs(*argv)
+ except RunQemuRootfsError as exc:
+ print('Error: %s' % exc)
+ return 1
+ return 0
--git a/scripts/runqemu-extract-sdk b/scripts/runqemu-extract-sdk
index db9813e1dc..6cad2fdf90 100755
--- a/scripts/runqemu-extract-sdk
+++ b/scripts/runqemu-extract-sdk
@@ -1,104 +1,13 @@
-#!/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 runqemu_utils import extract_sdk_main
-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
-
-# 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
+sys.exit(extract_sdk_main())
--
2.55.0
next prev parent reply other threads:[~2026-08-30 21:49 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-30 21:48 [PATCH v2 00/25] devtool: ide-sdk: NFS/slirp support, deploy filtering, and robustness fixes AdrianF
2026-08-30 21:48 ` [PATCH v2 01/25] runqemu-extract-sdk: set PSEUDO_INCLUDE_PATHS for the extraction AdrianF
2026-08-30 21:48 ` [PATCH v2 02/25] devtool: ide-sdk: dedupe solib_search_path entries AdrianF
2026-09-03 11:18 ` [OE-core] " Richard Purdie
2026-09-03 16:06 ` Freihofer, Adrian
2026-09-03 20:21 ` Richard Purdie
2026-08-30 21:48 ` [PATCH v2 03/25] devtool: ide-sdk: VSCode IntelliSense for rootfs-dbg sources AdrianF
2026-08-30 21:48 ` [PATCH v2 04/25] cpp-example: fix stuck breakpoints when attaching and daemonize properly AdrianF
2026-08-30 21:48 ` [PATCH v2 05/25] devtool: ide-sdk: auto-write image debug settings to bbappend AdrianF
2026-08-30 21:48 ` [PATCH v2 06/25] oe-selftest: devtool ide-sdk: adapt tests for auto-written image debug settings AdrianF
2026-08-30 21:48 ` [PATCH v2 07/25] oeqa: QemuTarget: set use_slirp when slirp is in runqemuparams AdrianF
2026-08-30 21:48 ` [PATCH v2 08/25] devtool: ide-sdk: support runqemu slirp AdrianF
2026-08-30 21:48 ` [PATCH v2 09/25] devtool: ide-sdk: auto-disable ssh host key checking for loopback targets AdrianF
2026-08-30 21:48 ` [PATCH v2 10/25] oe-selftest: devtool ide-sdk: add slirp networking test AdrianF
2026-08-30 21:48 ` [PATCH v2 11/25] devtool: deploy-target: add --package/--file-glob filters AdrianF
2026-08-30 22:11 ` Patchtest results for " patchtest
2026-08-30 21:48 ` [PATCH v2 12/25] oe-selftest: devtool deploy-target: test " AdrianF
2026-08-30 21:48 ` [PATCH v2 13/25] devtool: ide-sdk: forward --package/--file-glob deploy filters AdrianF
2026-08-30 21:48 ` [PATCH v2 14/25] oe-selftest: devtool ide-sdk: cover --package filters AdrianF
2026-08-30 21:48 ` AdrianF [this message]
2026-09-03 11:36 ` [OE-core] [PATCH v2 15/25] runqemu-extract-sdk: refactor in Python Richard Purdie
2026-08-30 21:48 ` [PATCH v2 16/25] runqemu-export-rootfs: " AdrianF
2026-08-30 21:48 ` [PATCH v2 17/25] devtool: deploy: split ssh deployment into a separate function AdrianF
2026-08-30 21:48 ` [PATCH v2 18/25] devtool: deploy-target: allow deploying directly into a local rootfs AdrianF
2026-08-30 21:48 ` [PATCH v2 19/25] oe-selftest: devtool deploy-target: test deploying into a local rootfs path AdrianF
2026-08-30 21:48 ` [PATCH v2 20/25] oe-selftest: tinfoil: test prepared task runner AdrianF
2026-08-30 21:48 ` [PATCH v2 21/25] devtool: ide-sdk: run do_install through BitBake AdrianF
2026-08-30 21:48 ` [PATCH v2 22/25] oe-selftest: devtool ide-sdk: test install task AdrianF
2026-08-30 21:48 ` [PATCH v2 23/25] devtool: ide-sdk: support NFS rootfs AdrianF
2026-08-30 21:48 ` [PATCH v2 24/25] oe-selftest: devtool ide-sdk: test NFS debug rootfs AdrianF
2026-08-30 21:48 ` [PATCH v2 25/25] devtool: ide-sdk: fix GDB loading stale libs instead of recipe's own build AdrianF
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260830214912.1346063-16-adrian.freihofer@siemens.com \
--to=adrian.freihofer@siemens.com \
--cc=openembedded-core@lists.openembedded.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).