mirror of
https://github.com/fosslinux/live-bootstrap.git
synced 2026-03-02 01:18:08 +01:00
There is nothing temporary about our "tmpdir" - its sole purpose is to contain the final product of the bootstrap process. Thus, removing it at the end of bootstrap amounts to doing the entire process for nothing. To remedy this, --tmpdir is renamed --target, keeping the -t short form, and defaulting to "target" instead of "tmp" to make its purpose clearer. The --preserve option is removed, as the target is now always preserved.
264 lines
11 KiB
Python
Executable file
264 lines
11 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""
|
|
A helper application used to start bootstrapping process.
|
|
It has a few modes of operation, you can create initramfs with
|
|
binary seeds and sources that you can boot into or alternatively
|
|
you can run bootstap inside chroot.
|
|
"""
|
|
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
# SPDX-FileCopyrightText: 2022 Dor Askayo <dor.askayo@gmail.com>
|
|
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
|
|
# SPDX-FileCopyrightText: 2021 Bastian Bittorf <bb@npl.de>
|
|
# SPDX-FileCopyrightText: 2021 Melg Eight <public.melg8@gmail.com>
|
|
# SPDX-FileCopyrightText: 2021-23 fosslinux <fosslinux@aussies.space>
|
|
|
|
import argparse
|
|
import os
|
|
|
|
from lib.utils import run, run_as_root
|
|
from lib.target import Target
|
|
from lib.generator import Generator, stage0_arch_map
|
|
|
|
def create_configuration_file(args):
|
|
"""
|
|
Creates bootstrap.cfg file which would contain options used to
|
|
customize bootstrap.
|
|
"""
|
|
config_path = os.path.join('steps', 'bootstrap.cfg')
|
|
with open(config_path, "w", encoding="utf_8") as config:
|
|
config.write(f"FORCE_TIMESTAMPS={args.force_timestamps}\n")
|
|
config.write(f"CHROOT={args.chroot or args.bwrap}\n")
|
|
config.write(f"UPDATE_CHECKSUMS={args.update_checksums}\n")
|
|
config.write(f"JOBS={args.cores}\n")
|
|
config.write(f"INTERNAL_CI={args.internal_ci or False}\n")
|
|
config.write(f"BARE_METAL={args.bare_metal}\n")
|
|
if (args.bare_metal or args.qemu) and not args.kernel:
|
|
if args.repo or args.external_sources:
|
|
config.write("DISK=sdb1\n")
|
|
else:
|
|
config.write("DISK=sda\n")
|
|
config.write("KERNEL_BOOTSTRAP=True\n")
|
|
else:
|
|
config.write("DISK=sda1\n")
|
|
config.write("KERNEL_BOOTSTRAP=False\n")
|
|
config.write(f"BUILD_KERNELS={args.update_checksums or args.build_kernels}\n")
|
|
|
|
# pylint: disable=too-many-statements
|
|
def main():
|
|
"""
|
|
A few command line arguments to customize bootstrap.
|
|
This function also creates object which prepares directory
|
|
structure with bootstrap seeds and all sources.
|
|
"""
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("-a", "--arch", help="Bootstrap architecture",
|
|
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("-t", "--target", help="Target directory",
|
|
default="target")
|
|
parser.add_argument("--tmpfs", help="Use a tmpfs on target",
|
|
action="store_true")
|
|
parser.add_argument("--tmpfs-size", help="Size of the tmpfs",
|
|
default="8G")
|
|
parser.add_argument("--cores", help="Cores to use for building",
|
|
default=2)
|
|
parser.add_argument("--force-timestamps",
|
|
help="Force all files timestamps to be 0 unix time",
|
|
action="store_true")
|
|
parser.add_argument("--update-checksums",
|
|
help="Update checksum files.",
|
|
action="store_true")
|
|
parser.add_argument("--external-sources",
|
|
help="Download sources externally from live-bootstrap.",
|
|
action="store_true")
|
|
parser.add_argument("--build-kernels",
|
|
help="Also build kernels in chroot and bwrap builds.",
|
|
action="store_true")
|
|
parser.add_argument("--no-create-config",
|
|
help="Do not automatically create config file",
|
|
action="store_true")
|
|
parser.add_argument("-r", "--repo",
|
|
help="Path to prebuilt binary packages.", nargs=None)
|
|
parser.add_argument("--early-preseed",
|
|
help="Skip early stages of live-bootstrap.", nargs=None)
|
|
parser.add_argument("--internal-ci", help="INTERNAL for github CI")
|
|
|
|
# QEMU arguments
|
|
parser.add_argument("-q", "--qemu", help="Use QEMU",
|
|
action="store_true")
|
|
parser.add_argument("-qc", "--qemu-cmd", help="QEMU command to run",
|
|
default="qemu-system-x86_64")
|
|
parser.add_argument("-qr", "--qemu-ram", help="Memory (in megabytes) allocated to QEMU VM",
|
|
default=4096)
|
|
parser.add_argument("-qs", "--target-size", help="Size of the target image (for QEMU only)",
|
|
default="16G")
|
|
parser.add_argument("-qk", "--kernel", help="Custom early kernel to use")
|
|
|
|
parser.add_argument("-b", "--bare-metal", help="Build images for bare metal",
|
|
action="store_true")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Mode validation
|
|
def check_types():
|
|
count = 0
|
|
if args.qemu:
|
|
count += 1
|
|
if args.chroot:
|
|
count += 1
|
|
if args.bwrap:
|
|
count += 1
|
|
if args.bare_metal:
|
|
count += 1
|
|
return count
|
|
|
|
if check_types() > 1:
|
|
raise ValueError("No more than one of qemu, chroot, bwrap, bare metal"
|
|
"may be used.")
|
|
if check_types() == 0:
|
|
raise ValueError("One of qemu, chroot, bwrap, or bare metal must be selected.")
|
|
|
|
# Arch validation
|
|
if args.arch != "x86":
|
|
print("Only x86 is supported at the moment, other arches are for development only.")
|
|
|
|
# Tmpfs validation
|
|
if args.bwrap and args.tmpfs:
|
|
raise ValueError("tmpfs cannot be used with bwrap.")
|
|
|
|
# Cores validation
|
|
if int(args.cores) < 1:
|
|
raise ValueError("Must use one or more cores.")
|
|
|
|
# Target image size validation
|
|
if args.qemu:
|
|
if int(str(args.target_size).rstrip('gGmM')) < 1:
|
|
raise ValueError("Please specify a positive target size for qemu.")
|
|
args.target_size = (int(str(args.target_size).rstrip('gGmM')) *
|
|
(1024 if str(args.target_size).lower().endswith('g') else 1))
|
|
else:
|
|
args.target_size = 0
|
|
|
|
# bootstrap.cfg
|
|
try:
|
|
os.remove(os.path.join('steps', 'bootstrap.cfg'))
|
|
except FileNotFoundError:
|
|
pass
|
|
if not args.no_create_config:
|
|
create_configuration_file(args)
|
|
else:
|
|
with open(os.path.join('steps', 'bootstrap.cfg'), 'a', encoding='UTF-8'):
|
|
pass
|
|
|
|
# target
|
|
target = Target(path=args.target)
|
|
if args.tmpfs:
|
|
target.tmpfs(size=args.tmpfs_size)
|
|
|
|
generator = Generator(arch=args.arch,
|
|
external_sources=args.external_sources,
|
|
repo_path=args.repo,
|
|
early_preseed=args.early_preseed)
|
|
|
|
bootstrap(args, generator, target, args.target_size)
|
|
|
|
def bootstrap(args, generator, target, size):
|
|
"""Kick off bootstrap process."""
|
|
print(f"Bootstrapping {args.arch}")
|
|
if args.chroot:
|
|
find_chroot = """
|
|
import shutil
|
|
print(shutil.which('chroot'))
|
|
"""
|
|
chroot_binary = run_as_root('python3', '-c', find_chroot,
|
|
capture_output=True).stdout.decode().strip()
|
|
|
|
generator.prepare(target, using_kernel=False)
|
|
|
|
arch = stage0_arch_map.get(args.arch, args.arch)
|
|
init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed')
|
|
run_as_root('env', '-i', 'PATH=/bin', chroot_binary, generator.target_dir, init)
|
|
|
|
elif args.bwrap:
|
|
init = '/init'
|
|
if not args.internal_ci or args.internal_ci == "pass1":
|
|
generator.prepare(target, using_kernel=False)
|
|
|
|
arch = stage0_arch_map.get(args.arch, args.arch)
|
|
init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed')
|
|
else:
|
|
generator.reuse(target)
|
|
|
|
run('env', '-i', 'bwrap', '--unshare-user',
|
|
'--uid', '0',
|
|
'--gid', '0',
|
|
'--unshare-net' if args.external_sources else None,
|
|
'--setenv', 'PATH', '/usr/bin',
|
|
'--bind', generator.target_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',
|
|
'--dev-bind', '/dev/ptmx', '/dev/ptmx',
|
|
'--dev-bind', '/dev/tty', '/dev/tty',
|
|
'--tmpfs', '/dev/shm',
|
|
'--proc', '/proc',
|
|
'--bind', '/sys', '/sys',
|
|
'--tmpfs', '/tmp',
|
|
init)
|
|
|
|
elif args.bare_metal:
|
|
if args.kernel:
|
|
generator.prepare(target, using_kernel=True, target_size=size)
|
|
path = os.path.join(args.target, os.path.relpath(generator.target_dir, args.target))
|
|
print("Please:")
|
|
print(f" 1. Take {path}/initramfs and your kernel, boot using this.")
|
|
print(f" 2. Take {path}/disk.img and put this on a writable storage medium.")
|
|
else:
|
|
generator.prepare(target, kernel_bootstrap=True, target_size=size)
|
|
path = os.path.join(args.target, os.path.relpath(generator.target_dir, args.target))
|
|
print("Please:")
|
|
print(f" 1. Take {path}.img and write it to a boot drive and then boot it.")
|
|
|
|
else:
|
|
if args.kernel:
|
|
generator.prepare(target, using_kernel=True, target_size=size)
|
|
|
|
run(args.qemu_cmd,
|
|
'-enable-kvm',
|
|
'-m', str(args.qemu_ram) + 'M',
|
|
'-smp', str(args.cores),
|
|
'-no-reboot',
|
|
'-drive', 'file=' + target.get_disk("disk") + ',format=raw',
|
|
'-drive', 'file=' + target.get_disk("external") + ',format=raw',
|
|
'-nic', 'user,ipv6=off,model=e1000',
|
|
'-kernel', args.kernel,
|
|
'-nographic',
|
|
'-append', 'console=ttyS0 root=/dev/sda1 rootfstype=ext3 init=/init rw')
|
|
else:
|
|
generator.prepare(target, kernel_bootstrap=True, target_size=size)
|
|
arg_list = [
|
|
'-enable-kvm',
|
|
'-m', str(args.qemu_ram) + 'M',
|
|
'-smp', str(args.cores),
|
|
'-no-reboot',
|
|
'-drive', 'file=' + generator.target_dir + '.img' + ',format=raw'
|
|
]
|
|
if target.get_disk("external") is not None:
|
|
arg_list += [
|
|
'-drive', 'file=' + target.get_disk("external") + ',format=raw',
|
|
]
|
|
arg_list += [
|
|
'-machine', 'kernel-irqchip=split',
|
|
'-nic', 'user,ipv6=off,model=e1000',
|
|
'-nographic'
|
|
]
|
|
run(args.qemu_cmd, *arg_list)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|