From 8c605f213a9c015886dc3923ee7131f50cd554cb Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 14:32:51 +0300 Subject: [PATCH 01/10] Ensure umount isn't called when self.mounted_tmpfs=False This is accomplished by calling SysGeneral's __del__() method, in which self.mounted_tmpfs is already checked. --- sysc.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sysc.py b/sysc.py index 19f24003..3e6c3172 100755 --- a/sysc.py +++ b/sysc.py @@ -38,9 +38,8 @@ class SysC(SysGeneral): if not self.chroot: print(f"Deleting {self.dev_name}") run('sudo', 'losetup', '-d', self.dev_name) - print(f"Unmounting tmpfs from {self.tmp_dir}") - umount(self.tmp_dir) - os.rmdir(self.tmp_dir) + + super().__del__() def prepare(self): """ From 537cdb6540e5edcdbbf59a3c243c1444cc9c0a4c Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 14:45:59 +0300 Subject: [PATCH 02/10] Detach loopback device only if it was attached Also change the print to better describe the action taken. --- sysc.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sysc.py b/sysc.py index 3e6c3172..06c4e852 100755 --- a/sysc.py +++ b/sysc.py @@ -16,6 +16,9 @@ class SysC(SysGeneral): """ Class responsible for preparing sources for System C. """ + + dev_name = None + # pylint: disable=too-many-instance-attributes def __init__(self, arch, preserve_tmp, tmpdir, chroot): self.git_dir = os.path.dirname(os.path.join(__file__)) @@ -35,8 +38,8 @@ class SysC(SysGeneral): def __del__(self): if not self.preserve_tmp: - if not self.chroot: - print(f"Deleting {self.dev_name}") + if self.dev_name is not None: + print(f"Detaching {self.dev_name}") run('sudo', 'losetup', '-d', self.dev_name) super().__del__() From 7040b550a9c6b6277d957e45a3ebfbf33d58f76f Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 15:32:00 +0300 Subject: [PATCH 03/10] Make rootfs_dir local to prepare() It's not needed by other methods. --- sysc.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sysc.py b/sysc.py index 06c4e852..54c5571c 100755 --- a/sysc.py +++ b/sysc.py @@ -49,26 +49,29 @@ class SysC(SysGeneral): Prepare directory structure for System C. """ self.mount_tmpfs() + + rootfs_dir = None + if not self.chroot: # Create + mount a disk for QEMU to use disk_path = os.path.join(self.tmp_dir, 'disk.img') self.dev_name = create_disk(disk_path, "msdos", "ext4", '8G') - self.rootfs_dir = os.path.join(self.tmp_dir, 'mnt') - os.mkdir(self.rootfs_dir) - mount(self.dev_name + "p1", self.rootfs_dir, 'ext4') + rootfs_dir = os.path.join(self.tmp_dir, 'mnt') + os.mkdir(rootfs_dir) + mount(self.dev_name + "p1", rootfs_dir, 'ext4') # Use chown to allow executing user to access it run('sudo', 'chown', getpass.getuser(), self.dev_name) - run('sudo', 'chown', getpass.getuser(), self.rootfs_dir) + run('sudo', 'chown', getpass.getuser(), rootfs_dir) else: - self.rootfs_dir = self.tmp_dir + rootfs_dir = self.tmp_dir self.get_packages() - copytree(self.sys_dir, self.rootfs_dir, ignore=shutil.ignore_patterns("tmp")) + copytree(self.sys_dir, rootfs_dir, ignore=shutil.ignore_patterns("tmp")) # Unmount tmp/mnt if it exists if not self.chroot: - umount(self.rootfs_dir) + umount(rootfs_dir) # pylint: disable=line-too-long,too-many-statements def get_packages(self): From c429cf9dd7deccac0fd386a80c3a88b815c34a5d Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 14:50:31 +0300 Subject: [PATCH 04/10] Keep chroot indication only in prepare() It's not actually needed by other methods. --- rootfs.py | 3 +-- sysa.py | 7 +++---- sysb.py | 3 +-- sysc.py | 9 ++++----- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/rootfs.py b/rootfs.py index 8a5c98c6..efcc546b 100755 --- a/rootfs.py +++ b/rootfs.py @@ -110,8 +110,7 @@ def main(): system_c = SysC(arch=args.arch, preserve_tmp=args.preserve, tmpdir=args.tmpdir, chroot=args.chroot) - system_b = SysB(arch=args.arch, preserve_tmp=args.preserve, - chroot=args.chroot) + system_b = SysB(arch=args.arch, preserve_tmp=args.preserve) system_a = SysA(arch=args.arch, preserve_tmp=args.preserve, tmpdir=args.tmpdir, chroot=args.chroot, sysb_dir=system_b.sys_dir, sysc_tmp=system_c.tmp_dir) diff --git a/sysa.py b/sysa.py index 3db37446..b50ecdca 100755 --- a/sysa.py +++ b/sysa.py @@ -33,14 +33,13 @@ class SysA(SysGeneral): self.cache_dir = os.path.join(self.sys_dir, 'distfiles') self.sysb_dir = sysb_dir self.sysc_tmp = sysc_tmp - self.chroot = chroot - self.prepare() + self.prepare(chroot) if not chroot: self.make_initramfs() - def prepare(self): + def prepare(self, chroot): """ Prepare directory structure for System A. We create an empty tmpfs, unpack stage0-posix. @@ -54,7 +53,7 @@ class SysA(SysGeneral): # sysb must be added to sysa as it is another initramfs stage self.sysb() - if self.chroot: + if chroot: self.sysc() def sysa(self): diff --git a/sysb.py b/sysb.py index e6a53bfa..3f02f48c 100755 --- a/sysb.py +++ b/sysb.py @@ -12,10 +12,9 @@ class SysB(SysGeneral): """ Class responsible for preparing sources for System B. """ - def __init__(self, arch, preserve_tmp, chroot): + def __init__(self, arch, preserve_tmp): self.git_dir = os.path.dirname(os.path.join(__file__)) self.arch = arch self.preserve_tmp = preserve_tmp - self.chroot = chroot self.sys_dir = os.path.join(self.git_dir, 'sysb') diff --git a/sysc.py b/sysc.py index 54c5571c..c0f422a5 100755 --- a/sysc.py +++ b/sysc.py @@ -24,7 +24,6 @@ class SysC(SysGeneral): self.git_dir = os.path.dirname(os.path.join(__file__)) self.arch = arch self.preserve_tmp = preserve_tmp - self.chroot = chroot self.sys_dir = os.path.join(self.git_dir, 'sysc') self.cache_dir = os.path.join(self.sys_dir, 'distfiles') @@ -34,7 +33,7 @@ class SysC(SysGeneral): self.tmp_dir = os.path.join(tmpdir, 'sysc') os.mkdir(self.tmp_dir) - self.prepare() + self.prepare(chroot) def __del__(self): if not self.preserve_tmp: @@ -44,7 +43,7 @@ class SysC(SysGeneral): super().__del__() - def prepare(self): + def prepare(self, chroot): """ Prepare directory structure for System C. """ @@ -52,7 +51,7 @@ class SysC(SysGeneral): rootfs_dir = None - if not self.chroot: + if not chroot: # Create + mount a disk for QEMU to use disk_path = os.path.join(self.tmp_dir, 'disk.img') self.dev_name = create_disk(disk_path, "msdos", "ext4", '8G') @@ -70,7 +69,7 @@ class SysC(SysGeneral): copytree(self.sys_dir, rootfs_dir, ignore=shutil.ignore_patterns("tmp")) # Unmount tmp/mnt if it exists - if not self.chroot: + if not chroot: umount(rootfs_dir) # pylint: disable=line-too-long,too-many-statements From fa2a09b63fac05597b093bc2c3968c8bceaa86d1 Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 16:00:07 +0300 Subject: [PATCH 05/10] Rename "chroot" to "create_disk_image" in sysc's prepare() This better describes the action, and will make more sense with the addition of the rootless bootstrap mode that doesn't require a disk image either. --- sysc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sysc.py b/sysc.py index c0f422a5..2404f324 100755 --- a/sysc.py +++ b/sysc.py @@ -33,7 +33,7 @@ class SysC(SysGeneral): self.tmp_dir = os.path.join(tmpdir, 'sysc') os.mkdir(self.tmp_dir) - self.prepare(chroot) + self.prepare(not chroot) def __del__(self): if not self.preserve_tmp: @@ -43,7 +43,7 @@ class SysC(SysGeneral): super().__del__() - def prepare(self, chroot): + def prepare(self, create_disk_image): """ Prepare directory structure for System C. """ @@ -51,7 +51,7 @@ class SysC(SysGeneral): rootfs_dir = None - if not chroot: + if create_disk_image: # Create + mount a disk for QEMU to use disk_path = os.path.join(self.tmp_dir, 'disk.img') self.dev_name = create_disk(disk_path, "msdos", "ext4", '8G') @@ -68,8 +68,8 @@ class SysC(SysGeneral): copytree(self.sys_dir, rootfs_dir, ignore=shutil.ignore_patterns("tmp")) - # Unmount tmp/mnt if it exists - if not chroot: + # Unmount tmp/mnt if it was mounted + if create_disk_image: umount(rootfs_dir) # pylint: disable=line-too-long,too-many-statements From 7075c901a931a624d7825ed60262916c569f4ccc Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 16:04:13 +0300 Subject: [PATCH 06/10] Move sysa's initramfs creation into prepare() --- sysa.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sysa.py b/sysa.py index b50ecdca..df61ca1c 100755 --- a/sysa.py +++ b/sysa.py @@ -36,9 +36,6 @@ class SysA(SysGeneral): self.prepare(chroot) - if not chroot: - self.make_initramfs() - def prepare(self, chroot): """ Prepare directory structure for System A. @@ -55,6 +52,8 @@ class SysA(SysGeneral): if chroot: self.sysc() + else: + self.make_initramfs() def sysa(self): """Copy in sysa files for sysa.""" From a7c7ddf977d552ee35093f864616651495688c44 Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 16:09:45 +0300 Subject: [PATCH 07/10] Split "chroot" into "copy_sysc" and "create_initramfs" in sysa's prepare() These better describe the actions, and will make more sense with the addition of the rootless bootstrap mode which would make use of these preparation steps. --- sysa.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sysa.py b/sysa.py index df61ca1c..58163bc3 100755 --- a/sysa.py +++ b/sysa.py @@ -34,9 +34,9 @@ class SysA(SysGeneral): self.sysb_dir = sysb_dir self.sysc_tmp = sysc_tmp - self.prepare(chroot) + self.prepare(chroot, not chroot) - def prepare(self, chroot): + def prepare(self, copy_sysc, create_initramfs): """ Prepare directory structure for System A. We create an empty tmpfs, unpack stage0-posix. @@ -50,9 +50,10 @@ class SysA(SysGeneral): # sysb must be added to sysa as it is another initramfs stage self.sysb() - if chroot: + if copy_sysc: self.sysc() - else: + + if create_initramfs: self.make_initramfs() def sysa(self): From 6d357226a9eab2ae74df4bb5fc584a33bba84b62 Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 14:18:52 +0300 Subject: [PATCH 08/10] Call prepare() externally to the sysa and sysc classes This keeps the prepartion and bootstrap initiation logic in the same place for each bootstrap mode, and allows each mode to specify its own requirements and expectations from the different bootstrap steps. --- rootfs.py | 20 ++++++++++++++++++-- sysa.py | 4 +--- sysc.py | 4 +--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/rootfs.py b/rootfs.py index efcc546b..fa695659 100755 --- a/rootfs.py +++ b/rootfs.py @@ -109,10 +109,10 @@ def main(): pass system_c = SysC(arch=args.arch, preserve_tmp=args.preserve, - tmpdir=args.tmpdir, chroot=args.chroot) + tmpdir=args.tmpdir) system_b = SysB(arch=args.arch, preserve_tmp=args.preserve) system_a = SysA(arch=args.arch, preserve_tmp=args.preserve, - tmpdir=args.tmpdir, chroot=args.chroot, + tmpdir=args.tmpdir, sysb_dir=system_b.sys_dir, sysc_tmp=system_c.tmp_dir) bootstrap(args, system_a, system_b, system_c) @@ -128,6 +128,10 @@ print(shutil.which('chroot')) chroot_binary = run('sudo', 'python3', '-c', find_chroot, capture_output=True).stdout.decode().strip() + system_c.prepare(create_disk_image=False) + system_a.prepare(copy_sysc=True, + create_initramfs=False) + # sysa arch = stage0_arch_map.get(args.arch, args.arch) init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed') @@ -137,6 +141,10 @@ print(shutil.which('chroot')) if os.path.isdir('kritis-linux'): shutil.rmtree('kritis-linux') + system_c.prepare(create_disk_image=True) + system_a.prepare(copy_sysc=False, + create_initramfs=True) + run('git', 'clone', '--depth', '1', '--branch', 'v0.7', 'https://github.com/bittorf/kritis-linux.git') @@ -154,11 +162,19 @@ print(shutil.which('chroot')) '--log', '/tmp/bootstrap.log') elif args.bare_metal: + system_c.prepare(create_disk_image=True) + system_a.prepare(copy_sysc=False, + create_initramfs=True) + print("Please:") print(" 1. Take sysa/tmp/initramfs and your kernel, boot using this.") print(" 2. Take sysc/tmp/disk.img and put this on a writable storage medium.") else: + system_c.prepare(create_disk_image=True) + system_a.prepare(copy_sysc=False, + create_initramfs=True) + run(args.qemu_cmd, '-enable-kvm', '-m', str(args.qemu_ram) + 'M', diff --git a/sysa.py b/sysa.py index 58163bc3..673b5103 100755 --- a/sysa.py +++ b/sysa.py @@ -17,7 +17,7 @@ class SysA(SysGeneral): Class responsible for preparing sources for System A. """ # pylint: disable=too-many-instance-attributes,too-many-arguments - def __init__(self, arch, preserve_tmp, tmpdir, chroot, sysb_dir, sysc_tmp): + def __init__(self, arch, preserve_tmp, tmpdir, sysb_dir, sysc_tmp): self.git_dir = os.path.dirname(os.path.join(__file__)) self.arch = arch self.preserve_tmp = preserve_tmp @@ -34,8 +34,6 @@ class SysA(SysGeneral): self.sysb_dir = sysb_dir self.sysc_tmp = sysc_tmp - self.prepare(chroot, not chroot) - def prepare(self, copy_sysc, create_initramfs): """ Prepare directory structure for System A. diff --git a/sysc.py b/sysc.py index 2404f324..c4eb427b 100755 --- a/sysc.py +++ b/sysc.py @@ -20,7 +20,7 @@ class SysC(SysGeneral): dev_name = None # pylint: disable=too-many-instance-attributes - def __init__(self, arch, preserve_tmp, tmpdir, chroot): + def __init__(self, arch, preserve_tmp, tmpdir): self.git_dir = os.path.dirname(os.path.join(__file__)) self.arch = arch self.preserve_tmp = preserve_tmp @@ -33,8 +33,6 @@ class SysC(SysGeneral): self.tmp_dir = os.path.join(tmpdir, 'sysc') os.mkdir(self.tmp_dir) - self.prepare(not chroot) - def __del__(self): if not self.preserve_tmp: if self.dev_name is not None: From 8330ab45047db0360b44d9b5f17de92bafebaef6 Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Mon, 23 May 2022 17:02:33 +0300 Subject: [PATCH 09/10] Add an option to avoid creating a tmpfs in prepare() Root access is required for creating tmpfs mounts in the context of the current mount namespace, and creating a tmpfs in the context of a new mount namespace is less useful because a process in the parent namespace can't easily access it. So add an option to avoid creating tmpfs mounts, which will be used by the rootless bootstrap mode for now. In addition, when tmp directories aren't mounted as tmpfs, their contents can't be removed using os.umount(). So instead remove them recursively using shutil.rmtree(). --- lib/sysgeneral.py | 16 ++++++++++++++-- rootfs.py | 26 +++++++++++++++++--------- sysa.py | 11 +++++++---- sysc.py | 9 ++++++--- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/lib/sysgeneral.py b/lib/sysgeneral.py index ebc51e0d..467b3e5b 100644 --- a/lib/sysgeneral.py +++ b/lib/sysgeneral.py @@ -3,11 +3,13 @@ This file contains a few functions to be shared by all Sys* classes """ +# SPDX-FileCopyrightText: 2022 Dor Askayo # SPDX-FileCopyrightText: 2021-22 fosslinux # SPDX-FileCopyrightText: 2021 Andrius Štikonas # SPDX-License-Identifier: GPL-3.0-or-later import os +import shutil import hashlib import glob import subprocess @@ -33,10 +35,20 @@ class SysGeneral: mounted_tmpfs = False def __del__(self): - if self.mounted_tmpfs and not self.preserve_tmp: + if not self.preserve_tmp: + self.remove_tmp() + + def remove_tmp(self): + """Remove the tmp directory""" + if self.tmp_dir is None: + return + + if self.mounted_tmpfs: print(f"Unmounting tmpfs from {self.tmp_dir}") umount(self.tmp_dir) - os.rmdir(self.tmp_dir) + + print(f"Removing {self.tmp_dir}") + shutil.rmtree(self.tmp_dir, ignore_errors=True) def mount_tmpfs(self): """Mount the tmpfs for this sysx""" diff --git a/rootfs.py b/rootfs.py index fa695659..33273d52 100755 --- a/rootfs.py +++ b/rootfs.py @@ -45,7 +45,7 @@ def main(): default="x86") parser.add_argument("-c", "--chroot", help="Run inside chroot", action="store_true") - parser.add_argument("-p", "--preserve", help="Do not unmount temporary dir", + parser.add_argument("-p", "--preserve", help="Do not remove temporary dir", action="store_true") parser.add_argument("-t", "--tmpdir", help="Temporary directory") parser.add_argument("--force-timestamps", @@ -128,8 +128,10 @@ print(shutil.which('chroot')) chroot_binary = run('sudo', 'python3', '-c', find_chroot, capture_output=True).stdout.decode().strip() - system_c.prepare(create_disk_image=False) - system_a.prepare(copy_sysc=True, + system_c.prepare(mount_tmpfs=True, + create_disk_image=False) + system_a.prepare(mount_tmpfs=True, + copy_sysc=True, create_initramfs=False) # sysa @@ -141,8 +143,10 @@ print(shutil.which('chroot')) if os.path.isdir('kritis-linux'): shutil.rmtree('kritis-linux') - system_c.prepare(create_disk_image=True) - system_a.prepare(copy_sysc=False, + system_c.prepare(mount_tmpfs=True, + create_disk_image=True) + system_a.prepare(mount_tmpfs=True, + copy_sysc=False, create_initramfs=True) run('git', 'clone', @@ -162,8 +166,10 @@ print(shutil.which('chroot')) '--log', '/tmp/bootstrap.log') elif args.bare_metal: - system_c.prepare(create_disk_image=True) - system_a.prepare(copy_sysc=False, + system_c.prepare(mount_tmpfs=True, + create_disk_image=True) + system_a.prepare(mount_tmpfs=True, + copy_sysc=False, create_initramfs=True) print("Please:") @@ -171,8 +177,10 @@ print(shutil.which('chroot')) print(" 2. Take sysc/tmp/disk.img and put this on a writable storage medium.") else: - system_c.prepare(create_disk_image=True) - system_a.prepare(copy_sysc=False, + system_c.prepare(mount_tmpfs=True, + create_disk_image=True) + system_a.prepare(mount_tmpfs=True, + copy_sysc=False, create_initramfs=True) run(args.qemu_cmd, diff --git a/sysa.py b/sysa.py index 673b5103..db8954db 100755 --- a/sysa.py +++ b/sysa.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """System A""" # SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-FileCopyrightText: 2022 Dor Askayo # SPDX-FileCopyrightText: 2021 Andrius Štikonas # SPDX-FileCopyrightText: 2021 Melg Eight # SPDX-FileCopyrightText: 2021-22 fosslinux @@ -27,20 +28,22 @@ class SysA(SysGeneral): self.tmp_dir = os.path.join(self.git_dir, 'tmp') else: self.tmp_dir = os.path.join(tmpdir, 'sysa') - os.mkdir(self.tmp_dir) self.sysa_dir = os.path.join(self.tmp_dir, 'sysa') self.base_dir = self.sysa_dir self.cache_dir = os.path.join(self.sys_dir, 'distfiles') self.sysb_dir = sysb_dir self.sysc_tmp = sysc_tmp - def prepare(self, copy_sysc, create_initramfs): + def prepare(self, mount_tmpfs, copy_sysc, create_initramfs): """ Prepare directory structure for System A. - We create an empty tmpfs, unpack stage0-posix. + We create an empty tmp directory, unpack stage0-posix. Rest of the files are unpacked into more structured directory /sysa """ - self.mount_tmpfs() + if mount_tmpfs: + self.mount_tmpfs() + else: + os.mkdir(self.tmp_dir) self.stage0_posix() self.sysa() diff --git a/sysc.py b/sysc.py index c4eb427b..a915c536 100755 --- a/sysc.py +++ b/sysc.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """System C""" # SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-FileCopyrightText: 2022 Dor Askayo # SPDX-FileCopyrightText: 2021-22 fosslinux # SPDX-FileCopyrightText: 2021 Andrius Štikonas @@ -31,7 +32,6 @@ class SysC(SysGeneral): self.tmp_dir = os.path.join(self.sys_dir, 'tmp') else: self.tmp_dir = os.path.join(tmpdir, 'sysc') - os.mkdir(self.tmp_dir) def __del__(self): if not self.preserve_tmp: @@ -41,11 +41,14 @@ class SysC(SysGeneral): super().__del__() - def prepare(self, create_disk_image): + def prepare(self, mount_tmpfs, create_disk_image): """ Prepare directory structure for System C. """ - self.mount_tmpfs() + if mount_tmpfs: + self.mount_tmpfs() + else: + os.mkdir(self.tmp_dir) rootfs_dir = None From 1e67477ff264693907083e1aab01c76cbdc5104c Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Sat, 25 Dec 2021 20:19:01 +0200 Subject: [PATCH 10/10] Add a rootless bootstrap mode using bubblewrap Set up a bubblewrap sandbox suitable for bootstrap. Since bubblewrap can operate without root permissions when user namespaces are allowed, this effectively adds a rootless bootstrap mode. --- README.rst | 6 ++++-- rootfs.py | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 5c068b77..f2935fbc 100644 --- a/README.rst +++ b/README.rst @@ -23,13 +23,15 @@ Get me started! installed. a. Alternatively, run ``./rootfs.py --chroot`` to run it in a chroot. - b. Alternatively, run ``./rootfs.py`` but don’t run the actual + b. Alternatively, run ``./rootfs.py --bwrap`` to run it in a bubblewrap + sandbox. When user namespaces are supported, this mode is rootless. + c. Alternatively, run ``./rootfs.py`` but don’t run the actual virtualization and instead copy sysa/tmp/initramfs to a USB or some other device and boot from bare metal. NOTE: we now require a hard drive. This is currently hardcoded as sda. You also need to put ``sysc/tmp/disk.img`` onto your sda on the bootstrapping machine. - c. Alternatively, do not use python at all, see "Python-less build" + d. Alternatively, do not use python at all, see "Python-less build" below. 5. Wait. diff --git a/rootfs.py b/rootfs.py index 33273d52..a1d49076 100755 --- a/rootfs.py +++ b/rootfs.py @@ -7,6 +7,7 @@ you can run bootstap inside chroot. """ # SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-FileCopyrightText: 2022 Dor Askayo # SPDX-FileCopyrightText: 2021 Andrius Štikonas # SPDX-FileCopyrightText: 2021 Bastian Bittorf # SPDX-FileCopyrightText: 2021 Melg Eight @@ -30,7 +31,7 @@ def create_configuration_file(args): config_path = os.path.join('sysa', 'bootstrap.cfg') with open(config_path, "w", encoding="utf_8") as config: config.write("FORCE_TIMESTAMPS=" + str(args.force_timestamps) + "\n") - config.write("CHROOT=" + str(args.chroot) + "\n") + config.write("CHROOT=" + str(args.chroot or args.bwrap) + "\n") config.write("UPDATE_CHECKSUMS=" + str(args.update_checksums) + "\n") config.write("DISK=sda1\n") @@ -45,6 +46,8 @@ def main(): default="x86") parser.add_argument("-c", "--chroot", help="Run inside chroot", action="store_true") + parser.add_argument("-bw", "--bwrap", help="Run inside a bwrap sandbox", + action="store_true") parser.add_argument("-p", "--preserve", help="Do not remove temporary dir", action="store_true") parser.add_argument("-t", "--tmpdir", help="Temporary directory") @@ -81,6 +84,8 @@ def main(): count += 1 if args.chroot: count += 1 + if args.bwrap: + count += 1 if args.minikernel: count += 1 if args.bare_metal: @@ -139,6 +144,38 @@ print(shutil.which('chroot')) init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed') run('sudo', 'env', '-i', 'PATH=/bin', chroot_binary, system_a.tmp_dir, init) + elif args.bwrap: + system_c.prepare(mount_tmpfs=False, + create_disk_image=False) + system_a.prepare(mount_tmpfs=False, + copy_sysc=True, + create_initramfs=False) + + # sysa + arch = stage0_arch_map.get(args.arch, args.arch) + init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed') + run('bwrap', '--unshare-user', + '--uid', '0', + '--gid', '0', + '--cap-add', 'CAP_SYS_CHROOT', # Required for chroot from sysa to sysc + '--clearenv', + '--setenv', 'PATH', '/usr/bin', + '--bind', system_a.tmp_dir, '/', + '--dir', '/dev', + '--dev-bind', '/dev/null', '/dev/null', + '--dev-bind', '/dev/zero', '/dev/zero', + '--dev-bind', '/dev/random', '/dev/random', + '--dev-bind', '/dev/urandom', '/dev/urandom', + '--dir', '/sysc/dev', + '--dev-bind', '/dev/null', '/sysc/dev/null', + '--dev-bind', '/dev/zero', '/sysc/dev/zero', + '--dev-bind', '/dev/random', '/sysc/dev/random', + '--dev-bind', '/dev/urandom', '/sysc/dev/urandom', + '--proc', '/sysc/proc', + '--bind', '/sys', '/sysc/sys', + '--tmpfs', '/sysc/tmp', + init) + elif args.minikernel: if os.path.isdir('kritis-linux'): shutil.rmtree('kritis-linux')