summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binsub.c277
-rwxr-xr-xbootstrap763
-rwxr-xr-xsetup-abuild362
-rwxr-xr-xsetup-packages13
-rwxr-xr-xsetup-preimage35
5 files changed, 1450 insertions, 0 deletions
diff --git a/binsub.c b/binsub.c
new file mode 100644
index 0000000..c66148c
--- /dev/null
+++ b/binsub.c
@@ -0,0 +1,277 @@
+/**
+ * binsub.c / 2022-12-09
+ *
+ * (C) 2022 Zach van Rijn <me@zv.io>
+ *
+ * MIT License
+ *
+ * This utility truncates or replaces needles in an input file;
+ * truncation meaning the replacement string is empty.
+ *
+ * Replacement string length must be less than or equal to that
+ * of the needle because the file length must remain unchanged.
+ *
+ * For efficient operation, consider deploying this on a '.tar'
+ * file instead of individual files within a directory.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/**
+ * Basic memory structure.
+ */
+struct buffer
+{
+ char *data;
+ size_t len;
+};
+
+
+/**
+ * Given a needle ('find') and optional replacement ('repl'), if
+ * the needle is found, truncate it, inject the replacement, and
+ * pad the tail end of the matching string with null bytes.
+ *
+ * The file length remains the same, and we hope that nobody is
+ * relying on precomputed offsets into the strings. Mega kludge!
+ *
+ * Replacement = "":
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * in |.|.|.|N|E|E|D|L|E|.|.|.|O|T|H|E|R| |D|A|T|A|.|.|.|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ^ shift data ^
+ * +-------------------------------+
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * out |.|.|.|.|.|.|O|T|H|E|R| |D|A|T|A|.|.|.|0|0|0|0|0|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ^ shift data ^
+ * +-------------------------------+
+ *
+ * Replacement = "FOO":
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * in |.|.|.|N|E|E|D|L|E|.|.|.|O|T|H|E|R| |D|A|T|A|.|.|.|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ^ shift data ^
+ * +-------------------------------+
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * out |.|.|.|F|O|O|.|.|.|O|T|H|E|R| |D|A|T|A|.|.|.|0|0|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ^ FOO ^ shift data ^
+ * +=====+-------------------------------+
+ */
+void
+replace (struct buffer *buf, const char *find, const char *repl)
+{
+ char *match; /* pointer to found needle */
+ size_t idx; /* cursor into file buffer */
+
+ size_t nlen; /* length of needle */
+ size_t rlen = 0; /* length of replacement */
+
+ size_t mlen; /* length of matching string */
+
+ nlen = strlen(find);
+
+ /**
+ * Iterate over each character in the current string in the
+ * buffer, because multiple full matches may be possible. If
+ * we cannot find a match in the current string, skip to the
+ * next string. I don't think there is a more optimal way?
+ */
+ for (idx = 0; idx <= buf->len; idx++)
+ {
+ /**
+ * Does the current string contain the needle?
+ */
+ match = strstr(buf->data + idx, find);
+ if (match)
+ {
+ /**
+ * How long is the current string? We need to search
+ * it until we cannot find any more matches.
+ */
+ mlen = strlen(match);
+ printf("%10zu bytes at offset 0x%010lx (%02ld%%)\n",
+ mlen,
+ (match - buf->data),
+ (100 * (match - buf->data)) / buf->len
+ );
+
+ /**
+ * The replacement string is l.e. the length of the
+ * needle, so if it is non-empty, inject it first.
+ */
+ if (repl)
+ {
+ rlen = strlen(repl);
+ memcpy(match, repl, rlen);
+ }
+
+ /**
+ * The replacement length may be zero (if empty). In
+ * any case, copy the non-needle string remainder to
+ * the current matched (needle) location plus offset
+ * of any injected replacement. Zero out the tail.
+ */
+ memmove(match + rlen, match + nlen, mlen - nlen);
+ memset(match + mlen - nlen + rlen, 0, nlen - rlen);
+ }
+ else
+ {
+ /**
+ * This is a partial optimization. Don't bother with
+ * searching for needles in the rest of this string;
+ * we already know none exist.
+ */
+ idx += strlen(buf->data + idx);
+ }
+ }
+}
+
+
+/**
+ * Read the contents of a file into a newly allocated buffer. It
+ * is possible to 'mmap()', but it leaves less room for checks.
+ */
+void
+scanner (const char *file, const char *find, const char *repl)
+{
+ FILE *fp = NULL;
+ size_t nb = 0;
+
+ struct buffer buf;
+ memset(&buf, 0, sizeof(struct buffer));
+
+ fp = fopen(file, "rb+");
+ if (!fp)
+ {
+ fprintf(stderr,
+ "E: Could not open FILE '%s' for reading!\n",
+ file
+ );
+ return;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ buf.len = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ /**
+ * Allocate memory for the entire file at once. This is not
+ * ideal, but we don't expect large files for our use case.
+ */
+ buf.data = malloc(buf.len + 1);
+ if (!buf.data)
+ {
+ fclose(fp);
+ fprintf(stderr,
+ "E: Could not allocate '%zu' bytes for file '%s'\n",
+ buf.len,
+ file
+ );
+ return;
+ }
+ buf.data[buf.len] = 0; /* extra byte needs to be nil */
+
+ nb = fread(buf.data, 1, buf.len, fp);
+ if (nb != buf.len)
+ {
+ free(buf.data);
+ buf.data = NULL;
+ fclose(fp);
+ fprintf(stderr,
+ "E: Only read '%zu' / '%zu' bytes of file '%s'\n",
+ nb,
+ buf.len,
+ file
+ );
+ return;
+ }
+ fclose(fp);
+
+ printf("Examining file '%s'...\n", file);
+ replace(&buf, find, repl);
+
+ fp = fopen(file, "wb");
+ if (!fp)
+ {
+ fprintf(stderr,
+ "E: Could not open FILE '%s' for writing!\n",
+ file
+ );
+ return;
+ }
+
+ nb = fwrite(buf.data, 1, buf.len, fp);
+ if (nb != buf.len)
+ {
+ free(buf.data);
+ buf.data = NULL;
+ fclose(fp);
+ fprintf(stderr,
+ "E: Only wrote '%zu' / '%zu' bytes of file '%s'\n",
+ nb,
+ buf.len,
+ file
+ );
+ return;
+ }
+ fclose(fp);
+
+ free(buf.data);
+}
+
+
+/**
+ * WARNING!
+ *
+ * This program replaces all occurrences of NEEDLE within string
+ * sections of an input file with the string REPLACE. The input
+ * file is overwritten. Few, if any, sanity checks are in place.
+ */
+int
+main (int argc, char **argv)
+{
+ char *prog = NULL;
+ char *file = NULL;
+ char *find = NULL;
+ char *repl = NULL;
+
+ prog = argv[0];
+
+ switch (argc)
+ {
+ case 3:
+ file = argv[1];
+ find = argv[2];
+ break;
+ case 4:
+ file = argv[1];
+ find = argv[2];
+ repl = argv[3];
+ if (strlen(repl) > strlen(find))
+ {
+ fprintf(stderr,
+ "E: REPLACE cannot be longer than NEEDLE\n"
+ );
+ return 1;
+ }
+ break;
+ default:
+ fprintf(stderr,
+ "Usage: %s FILE NEEDLE [REPLACE]\n",
+ prog
+ );
+ return 1;
+ }
+
+ scanner(file, find, repl);
+
+ return 0;
+}
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 0000000..d2fcf08
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,763 @@
+#!/bin/sh -e
+
+#===============================================================
+# Filename : bootstrap
+# Purpose : Bootstraps Adélie from source for any architecture.
+# Authors : Zach van Rijn <me@zv.io>
+# License : MIT
+# Revision : 20221209
+#===============================================================
+
+#===============================================================
+# README
+#===============================================================
+#
+# overview
+# --------
+#
+# Given a basic development environment ("Baseline System") that
+# contains standard system utilities, this script bootstraps the
+# Adélie Linux distribution for any suported target architecture
+# (assuming that musl, gcc, etc. have been ported to it) WITHOUT
+# requiring 'root' privileges. This process is slow* and costly,
+# but demonstrates that bootstrapping from source is possible.
+#
+# Effort has been focused on correctness instead of performance.
+# This means, some files can be deleted sooner and some of the
+# binaries can run natively on the build machine. We know and do
+# appreciate there are different opinions on how to approach the
+# bootstrap process. This meets our needs and hopefully offers a
+# different perspective on how to simplify cross compilation.
+#
+# (*) See the "requirements" section for mitigations/discussion.
+#
+#
+# features
+# --------
+#
+# * One-click bootstrap. Just start the script and walk away.
+#
+# $ ./bootstrap.sh ppc64 /path/to/new/scratch/dir
+#
+# * Can be done without root privileges: no 'chroot(8)'.
+#
+# * This is the real deal. No "seed" binaries are required to
+# go from start to finish. The final output is what we use
+# to set up our official build servers totally* from source.
+#
+# * Can be done on a wide range of platforms, almost certainly
+# those supported by mcmtools (want to contribute???).
+#
+# * Minimal dependencies. Nothing fancy. Shell scripts only.
+#
+# * Can be adapted to assist with porting Adélie to new target
+# architectures. TODO: write a tool to automatically do so.
+#
+# (*) We don't count binaries in your starting environment, and
+# recommend https://www.gnu.org/software/mes/ for the brave.
+#
+#
+# design
+# ------
+#
+# The goal of this script is to support as wide a range of uses
+# as possible. For example, a full cross-platform bootstrap that
+# needs to be done without target hardware or virtual machines.
+#
+# There are a few different strategies, depending on your needs
+# and what type of privileges/hardware you have access to.
+#
+# In this diagram, indentation refers to an output product, and
+# moving down vertically refers to an input step. CPU A is the
+# build architecture, and CPU B is the target architecture. Your
+# mileage may vary, and you can mix/match other approaches..
+#
+# * CPU A --> CPU B (slowest: no privilege, no CPU B hardware)
+# --> Bootstrap 1 (Cross Libc + Partial Cross CPU B)
+# --> CPU A + CPU B Mixed Rootfs
+# --> Partial Emulation (PRoot)
+# --> Bootstrap 2 (Full Cross CPU B)
+# --> CPU B Host Rootfs
+# --> Full Emulation (PRoot)
+# --> Adélie Bootstrap
+# --> Adélie Rootfs for CPU B
+#
+# * CPU A --> CPU B (slower: privilege, no CPU B hardware)
+# --> Bootstrap 1 (Cross Libc + Partial Cross CPU B)
+# --> CPU A + CPU B Mixed Rootfs
+# --> Partial Emulation (registered binfmt_misc)
+# --> Bootstrap 2 (Full Cross CPU B)
+# --> CPU B Host Rootfs
+# --> Full Emulation (registered binfmt_misc)
+# --> Adélie Bootstrap
+# --> Adélie Rootfs for CPU B
+#
+# * CPU A --> CPU B (faster; no privilege, CPU B hardware)
+# --> Bootstrap 1 (Cross Libc + Partial Cross CPU B)
+# --> CPU A + CPU B Mixed Rootfs
+# --> Partial Emulation (PRoot)
+# --> Bootstrap 2 (Full Cross CPU B)
+# --> CPU B Host Rootfs
+# --> Copy to Native CPU B Hardware
+# --> Adélie Bootstrap
+# --> Adélie Rootfs for CPU B
+#
+# * CPU B --> CPU B (fastest; QEMU-system or native hardware)
+# --> Bootstrap 1 (Cross Libc)
+# --> CPU B Mixed Rootfs
+# --> Bootstrap 2 (Remove Contamination)
+# --> CPU B Host Rootfs
+# --> Adélie Bootstrap
+# --> Adélie Rootfs for CPU B
+#
+# The resulting Adélie Rootfs is capable of building the entire
+# Adélie Linux distribution from source. We use it to seed our
+# official build servers. This removes the dependency on using
+# previous binary releases of our distribution, which had been
+# manually bootstrapped way back from Gentoo and/or on a G5.
+#
+#
+# requirements
+# ------------
+#
+# TL;DR: You must be able to run the mcmtools bootstrap script.
+#
+# Cross builds take up a lot of TIME and SPACE, and this cannot
+# be improved by throwing hardware at it. This is primarily due
+# to the tradeoff of not requiring root privileges at any point,
+# and the decision to emulate a native environment instead of to
+# force explicit cross-compilation at each step in the process.
+#
+# Targeting an architecture of opposite endianness will be even
+# slower; this is a QEMU limitation.
+#
+# If you wish to bootstrap to the same target CPU architecture,
+# or a compatible mode (e.g. i686 on x86_64), it will be faster.
+#
+# mcmtools is a hard dependency for our bootstrap process now:
+#
+# https://git.zv.io/toolchains/bootstrap
+#
+# It is a simple analog to Buildroot or Yocto. Those tools could
+# be used, too, and would provide the "host rootfs" environment.
+#
+# Internet access is required, but (as an exercise left to the
+# reader) it is possible to pre-download all required sources if
+# you provide your own rootfs for the static QEMU build process.
+#
+# If you are in a position to use native hardware, then you are
+# able to get away with only the final stages of bootstrapping.
+# To do this, you'd essentially comment out the first stages or
+# copy the results of the first stages elsewhere and continue.
+#
+# Other requirements that you should be aware of, estimated:
+#
+# * As many CPU cores as you can throw at it;
+#
+# * ~15 GB for each mcmtools rootfs ("seed" and "host");
+#
+# * ~ 3 GB for toolchains;
+#
+# * ~ 2 GB for each intermediate rootfs;
+#
+# * ~ 2 GB for the "system/" package repository, when built;
+#
+# * Please refer to the README in 'bootstrap', linked above,
+# for more information about performance. Most of this can
+# be gained back if you adapt this script to use 'chroot(8)'
+# instead of 'PRoot', at the expense of requiring privilege,
+# with the correct registration of QEMU with 'binfmt_misc'.
+#
+# In brief, there is an approximate factor of 13 slowdown on
+# practical workloads when using QEMU user and 'PRoot' to do
+# dynamic binary translation and emulate a foreign machine.
+#
+#
+# process
+# -------
+#
+# The illustration below outlines the complete bootstrap process
+# and roughly corresponds to the script layout/organization. Our
+# terminology is not perfectly consistent; please excuse this.
+#
+# The term "build" is shorthand for "build-native" CPU, which
+# is the machine on which you are performing the bootstrap.
+#
+# The term "native" is shorthand for "foreign-native" CPU, which
+# is the machine to which you are targeting the bootstrap, and
+# relates to the "host" CPU on which the code will run, but that
+# with the help of dynamic binary translation, runs "natively".
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# build (unstable, everything provided by user)
+#
+# +-----------------+ User-provided tools. Dependency
+# | Baseline System | of 'mcmtools', which will verify
+# +-----------------+ that these tools are available.
+# |
+# +----------+ Script to build pinned versions
+# | mcmtools | of common system utilities, a
+# +----------+ host-arch host-libc toolchain, a
+# | host-arch musl-libc toolchain...
+# |
+# - - - - -|- - - - - - - - - - - - - - - - - - - - - - - -
+# mixed | (stable versions, unstable libc)
+# |
+# +-------------+ ...and a 'chroot'-able rootfs. A
+# | seed rootfs | sane, but not clean, environment
+# +-------------+ in which we begin the bootstrap.
+# |
+# +-----------+ Script to build 'PRoot' and its
+# | emulators | dependencies, as well as static
+# +-----------+ QEMU user binaries. Add to seed.
+# |
+# +-----------------+ Static musl toolchains targeting
+# | musl toolchains | a given architecture: cross from
+# +-----------------+ the host CPU & foreign "native".
+# | Output binaries will run via the
+# | 'binfmt_misc' mechanism + QEMU.
+# |
+# +-------------+ Script to build Alpine Package
+# | build tools | Keeper (APK) and dependencies.
+# +-------------+ All binaries are cross-compiled!
+# | This step is a sanity check.
+# |
+# +----------+ Script to build pinned versions
+# | mcmtools | of common system utilities. This
+# +----------+ time, all utilities are target-
+# | native. Build more toolchains...
+# |
+# - - - - -|- - - - - - - - - - - - - - - - - - - - - - - -
+# host | (stable versions, stable libc)
+# |
+# +-------------+ ...and a 'chroot'-able rootfs. A
+# | host rootfs | sane, clean, foreign "native"
+# +-------------+ rootfs that requires QEMU, or is
+# | able to run on native hardware.
+# |
+# +-------------+ Script to build Alpine Package
+# | build tools | Keeper (APK) and dependencies.
+# +-------------+ These binaries are native built!
+# | This step is required!
+# |
+# +-------------+ Script to build the Adélie Linux
+# | system repo | "system/" package repository. It
+# +-------------+ is used to build core packages.
+# |
+# +---------------+ Script to install packages into
+# | image creator | a clean rootfs. Carryover from
+# +---------------+ the mcmtools process is removed.
+# |
+# - - - - -|- - - - - - - - - - - - - - - - - - - - - - - -
+# verify | (optional verification)
+# |
+# ... The "host" stage can be repeated
+# | zero or more times to ensure the
+# | final image is not contaminated.
+# |
+# - - - - -|- - - - - - - - - - - - - - - - - - - - - - - -
+# output | (Welcome to Adélie Linux)
+# |
+# +---------------+ This is a minimal Adélie rootfs.
+# | adelie rootfs | Copy it to native hardware, then
+# +---------------+ use it as a builder 'chroot'. It
+# is used to seed official Adélie
+# build boxen (e.g. autobuilder).
+#
+# limitations
+# -----------
+#
+# The builds are not hermetically sealed. That is not the point.
+# The build environment should not *need* anything from outside,
+# but it is not *prevented* from accessing anything. You should
+# run this on a clean, trusted machine.
+#
+# There is no guarantee of byte-for-byte reproducible builds at
+# this time. This is, in part, due to timestamps and tar headers
+# but may involve a lack of determinism in parallel builds.
+#
+# QEMU user emulation may cause subtle incompatibilites with the
+# target CPU hardware. For example, CPU feature (mis)detection.
+#
+# It is not currently possible to safely reuse any of the output
+# if the target architecture is changed. You will need to start
+# from scratch if you wish to change the target. This is a TODO.
+#
+#
+# todo
+# ----
+#
+# * Do not inherit the build environment; avoid contamination.
+#
+# * Finish the "system/" build; the "bootstrap.sh" script will
+# require some work. Current status: preimage is finished.
+#
+
+HERE="$(dirname $(readlink -f ${0}))";
+
+
+#---------------------------------------------------------------
+# initialization
+
+##
+# Haaaalp!
+#
+usage ()
+{
+ printf "Usage: %s ARCH BASE\n\n" "${0}";
+ cat <<EOF
+ ARCH { aarch64, armv7, ppc64, ppc, x86_64, pmmx }
+
+ BASE an absolute path to bootstrap out of.
+ ** MAY CAUSE DATA LOSS IF SET INCORRECTLY! **
+EOF
+ exit 0;
+}
+
+
+##
+# argv[1]: ARCH
+#
+# ARCH is the Adélie Linux target. This is the first step in the
+# porting process, so e.g. mips64, sparc64, riscv64 will need to
+# be added to this table when the time comes to port to them.
+#
+# ARCH is translated to canonical GCC and QEMU machine types.
+#
+case "${1}" in
+# adelie gcc qemu
+# ------ --- ----
+ aarch64) m=aarch64: ; q=aarch64 ; ;;
+ armv7) m=armv7l:eabihf ; q=arm ; ;;
+ ppc) m=powerpc: ; q=ppc ; ;;
+ ppc64) m=powerpc64: ; q=ppc64 ; ;;
+ riscv64) m=riscv64: ; q=riscv64 ; ;;
+ x86_64) m=x86_64: ; q=x86_64 ; ;;
+ pmmx) m=i586: ; q=i386 ; ;;
+ *) usage ;;
+esac
+shift;
+
+
+##
+# argv[2]: BASE
+#
+# BASE is a semi-permanent scratch directory. It is where all of
+# the magic happens, and probably cannot be relocated easily. Be
+# careful to not set it incorrectly or to a place you'd regret
+# being overwritten, corrupted, or deleted.
+#
+case "${1}" in
+ /*) BASE="${1}";
+ ;;
+ *) printf "BASE not set, or not an absolute path!\n";
+ exit 1;
+ ;;
+esac
+shift;
+
+
+##
+# Internal variables. Do not modify this section directly.
+#
+CHAINS=https://git.zv.io/toolchains;
+printf "CHAINS=%s\n" "${CHAINS}";
+
+SYSTEM="-adelie-linux-musl"; # we only target musl on Linux
+printf "SYSTEM=%s\n" "${SYSTEM}";
+
+NATIVE=$(cc -dumpmachine); # host arch, host libc
+printf "NATIVE=%s\n" "${NATIVE}";
+
+BUILDS="${NATIVE%%-*}${SYSTEM}"; # host arch, musl libc
+printf "BUILDS=%s\n" "${BUILDS}";
+
+TARGET="${m%:*}${SYSTEM}${m#*:}"; # ultimate Adélie Linux target
+printf "TARGET=%s\n" "${TARGET}";
+
+MTOOLS=${MCMTOOLS:-"${BASE}/mcmtools"}; # CAREFUL! MAY CAUSE DATA LOSS!
+printf "MTOOLS=%s\n" "${MTOOLS}";
+
+##
+# Default 'PATH' for use inside various rootfs environments.
+#
+DEF_PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
+
+mkdir -p "${BASE}";
+
+
+#---------------------------------------------------------------
+# mcmtools (seed)
+
+##
+# Allow the user to supply an existing mcmtools installation. It
+# is not ideal but we can allow the user to save some CPU cycles
+# at the cost of adding new tools to the existing installation.
+#
+# If they wish to keep the existing mcmtools installation clean,
+# the 'binsub' tool can be used to relocate it. A temporary dir
+# is used if this environment variable is omitted. Another case
+# for providing a custom value is if '/tmp' is mounted weird.
+#
+if ! test -d "${MTOOLS}"/sys/emus/bin; then # FIXME: no hard code
+ cd "${BASE}";
+
+ test -d bootstrap \
+ || git clone ${CHAINS}/bootstrap.git;
+ cd bootstrap;
+ git checkout 371f5e2624acd89dd05a9bd8c68f369b16dfdde6;
+
+ ## seed rootfs
+ #
+ # This will build absolutely everything that is needed to be
+ # self-reliant, except for some build deps for QEMU.
+ #
+ # We copy 'config.mak' from mcmtools bootstrap to the rootfs
+ # so that when we build "real" toolchain they are the same.
+ #
+ DEST="${MTOOLS}" \
+ ARCH=${BUILDS} \
+ ./bootstrap \
+ ;
+ test -f "${MTOOLS}"/config.mak || \
+ cp "${MTOOLS}"/tmp/musl-cross-make/config.mak \
+ "${MTOOLS}"/config.mak \
+ ;
+ # cleaning
+ (
+ cd "${MTOOLS}";
+ rm -fr tmp; # save 10 GB
+ )
+
+ # is any of this actually needed?
+ (
+ cd "${MTOOLS}"/sys;
+ mkdir -p dev;
+ mkdir -p proc;
+ mkdir -p sys;
+ rm -fr usr;
+ ln -s . usr;
+ )
+
+ ## emulators
+ #
+ # Dependencies are built with the mcmtools host toolchain; a
+ # reason to not force musl here is in the event that these
+ # cannot be built statically and the host libc is different.
+ # Our priority is to obtain a functioning 'PRoot' above all.
+ #
+ # QEMU itself is built inside an Alpine Linux rootfs; we do
+ # this because we still need Python 3 to build it. You can
+ # manually provide your own static QEMU user binaries and be
+ # on your way without Alpine, but it is a good 'PRoot' test.
+ #
+ test -d "${MTOOLS}/sys/emus/bin" || \
+ PATH="${MTOOLS}/host/bin:${MTOOLS}/sys/bin" \
+ DEST="${MTOOLS}" \
+ ./prootemu \
+ ;
+fi
+
+
+#---------------------------------------------------------------
+# musl toolchains
+
+##
+# We have a musl-targeting toolchain that runs on the host, but
+# it is linked to the host libc and may not run in this chroot.
+#
+# We need to build the same toolchain, but static. There are two
+# possible directions to go: (1) a cross toolchain that runs at
+# full speed on the build machine, at the cost of having to tell
+# downstream build scripts how to cross compile, or (2) a native
+# toolchain for the foreign (target) architecture that runs slow
+# in QEMU and still requires the cross toolchain to build it.
+#
+# Build both. We will eventually need both toolchains, anyway.
+#
+if ! test -d "${MTOOLS}"/sys/tc/native; then # FIXME: no hard code
+ cd "${BASE}";
+
+ test -d musl-cross-make \
+ || git clone ${CHAINS}/musl-cross-make.git;
+ cd musl-cross-make;
+ git pull; # always use the latest
+
+ ##
+ # Ensure consistent 'config.mak' for all toolchain builds.
+ #
+ cp "${MTOOLS}"/config.mak config.mak;
+
+ ## musl toolchains
+ #
+ # Build these toolchains statically using the musl toolchain
+ # from the seed rootfs so that it is known to work correctly
+ # (the original musl toolchain itself may itself be linked
+ # with glibc or be unsafe to use in some contexts).
+ #
+ # Note: "native" is for the foreign target CPU architecture.
+ #
+ MCMTOOLS="${MTOOLS}" \
+ ./scripts/build ${TARGET} \
+ ;
+ for k in cross native; do
+ rm -fr "${MTOOLS}"/sys/tc/${k};
+ mkdir "${MTOOLS}"/sys/tc/${k};
+ tar -C "${MTOOLS}"/sys/tc/${k} \
+ --strip-components=1 \
+ -xzf output/${TARGET}-${k}.tgz \
+ ;
+ done
+fi
+
+
+#---------------------------------------------------------------
+# build tools (cross)
+
+##
+# Build 'abuild', its dependencies, and other utilities.
+#
+PROOT_NO_SECCOMP=1 \
+PATH="/tc/cross/bin:${DEF_PATH}" \
+SHELL=/bin/sh \
+DEST=/usr/local \
+CURL_CA_BUNDLE=/cacert.pem \
+CC=${TARGET}-gcc \
+CXX=${TARGET}-g++ \
+AR=${TARGET}-ar \
+LD=${TARGET}-ld \
+CPP=${TARGET}-cpp \
+RANLIB=${TARGET}-ranlib \
+${MTOOLS}/sys/emus/bin/proot \
+ -S "${MTOOLS}"/sys \
+ -q "${MTOOLS}"/sys/emus/bin/qemu-${q} \
+ -b "${HERE}" \
+ "${HERE}"/setup-abuild \
+ ;
+
+
+#---------------------------------------------------------------
+# rootfs: build
+
+##
+# Create a tarball of the build rootfs. The image creator could
+# use this as input if the target architecture matches.
+#
+cd "${BASE}";
+if ! test -f rootfs-${BUILDS}.tgz; then
+ tar -C mcmtools/sys \
+ -pczf rootfs-${BUILDS}.tgz \
+ . \
+ ;
+fi
+
+
+#---------------------------------------------------------------
+# mcmtools (host)
+
+##
+# NOTE: The 'PATH' order is *really* important. Foreign "native"
+# toolchains must be the first ones found; e.g. '/usr/bin/gcc'
+# is a symlink to 'ccache' and isn't a functional compiler.
+#
+# NOTE: 'LD_LIBRARY_PATH' is needed because of nonstandard path
+# of toolchain, which otherwise produces these errors:
+#
+# Error loading shared library libstdc++.so.6:
+# Exec format error (needed by ...)
+# Error loading shared library libgcc_s.so.1:
+# Exec format error (needed by ...)
+#
+# NOTE: We *do* need to build 'musl-cross-make' (even though it
+# may seem redundant) so that we can safely install the dynamic
+# loader. If we do not do this, we're on the hook to symlink it.
+#
+# Once 'coreutils' is built, 'uname' will return correctly, then
+# future software should(tm) build as if it is built natively.
+#
+# FIXME: is Linux 3.2.0 really appropriate here?
+#
+cd "${BASE}";
+if ! test -d mcmtools-${TARGET}/sys/tc/musl/bin; then # FIXME: no hard code
+PROOT_NO_SECCOMP=1 \
+PATH="/tc/native/bin:${DEF_PATH}" \
+LD_LIBRARY_PATH=/tc/native/lib \
+SHELL=/bin/sh \
+BASE="${BASE}" \
+DEST="${BASE}"/mcmtools-${TARGET} \
+ARCH=${TARGET} \
+CURL_CA_BUNDLE=/cacert.pem \
+${MTOOLS}/sys/emus/bin/proot \
+ -S "${MTOOLS}"/sys \
+ -q "${MTOOLS}"/sys/emus/bin/qemu-${q} \
+ -b "${HERE}" \
+ -k "3.2.0" \
+ "${BASE}"/bootstrap/bootstrap \
+ ;
+fi
+
+# cleaning
+(
+ cd mcmtools-${TARGET};
+ rm -fr tmp; # save 10 GB
+)
+
+##
+# Install the native static toolchain over the native rootfs for
+# a quick way to have the dynamic loader. Overwrite the symlink!
+#
+if test -h mcmtools-${TARGET}/sys/bin/gcc; then # FIXME: no hard code
+ tar -C mcmtools-${TARGET}/sys \
+ --strip-components=1 \
+ -xzf musl-cross-make/output/${TARGET}-native.tgz \
+ ;
+fi
+
+
+#---------------------------------------------------------------
+# build tools (host)
+
+##
+# Build 'abuild', its dependencies, and other utilities.
+#
+PROOT_NO_SECCOMP=1 \
+PATH="/tc/musl/bin:${DEF_PATH}" \
+SHELL=/bin/sh \
+DEST=/usr/local \
+CURL_CA_BUNDLE=/cacert.pem \
+CC=gcc \
+CXX=g++ \
+AR=ar \
+LD=ld \
+CPP=cpp \
+${MTOOLS}/sys/emus/bin/proot \
+ -S "${BASE}"/mcmtools-${TARGET}/sys \
+ -q "${MTOOLS}"/sys/emus/bin/qemu-${q} \
+ -b "${HERE}" \
+ "${HERE}"/setup-abuild \
+ ;
+
+
+#---------------------------------------------------------------
+# rootfs: host
+
+##
+# Create a tarball of the host rootfs. This is a safety measure.
+#
+cd "${BASE}";
+if ! test -f rootfs-${TARGET}.tgz; then
+ tar -C mcmtools-${TARGET}/sys \
+ -pczf rootfs-${TARGET}.tgz \
+ . \
+ ;
+fi
+
+
+#---------------------------------------------------------------
+# patch rootfs
+
+##
+# Some paths are hard-coded into various binaries. Since we need
+# to "relocate" everything to run at '/', we can decompress the
+# '.tar' file and perform the appropriate substititons at once.
+#
+cd "${BASE}";
+if ! test -f rootfs-${TARGET}-patched.tgz; then
+ gzip -dk rootfs-${TARGET}.tgz;
+
+ ##
+ # Build 'binsub', a string patch tool.
+ #
+ "${MTOOLS}"/musl/bin/gcc -static -o binsub binsub.c -O3;
+
+ ##
+ # Replace with explicit '/' ('/foo/bar/baz' --> '/' instead
+ # of the empty string) to avoid gotchas. Assumes '//' is the
+ # same as '/'. I can't think of a counterexample.
+ #
+ ./binsub rootfs-${TARGET}.tar \
+ "${BASE}"/mcmtools-${TARGET}/sys \
+ / \
+ ;
+
+ gzip -c9 rootfs-${TARGET}.tar > rootfs-${TARGET}-patched.tgz;
+
+ rm -f rootfs-${TARGET}.tar;
+fi
+
+
+#---------------------------------------------------------------
+# preimage
+
+##
+# The preimage has some modifications to support using the real
+# "bootstrap.sh" script. Note that we need to bind-mount and use
+# a different working directory because PRoot has a few defaults
+# that would otherwise shadow paths we're trying to create.
+#
+cd "${BASE}";
+if ! test -f rootfs-${TARGET}-preimage.tgz; then # FIXME: no hard code
+ rm -fr rootfs-${TARGET}-preimage;
+ mkdir rootfs-${TARGET}-preimage;
+ tar -C rootfs-${TARGET}-preimage \
+ -xzf rootfs-${TARGET}-patched.tgz \
+ || true; # we're somehow messing up some bzip binaries?
+
+PROOT_NO_SECCOMP=1 \
+PATH="${DEF_PATH}" \
+SHELL=/bin/sh \
+CURL_CA_BUNDLE=/cacert.pem \
+${MTOOLS}/sys/emus/bin/proot \
+ -S "${MTOOLS}"/sys \
+ -b "${BASE}"/rootfs-${TARGET}-preimage \
+ -w "${BASE}"/rootfs-${TARGET}-preimage \
+ -b "${HERE}" \
+ "${HERE}"/setup-preimage \
+ ;
+
+ tar -C rootfs-${TARGET}-preimage \
+ -pczf rootfs-${TARGET}-preimage.tgz \
+ . \
+ ;
+fi
+
+
+#---------------------------------------------------------------
+# packages
+
+##
+# This is where the original "bootstrap.sh" script runs. The aim
+# of this step is to produce '.apk' files that were built using
+# non-Adélie-packaged tools, but would install Adélie tools.
+#
+if ! test -f rootfs-${TARGET}-packages.tgz; then # FIXME: no hard code
+ rm -fr rootfs-${TARGET}-packages;
+ mkdir rootfs-${TARGET}-packages;
+ tar -C rootfs-${TARGET}-packages \
+ -xzf rootfs-${TARGET}-preimage.tgz \
+ ;
+
+PROOT_NO_SECCOMP=1 \
+PATH="${DEF_PATH}" \
+SHELL=/bin/sh \
+TARGET_ARCH=${TARGET} \
+CURL_CA_BUNDLE=/cacert.pem \
+${MTOOLS}/sys/emus/bin/proot \
+ -R "${BASE}"/rootfs-${TARGET}-packages \
+ -i 1000:300 \
+ -q "${MTOOLS}"/sys/emus/bin/qemu-${q} \
+ -b "${HERE}" \
+ "${HERE}"/setup-packages \
+ ;
+fi
+
+# TODO: create tarball of this directory
+
+
+#---------------------------------------------------------------
+# image creator
+
+# TODO
+
+# apk --root /foo --arch armv7 --initdb add
+# apk --root /foo add adelie-core dash-binsh build-tools
diff --git a/setup-abuild b/setup-abuild
new file mode 100755
index 0000000..686df6d
--- /dev/null
+++ b/setup-abuild
@@ -0,0 +1,362 @@
+#!/bin/sh -e
+
+HERE="$(dirname $(readlink -f ${0}))";
+DEST=/usr/local;
+
+git config --global http.sslCAInfo "${CURL_CA_BUNDLE}";
+
+
+mkdir -p "${DEST}";
+cd "${DEST}"; # this directory will already exist if correct
+
+##
+# musl
+#
+# This provides the dynamic loader for the foreign (target) arch
+# so that we do not have to force building static musl binaries.
+#
+nmus=musl;
+vmus=1.2.3;
+test ! -f ._${nmus}-${vmus} && \
+(
+ test ! -d ${nmus}-${vmus} \
+ && curl -s https://musl.libc.org/releases/${nmus}-${vmus}.tar.gz \
+ | tar -xzf - \
+ ;
+ cd ${nmus}-${vmus};
+ rm -fr x; mkdir x; cd x;
+ ../configure \
+ --prefix=/usr \
+ --enable-static \
+ --enable-shared \
+ ;
+ make -j$(nproc);
+ make install;
+)
+touch ._${nmus}-${vmus};
+rm -fr ${nmus}-${vmus};
+
+
+##
+# OpenSSL
+#
+nssl=openssl;
+vssl=1.1.1s;
+test ! -f ._${nssl}-${vssl} && \
+(
+ test ! -d ${nssl}-${vssl} \
+ && curl -s https://www.openssl.org/source/${nssl}-${vssl}.tar.gz \
+ | tar -xzf - \
+ ;
+ cd ${nssl}-${vssl};
+ rm -fr x; mkdir x; cd x;
+ ../Configure cc \
+ --prefix="${DEST}" \
+ --openssldir="${DEST}" \
+ no-shared \
+ ;
+ make -j$(nproc);
+ make install_sw install_ssldirs;
+)
+touch ._${nssl}-${vssl};
+rm -fr ${nssl}-${vssl};
+
+
+##
+# zlib
+#
+nzlb=zlib;
+vzlb=1.2.13;
+test ! -f ._${nzlb}-${vzlb} && \
+(
+ test ! -d ${nzlb}-${vzlb} \
+ && curl -s https://www.zlib.net/${nzlb}-${vzlb}.tar.gz \
+ | tar -xzf - \
+ ;
+ cd ${nzlb}-${vzlb};
+ rm -fr x; mkdir x; cd x;
+ ../configure \
+ --prefix="${DEST}" \
+ --static \
+ ;
+ make -j$(nproc);
+ make install;
+)
+touch ._${nzlb}-${vzlb};
+rm -fr ${nzlb}-${vzlb};
+
+
+##
+# abuild
+#
+nbld=abuild;
+vbld=f75ebd1953f6e41416b5037c4049b55b9a21a1ea;
+test ! -f ._${nbld}-${vbld} && \
+(
+ test ! -d ${nbld}-${vbld} \
+ && git clone https://git.adelielinux.org/adelie/${nbld}.git ${nbld}-${vbld} \
+ ;
+ cd abuild-${vbld};
+ git checkout ${vbld};
+ while read k; do curl -s ${k} | patch -p1 || true; done <<EOF
+http://ix.io/4ifN
+EOF
+ rm -fr x; mkdir x; cd x;
+ export SSL_CFLAGS="-I${DEST}/include";
+ export SSL_LDFLAGS="-L${DEST}/lib";
+ export SSL_LIBS="-lssl -lcrypto"; # not in mcmtools
+ export ZLIB_LIBS="-lz"; # do not use from mcmtools
+ export LDFLAGS="-L${DEST}/lib -lssl -lcrypto";
+ export CFLAGS="-static -I${DEST}/include";
+ sed -i "${DEST}/abuild-${vbld}/abuild-sudo.c" \
+ -e "s@__DEST__@${DEST}@" \
+ ; # hardcoded
+ make -j$(nproc) -C .. install \
+ prefix="${DEST}" \
+ sysconfdir="${DEST}" \
+ SCDOC=true \
+ ;
+ sed -i "${DEST}/bin/abuild" \
+ -e 's@/bin/ash -e@/usr/bin/env bash@' \
+ ; # hardcoded
+)
+touch ._${nbld}-${vbld};
+rm -fr ${nbld}-${vbld};
+
+
+##
+# util-linux (for 'getopt' used by 'abuild-keygen')
+#
+nutl=util-linux;
+vutl=08431acdf5b3accd0887ab550bfa4efabed751d6;
+test ! -f ._${nutl}-${vutl} && \
+(
+ test ! -d ${nutl}-${vutl} \
+ && mkdir ${nutl}-${vutl} \
+ && git clone https://github.com/karelzak/${nutl}.git ${nutl}-${vutl} \
+ ;
+ cd ${nutl}-${vutl};
+ git checkout ${vutl};
+ test -f configure || ./autogen.sh;
+ rm -fr x; mkdir x; cd x;
+ ../configure \
+ --prefix="${DEST}" \
+ --host="$(${CC} -dumpmachine)" \
+ --enable-static \
+ --disable-shared \
+ ;
+ sed -i Makefile \
+ -e 's/chgrp/-chgrp/g' \
+ -e 's/chmod/-chmod/g' \
+ -e 's/chown/-chown/g' \
+ ; # allow non-root installation
+ make -j$(nproc) install;
+)
+touch ._${nutl}-${vutl};
+rm -fr ${nutl}-${vutl};
+
+
+##
+# pkgconf (pkg-config replacement)
+#
+npkg=pkgconf;
+vpkg=623b8f7851648a5c476de904a8ffed7b7b679aab; # until autoconf 2.71
+test ! -f ._${npkg}-${vpkg} &&
+(
+ test ! -d ${npkg}-${vpkg} \
+ && git clone https://github.com/${npkg}/${npkg}.git ${npkg}-${vpkg} \
+ ;
+ cd ${npkg}-${vpkg};
+ git checkout ${vpkg};
+ ./autogen.sh;
+ ./configure \
+ --prefix="${DEST}" \
+ --host="$(${CC} -dumpmachine)" \
+ --enable-static \
+ --disable-shared \
+ --with-system-libdir=/lib:/usr/lib \
+ --with-system-includedir=/usr/include \
+ ;
+ make -j$(nproc) install;
+ ln -s pkgconf "${DEST}"/bin/pkg-config
+)
+touch ._${npkg}-${vpkg};
+rm -fr ${npkg}-${vpkg};
+
+
+##
+# samurai (ninja replacement)
+#
+nsam=samurai;
+vsam=4cc8f4a3654b72c977e0e62367d1ab6d5b873def;
+test ! -f ._${nsam}-${vsam} &&
+(
+ test ! -d ${nsam}-${vsam} \
+ && git clone https://github.com/michaelforney/${nsam}.git ${nsam}-${vsam} \
+ ;
+ cd ${nsam}-${vsam};
+ make -j$(nproc) install \
+ PREFIX="" \
+ DESTDIR="${DEST}" \
+ ;
+
+)
+touch ._${nsam}-${vsam};
+rm -fr ${nsam}-${vsam};
+
+
+##
+# muon (meson replacement)
+#
+nmun=muon;
+vmun=62ce4561b4444e5020dc39aad0381655afeda0d6;
+test ! -f ._${nmun}-${vmun} &&
+(
+ test ! -d ${nmun}-${vmun} \
+ && git clone https://git.sr.ht/~lattis/${nmun} ${nmun}-${vmun} \
+ ;
+ cd ${nmun}-${vmun};
+ sed -i bootstrap.sh \
+ -e 's/if.*then/if false; then/g' \
+ ;
+ ./bootstrap.sh \
+ bootstrap \
+ ;
+ bootstrap/muon setup \
+ -Dstatic=true \
+ build \
+ ;
+ sed -i build/build.ninja \
+ -e "s@\bar\b@${AR}@g" \
+ ;
+ samu -C build;
+ cp build/muon "${DEST}/bin";
+)
+touch ._${nmun}-${vmun};
+rm -fr ${nmun}-${vmun};
+
+
+##
+# apk-tools
+#
+# Ariadne says use meson, and 'muon' doesn't work so... kludges!
+# Also, '-j' will break the build.
+#
+natl=apk-tools;
+vatl=be4ce40797af9056c79be4dc74ff978f1f4957e4;
+test ! -f ._${natl}-${vatl} && \
+(
+ test ! -d ${natl}-${vatl} \
+ && git clone https://git.alpinelinux.org/${natl} ${natl}-${vatl} \
+ ;
+ cd ${natl}-${vatl};
+ sed -i Make.rules \
+ -e '/targets += $(__shlibs) $(shobjs)/d' \
+ ; # disable shared libs
+ sed -i Make.rules \
+ -e '/CC.*:=/d' \
+ -e '/AR.*:=/d' \
+ -e '/LD.*:=/d' \
+ ; # inherit from environment
+ sed -i src/Makefile \
+ -e 's/$(install-libapk_so)//g' -e 's/$(libapk_so)//g' \
+ -e 's/ version.o/ version.o strlcpy.o/' \
+ ; # disable shared libs, hack the hack
+ sed -i src/context.c \
+ -e "s@var/log@${DEST}/${1}/var/log@" \
+ ; # hardcoded
+ ln -sf ../portability/strlcpy.c src/strlcpy.c;
+ export LUA=no; # documentation requires lua
+ make clean;
+ make \
+ INSTALLDIR="${DEST}" \
+ CFLAGS="-I${DEST}/include -DNEED_STRLCPY -Wno-error" \
+ LDFLAGS="-L${DEST}/lib -L${DEST}/${natl}-${vatl}/libfetch" \
+ LIBS="-lapk -lfetch -lssl -lcrypto -lz" \
+ ;
+ cp src/apk "${DEST}/bin";
+)
+touch ._${natl}-${vatl};
+rm -fr ${natl}-${vatl};
+
+
+##
+# pax-utils
+#
+npax=pax-utils;
+vpax=974b9359c2f89d57e69598572aafcd8f920d79e2;
+test ! -f ._${npax}-${vpax} && \
+(
+ test ! -d ${npax}-${vpax} \
+ && git clone https://anongit.gentoo.org/git/proj/${npax}.git ${npax}-${vpax} \
+ ;
+ cd ${npax}-${vpax};
+ git checkout ${vpax};
+ muon setup build;
+ samu -C build;
+ muon -C build install;
+)
+touch ._${npax}-${vpax};
+rm -fr ${npax}-${vpax};
+
+
+##
+# fakeroot
+#
+nfrt=fakeroot;
+vfrt=8c0260009e85264fd1ea282fbb22063fc694c552; # until autoconf 2.71
+test ! -f ._${nfrt}-${vfrt#*:} && \
+(
+ test ! -d ${nfrt}-${vfrt} \
+ && git clone https://salsa.debian.org/clint/${nfrt}.git ${nfrt}-${vfrt} \
+ ;
+ cd ${nfrt}-${vfrt};
+ git checkout ${vfrt};
+ while read k; do curl -s ${k} | patch -p1 || true; done <<EOF
+https://git.alpinelinux.org/aports/plain/main/fakeroot/do-not-redefine-id_t.patch?id=bb497eeb2155d0332284942105692bc05fec25a9
+https://git.alpinelinux.org/aports/plain/main/fakeroot/fakeroot-no64.patch?id=bb497eeb2155d0332284942105692bc05fec25a9
+https://git.alpinelinux.org/aports/plain/main/fakeroot/fakeroot-stdint.patch?id=bb497eeb2155d0332284942105692bc05fec25a9
+https://git.alpinelinux.org/aports/plain/main/fakeroot/fix-format.patch?id=bb497eeb2155d0332284942105692bc05fec25a9
+https://git.alpinelinux.org/aports/plain/main/fakeroot/fix-shell-in-fakeroot.patch?id=bb497eeb2155d0332284942105692bc05fec25a9
+EOF
+ ./bootstrap;
+ f=$(mktemp); # needed due to "error: unknown type name 'cap_user_header_t'"
+ echo > ${f} "#include <linux/capability.h>";
+ cat libfakeroot.c >> ${f};
+ mv ${f} libfakeroot.c;
+ rm -fr x; mkdir x; cd x;
+ CFLAGS="-D_STAT_VER=0 $CFLAGS" \
+ ../configure \
+ --prefix="${DEST}" \
+ ;
+ sed -i Makefile \
+ -e '/^SUBDIRS =/ s/doc//g' \
+ ;
+ make -j$(nproc) install;
+)
+touch ._${nfrt}-${vfrt#*:};
+rm -fr ${nfrt}-${vfrt#*:};
+
+
+##
+# attr
+#
+natt=attr;
+vatt=2979615e71fb53b3f2f9085eea516d4e2b3174ea;
+test ! -f ._${natt}-${vatt} &&
+(
+ test ! -d ${natt}-${vatt} \
+ && git clone https://git.savannah.nongnu.org/git/${natt}.git ${natt}-${vatt} \
+ ;
+ cd ${natt}-${vatt};
+ git checkout ${vatt};
+ ./autogen.sh;
+ ./configure \
+ --prefix="${DEST}" \
+ --enable-static \
+ --disable-shared \
+ ;
+ make -j$(nproc) install;
+)
+touch ._${natt}-${vatt};
+rm -fr ${natt}-${vatt};
diff --git a/setup-packages b/setup-packages
new file mode 100755
index 0000000..ea449dc
--- /dev/null
+++ b/setup-packages
@@ -0,0 +1,13 @@
+#!/bin/sh -e
+
+d=$(mktemp -d);
+cd "${d}";
+pwd;
+
+git clone https://git.adelielinux.org/adelie/packages.git;
+cd packages;
+git checkout 198e0130d845f7466c09a61f3829905d95313c06;
+
+# FIXME: this script needs a lot of work
+#./scripts/bootstrap.sh ${TARGET_ARCH};
+bash
diff --git a/setup-preimage b/setup-preimage
new file mode 100755
index 0000000..7892a0d
--- /dev/null
+++ b/setup-preimage
@@ -0,0 +1,35 @@
+#!/bin/sh -e
+
+set -x;
+
+# these will require proper mounting when actually used
+mkdir -p dev proc sys tmp;
+
+# overwrite leftovers from mcmtools bootstrap
+cat > root/.bashrc <<EOF
+PATH="${PATH}";
+EOF
+
+# handle git backend issue (hardcoded paths)
+# git config --global http.sslCAInfo /cacert.pem
+cat > root/.gitconfig <<EOF
+[http]
+ sslCAInfo = "${CURL_CA_BUNDLE}"
+EOF
+
+# handle CA certificate issue (this or 'CURL_CA_BUNDLE' env var)
+cat > root/.curlrc <<EOF
+--cacert "${CURL_CA_BUNDLE}"
+EOF
+
+# hack to create abuild user and group
+# FIXME: have to use a patched 'abuild' anyway, debug me!
+cat > etc/group <<EOF
+abuild:x:300:builder
+EOF
+cat > etc/passwd <<EOF
+builder:x:1000:300::/usr/src:/bin/sh
+EOF
+
+# maybe not necessary?
+chown -R 1000:300 root etc;