Add sysb and sysc scaffolding.

Now that we have the Linux Kernel built, we move to a full-disk (rather
than initramfs) setup in sysc. However, we cannot assume the seed kernel
has support for mounting hard drives. So, first we need to kexec into
sysb, which is used as a jumping off point to create the hard drive for
sysc.

Additionally, since 2.6.16 does not have support for on-demand initramfs
(initramfs must be built into kernel), we will have to rebuild the linux
kernel within sysb without the initramfs.

All of this process is not performed for chroot mode. Instead, we skip
sysb and jump straight to sysc, copying over appropriate data.

The python scripts have been changed slightly. Each sys* inherits
SysGeneral, which contains various functions which are not specific to
any sys* and simplifies those files. rootfs now also handles sysb and
sysc.

bootstrap.cfg also gives an indication whether we are running in a
chroot to avoid attempting to kexec/mount within a chroot.
This commit is contained in:
fosslinux 2021-07-06 10:52:10 +10:00
parent 925ce198c1
commit 5c88f1c87f
75 changed files with 624 additions and 176 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ tmp/
kernel
sources/
__pycache__
sysglobal/bootstrap.cfg

View File

@ -9,6 +9,6 @@ Source: https://github.com/fosslinux/live-bootstrap
# Copyright: $YEAR $NAME <$CONTACT>
# License: ...
Files: SHA256SUMS.sources sysa/pre-sha.sha256sums sysa/*/checksums sysa/*/checksums/*
Files: SHA256SUMS.sources sysa/pre-sha.sha256sums sysa/*/checksums sysa/*/checksums/* sysc/*/checksums sysc/*/checksums/*
Copyright: none
License: MIT

151
lib/sysgeneral.py Normal file
View File

@ -0,0 +1,151 @@
#!/usr/bin/env python3
"""
This file contains a few functions to be shared by all Sys* classes
"""
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
# SPDX-License-Identifier: GPL-3.0-or-later
import os
import hashlib
import shutil
import glob
import subprocess
import requests
from lib.utils import mount, umount, get_target, copytree
class SysGeneral:
"""
A class from which all Sys* class are extended.
Contains functions used in all Sys*
"""
def __del__(self):
if not self.preserve_tmp:
print("Unmounting tmpfs from %s" % (self.tmp_dir))
umount(self.tmp_dir)
os.rmdir(self.tmp_dir)
def mount_tmpfs(self):
"""Mount the tmpfs for this sysx"""
if not os.path.isdir(self.tmp_dir):
os.mkdir(self.tmp_dir)
print("Mounting tmpfs on %s" % (self.tmp_dir))
mount('tmpfs', self.tmp_dir, 'tmpfs', 'size=8G')
def check_file(self, file_name):
"""Check hash of downloaded source file."""
checksum_store = os.path.join(self.git_dir, 'SHA256SUMS.sources')
with open(checksum_store) as checksum_file:
hashes = checksum_file.read().splitlines()
for hash_line in hashes:
if os.path.basename(file_name) in hash_line:
# Hash is in store, check it
expected_hash = hash_line.split()[0]
with open(file_name, "rb") as downloaded_file:
downloaded_content = downloaded_file.read() # read entire file as bytes
readable_hash = hashlib.sha256(downloaded_content).hexdigest()
if expected_hash == readable_hash:
return
raise Exception("Checksum mismatch")
raise Exception("File checksum is not yet recorded")
def download_file(self, url, file_name=None):
"""
Download a single source archive.
"""
cache_dir = os.path.join(self.git_dir, 'sources')
# Automatically determine file name based on URL.
if file_name is None:
file_name = os.path.basename(url)
abs_file_name = os.path.join(cache_dir, file_name)
# Create a cache directory for downloaded sources
if not os.path.isdir(cache_dir):
os.mkdir(cache_dir)
# Actually download the file
if not os.path.isfile(abs_file_name):
print("Downloading: %s" % (file_name))
request = requests.get(url, allow_redirects=True)
open(abs_file_name, 'wb').write(request.content)
# Check SHA256 hash
self.check_file(abs_file_name)
return abs_file_name
def get_file(self, url, mkbuild=False, output=None):
"""
Download and prepare source packages
url can be either:
1. a single URL
2. list of URLs to download. In this case the first URL is the primary URL
from which we derive the name of package directory
output can be used to override file name of the downloaded file(s).
mkbuild=True can be used to pre-create build directories before
mkdir is available.
"""
# Single URL
if isinstance(url, str):
assert output is None or isinstance(output, str)
file_name = url if output is None else output
urls = [url]
outputs = [output]
# Multiple URLs
elif isinstance(url, list):
assert output is None or len(output) == len(url)
file_name = url[0] if output is None else output[0]
urls = url
outputs = output if output is not None else [None] * len(url)
else:
raise TypeError("url must be either a string or a list of strings")
# Determine installation directory
target_name = get_target(file_name)
target_src_dir = os.path.join(self.base_dir, target_name, 'src')
# Install base files
src_tree = os.path.join(self.sys_dir, target_name)
copytree(src_tree, self.base_dir)
if not os.path.isdir(target_src_dir):
os.mkdir(target_src_dir)
for i, _ in enumerate(urls):
# Download files into cache directory
tarball = self.download_file(urls[i], outputs[i])
# Install sources into target directory
shutil.copy2(tarball, target_src_dir)
if mkbuild:
os.mkdir(os.path.join(self.base_dir, target_name, 'build'))
def deploy_sysglobal_files(self):
"""Deploy files common to all Sys*"""
sysglobal_files = ['bootstrap.cfg', 'helpers.sh']
for f in sysglobal_files:
shutil.copy2(os.path.join(self.git_dir, 'sysglobal', f),
self.base_dir)
def make_initramfs(self):
"""Package binary bootstrap seeds and sources into initramfs."""
self.initramfs_path = os.path.join(self.tmp_dir, 'initramfs')
# Create a list of files to go within the initramfs
file_list = glob.glob(os.path.join(self.tmp_dir, '**'), recursive=True)
# Use built-in removeprefix once we can use Python 3.9
def remove_prefix(text, prefix):
if text.startswith(prefix):
return text[len(prefix):]
return text # or whatever
file_list = [remove_prefix(f, self.tmp_dir + os.sep) for f in file_list]
# Create the initramfs
with open(self.initramfs_path, "w") as initramfs:
cpio = subprocess.Popen(["cpio", "--format", "newc", "--create", "--directory", self.tmp_dir],
stdin=subprocess.PIPE, stdout=initramfs)
cpio.communicate(input='\n'.join(file_list).encode())

View File

@ -5,13 +5,13 @@ This file contains a few self-contained helper functions
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
import os
import shutil
import subprocess
import sys
def run(*args, **kwargs):
"""A small wrapper around subprocess.run"""
arguments = [str(arg) for arg in args]
@ -25,6 +25,19 @@ def run(*args, **kwargs):
print("Bootstrapping failed")
sys.exit(1)
def create_disk(image, disk_type, fs_type, size):
"""Create a disk image, with a filesystem on it"""
run('truncate', '-s', size, image)
# First find the device we will use, then actually use it
loop_dev = run('losetup', '-f', capture_output=True).stdout.decode().strip()
run('sudo', 'losetup', loop_dev, image)
# Create the partition
run('sudo', 'parted', '--script', image, 'mklabel', disk_type, 'mkpart',
'primary', 'ext4', '0%', '100%')
run('sudo', 'partprobe', loop_dev)
run('sudo', 'mkfs.' + fs_type, loop_dev + "p1")
return loop_dev
def mount(source, target, fs_type, options='', **kwargs):
"""Mount filesystem"""
run('sudo', 'mount', source, target, '-t', fs_type, '-o', options, **kwargs)

View File

@ -10,6 +10,7 @@ you can run bootstap inside chroot.
# 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 fosslinux <fosslinux@aussies.space>
import argparse
import glob
@ -18,7 +19,20 @@ import subprocess
import shutil
from sysa import SysA
from lib.utils import run
from sysb import SysB
from sysc import SysC
from lib.utils import run, umount
def create_configuration_file(args):
"""
Creates bootstrap.cfg file which would contain options used to
customize bootstrap.
"""
config_path = os.path.join('sysglobal', 'bootstrap.cfg')
with open(config_path, "w") as config:
config.write("FORCE_TIMESTAMPS=" + str(args.force_timestamps) + "\n")
config.write("CHROOT=" + str(args.chroot) + "\n")
config.write("DISK=hda1\n")
def main():
"""
@ -56,35 +70,17 @@ def main():
if args.arch != "x86":
raise ValueError("Only x86 is supported at the moment.")
system_a = SysA(arch=args.arch, preserve_tmp=args.preserve, tmpdir=args.tmpdir,
force_timestamps=args.force_timestamps)
initramfs_path = os.path.join(system_a.tmp_dir, "initramfs")
create_configuration_file(args)
if not args.chroot:
make_initramfs(system_a.tmp_dir, initramfs_path)
system_b = SysB(arch=args.arch, preserve_tmp=args.preserve, tmpdir=args.tmpdir, chroot=args.chroot)
system_a = SysA(arch=args.arch, preserve_tmp=args.preserve, tmpdir=args.tmpdir, chroot=args.chroot, sysb_tmp=system_b.tmp_dir)
system_c = SysC(arch=args.arch, preserve_tmp=args.preserve, tmpdir=args.tmpdir, chroot=args.chroot)
bootstrap(args, system_a.tmp_dir, initramfs_path)
bootstrap(args, system_a, system_b, system_c)
def make_initramfs(tmp_dir, initramfs_path):
"""Package binary bootstrap seeds and sources into initramfs."""
file_list = glob.glob(os.path.join(tmp_dir, '**'), recursive=True)
# Use built-in removeprefix once we can use Python 3.9
def remove_prefix(text, prefix):
if text.startswith(prefix):
return text[len(prefix):]
return text # or whatever
file_list = [remove_prefix(f, tmp_dir + os.sep) for f in file_list]
with open(initramfs_path, "w") as initramfs:
cpio = subprocess.Popen(["cpio", "--format", "newc", "--create", "--directory", tmp_dir],
stdin=subprocess.PIPE, stdout=initramfs)
cpio.communicate(input='\n'.join(file_list).encode())
def bootstrap(args, tmp_dir, initramfs_path):
def bootstrap(args, system_a, system_b, system_c):
"""Kick off bootstrap process."""
print("Bootstrapping %s" % (args.arch))
print("Bootstrapping %s -- SysA" % (args.arch))
if args.chroot:
find_chroot = """
import shutil
@ -92,11 +88,19 @@ print(shutil.which('chroot'))
"""
chroot_binary = run('sudo', 'python3', '-c', find_chroot,
capture_output=True).stdout.decode().strip()
# sysa
init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', args.arch, 'kaem-optional-seed')
run('sudo', 'env', '-i', 'PATH=/bin', chroot_binary, tmp_dir, init)
return
run('sudo', 'env', '-i', 'PATH=/bin', chroot_binary, system_a.tmp_dir, init)
# Perform the steps for sysa -> sysc transition that would occur within
# qemu if we were running not in chroot
# We skip sysb as that is only pertinent to "hardware" (not chroot)
# system_c.chroot_transition(system_a.tmp_dir)
# sysc
print("Bootstrapping %s -- SysC" % (args.arch))
# init = os.path.join(os.sep, 'init')
# run('sudo', chroot_binary, system_c.tmp_dir, init)
if args.minikernel:
elif args.minikernel:
if os.path.isdir('kritis-linux'):
shutil.rmtree('kritis-linux')
@ -111,19 +115,20 @@ print(shutil.which('chroot'))
'--qemucpu', '486',
'--kernel', '3.18.140',
'--features', 'kflock,highrestimers',
'--ramsize', str(args.qemu_ram) + 'M',
'--initrd', initramfs_path,
# Hack to add -hda /dev/blah
'--ramsize', str(args.qemu_ram) + 'M -hda ' + sysb.dev_name,
'--initrd', system_a.initramfs_path,
'--log', '/tmp/bootstrap.log')
return
else:
run(args.qemu_cmd,
'-enable-kvm',
'-m', str(args.qemu_ram) + 'M',
'-nographic',
'-no-reboot',
'-hda', system_c.dev_name,
'-kernel', args.kernel,
'-initrd', initramfs_path,
'-append', "console=ttyS0")
'-initrd', system_a.initramfs_path,
'-display', 'curses')
if __name__ == "__main__":
main()

158
sysa.py
View File

@ -3,36 +3,39 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
# SPDX-FileCopyrightText: 2021 Melg Eight <public.melg8@gmail.com>
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
import hashlib
import glob
import os
from distutils.dir_util import copy_tree
import shutil
import requests
import subprocess
from lib.utils import mount, umount, copytree, get_target
from lib.sysgeneral import SysGeneral
class SysA:
class SysA(SysGeneral):
"""
Class responsible for preparing sources for System A.
"""
def __init__(self, arch, preserve_tmp, tmpdir, force_timestamps):
def __init__(self, arch, preserve_tmp, tmpdir, chroot, sysb_tmp):
self.git_dir = os.path.dirname(os.path.join(__file__))
self.arch = arch
self.preserve_tmp = preserve_tmp
self.sys_dir = os.path.join(self.git_dir, 'sysa')
if tmpdir is None:
self.tmp_dir = os.path.join(self.git_dir, 'sysa', 'tmp')
self.tmp_dir = os.path.join(self.sys_dir, 'tmp')
else:
self.tmp_dir = tmpdir
self.sysa_dir = os.path.join(self.git_dir, 'sysa')
self.tmp_dir = os.path.join(tmpdir, 'sysa')
os.mkdir(self.tmp_dir)
self.after_dir = os.path.join(self.tmp_dir, 'after')
self.force_timestamps = force_timestamps
self.base_dir = self.after_dir
self.sysb_tmp = sysb_tmp
self.prepare()
<<<<<<< HEAD
def __del__(self):
if not self.preserve_tmp:
print("Unmounting tmpfs from %s" % (self.tmp_dir))
@ -128,6 +131,10 @@ class SysA:
# Install sources into target directory
shutil.copy2(tarball, target_src_dir)
=======
if not chroot:
self.make_initramfs()
>>>>>>> 6252572 (Add sysb and sysc scaffolding.)
def prepare(self):
"""
@ -135,17 +142,23 @@ class SysA:
We create an empty tmpfs, unpack stage0-posix.
Rest of the files are unpacked into more structured directory /after
"""
if not os.path.isdir(self.tmp_dir):
os.mkdir(self.tmp_dir)
print("Mounting tmpfs on %s" % (self.tmp_dir))
mount('tmpfs', self.tmp_dir, 'tmpfs', 'size=8G')
self.mount_tmpfs()
os.mkdir(self.after_dir)
self.stage0_posix()
self.after()
# sysb must be added to sysa as it is another initramfs stage
self.sysb()
def sysb(self):
"""Copy in sysb files for sysb."""
shutil.copytree(self.sysb_tmp, os.path.join(self.tmp_dir, 'sysb'),
shutil.ignore_patterns('tmp'))
def stage0_posix(self):
"""Copy in all of the stage0-posix"""
stage0_posix_base_dir = os.path.join(self.sysa_dir, 'stage0-posix', 'src')
stage0_posix_base_dir = os.path.join(self.sys_dir, 'stage0-posix', 'src')
stage0_posix_arch_dir = os.path.join(stage0_posix_base_dir, self.arch)
copy_tree(stage0_posix_arch_dir, self.tmp_dir)
@ -166,14 +179,14 @@ class SysA:
copytree(mescc_tools_extra_dir, self.tmp_dir)
# bootstrap seeds
bootstrap_seeds_dir = os.path.join(self.sysa_dir, 'stage0-posix', 'src', 'bootstrap-seeds')
bootstrap_seeds_dir = os.path.join(self.sys_dir, 'stage0-posix', 'src', 'bootstrap-seeds')
copytree(bootstrap_seeds_dir, self.tmp_dir)
kaem_optional_seed = os.path.join(bootstrap_seeds_dir, 'POSIX',
self.arch, 'kaem-optional-seed')
shutil.copy2(kaem_optional_seed, os.path.join(self.tmp_dir, 'init'))
# stage0-posix hook to continue running live-bootstrap
shutil.copy2(os.path.join(self.sysa_dir, 'after.kaem'),
shutil.copy2(os.path.join(self.sys_dir, 'after.kaem'),
os.path.join(self.tmp_dir, 'after.kaem'))
# create directories needed
@ -190,25 +203,15 @@ class SysA:
the stage0-posix one is hella messy.
"""
self.create_configuration_file()
self.deploy_extra_files()
self.deploy_sysglobal_files()
self.get_packages()
def create_configuration_file(self):
"""
Creates bootstrap.cfg file which would contain options used to
customize bootstrap.
"""
os.mkdir(self.after_dir)
config_path = os.path.join(self.after_dir, "bootstrap.cfg")
with open(config_path, "w") as config:
config.write("FORCE_TIMESTAMPS=" + str(self.force_timestamps))
def deploy_extra_files(self):
"""Deploy misc files"""
extra_files = ['helpers.sh', 'run.sh', 'run2.sh']
extra_files = ['run.sh']
for extra_file in extra_files:
shutil.copy2(os.path.join(self.sysa_dir, extra_file), self.after_dir)
shutil.copy2(os.path.join(self.sys_dir, extra_file), self.after_dir)
shutil.copy2(os.path.join(self.git_dir, 'SHA256SUMS.sources'), self.after_dir)
@ -384,98 +387,9 @@ class SysA:
self.get_file("https://github.com/horms/kexec-tools/archive/refs/tags/v2.0.22.tar.gz",
output="kexec-tools-2.0.22.tar.gz")
# kbd 1.15
self.get_file("https://mirrors.edge.kernel.org/pub/linux/utils/kbd/kbd-1.15.tar.gz")
# linux kernel 2.6.16.62
# for some reason this is no longer on kernel.org
self.get_file("https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/snapshot/linux-2.6.16.62.tar.gz")
# bash 5.1
self.get_file("https://mirrors.kernel.org/gnu/bash/bash-5.1.tar.gz")
# xz 5.0.5
self.get_file("https://tukaani.org/xz/xz-5.0.5.tar.bz2")
# automake 1.11.2
self.get_file("https://mirrors.kernel.org/gnu/automake/automake-1.11.2.tar.bz2")
# autoconf 2.69
self.get_file("https://mirrors.kernel.org/gnu/autoconf/autoconf-2.69.tar.xz")
# automake 1.15.1
self.get_file("https://mirrors.kernel.org/gnu/automake/automake-1.15.1.tar.xz")
# tar 1.34
self.get_file(["https://mirrors.kernel.org/gnu/tar/tar-1.34.tar.xz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-30820c.tar.gz"])
# coreutils 8.32
self.get_file(["https://git.savannah.gnu.org/cgit/coreutils.git/snapshot/coreutils-8.32.tar.gz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-d279bc.tar.gz"])
# pkg-config 0.29.2
self.get_file("https://pkgconfig.freedesktop.org/releases/pkg-config-0.29.2.tar.gz")
# make 4.2.1
self.get_file("https://ftp.gnu.org/gnu/make/make-4.2.1.tar.gz")
# gmp 6.2.1
self.get_file("https://mirrors.kernel.org/gnu/gmp/gmp-6.2.1.tar.xz")
# autoconf archive 2021.02.19
self.get_file("https://mirrors.kernel.org/gnu/autoconf-archive/autoconf-archive-2021.02.19.tar.xz")
# mpfr 4.1.0
self.get_file("https://mirrors.kernel.org/gnu/mpfr/mpfr-4.1.0.tar.xz")
# mpc 1.2.1
self.get_file("https://mirrors.kernel.org/gnu/mpc/mpc-1.2.1.tar.gz")
# flex 2.5.33
self.get_file("http://download.nust.na/pub2/openpkg1/sources/DST/flex/flex-2.5.33.tar.gz")
# bison 2.3
self.get_file(["https://mirrors.kernel.org/gnu/bison/bison-2.3.tar.bz2",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-b28236b.tar.gz"])
# bison 3.4.2
self.get_file(["https://mirrors.kernel.org/gnu/bison/bison-3.4.2.tar.xz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-672663a.tar.gz"])
# perl 5.10.5
self.get_file("https://www.cpan.org/src/5.0/perl-5.10.1.tar.bz2")
# dist 3.5-236
# Debian's version is used because upstream is not to be found (dead?)
self.get_file("https://salsa.debian.org/perl-team/interpreter/dist/-/archive/d1de81f/dist-d1de81f.tar.gz",
output="dist-3.5-236.tar.gz")
# perl 5.32.1
self.get_file(["https://www.cpan.org/src/5.0/perl-5.32.1.tar.xz",
"https://salsa.debian.org/perl-team/interpreter/perl/-/archive/5f2dc80/perl-5f2dc80.tar.bz2"])
# automake 1.16.3
self.get_file("https://mirrors.kernel.org/gnu/automake/automake-1.16.3.tar.gz")
# patch 2.7.6
self.get_file(["https://mirrors.kernel.org/gnu/patch/patch-2.7.6.tar.xz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-e017871.tar.gz"])
# gettext 0.21
self.get_file(["https://mirrors.kernel.org/gnu/gettext/gettext-0.21.tar.xz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-7daa86f.tar.gz"])
# texinfo 6.7
self.get_file(["https://mirrors.kernel.org/gnu/texinfo/texinfo-6.7.tar.xz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-b81ec69.tar.gz"])
# zlib 1.2.11
self.get_file("https://www.zlib.net/zlib-1.2.11.tar.xz")
# gcc 4.7.4
self.get_file("https://mirrors.kernel.org/gnu/gcc/gcc-4.7.4/gcc-4.7.4.tar.bz2")
# gperf 3.1
self.get_file("https://mirrors.kernel.org/gnu/gperf/gperf-3.1.tar.gz")
# libunistring 0.9.10
self.get_file(["https://mirrors.kernel.org/gnu/libunistring/libunistring-0.9.10.tar.xz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-52a06cb3.tar.gz"])

View File

@ -1 +1 @@
0254b0de266d8dd8de847315c5ee9602e0ae7875c75e762bf043bb13510e628f after/boot/linux-2.6.16.62
0254b0de266d8dd8de847315c5ee9602e0ae7875c75e762bf043bb13510e628f /after/boot/linux-2.6.16.62

View File

@ -9,15 +9,40 @@
set -e
# shellcheck source=sysa/helpers.sh
. helpers.sh
. bootstrap.cfg
populate_device_nodes() {
# http://www.linuxfromscratch.org/lfs/view/6.1/chapter06/devices.html
test -c /dev/null || mknod -m 666 /dev/null c 1 3
test -c /dev/zero || mknod -m 666 /dev/zero c 1 5
test -c /dev/ptmx || mknod -m 666 /dev/ptmx c 5 2
test -c /dev/tty || mknod -m 666 /dev/tty c 5 0
test -c /dev/random || mknod -m 444 /dev/random c 1 8
test -c /dev/urandom || mknod -m 444 /dev/urandom c 1 9
mkdir -p "${1}/dev"
test -c "${1}/dev/null" || mknod -m 666 "${1}/dev/null" c 1 3
test -c "${1}/dev/zero" || mknod -m 666 "${1}/dev/zero" c 1 5
test -c "${1}/dev/ptmx" || mknod -m 666 "${1}/dev/ptmx" c 5 2
test -c "${1}/dev/tty" || mknod -m 666 "${1}/dev/tty" c 5 0
test -c "${1}/dev/random" || mknod -m 444 "${1}/dev/random" c 1 8
test -c "${1}/dev/urandom" || mknod -m 444 "${1}/dev/urandom" c 1 9
test -c "${1}/dev/console" || mknod -m 666 "${1}/dev/console" c 5 1
}
create_sysb() {
# Copy everything in
echo "Creating sysb rootfs"
mkdir -p /sysb/usr
for d in bin include lib libexec sbin share; do
cp -r "/after/${d}" "/sysb/usr/${d}"
done
populate_device_nodes /sysb
}
go_sysb() {
# Mount proc for kexec
mkdir /proc /etc
mount -t proc proc /proc
# kexec time
echo "Loading kernel + sysb initramfs using kexec"
kexec -l "${PREFIX}/boot/linux-2.6.16.62" --console-serial \
--append="console=ttyS0 root=/dev/ram0 init=/init"
echo "kexecing into sysb"
kexec -e
}
export PREFIX=/image
@ -149,12 +174,18 @@ build musl-1.2.2
build gcc-4.0.4 pass2.sh checksums/pass2
build util-linux-2.19.1
if [ "${CHROOT}" = False ]; then
build util-linux-2.19.1
build kexec-tools-2.0.22
build kexec-tools-2.0.22
build linux-2.6.16.62
create_sysb
build bash-5.1
build linux-2.6.16.62
<<<<<<< HEAD
exec env -i PATH=${PREFIX}/bin PREFIX=${PREFIX} SOURCES=${SOURCES} bash run2.sh
=======
go_sysb
fi
>>>>>>> a95c6f2 (Add sysb and sysc scaffolding.)

50
sysb.py Executable file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""System B"""
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
import os
import shutil
import getpass
from lib.utils import mount, umount, copytree, create_disk, run
from lib.sysgeneral import SysGeneral
class SysB(SysGeneral):
"""
Class responsible for preparing sources for System B.
"""
def __init__(self, arch, preserve_tmp, tmpdir, chroot):
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')
if tmpdir is None:
self.tmp_dir = os.path.join(self.sys_dir, 'tmp')
else:
self.tmp_dir = os.path.join(tmpdir, 'sysb')
os.mkdir(self.tmp_dir)
self.base_dir = os.path.join(self.tmp_dir, 'usr', 'src')
self.prepare()
def prepare(self):
"""
Prepare directory structure for System B.
"""
self.mount_tmpfs()
os.makedirs(self.base_dir)
# Misc files/scripts
self.deploy_sysglobal_files()
self.deploy_scripts()
def deploy_scripts(self):
"""Add the scripts to the chroot"""
# init script
shutil.copy2(os.path.join(self.sys_dir, 'init'), self.tmp_dir)
# run.sh
shutil.copy2(os.path.join(self.sys_dir, 'run.sh'), self.base_dir)

11
sysb/init Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/bash
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
#
# SPDX-License-Identifier: GPL-3.0-or-later
set -e
# Begin sysb bootstrapping process
cd /usr/src
./run.sh

65
sysb/run.sh Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/bash
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
#
# SPDX-License-Identifier: GPL-3.0-or-later
set -e
. bootstrap.cfg
export PATH=/usr/bin:/usr/sbin
# Unload the current kernel before things go weird
kexec -u
populate_device_nodes() {
# http://www.linuxfromscratch.org/lfs/view/6.1/chapter06/devices.html
test -c /dev/null || mknod -m 666 /dev/null c 1 3
test -c /dev/zero || mknod -m 666 /dev/zero c 1 5
test -c /dev/ptmx || mknod -m 666 /dev/ptmx c 5 2
test -c /dev/tty || mknod -m 666 /dev/tty c 5 0
test -c /dev/random || mknod -m 444 /dev/random c 1 8
test -c /dev/urandom || mknod -m 444 /dev/urandom c 1 9
}
create_hdx() {
# Create all of the hd{a,b,c..}
minor=0
alpha="a b c d e f g h i j k l m n o p" # 16 disks -- more than enough
# For each disk...
for a in ${alpha}; do
mknod -m 600 "/dev/hd${a}" b 3 "$((minor++))"
# For each partition...
for p in $(seq 15); do
mknod -m 600 "/dev/hd${a}${p}" b 3 "$((minor++))"
done
done
}
# If there is no disk specified error out
if [ -z "${DISK}" ]; then
echo "You must specify a disk where sysb will be located!"
exit 1
fi
# Otherwise, add stuff from sysa to sysb
echo "Mounting sysc"
mkdir /sysc
# All the various structures that don't exist but needed to mount
mkdir -p /etc /dev
populate_device_nodes
create_hdx
mount -t ext2 "/dev/${DISK}" /sysc
# Copy over appropriate data
echo "Copying data into sysc"
cp -r /dev /sysc/
# Don't include /usr/src
find /usr -mindepth 1 -maxdepth 1 -type d -not -name src -exec cp -r {} /sysc/{} \;
sync
# switch_root into sysc 1. for simplicity 2. to avoid kexecing again
# spouts a few errors because we don't have /proc /sys or /dev mounted
echo "Switching into sysc"
exec switch_root /sysc /init

159
sysc.py Executable file
View File

@ -0,0 +1,159 @@
#!/usr/bin/env python3
"""System C"""
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
import os
import shutil
import getpass
from lib.utils import mount, umount, copytree, create_disk, run
from lib.sysgeneral import SysGeneral
class SysC(SysGeneral):
"""
Class responsible for preparing sources for System C.
"""
def __init__(self, arch, preserve_tmp, tmpdir, chroot):
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')
if tmpdir is None:
self.tmp_dir = os.path.join(self.sys_dir, 'tmp')
else:
self.tmp_dir = os.path.join(tmpdir, 'sysc')
os.mkdir(self.tmp_dir)
self.prepare()
def __del__(self):
if not self.preserve_tmp:
if not self.chroot:
print("Deleting %s" % (self.dev_name))
run('sudo', 'losetup', '-d', self.dev_name)
print("Unmounting tmpfs from %s" % (self.tmp_dir))
umount(self.tmp_dir)
os.rmdir(self.tmp_dir)
def prepare(self):
"""
Prepare directory structure for System C.
"""
self.mount_tmpfs()
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", "ext2", '8G')
self.rootfs_dir = os.path.join(self.tmp_dir, 'mnt')
os.mkdir(self.rootfs_dir)
mount(self.dev_name + "p1", self.rootfs_dir, 'ext2')
# 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)
else:
self.rootfs_dir = self.tmp_dir
# Expand to the full base dir
self.base_dir = os.path.join(self.rootfs_dir, 'usr', 'src')
os.makedirs(self.base_dir)
# Misc files/scripts
self.deploy_scripts()
self.deploy_sysglobal_files()
self.get_packages()
# Unmount tmp/mnt if it exists
if not self.chroot:
umount(self.rootfs_dir)
def chroot_transition(sysb_tmp, self):
# See create_sysb in sysb/run.sh
# We skip sysb when using chroot, as sysb is entirely irrelevant
# to chrooting (only for kernel shenanigans)
# Copy directories from /after (sysa) -> /usr (sysc)
usr_dirs = ['bin', 'include', 'lib', 'sbin', 'share']
for d in usr_dirs:
copy_tree(os.path.join(sysa_tmp, 'after', d),
os.path.join(self.rootfs_dir, 'usr'))
# Copy /boot
copy_tree(os.path.join(sysa_tmp, 'after', 'boot'),
os.path.join(self.rootfs_dir, 'boot'))
def deploy_scripts(self):
"""Add the scripts to the chroot"""
src_files = ['run.sh', 'run2.sh']
for f in src_files:
shutil.copy2(os.path.join(self.sys_dir, f),
os.path.join(self.base_dir, f))
# init script
os.mkdir(os.path.join(self.rootfs_dir, 'sbin'))
shutil.copy2(os.path.join(self.sys_dir, 'init'), self.rootfs_dir)
# pylint: disable=line-too-long,too-many-statements
def get_packages(self):
"""Prepare remaining sources"""
# bash 5.1
self.get_file("https://mirrors.kernel.org/gnu/bash/bash-5.1.tar.gz")
# xz 5.0.5
self.get_file("https://tukaani.org/xz/xz-5.0.5.tar.bz2")
# automake 1.11.2
self.get_file("https://mirrors.kernel.org/gnu/automake/automake-1.11.2.tar.bz2")
# autoconf 2.69
self.get_file("https://mirrors.kernel.org/gnu/autoconf/autoconf-2.69.tar.xz")
# automake 1.15.1
self.get_file("https://mirrors.kernel.org/gnu/automake/automake-1.15.1.tar.xz")
# tar 1.34
self.get_file(["https://mirrors.kernel.org/gnu/tar/tar-1.34.tar.xz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-30820c.tar.gz"])
# coreutils 8.32
self.get_file(["https://git.savannah.gnu.org/cgit/coreutils.git/snapshot/coreutils-8.32.tar.gz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-d279bc.tar.gz"])
# make 4.2.1
self.get_file("https://ftp.gnu.org/gnu/make/make-4.2.1.tar.gz")
# gmp 6.2.1
self.get_file("https://mirrors.kernel.org/gnu/gmp/gmp-6.2.1.tar.xz")
# autoconf archive 2021.02.19
self.get_file("https://mirrors.kernel.org/gnu/autoconf-archive/autoconf-archive-2021.02.19.tar.xz")
# mpfr 4.1.0
self.get_file("https://mirrors.kernel.org/gnu/mpfr/mpfr-4.1.0.tar.xz")
# mpc 1.2.1
self.get_file("https://mirrors.kernel.org/gnu/mpc/mpc-1.2.1.tar.gz")
# flex 2.5.33
self.get_file("http://download.nust.na/pub2/openpkg1/sources/DST/flex/flex-2.5.33.tar.gz")
# bison 2.3
self.get_file(["https://mirrors.kernel.org/gnu/bison/bison-2.3.tar.bz2",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-b28236b.tar.gz"])
# bison 3.4.2
self.get_file(["https://mirrors.kernel.org/gnu/bison/bison-3.4.2.tar.xz",
"https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-672663a.tar.gz"])
# perl 5.10.5
self.get_file("https://www.cpan.org/src/5.0/perl-5.10.1.tar.bz2")
# dist 3.5-236
# Debian's version is used because upstream is not to be found (dead?)
self.get_file("https://salsa.debian.org/perl-team/interpreter/dist/-/archive/d1de81f/dist-d1de81f.tar.gz",
output="dist-3.5-236.tar.gz")
# perl 5.32.1
self.get_file(["https://www.cpan.org/src/5.0/perl-5.32.1.tar.xz",
"https://salsa.debian.org/perl-team/interpreter/perl/-/archive/5f2dc80/perl-5f2dc80.tar.bz2"])

11
sysc/init Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/bash
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
#
# SPDX-License-Identifier: GPL-3.0-or-later
set -e
# Begin sysc bootstrapping process
cd /usr/src
./run.sh

33
sysc/run.sh Executable file
View File

@ -0,0 +1,33 @@
#!/usr/bin/bash
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
# SPDX-FileCopyrightText: 2021 fosslinux <fosslinux@aussies.space>
# SPDX-FileCopyrightText: 2021 Paul Dersey <pdersey@gmail.com>
#
# SPDX-License-Identifier: GPL-3.0-or-later
set -e
. helpers.sh
export PATH=/usr/bin:/usr/sbin
export PREFIX=/usr
export SOURCES=/usr/src
create_fhs() {
# Add the rest of the FHS that we will use and is not created pre-boot
for d in bin lib sbin; do
ln -s "usr/${d}" "/${d}"
done
mkdir /etc /proc /run /sys /tmp /var
mount -t proc proc /proc
mount -t sysfs sysfs /sys
# Make /tmp a ramdisk (speeds up configure etc significantly)
mount -t tmpfs tmpfs /tmp
}
create_fhs
build bash-5.1
exec env -i PATH=${PATH} PREFIX=${PREFIX} SOURCES=${SOURCES} bash run2.sh

View File

@ -9,7 +9,8 @@
set -e
# shellcheck source=sysa/helpers.sh
trap "env - PATH=${PREFIX}/bin PS1='\w # ' bash -i" EXIT
. helpers.sh
. bootstrap.cfg

3
sysglobal/bootstrap.cfg Normal file
View File

@ -0,0 +1,3 @@
FORCE_TIMESTAMPS=False
CHROOT=False
DISK=hda1