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 19f2400..3e6c317 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 3e6c317..06c4e85 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 06c4e85..54c5571 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 8a5c98c..efcc546 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 3db3744..b50ecdc 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 e6a53bf..3f02f48 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 54c5571..c0f422a 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 c0f422a..2404f32 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 b50ecdc..df61ca1 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 df61ca1..58163bc 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 efcc546..fa69565 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 58163bc..673b510 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 2404f32..c4eb427 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 ebc51e0..467b3e5 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 fa69565..33273d5 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 673b510..db8954d 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 c4eb427..a915c53 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 5c068b7..f2935fb 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 33273d5..a1d4907 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')