From 67177463b9c07c80e8d9a5dddf20eb87f1d1eb6a Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Tue, 25 Feb 2025 09:33:43 +0000 Subject: [PATCH 01/11] support arm64 chroot on amd64 host --- chroot/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/chroot/__init__.py b/chroot/__init__.py index dceb9d4..2f10eae 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -97,6 +97,9 @@ def __init__(self, mnt_profile: Dict[str, str], root: str = "/"): self.profile = mnt_profile + if "ARM_ON_AMD" in os.environ: + self.profile['/usr/bin/qemu-arm-static'] = "usr/bin" + self.path: Dict[str, str] = {} self.mounted: Dict[str, str] = {} for k, v in self.profile.items(): @@ -116,6 +119,8 @@ def mount(self) -> None: if is_mounted(chr_path): continue switch = self.profile['switch'] + if host_mnt.endswith("qemu-arm-static"): + switch = "-o" command = ['mount', switch] if switch == '-o': command.extend(['bind', host_mnt, chr_path]) From dde97ebd9b00c192bf07a011732c4d86c0070c11 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 26 Feb 2025 06:45:16 +0000 Subject: [PATCH 02/11] Hopefully this is close... --- chroot/__init__.py | 110 +++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 49 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index 2f10eae..3b0e966 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021 TurnkeyLinux +# Copyright (c) 2021-2025 TurnkeyLinux # # turnkey-chroot is open source software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -9,25 +9,31 @@ from os.path import abspath, join, realpath import shlex import subprocess +import shutil from contextlib import contextmanager from typing import Dict, Optional, Union, TypeVar, Generator, List, Any AnyPath = TypeVar('AnyPath', str, os.PathLike) -MNT_DEFAULT = { +MNT_DEFAULT = [ # Mounts 'devpts' and 'proc' type mounts into the chroot - 'switch': '-t', # use '-t' (type) switch with mount - 'proc' : 'proc', # label/mount_type: mount_point - 'devpts': 'dev/pts'} + ("-t", "proc", "proc"), + ("-t", "sysfs", "sys"), + ("-t", "devpts", "dev/pts"), + ] -MNT_FULL = { +MNT_FULL = [ # Bind mounts /dev, /sys, /proc & /run into the chroot - 'switch': '-o', # use '-o (bind)' (option) switch with mount - 'proc': 'proc', # label/host_mount: mount_point - 'dev': 'dev', - 'sys': 'sys', - 'run': 'run'} + ("--bind", "proc", "proc"), + ("--bind", "sys", "sys"), + ("--bind", "dev", "dev"), + ("--bind", "dev/pts", "dev/pts"), + ("--bind", "run", "run"), + ] + +MNT_ARM_ON_AMD = ( + "--bind", "proc/sys/fs/binfmt_misc", "proc/sys/fs/binfmt_misc") def debug(*s: Any) -> None: @@ -65,7 +71,7 @@ def is_mounted(path: AnyPath) -> bool: def mount( target: os.PathLike, environ: Optional[Dict[str, str]] = None, - mnt_profile: Optional[Dict[str, str]] = None + mnt_profile: Optional[list[tuple[str, str, str]]] = None ) -> Generator['Chroot', None, None]: '''magic mount context manager @@ -92,21 +98,23 @@ class MagicMounts: You *probably* don't want to use this object directly but rather the `mount` context manager, or the `Chroot` object. ''' - def __init__(self, mnt_profile: Dict[str, str], root: str = "/"): - root = os.fspath(abspath(root)) - + def __init__(self, + mnt_profile: list[tuple[str, str, str]], + root: str = "/", + qemu_arch_bin: str = ""): self.profile = mnt_profile - - if "ARM_ON_AMD" in os.environ: - self.profile['/usr/bin/qemu-arm-static'] = "usr/bin" - - self.path: Dict[str, str] = {} - self.mounted: Dict[str, str] = {} - for k, v in self.profile.items(): - if k != 'switch': - self.path[k] = join(root, v) - self.mounted[k] = False - + root = os.fspath(abspath(root)) + self.qemu_arch_static = () + if qemu_arch_bin: + self.qemu_arch_static = (f"/{qemu_arch_bin}", + join(root, qemu_arch_bin)) + self.paths = tuple() + self.mounted: dict[str, str] = {} + + for mount_item in sorted(self.profile): + for switch, host_mnt, chr_mnt in mount_item: + self.paths = tuple(*self.paths, (swtch, host_mnt, join(root, chr_mnt)) + self.mounted[host_mnt] = False self.mount() def mount(self) -> None: @@ -115,25 +123,17 @@ def mount(self) -> None: Raises: MountError: An error occured while trying to mount chroot ''' - for host_mnt, chr_path in self.path.items(): + for switch, host_mnt, chr_path in self.paths: if is_mounted(chr_path): continue - switch = self.profile['switch'] - if host_mnt.endswith("qemu-arm-static"): - switch = "-o" - command = ['mount', switch] - if switch == '-o': - command.extend(['bind', host_mnt, chr_path]) - elif switch == '-t': - command.extend([host_mnt, f'{host_mnt}-chroot', chr_path]) - else: - raise MountError( - f"Unknown switch passed to mount() method: '{switch}'.") try: - subprocess.run(command, check=True) + subprocess.run( + ['mount', switch, host_mnt, chr_path]. check=True) self.mounted[host_mnt] = True except subprocess.CalledProcessError as e: raise MountError(*e.args) from e + if self.qemu_arch_static: + shutil.copy(*self.qemu_arch_static) def umount(self) -> None: ''' un-mount this chroot @@ -141,11 +141,13 @@ def umount(self) -> None: Raises: MountError: An error occured while trying to un-mount chroot ''' + if self.qemu_arch_static: + os.remove(self.qemu_arch_static[-1]) command = ['umount', '-f'] - for mount in self.mounted.keys(): - if self.mounted[mount]: - subprocess.run([*command, self.path[mount]]) - self.mounted[mount] = False + for _, host_mnt, chr_mnt in reversed(self.paths): + if self.mounted[host_mnt]: + subprocess.run(["umount", "-f", chr_mnt]) + self.mounted[host_mnt] = False def __del__(self) -> None: self.umount() @@ -163,8 +165,8 @@ class Chroot: def __init__( self, newroot: AnyPath, environ: Optional[Dict[str, str]] = None, - mnt_profile: Optional[Dict[str, str]] = None): - + mnt_profile: Optional[list[tuple[str, str, str]]] = None + ): if environ is None: environ = {} self.environ = { @@ -173,11 +175,21 @@ def __init__( 'LC_ALL': 'C', 'PATH': "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/bin:/usr/sbin" } + self.qemu_arch_static = "" + if os.getenv('ARM_ON_AMD', ''): + # ideally we probably should be just adding binfmt to the existing + # profile - however, it's easier to just use bind mounts to ensure + # that chroot's proc/sys/fs/binfmt_misc is populated from host + mnt_profile = MNT_FULL.append(MNT_ARM_ON_AMD) + self.qemu_arch_static = "usr/bin/qemu-aarch64-static" + self.environ.update(environ) + self.profile = MNT_DEFAULT if not mnt_profile else mnt_profile - self.path: str = realpath(os.fspath(newroot)) - self.magicmounts = MagicMounts(self.profile, self.path) + self.chr_path: str = realpath(os.fspath(newroot)) + self.magicmounts = MagicMounts(self.profile, self.chr_path, + self.qemu_arch_static) def _prepare_command(self, *commands: str) -> List[str]: if '>' in commands or '<' in commands or '|' in commands: @@ -190,7 +202,7 @@ def _prepare_command(self, *commands: str) -> List[str]: except TypeError as e: raise ChrootError(f'failed to prepare command {command!r} for chroot') from e return [ - 'chroot', self.path, + 'chroot', self.chr_path, 'sh', '-c', ' '.join(quoted_commands) ] @@ -214,7 +226,7 @@ def system(self, command: Optional[str] = None) -> int: """ debug('chroot.system (args) => \x1b[34m', repr(command), '\x1b[0m') - command_chroot = ['chroot', self.path, '/bin/bash'] + command_chroot = ['chroot', self.chr_path, '/bin/bash'] if command: command_chroot.extend(['-c', command]) return subprocess.run(command_chroot, env=self.environ).returncode From 2b959090102b38b1af2077ac530344f810b24d6a Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 26 Feb 2025 18:12:32 +1100 Subject: [PATCH 03/11] linting/formatting --- chroot/__init__.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index 3b0e966..2265f4d 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -61,7 +61,7 @@ def is_mounted(path: AnyPath) -> bool: sep = b' ' if isinstance(raw_path, bytes) else ' ' with open('/proc/mounts', mode) as fob: for line in fob: - host, guest, *others = line.split(sep) + _, guest, *_ = line.split(sep) if guest == path: return True return False @@ -109,11 +109,15 @@ def __init__(self, self.qemu_arch_static = (f"/{qemu_arch_bin}", join(root, qemu_arch_bin)) self.paths = tuple() - self.mounted: dict[str, str] = {} + self.mounted: dict[str, bool] = {} for mount_item in sorted(self.profile): for switch, host_mnt, chr_mnt in mount_item: - self.paths = tuple(*self.paths, (swtch, host_mnt, join(root, chr_mnt)) + self.paths = tuple( + *self.paths, + # pyright "Expected 1 positional argument" here: (?!) + (switch, host_mnt, join(root,chr_mnt)) + ) self.mounted[host_mnt] = False self.mount() @@ -128,7 +132,8 @@ def mount(self) -> None: continue try: subprocess.run( - ['mount', switch, host_mnt, chr_path]. check=True) + ['mount', switch, host_mnt, chr_path], + check=True) self.mounted[host_mnt] = True except subprocess.CalledProcessError as e: raise MountError(*e.args) from e @@ -143,7 +148,6 @@ def umount(self) -> None: ''' if self.qemu_arch_static: os.remove(self.qemu_arch_static[-1]) - command = ['umount', '-f'] for _, host_mnt, chr_mnt in reversed(self.paths): if self.mounted[host_mnt]: subprocess.run(["umount", "-f", chr_mnt]) @@ -200,7 +204,9 @@ def _prepare_command(self, *commands: str) -> List[str]: try: quoted_commands.append(shlex.quote(command)) except TypeError as e: - raise ChrootError(f'failed to prepare command {command!r} for chroot') from e + raise ChrootError( + f'failed to prepare command {command!r} for chroot' + ) from e return [ 'chroot', self.chr_path, 'sh', '-c', @@ -231,7 +237,8 @@ def system(self, command: Optional[str] = None) -> int: command_chroot.extend(['-c', command]) return subprocess.run(command_chroot, env=self.environ).returncode - def run(self, command: str, *args: Any, **kwargs: Any) -> subprocess.CompletedProcess: + def run(self, command: str, *args: Any, **kwargs: Any + ) -> subprocess.CompletedProcess: """execute system command in chroot roughly analagous to `subprocess.run` except within the context of a From 49604f0d94c5f3442b6002d9323c89cb3023088a Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 26 Feb 2025 18:16:00 +1100 Subject: [PATCH 04/11] Update typing --- chroot/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index 2265f4d..788660c 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -12,7 +12,7 @@ import shutil from contextlib import contextmanager -from typing import Dict, Optional, Union, TypeVar, Generator, List, Any +from typing import TypeVar, Generator, Any AnyPath = TypeVar('AnyPath', str, os.PathLike) @@ -56,7 +56,7 @@ def is_mounted(path: AnyPath) -> bool: os.PathLike interface, this includes `str`, `bytes` and path objects provided by `pathlib` in the standard library. ''' - raw_path: Union[str, bytes] = os.fspath(path) + raw_path: str | bytes = os.fspath(path) mode = 'rb' if isinstance(raw_path, bytes) else 'r' sep = b' ' if isinstance(raw_path, bytes) else ' ' with open('/proc/mounts', mode) as fob: @@ -70,8 +70,8 @@ def is_mounted(path: AnyPath) -> bool: @contextmanager def mount( target: os.PathLike, - environ: Optional[Dict[str, str]] = None, - mnt_profile: Optional[list[tuple[str, str, str]]] = None + environ: dict[str, str] | None = None, + mnt_profile: list[tuple[str, str, str]] | None = None ) -> Generator['Chroot', None, None]: '''magic mount context manager @@ -168,8 +168,8 @@ class Chroot: ''' def __init__( self, newroot: AnyPath, - environ: Optional[Dict[str, str]] = None, - mnt_profile: Optional[list[tuple[str, str, str]]] = None + environ: dict[str, str] | None = None, + mnt_profile: list[tuple[str, str, str]] | None = None ): if environ is None: environ = {} @@ -195,7 +195,7 @@ def __init__( self.magicmounts = MagicMounts(self.profile, self.chr_path, self.qemu_arch_static) - def _prepare_command(self, *commands: str) -> List[str]: + def _prepare_command(self, *commands: str) -> list[str]: if '>' in commands or '<' in commands or '|' in commands: raise ChrootError("Output redirects and pipes not supported in" f"fab-chroot (command: `{commands}')") @@ -213,7 +213,7 @@ def _prepare_command(self, *commands: str) -> List[str]: ' '.join(quoted_commands) ] - def system(self, command: Optional[str] = None) -> int: + def system(self, command: str | None = None) -> int: """execute system command in chroot roughly analagous to `os.system` except within the context of a chroot From 19ce80b538c667d0960c8da2fc82abb488726e38 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Fri, 28 Feb 2025 04:28:20 +0000 Subject: [PATCH 05/11] Just use env vars to support arm on amd for now --- chroot/__init__.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index 788660c..774c2d5 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -101,14 +101,27 @@ class MagicMounts: def __init__(self, mnt_profile: list[tuple[str, str, str]], root: str = "/", - qemu_arch_bin: str = ""): + ): self.profile = mnt_profile root = os.fspath(abspath(root)) + + host_arch = os.getenv("HOST_ARCH") + fab_arch = os.getenv("FAB_ARCH") + if not host_arch: + raise ChrootError("HOST_ARCH is required but not set") + if not fab_arch: + fab_arch = host_arch self.qemu_arch_static = () - if qemu_arch_bin: + if fab_arch != host_arch: + # for now: + # - assume that we're building arm64 on amd64 + # - override mnt_profile + self.profile = MNT_FULL.append(MNT_ARM_ON_AMD) + qemu_arch_bin = "usr/bin/qemu-aarch64-static" self.qemu_arch_static = (f"/{qemu_arch_bin}", join(root, qemu_arch_bin)) - self.paths = tuple() + + self.paths = () self.mounted: dict[str, bool] = {} for mount_item in sorted(self.profile): @@ -116,7 +129,7 @@ def __init__(self, self.paths = tuple( *self.paths, # pyright "Expected 1 positional argument" here: (?!) - (switch, host_mnt, join(root,chr_mnt)) + (switch, host_mnt, join(root, chr_mnt)) ) self.mounted[host_mnt] = False self.mount() @@ -179,21 +192,12 @@ def __init__( 'LC_ALL': 'C', 'PATH': "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/bin:/usr/sbin" } - self.qemu_arch_static = "" - if os.getenv('ARM_ON_AMD', ''): - # ideally we probably should be just adding binfmt to the existing - # profile - however, it's easier to just use bind mounts to ensure - # that chroot's proc/sys/fs/binfmt_misc is populated from host - mnt_profile = MNT_FULL.append(MNT_ARM_ON_AMD) - self.qemu_arch_static = "usr/bin/qemu-aarch64-static" - self.environ.update(environ) self.profile = MNT_DEFAULT if not mnt_profile else mnt_profile self.chr_path: str = realpath(os.fspath(newroot)) - self.magicmounts = MagicMounts(self.profile, self.chr_path, - self.qemu_arch_static) + self.magicmounts = MagicMounts(self.profile, self.chr_path) def _prepare_command(self, *commands: str) -> list[str]: if '>' in commands or '<' in commands or '|' in commands: From 88845b80862440205411f4e03b59270eabae4c78 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Fri, 28 Feb 2025 05:10:47 +0000 Subject: [PATCH 06/11] not working, but committing what I have... --- chroot/__init__.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index 774c2d5..95a7735 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -102,11 +102,14 @@ def __init__(self, mnt_profile: list[tuple[str, str, str]], root: str = "/", ): - self.profile = mnt_profile + self.profile = mnt_profile if mnt_profile else MNT_DEFAULT + print(f"{self.profile=}") root = os.fspath(abspath(root)) host_arch = os.getenv("HOST_ARCH") fab_arch = os.getenv("FAB_ARCH") + print(f"{host_arch=} {fab_arch=}") + print(f"* {MNT_DEFAULT=}\n* {MNT_FULL=}\n* {MNT_ARM_ON_AMD=}") if not host_arch: raise ChrootError("HOST_ARCH is required but not set") if not fab_arch: @@ -116,22 +119,26 @@ def __init__(self, # for now: # - assume that we're building arm64 on amd64 # - override mnt_profile - self.profile = MNT_FULL.append(MNT_ARM_ON_AMD) + MNT_FULL.append(MNT_ARM_ON_AMD) + self.profile = MNT_FULL qemu_arch_bin = "usr/bin/qemu-aarch64-static" self.qemu_arch_static = (f"/{qemu_arch_bin}", join(root, qemu_arch_bin)) - + print(f"{self.profile=}") self.paths = () self.mounted: dict[str, bool] = {} for mount_item in sorted(self.profile): - for switch, host_mnt, chr_mnt in mount_item: - self.paths = tuple( - *self.paths, - # pyright "Expected 1 positional argument" here: (?!) - (switch, host_mnt, join(root, chr_mnt)) - ) - self.mounted[host_mnt] = False + + print(f"{mount_item=}") + print(f"{len(mount_item)=}") + switch, host_mnt, chr_mnt = mount_item + self.paths = tuple( + *self.paths, + # pyright "Expected 1 positional argument" here: (?!) + (switch, host_mnt, join(root, chr_mnt)) + ) + self.mounted[host_mnt] = False self.mount() def mount(self) -> None: From 3e5daaf7eba461c3b3afa00c05668eec006f750f Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Fri, 28 Feb 2025 16:12:33 +1100 Subject: [PATCH 07/11] ah silly mistake... --- chroot/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index 95a7735..ed91431 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -134,9 +134,9 @@ def __init__(self, print(f"{len(mount_item)=}") switch, host_mnt, chr_mnt = mount_item self.paths = tuple( - *self.paths, - # pyright "Expected 1 positional argument" here: (?!) - (switch, host_mnt, join(root, chr_mnt)) + [*self.paths, + (switch, host_mnt, join(root, chr_mnt)) + ] ) self.mounted[host_mnt] = False self.mount() From d4369f5e3c214dd3233c2e51b1adc5664c8bed4e Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Fri, 28 Feb 2025 06:58:35 +0000 Subject: [PATCH 08/11] Seems to be working now - Yay :) --- chroot/__init__.py | 75 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index ed91431..51bd318 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -6,7 +6,7 @@ # License, or (at your option) any later version. import os -from os.path import abspath, join, realpath +from os.path import abspath, join, realpath, exists import shlex import subprocess import shutil @@ -25,15 +25,15 @@ MNT_FULL = [ # Bind mounts /dev, /sys, /proc & /run into the chroot - ("--bind", "proc", "proc"), - ("--bind", "sys", "sys"), - ("--bind", "dev", "dev"), - ("--bind", "dev/pts", "dev/pts"), - ("--bind", "run", "run"), + ("--bind", "/proc", "proc"), + ("--bind", "/sys", "sys"), + ("--bind", "/dev", "dev"), + ("--bind", "/dev/pts", "dev/pts"), + ("--bind", "/run", "run"), ] MNT_ARM_ON_AMD = ( - "--bind", "proc/sys/fs/binfmt_misc", "proc/sys/fs/binfmt_misc") + "--bind", "/proc/sys/fs/binfmt_misc", "proc/sys/fs/binfmt_misc") def debug(*s: Any) -> None: @@ -103,42 +103,37 @@ def __init__(self, root: str = "/", ): self.profile = mnt_profile if mnt_profile else MNT_DEFAULT - print(f"{self.profile=}") root = os.fspath(abspath(root)) + self.qemu_arch_static = () host_arch = os.getenv("HOST_ARCH") fab_arch = os.getenv("FAB_ARCH") - print(f"{host_arch=} {fab_arch=}") - print(f"* {MNT_DEFAULT=}\n* {MNT_FULL=}\n* {MNT_ARM_ON_AMD=}") - if not host_arch: - raise ChrootError("HOST_ARCH is required but not set") - if not fab_arch: - fab_arch = host_arch - self.qemu_arch_static = () - if fab_arch != host_arch: - # for now: - # - assume that we're building arm64 on amd64 - # - override mnt_profile - MNT_FULL.append(MNT_ARM_ON_AMD) - self.profile = MNT_FULL - qemu_arch_bin = "usr/bin/qemu-aarch64-static" - self.qemu_arch_static = (f"/{qemu_arch_bin}", - join(root, qemu_arch_bin)) - print(f"{self.profile=}") + if fab_arch: + if not host_arch: + raise ChrootError( + "If FAB_ARCH is set, HOST_ARCH is also required") + elif host_arch and host_arch != fab_arch: + # for now: + # - assume that we're building arm64 on amd64 + # - override mnt_profile + MNT_FULL.append(MNT_ARM_ON_AMD) + self.profile = MNT_FULL + qemu_arch_bin = "usr/bin/qemu-aarch64-static" + self.qemu_arch_static = (f"/{qemu_arch_bin}", + join(root, qemu_arch_bin)) + self.paths = () self.mounted: dict[str, bool] = {} for mount_item in sorted(self.profile): - - print(f"{mount_item=}") - print(f"{len(mount_item)=}") switch, host_mnt, chr_mnt = mount_item + chr_mnt = join(root, chr_mnt) self.paths = tuple( [*self.paths, - (switch, host_mnt, join(root, chr_mnt)) + (switch, host_mnt, chr_mnt) ] ) - self.mounted[host_mnt] = False + self.mounted[chr_mnt] = False self.mount() def mount(self) -> None: @@ -147,14 +142,15 @@ def mount(self) -> None: Raises: MountError: An error occured while trying to mount chroot ''' - for switch, host_mnt, chr_path in self.paths: - if is_mounted(chr_path): + for switch, host_mnt, chr_mnt in self.paths: + if is_mounted(chr_mnt): + self.mounted[chr_mnt] = True continue try: subprocess.run( - ['mount', switch, host_mnt, chr_path], + ['mount', switch, host_mnt, chr_mnt], check=True) - self.mounted[host_mnt] = True + self.mounted[chr_mnt] = True except subprocess.CalledProcessError as e: raise MountError(*e.args) from e if self.qemu_arch_static: @@ -167,11 +163,14 @@ def umount(self) -> None: MountError: An error occured while trying to un-mount chroot ''' if self.qemu_arch_static: - os.remove(self.qemu_arch_static[-1]) + try: + os.remove(self.qemu_arch_static[-1]) + except FileNotFoundError: + pass for _, host_mnt, chr_mnt in reversed(self.paths): - if self.mounted[host_mnt]: - subprocess.run(["umount", "-f", chr_mnt]) - self.mounted[host_mnt] = False + if self.mounted[chr_mnt]: + p = subprocess.run(["umount", "-f", chr_mnt], capture_output=True, text=True) + self.mounted[chr_mnt] = False def __del__(self) -> None: self.umount() From 826936adc6026d44a8004f822105f51a960eaf50 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Fri, 28 Feb 2025 18:45:51 +1100 Subject: [PATCH 09/11] Some minor tidying --- chroot/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index 51bd318..b83ac4d 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -167,9 +167,9 @@ def umount(self) -> None: os.remove(self.qemu_arch_static[-1]) except FileNotFoundError: pass - for _, host_mnt, chr_mnt in reversed(self.paths): + for _, _, chr_mnt in reversed(self.paths): if self.mounted[chr_mnt]: - p = subprocess.run(["umount", "-f", chr_mnt], capture_output=True, text=True) + subprocess.run(["umount", "-f", chr_mnt]) self.mounted[chr_mnt] = False def __del__(self) -> None: From fd8e5dc6a5eb95a2d4f7f2a841207c5fa53c5276 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Fri, 28 Feb 2025 08:13:07 +0000 Subject: [PATCH 10/11] getting close... --- chroot/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/chroot/__init__.py b/chroot/__init__.py index b83ac4d..aaeca22 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -203,6 +203,7 @@ def __init__( self.profile = MNT_DEFAULT if not mnt_profile else mnt_profile self.chr_path: str = realpath(os.fspath(newroot)) + self.path = self.chr_path # for backwards compatability self.magicmounts = MagicMounts(self.profile, self.chr_path) def _prepare_command(self, *commands: str) -> list[str]: From 71f8144a4fadd3e50d45c8ae03dc29442e89487f Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Tue, 11 Mar 2025 05:47:41 +0000 Subject: [PATCH 11/11] set arch as 'all' --- chroot/__init__.py | 5 ++++- debian/control | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/chroot/__init__.py b/chroot/__init__.py index aaeca22..de7df7f 100644 --- a/chroot/__init__.py +++ b/chroot/__init__.py @@ -102,7 +102,8 @@ def __init__(self, mnt_profile: list[tuple[str, str, str]], root: str = "/", ): - self.profile = mnt_profile if mnt_profile else MNT_DEFAULT + #self.profile = mnt_profile if mnt_profile else MNT_DEFAULT + self.profile = MNT_FULL root = os.fspath(abspath(root)) self.qemu_arch_static = () @@ -121,6 +122,8 @@ def __init__(self, qemu_arch_bin = "usr/bin/qemu-aarch64-static" self.qemu_arch_static = (f"/{qemu_arch_bin}", join(root, qemu_arch_bin)) + elif host_arch: + self.profile = MNT_FULL self.paths = () self.mounted: dict[str, bool] = {} diff --git a/debian/control b/debian/control index 7292fdc..8cb2a9d 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,7 @@ Standards-Version: 4.0.0 X-Python-Version: >= 3.5 Package: turnkey-chroot -Architecture: any +Architecture: all Depends: ${misc:Depends}, ${python3:Depends},