2021-04-06 00:12:02 +01:00
|
|
|
#!/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
|
2021-12-25 18:19:01 +00:00
|
|
|
# SPDX-FileCopyrightText: 2022 Dor Askayo <dor.askayo@gmail.com>
|
2021-04-06 00:12:02 +01:00
|
|
|
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
|
2021-04-16 18:35:24 +01:00
|
|
|
# SPDX-FileCopyrightText: 2021 Bastian Bittorf <bb@npl.de>
|
2021-05-18 12:37:34 +01:00
|
|
|
# SPDX-FileCopyrightText: 2021 Melg Eight <public.melg8@gmail.com>
|
2023-01-28 00:11:32 +00:00
|
|
|
# SPDX-FileCopyrightText: 2021-23 fosslinux <fosslinux@aussies.space>
|
2024-01-01 21:51:33 +00:00
|
|
|
# SPDX-FileCopyrightText: 2023-24 Gábor Stefanik <netrolller.3d@gmail.com>
|
2021-04-06 00:12:02 +01:00
|
|
|
|
|
|
|
import argparse
|
|
|
|
import os
|
|
|
|
|
2023-11-08 15:24:19 +00:00
|
|
|
from lib.utils import run, run_as_root
|
2023-12-26 03:28:47 +00:00
|
|
|
from lib.target import Target
|
2023-11-08 00:30:20 +00:00
|
|
|
from lib.generator import Generator, stage0_arch_map
|
2021-07-06 01:52:10 +01:00
|
|
|
|
|
|
|
def create_configuration_file(args):
|
|
|
|
"""
|
|
|
|
Creates bootstrap.cfg file which would contain options used to
|
|
|
|
customize bootstrap.
|
|
|
|
"""
|
2023-11-08 00:30:20 +00:00
|
|
|
config_path = os.path.join('steps', 'bootstrap.cfg')
|
2021-08-05 13:16:19 +01:00
|
|
|
with open(config_path, "w", encoding="utf_8") as config:
|
2024-02-14 14:38:06 +00:00
|
|
|
config.write(f"ARCH={args.arch}\n")
|
|
|
|
config.write(f"ARCH_DIR={stage0_arch_map.get(args.arch, args.arch)}\n")
|
2023-04-10 06:30:16 +01:00
|
|
|
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")
|
2024-01-01 21:51:33 +00:00
|
|
|
config.write(f"SWAP_SIZE={args.swap}\n")
|
2024-01-01 22:18:55 +00:00
|
|
|
config.write(f"FINAL_JOBS={args.cores}\n")
|
2023-12-23 06:16:59 +00:00
|
|
|
config.write(f"INTERNAL_CI={args.internal_ci or False}\n")
|
2024-01-01 21:37:32 +00:00
|
|
|
config.write(f"INTERACTIVE={args.interactive}\n")
|
2024-02-25 01:39:43 +00:00
|
|
|
config.write(f"BARE_METAL={args.bare_metal or (args.qemu and args.interactive)}\n")
|
2023-04-03 19:07:24 +01:00
|
|
|
if (args.bare_metal or args.qemu) and not args.kernel:
|
2023-11-08 00:30:20 +00:00
|
|
|
if args.repo or args.external_sources:
|
|
|
|
config.write("DISK=sdb1\n")
|
|
|
|
else:
|
2023-12-17 20:59:00 +00:00
|
|
|
config.write("DISK=sda\n")
|
2023-03-31 19:08:50 +01:00
|
|
|
config.write("KERNEL_BOOTSTRAP=True\n")
|
2023-04-03 19:07:24 +01:00
|
|
|
else:
|
2023-05-10 15:33:42 +01:00
|
|
|
config.write("DISK=sda1\n")
|
2023-04-03 19:07:24 +01:00
|
|
|
config.write("KERNEL_BOOTSTRAP=False\n")
|
2023-04-16 11:14:26 +01:00
|
|
|
config.write(f"BUILD_KERNELS={args.update_checksums or args.build_kernels}\n")
|
2021-04-06 00:12:02 +01:00
|
|
|
|
2024-01-01 21:51:33 +00:00
|
|
|
# pylint: disable=too-many-statements,too-many-branches
|
2021-04-06 00:12:02 +01:00
|
|
|
def main():
|
|
|
|
"""
|
|
|
|
A few command line arguments to customize bootstrap.
|
2023-11-08 00:30:20 +00:00
|
|
|
This function also creates object which prepares directory
|
2021-04-06 00:12:02 +01:00
|
|
|
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")
|
2021-12-25 18:19:01 +00:00
|
|
|
parser.add_argument("-bw", "--bwrap", help="Run inside a bwrap sandbox",
|
|
|
|
action="store_true")
|
2023-12-26 03:28:47 +00:00
|
|
|
parser.add_argument("-t", "--target", help="Target directory",
|
|
|
|
default="target")
|
|
|
|
parser.add_argument("--tmpfs", help="Use a tmpfs on target",
|
2023-01-28 00:11:32 +00:00
|
|
|
action="store_true")
|
|
|
|
parser.add_argument("--tmpfs-size", help="Size of the tmpfs",
|
|
|
|
default="8G")
|
2023-04-10 06:30:16 +01:00
|
|
|
parser.add_argument("--cores", help="Cores to use for building",
|
|
|
|
default=2)
|
2022-04-07 00:09:45 +01:00
|
|
|
parser.add_argument("--force-timestamps",
|
2021-05-18 12:37:34 +01:00
|
|
|
help="Force all files timestamps to be 0 unix time",
|
|
|
|
action="store_true")
|
2022-04-07 00:09:45 +01:00
|
|
|
parser.add_argument("--update-checksums",
|
2024-01-01 21:37:32 +00:00
|
|
|
help="Update checksum files",
|
2022-04-07 00:09:45 +01:00
|
|
|
action="store_true")
|
2022-05-22 01:03:21 +01:00
|
|
|
parser.add_argument("--external-sources",
|
2024-01-01 21:37:32 +00:00
|
|
|
help="Download sources externally from live-bootstrap",
|
2022-05-23 06:56:18 +01:00
|
|
|
action="store_true")
|
2023-04-14 22:16:05 +01:00
|
|
|
parser.add_argument("--build-kernels",
|
2024-01-01 21:37:32 +00:00
|
|
|
help="Also build kernels in chroot and bwrap builds",
|
2023-04-14 22:16:05 +01:00
|
|
|
action="store_true")
|
2021-10-03 02:28:08 +01:00
|
|
|
parser.add_argument("--no-create-config",
|
|
|
|
help="Do not automatically create config file",
|
|
|
|
action="store_true")
|
2024-01-01 21:37:32 +00:00
|
|
|
parser.add_argument("-i", "--interactive",
|
|
|
|
help="Use interactive prompts to resolve issues during bootstrap",
|
|
|
|
action="store_true")
|
2022-05-28 22:59:42 +01:00
|
|
|
parser.add_argument("-r", "--repo",
|
2024-01-01 21:37:32 +00:00
|
|
|
help="Path to prebuilt binary packages", nargs=None)
|
2022-12-21 03:17:37 +00:00
|
|
|
parser.add_argument("--early-preseed",
|
2024-01-01 21:37:32 +00:00
|
|
|
help="Skip early stages of live-bootstrap", nargs=None)
|
2023-05-01 11:49:41 +01:00
|
|
|
parser.add_argument("--internal-ci", help="INTERNAL for github CI")
|
2024-01-01 21:51:33 +00:00
|
|
|
parser.add_argument("-s", "--swap", help="Swap space to allocate in Linux",
|
|
|
|
default=0)
|
2021-04-06 00:12:02 +01:00
|
|
|
|
|
|
|
# QEMU arguments
|
2021-10-03 02:28:08 +01:00
|
|
|
parser.add_argument("-q", "--qemu", help="Use QEMU",
|
|
|
|
action="store_true")
|
|
|
|
parser.add_argument("-qc", "--qemu-cmd", help="QEMU command to run",
|
2021-04-06 00:12:02 +01:00
|
|
|
default="qemu-system-x86_64")
|
2021-10-03 02:28:08 +01:00
|
|
|
parser.add_argument("-qr", "--qemu-ram", help="Memory (in megabytes) allocated to QEMU VM",
|
2021-10-09 08:04:00 +01:00
|
|
|
default=4096)
|
2023-12-17 20:59:00 +00:00
|
|
|
parser.add_argument("-qs", "--target-size", help="Size of the target image (for QEMU only)",
|
|
|
|
default="16G")
|
2023-12-17 21:09:04 +00:00
|
|
|
parser.add_argument("-qk", "--kernel", help="Custom early kernel to use")
|
2021-04-06 00:12:02 +01:00
|
|
|
|
2021-10-03 02:28:08 +01:00
|
|
|
parser.add_argument("-b", "--bare-metal", help="Build images for bare metal",
|
|
|
|
action="store_true")
|
2021-04-06 00:12:02 +01:00
|
|
|
|
|
|
|
args = parser.parse_args()
|
2021-10-03 02:28:08 +01:00
|
|
|
|
2023-01-28 00:11:32 +00:00
|
|
|
# Mode validation
|
2021-10-03 02:28:08 +01:00
|
|
|
def check_types():
|
|
|
|
count = 0
|
|
|
|
if args.qemu:
|
|
|
|
count += 1
|
|
|
|
if args.chroot:
|
|
|
|
count += 1
|
2021-12-25 18:19:01 +00:00
|
|
|
if args.bwrap:
|
|
|
|
count += 1
|
2021-10-03 02:28:08 +01:00
|
|
|
if args.bare_metal:
|
|
|
|
count += 1
|
|
|
|
return count
|
|
|
|
|
|
|
|
if check_types() > 1:
|
2023-01-28 00:11:32 +00:00
|
|
|
raise ValueError("No more than one of qemu, chroot, bwrap, bare metal"
|
2023-01-13 08:28:30 +00:00
|
|
|
"may be used.")
|
2021-10-03 02:28:08 +01:00
|
|
|
if check_types() == 0:
|
2023-01-28 00:11:32 +00:00
|
|
|
raise ValueError("One of qemu, chroot, bwrap, or bare metal must be selected.")
|
2021-04-06 00:12:02 +01:00
|
|
|
|
2023-01-28 00:11:32 +00:00
|
|
|
# Arch validation
|
2021-04-06 00:12:02 +01:00
|
|
|
if args.arch != "x86":
|
2023-11-19 01:42:07 +00:00
|
|
|
print("Only x86 is supported at the moment, other arches are for development only.")
|
2021-04-06 00:12:02 +01:00
|
|
|
|
2023-12-26 03:28:47 +00:00
|
|
|
# Tmpfs validation
|
2023-01-28 00:11:32 +00:00
|
|
|
if args.bwrap and args.tmpfs:
|
2023-01-28 17:14:20 +00:00
|
|
|
raise ValueError("tmpfs cannot be used with bwrap.")
|
2023-01-28 00:11:32 +00:00
|
|
|
|
2023-04-10 06:30:16 +01:00
|
|
|
# Cores validation
|
|
|
|
if int(args.cores) < 1:
|
|
|
|
raise ValueError("Must use one or more cores.")
|
|
|
|
|
2023-12-17 20:59:00 +00:00
|
|
|
# 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
|
|
|
|
|
2024-01-01 21:51:33 +00:00
|
|
|
# Swap file size validation
|
|
|
|
if args.qemu or args.bare_metal:
|
|
|
|
args.swap = (int(str(args.swap).rstrip('gGmM')) *
|
|
|
|
(1024 if str(args.swap).lower().endswith('g') else 1))
|
|
|
|
else:
|
|
|
|
args.swap = 0
|
|
|
|
|
2024-01-24 06:30:12 +00:00
|
|
|
# Set constant umask
|
|
|
|
os.umask(0o022)
|
|
|
|
|
2023-01-28 00:11:32 +00:00
|
|
|
# bootstrap.cfg
|
2021-10-03 02:28:08 +01:00
|
|
|
try:
|
2023-12-17 21:09:04 +00:00
|
|
|
os.remove(os.path.join('steps', 'bootstrap.cfg'))
|
2021-10-03 02:28:08 +01:00
|
|
|
except FileNotFoundError:
|
|
|
|
pass
|
|
|
|
if not args.no_create_config:
|
|
|
|
create_configuration_file(args)
|
|
|
|
else:
|
2023-12-17 21:09:04 +00:00
|
|
|
with open(os.path.join('steps', 'bootstrap.cfg'), 'a', encoding='UTF-8'):
|
2021-10-03 02:28:08 +01:00
|
|
|
pass
|
2021-04-06 00:12:02 +01:00
|
|
|
|
2023-12-26 03:28:47 +00:00
|
|
|
# target
|
|
|
|
target = Target(path=args.target)
|
2023-01-28 00:11:32 +00:00
|
|
|
if args.tmpfs:
|
2023-12-26 03:28:47 +00:00
|
|
|
target.tmpfs(size=args.tmpfs_size)
|
2021-04-06 00:12:02 +01:00
|
|
|
|
2023-12-22 11:47:09 +00:00
|
|
|
generator = Generator(arch=args.arch,
|
2023-11-08 00:30:20 +00:00
|
|
|
external_sources=args.external_sources,
|
|
|
|
repo_path=args.repo,
|
|
|
|
early_preseed=args.early_preseed)
|
2022-09-07 21:37:00 +01:00
|
|
|
|
2023-12-26 03:28:47 +00:00
|
|
|
bootstrap(args, generator, target, args.target_size)
|
2021-04-06 00:12:02 +01:00
|
|
|
|
2023-12-26 03:28:47 +00:00
|
|
|
def bootstrap(args, generator, target, size):
|
2021-04-06 00:12:02 +01:00
|
|
|
"""Kick off bootstrap process."""
|
2023-12-28 06:25:35 +00:00
|
|
|
print(f"Bootstrapping {args.arch}", flush=True)
|
2021-04-06 00:12:02 +01:00
|
|
|
if args.chroot:
|
2021-04-21 23:54:14 +01:00
|
|
|
find_chroot = """
|
|
|
|
import shutil
|
|
|
|
print(shutil.which('chroot'))
|
|
|
|
"""
|
2023-11-08 15:24:19 +00:00
|
|
|
chroot_binary = run_as_root('python3', '-c', find_chroot,
|
|
|
|
capture_output=True).stdout.decode().strip()
|
2021-10-20 21:11:48 +01:00
|
|
|
|
2023-12-26 03:28:47 +00:00
|
|
|
generator.prepare(target, using_kernel=False)
|
2022-05-23 12:18:52 +01:00
|
|
|
|
2021-10-20 21:11:48 +01:00
|
|
|
arch = stage0_arch_map.get(args.arch, args.arch)
|
|
|
|
init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed')
|
2023-12-26 03:28:47 +00:00
|
|
|
run_as_root('env', '-i', 'PATH=/bin', chroot_binary, generator.target_dir, init)
|
2021-07-06 01:52:10 +01:00
|
|
|
|
2021-12-25 18:19:01 +00:00
|
|
|
elif args.bwrap:
|
2023-12-25 16:43:31 +00:00
|
|
|
init = '/init'
|
2023-05-01 11:49:41 +01:00
|
|
|
if not args.internal_ci or args.internal_ci == "pass1":
|
2023-12-26 03:28:47 +00:00
|
|
|
generator.prepare(target, using_kernel=False)
|
2023-05-01 11:49:41 +01:00
|
|
|
|
|
|
|
arch = stage0_arch_map.get(args.arch, args.arch)
|
|
|
|
init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed')
|
2023-12-25 16:43:31 +00:00
|
|
|
else:
|
2023-12-26 03:28:47 +00:00
|
|
|
generator.reuse(target)
|
2023-12-25 16:43:31 +00:00
|
|
|
|
|
|
|
run('env', '-i', 'bwrap', '--unshare-user',
|
|
|
|
'--uid', '0',
|
|
|
|
'--gid', '0',
|
|
|
|
'--unshare-net' if args.external_sources else None,
|
|
|
|
'--setenv', 'PATH', '/usr/bin',
|
2023-12-26 03:28:47 +00:00
|
|
|
'--bind', generator.target_dir, '/',
|
2023-12-25 16:43:31 +00:00
|
|
|
'--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)
|
2023-02-06 17:06:11 +00:00
|
|
|
|
2021-10-03 02:28:08 +01:00
|
|
|
elif args.bare_metal:
|
2023-03-31 19:08:50 +01:00
|
|
|
if args.kernel:
|
2023-12-26 03:28:47 +00:00
|
|
|
generator.prepare(target, using_kernel=True, target_size=size)
|
|
|
|
path = os.path.join(args.target, os.path.relpath(generator.target_dir, args.target))
|
2023-03-31 19:08:50 +01:00
|
|
|
print("Please:")
|
2023-12-26 03:28:47 +00:00
|
|
|
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.")
|
2023-03-31 19:08:50 +01:00
|
|
|
else:
|
2023-12-26 03:28:47 +00:00
|
|
|
generator.prepare(target, kernel_bootstrap=True, target_size=size)
|
|
|
|
path = os.path.join(args.target, os.path.relpath(generator.target_dir, args.target))
|
2023-03-31 19:08:50 +01:00
|
|
|
print("Please:")
|
2023-12-26 03:28:47 +00:00
|
|
|
print(f" 1. Take {path}.img and write it to a boot drive and then boot it.")
|
2021-10-03 02:28:08 +01:00
|
|
|
|
2021-07-06 01:52:10 +01:00
|
|
|
else:
|
2023-03-31 19:08:50 +01:00
|
|
|
if args.kernel:
|
2023-12-26 03:28:47 +00:00
|
|
|
generator.prepare(target, using_kernel=True, target_size=size)
|
2023-03-31 19:08:50 +01:00
|
|
|
|
2024-01-10 18:03:50 +00:00
|
|
|
arg_list = [
|
2023-03-31 19:08:50 +01:00
|
|
|
'-enable-kvm',
|
|
|
|
'-m', str(args.qemu_ram) + 'M',
|
2023-04-10 06:30:16 +01:00
|
|
|
'-smp', str(args.cores),
|
2024-01-10 18:03:50 +00:00
|
|
|
'-drive', 'file=' + target.get_disk("disk") + ',format=raw'
|
|
|
|
]
|
|
|
|
if target.get_disk("external") is not None:
|
|
|
|
arg_list += [
|
|
|
|
'-drive', 'file=' + target.get_disk("external") + ',format=raw',
|
|
|
|
]
|
|
|
|
arg_list += [
|
2023-03-31 19:08:50 +01:00
|
|
|
'-nic', 'user,ipv6=off,model=e1000',
|
|
|
|
'-kernel', args.kernel,
|
2024-02-25 01:39:43 +00:00
|
|
|
'-append',
|
2024-01-10 18:03:50 +00:00
|
|
|
]
|
2024-02-25 01:39:43 +00:00
|
|
|
if args.interactive:
|
|
|
|
arg_list += ['consoleblank=0 earlyprintk=vga root=/dev/sda1 '
|
|
|
|
'rootfstype=ext3 init=/init rw']
|
|
|
|
else:
|
|
|
|
arg_list += ['console=ttyS0 earlycon=uart8250,io,0x3f8,115200n8 '
|
|
|
|
'root=/dev/sda1 rootfstype=ext3 init=/init rw']
|
2023-03-31 19:08:50 +01:00
|
|
|
else:
|
2023-12-26 03:28:47 +00:00
|
|
|
generator.prepare(target, kernel_bootstrap=True, target_size=size)
|
2023-12-17 20:59:00 +00:00
|
|
|
arg_list = [
|
2023-03-31 19:08:50 +01:00
|
|
|
'-enable-kvm',
|
2023-12-17 20:59:00 +00:00
|
|
|
'-m', str(args.qemu_ram) + 'M',
|
2023-04-10 06:30:16 +01:00
|
|
|
'-smp', str(args.cores),
|
2023-12-26 03:28:47 +00:00
|
|
|
'-drive', 'file=' + generator.target_dir + '.img' + ',format=raw'
|
2023-12-17 20:59:00 +00:00
|
|
|
]
|
2023-12-26 03:28:47 +00:00
|
|
|
if target.get_disk("external") is not None:
|
2023-12-17 20:59:00 +00:00
|
|
|
arg_list += [
|
2023-12-26 03:28:47 +00:00
|
|
|
'-drive', 'file=' + target.get_disk("external") + ',format=raw',
|
2023-12-17 20:59:00 +00:00
|
|
|
]
|
|
|
|
arg_list += [
|
2023-03-31 19:08:50 +01:00
|
|
|
'-machine', 'kernel-irqchip=split',
|
2024-02-25 01:39:43 +00:00
|
|
|
'-nic', 'user,ipv6=off,model=e1000'
|
2023-12-17 20:59:00 +00:00
|
|
|
]
|
2024-02-25 01:39:43 +00:00
|
|
|
if not args.interactive:
|
|
|
|
arg_list += ['-no-reboot', '-nographic']
|
|
|
|
run(args.qemu_cmd, *arg_list)
|
2021-04-06 00:12:02 +01:00
|
|
|
|
2021-04-16 18:35:24 +01:00
|
|
|
if __name__ == "__main__":
|
2021-04-06 00:12:02 +01:00
|
|
|
main()
|