index : archiso32 | |
Archlinux32 iso tools | gitolite user |
summaryrefslogtreecommitdiff |
author | Andreas Baumann <mail@andreasbaumann.cc> | 2022-02-01 19:15:22 +0100 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2022-02-01 19:15:22 +0100 |
commit | 30fa0d760efa7404b85829ac144b88aaf980525e (patch) | |
tree | 6de0e5eda482e490317ffa8d1103442351b89b00 | |
parent | a231f14524e85f7e751c6ce95d426afed19df1a1 (diff) | |
parent | f8225782e27e581a97d807a9d152b94771ee559a (diff) |
diff --git a/.editorconfig b/.editorconfig index 4a540f3..74ed4eb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,7 @@ -# EditorConfig configuration for archiso -# http://EditorConfig.org +# EditorConfig for archiso +# https://editorconfig.org/ +# +# SPDX-License-Identifier: GPL-3.0-or-later # Top-most EditorConfig file root = true @@ -22,3 +24,11 @@ trim_trailing_whitespace = true charset = utf-8 indent_style = space indent_size = 2 + +[*.rst] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 +indent_style = space +indent_size = 2 @@ -1,4 +1,7 @@ *~ archiso32-*.tar.gz* -configs/*/work -configs/*/out +work/ +out/ +*.iso +user-data +meta-data diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e69ab5e..c674294 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,11 +1,46 @@ --- +# +# SPDX-License-Identifier: GPL-3.0-or-later -default: - image: archlinux/base - before_script: - - pacman --noconfirm -Syu --needed base-devel shellcheck +# NOTE: most functionality (apart from building) is abstracted by this include +include: + - project: 'archlinux/ci-scripts' + ref: master + file: '/prepare_archiso_vm.yml' + +variables: + BUILD_SCRIPT: ./.gitlab/ci/build_archiso.sh + PACKAGE_LIST: dosfstools e2fsprogs erofs-utils jq libisoburn mtools openssl qemu-headless squashfs-tools zsync + QEMU_BUILD_TIMEOUT: 2400 + QEMU_COPY_ARTIFACTS_TIMEOUT: 120 + QEMU_VM_MEMORY: 3072 + ARCHISO_COW_SPACE_SIZE: 2g + +stages: + - check + - build -lint: - stage: build +check: + before_script: + - pacman --noconfirm -Syu --needed make shellcheck script: - make check + stage: check + +build_short: + extends: .build + parallel: + matrix: + - BUILD_SCRIPT_ARGS: baseline bootstrap + - BUILD_SCRIPT_ARGS: releng bootstrap + +build_long: + extends: .build + parallel: + matrix: + - BUILD_SCRIPT_ARGS: baseline iso + - BUILD_SCRIPT_ARGS: baseline netboot + - BUILD_SCRIPT_ARGS: releng iso + - BUILD_SCRIPT_ARGS: releng netboot + tags: + - fast-single-thread diff --git a/.gitlab/ci/build_archiso.sh b/.gitlab/ci/build_archiso.sh new file mode 100755 index 0000000..5250b51 --- /dev/null +++ b/.gitlab/ci/build_archiso.sh @@ -0,0 +1,273 @@ +#!/usr/bin/env bash +# +# This script is run within a virtual environment to build the available archiso profiles and their available build +# modes and create checksum files for the resulting images. +# The script needs to be run as root and assumes $PWD to be the root of the repository. +# +# Dependencies: +# * all archiso dependencies +# * coreutils +# * gnupg +# * openssl +# * zsync +# +# $1: profile +# $2: buildmode + +set -euo pipefail +shopt -s extglob + +readonly orig_pwd="${PWD}" +readonly output="${orig_pwd}/output" +readonly tmpdir_base="${orig_pwd}/tmp" +readonly profile="${1}" +readonly buildmode="${2}" +readonly install_dir="arch" + +tmpdir="" +tmpdir="$(mktemp --dry-run --directory --tmpdir="${tmpdir_base}")" +gnupg_homedir="" +codesigning_dir="" +codesigning_cert="" +codesigning_key="" +pgp_key_id="" + +print_section_start() { + # gitlab collapsible sections start: https://docs.gitlab.com/ee/ci/jobs/#custom-collapsible-sections + local _section _title + _section="${1}" + _title="${2}" + + printf "\e[0Ksection_start:%(%s)T:%s\r\e[0K%s\n" '-1' "${_section}" "${_title}" +} + +print_section_end() { + # gitlab collapsible sections end: https://docs.gitlab.com/ee/ci/jobs/#custom-collapsible-sections + local _section + _section="${1}" + + printf "\e[0Ksection_end:%(%s)T:%s\r\e[0K\n" '-1' "${_section}" +} + +cleanup() { + # clean up temporary directories + print_section_start "cleanup" "Cleaning up temporary directory" + + if [ -n "${tmpdir_base:-}" ]; then + rm -fr "${tmpdir_base}" + fi + + print_section_end "cleanup" +} + +create_checksums() { + # create checksums for files + # $@: files + local _file_path _file_name _current_pwd + _current_pwd="${PWD}" + + print_section_start "checksums" "Creating checksums" + + for _file_path in "$@"; do + cd "$(dirname "${_file_path}")" + _file_name="$(basename "${_file_path}")" + b2sum "${_file_name}" > "${_file_name}.b2" + md5sum "${_file_name}" > "${_file_name}.md5" + sha1sum "${_file_name}" > "${_file_name}.sha1" + sha256sum "${_file_name}" > "${_file_name}.sha256" + sha512sum "${_file_name}" > "${_file_name}.sha512" + ls -lah "${_file_name}."{b2,md5,sha{1,256,512}} + cat "${_file_name}."{b2,md5,sha{1,256,512}} + done + cd "${_current_pwd}" + + print_section_end "checksums" +} + +create_zsync_delta() { + # create zsync control files for files + # $@: files + local _file + + print_section_start "zsync_delta" "Creating zsync delta" + + for _file in "$@"; do + if [[ "${buildmode}" == "bootstrap" ]]; then + # zsyncmake fails on 'too long between blocks' with default block size on bootstrap image + zsyncmake -v -b 512 -C -u "${_file##*/}" -o "${_file}".zsync "${_file}" + else + zsyncmake -v -C -u "${_file##*/}" -o "${_file}".zsync "${_file}" + fi + done + + print_section_end "zsync_delta" +} + +create_metrics() { + local _metrics="${output}/metrics.txt" + # create metrics + print_section_start "metrics" "Creating metrics" + + { + # create metrics based on buildmode + case "${buildmode}" in + iso) + printf 'image_size_mebibytes{image="%s"} %s\n' \ + "${profile}" \ + "$(du -m -- "${output}/"*.iso | cut -f1)" + printf 'package_count{image="%s"} %s\n' \ + "${profile}" \ + "$(sort -u -- "${tmpdir}/iso/"*/pkglist.*.txt | wc -l)" + if [[ -e "${tmpdir}/efiboot.img" ]]; then + printf 'eltorito_efi_image_size_mebibytes{image="%s"} %s\n' \ + "${profile}" \ + "$(du -m -- "${tmpdir}/efiboot.img" | cut -f1)" + fi + # shellcheck disable=SC2046 + # shellcheck disable=SC2183 + printf 'initramfs_size_mebibytes{image="%s",initramfs="%s"} %s\n' \ + $(du -m -- "${tmpdir}/iso/"*/boot/**/initramfs*.img | \ + awk -v profile="${profile}" \ + 'function basename(file) { + sub(".*/", "", file) + return file + } + { print profile, basename($2), $1 }' + ) + ;; + netboot) + printf 'netboot_size_mebibytes{image="%s"} %s\n' \ + "${profile}" \ + "$(du -m -- "${output}/${install_dir}/" | tail -n1 | cut -f1)" + printf 'netboot_package_count{image="%s"} %s\n' \ + "${profile}" \ + "$(sort -u -- "${tmpdir}/iso/"*/pkglist.*.txt | wc -l)" + ;; + bootstrap) + printf 'bootstrap_size_mebibytes{image="%s"} %s\n' \ + "${profile}" \ + "$(du -m -- "${output}/"*.tar*(.gz|.xz|.zst) | cut -f1)" + printf 'bootstrap_package_count{image="%s"} %s\n' \ + "${profile}" \ + "$(sort -u -- "${tmpdir}/"*/bootstrap/root.*/pkglist.*.txt | wc -l)" + ;; + esac + } > "${_metrics}" + ls -lah "${_metrics}" + cat "${_metrics}" + + print_section_end "metrics" +} + +create_ephemeral_pgp_key() { + # create an ephemeral PGP key for signing the rootfs image + print_section_start "ephemeral_pgp_key" "Creating ephemeral PGP key" + + gnupg_homedir="$tmpdir/.gnupg" + mkdir -p "${gnupg_homedir}" + chmod 700 "${gnupg_homedir}" + + cat << __EOF__ > "${gnupg_homedir}"/gpg.conf +quiet +batch +no-tty +no-permission-warning +export-options no-export-attributes,export-clean +list-options no-show-keyring +armor +no-emit-version +__EOF__ + + gpg --homedir "${gnupg_homedir}" --gen-key <<EOF +%echo Generating ephemeral Arch Linux release engineering key pair... +Key-Type: default +Key-Length: 3072 +Key-Usage: sign +Name-Real: Arch Linux Release Engineering +Name-Comment: Ephemeral Signing Key +Name-Email: arch-releng@lists.archlinux.org +Expire-Date: 0 +%no-protection +%commit +%echo Done +EOF + + pgp_key_id="$( + gpg --homedir "${gnupg_homedir}" \ + --list-secret-keys \ + --with-colons \ + | awk -F':' '{if($1 ~ /sec/){ print $5 }}' + )" + + pgp_sender="Arch Linux Release Engineering (Ephemeral Signing Key) <arch-releng@lists.archlinux.org>" + + print_section_end "ephemeral_pgp_key" +} + +create_ephemeral_codesigning_key() { + # create ephemeral certificates used for codesigning + print_section_start "ephemeral_codesigning_key" "Creating ephemeral codesigning key" + + codesigning_dir="${tmpdir}/.codesigning/" + local codesigning_conf="${codesigning_dir}/openssl.cnf" + local codesigning_subj="/C=DE/ST=Berlin/L=Berlin/O=Arch Linux/OU=Release Engineering/CN=archlinux.org" + codesigning_cert="${codesigning_dir}/codesign.crt" + codesigning_key="${codesigning_dir}/codesign.key" + mkdir -p "${codesigning_dir}" + cp -- /etc/ssl/openssl.cnf "${codesigning_conf}" + printf "\n[codesigning]\nkeyUsage=digitalSignature\nextendedKeyUsage=codeSigning\n" >> "${codesigning_conf}" + openssl req \ + -newkey rsa:4096 \ + -keyout "${codesigning_key}" \ + -nodes \ + -sha256 \ + -x509 \ + -days 365 \ + -out "${codesigning_cert}" \ + -config "${codesigning_conf}" \ + -subj "${codesigning_subj}" \ + -extensions codesigning + + print_section_end "ephemeral_codesigning_key" +} + +run_mkarchiso() { + # run mkarchiso + create_ephemeral_pgp_key + create_ephemeral_codesigning_key + + print_section_start "mkarchiso" "Running mkarchiso" + mkdir -p "${output}/" "${tmpdir}/" + GNUPGHOME="${gnupg_homedir}" ./archiso/mkarchiso \ + -D "${install_dir}" \ + -c "${codesigning_cert} ${codesigning_key}" \ + -g "${pgp_key_id}" \ + -G "${pgp_sender}" \ + -o "${output}/" \ + -w "${tmpdir}/" \ + -m "${buildmode}" \ + -v "configs/${profile}" + + print_section_end "mkarchiso" + + if [[ "${buildmode}" =~ "iso" ]]; then + create_zsync_delta "${output}/"*.iso + create_checksums "${output}/"*.iso + fi + if [[ "${buildmode}" == "bootstrap" ]]; then + create_zsync_delta "${output}/"*.tar*(.gz|.xz|.zst) + create_checksums "${output}/"*.tar*(.gz|.xz|.zst) + fi + create_metrics + + print_section_start "ownership" "Setting ownership on output" + + if [[ -n "${SUDO_UID:-}" ]] && [[ -n "${SUDO_GID:-}" ]]; then + chown -Rv "${SUDO_UID}:${SUDO_GID}" -- "${output}" + fi + print_section_end "ownership" +} + +trap cleanup EXIT + +run_mkarchiso diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..d0456ac --- /dev/null +++ b/.mailmap @@ -0,0 +1,16 @@ +Aaron Griffin <aaron@archlinux.org> <aaronmgriffin@gmail.com> +Chandan Singh <cks071g2@gmail.com> chandan <cks071g2@gmail.com> +Charles Vejnar <ce@vejnar.org> Charles <ce@vejnar.org> +Christopher Brannon <cmbrannon79@gmail.com> <cmbrannon@cox.net> +David Runge <dvzrv@archlinux.org> <dave@sleepmap.de> +Eli Schwartz <eschwartz@archlinux.org> Eli Schwartz via arch-releng <arch-releng@archlinux.org> +Francois Dupoux <fdupoux@users.sourceforge.net> fdupoux <fdupoux@users.sourceforge.net> +Gerardo Exequiel Pozzi <vmlinuz386@gmail.com> <vmlinuz386@yahoo.com.ar> +James Sitegen <jamesm.sitegen@gmail.com> jamesm-sitegen <jamesm.sitegen@gmail.com> +Keshav Amburay <the.ridikulus.rat@gmail.com> Keshav P R <the.ridikulus.rat@gmail.com> +Martin Damian Fernandez <martin.damian.fernandez@gmail.com> martindamianfernandez <martin.damian.fernandez@gmail.com> +Michael Vorburger <mike@vorburger.ch> Michael Vorburger.ch <mike@vorburger.ch> +Sean Enck <enckse@voidedtech.com> Sean Enck via arch-releng <arch-releng@archlinux.org> +Simo Leone <simo@archlinux.org> <leone.simo@gmail.com> +Sven-Hendrik Haase <svenstaro@gmail.com> <sh@lutzhaase.com> +Yu Li-Yu <afg984@gmail.com> Li-Yu Yu via arch-releng <arch-releng@archlinux.org> diff --git a/AUTHORS.rst b/AUTHORS.rst new file mode 100644 index 0000000..3a03c0e --- /dev/null +++ b/AUTHORS.rst @@ -0,0 +1,36 @@ +=============== +Archiso Authors +=============== + +* Aaron Griffin <aaron@archlinux.org> +* Adam Purkrt <adam@purkrt.net> +* Alexander Epaneshnikov <aarnaarn2@gmail.com> +* Chandan Singh <cks071g2@gmail.com> +* Charles Vejnar <ce@vejnar.org> +* Christian Hesse <mail@eworm.de> +* Christopher Brannon <cmbrannon79@gmail.com> +* Dan McGee <dan@archlinux.org> +* David Runge <dvzrv@archlinux.org> +* David Thurstenson <thurstylark@gmail.com> +* Dieter Plaetinck <dieter@plaetinck.be> +* Eli Schwartz <eschwartz@archlinux.org> +* Florian Pritz <bluewind@xinu.at> +* Francois Dupoux <fdupoux@users.sourceforge.net> +* Gerardo Exequiel Pozzi <vmlinuz386@gmail.com> +* Gerhard Brauer <gerbra@archlinux.de> +* James Sitegen <jamesm.sitegen@gmail.com> +* Justin Kromlinger <hashworks@archlinux.org> +* Keshav Amburay <the.ridikulus.rat@gmail.com> +* Loui Chang <louipc.ist@gmail.com> +* Lukas Fleischer <archlinux@cryptocrack.de> +* Martin Damian Fernandez <martin.damian.fernandez@gmail.com> +* Michael Vorburger <mike@vorburger.ch> +* Pierre Schmitz <pierre@archlinux.de> +* Sean Enck <enckse@voidedtech.com> +* Simo Leone <simo@archlinux.org> +* Steffen Bönigk <boenki@gmx.de> +* Sven-Hendrik Haase <svenstaro@gmail.com> +* Thomas Bächler <thomas@archlinux.org> +* Yu Li-Yu <afg984@gmail.com> +* nl6720 <nl6720@gmail.com> +* Øyvind Heggstad <heggstad@gmail.com> diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 0000000..a166bf7 --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,249 @@ +######### +Changelog +######### + +[XX] - YYYY-MM-DD +================= + +Added +----- + +Changed +------- + +Removed +------- + +[60] - 2021-12-28 +================= + +Added +----- + +- Add `BB8E6F1B81CF0BB301D74D1CBF425A01E68B38EF` in the Releases section of the README, giving maintainer power to + nl6720. + +Changed +------- + +- Show a more descriptive message when no code signing certificate is used + +Removed +------- + +- Remove unused archiso_shutdown hook from the releng profile's mkinitcpio config + +[59] - 2021-11-30 +================= + +Added +----- + +- Add mailmap file for easier author integration with git +- Add grub and refind to the package list of the releng profile + +Changed +------- + +- Replace use of date with printf +- Silence command output more efficiently when using --quiet +- Modify curl call to retry up to ten times before giving up on downloading an automated script + +Removed +------- + +- Remove requirement on setting a Boot mode when building a netboot image + +[58] - 2021-08-25 +================= + +Added +----- + +- Add support for ``gpg``'s ``--sender`` option + +Changed +------- + +- Change the way ``mkarchiso`` uses ext4 images to copying files to it directly instead of mounting (this action now + does not require elevated privileges anymore) +- Add version files when using ``netboot`` buildmode as well +- Update the sshd configuration to be compatible with openssh 8.7p1 +- Overhaul the used ``gpg`` options +- Fix use of potentially unbound variables +- Refactor the validation functions to have fewer large functions and less code duplication + +Removed +------- + +- Remove all files related to ``mkinitcpio`` integration, as they now live in + https://gitlab.archlinux.org/mkinitcpio/mkinitcpio-archiso + +[57] - 2021-07-30 +================= + +Added +----- + +- Add a missing line in the systemd-networkd-wait-online.service in the baseline profile + +Changed +------- + +- Adapt systemd-networkd configuration to systemd ≥ 249 +- Improve documentation in ``mkarchiso`` and systemd-networkd related configuration files +- Fix an issue that may prevent continuing an aborted build of the ``netboot`` or ``iso`` buildmode + +Removed +------- + +- Remove SPDX license identifier from files that are not eligible for copyright (e.g. configuration files) + +[56.1] - 2021-07-11 +=================== + +Added +----- + +Changed +------- + +- Simplify gitlab CI setup by using ci-scripts (shared amongst several projects) +- Fix an issue with the unsetting of environment variables before using pacstrap/arch-chroot +- Remove termite-terminfo from the releng profile's list of packages (it is not in the official repositories anymore) +- Set LC_ALL instead of LANG + +[56] - 2021-07-01 +================= + +Added +----- + +- Add pacman >= 6 compatible configuration +- Add documentation for the `script` boot parameter + +Changed +------- + +- Clear environment variables before working in chroot +- Update Arch Wiki URLs +- Pass SOURCE_DATE_EPOCH to chroot +- Enable parallel downloads in profile pacman configurations +- Generalize the approach of interacting with ucode images +- Execute the netboot build mode for the baseline profile in CI + +[55] - 2021-06-01 +================= + +Added +----- + +- Add integration for pv when using the copytoram boot parameter so that progress on copying the image to RAM is shown +- Add experimental support for EROFS by using it for the rootfs image in the baseline profile + +Changed +------- + +- Change information on IRC channel, as Arch Linux moved to Libera Chat +- Fix a regression, that would prevent network interfaces to be configured under certain circumstances + +[54] - 2021-05-13 +================= + +Added +----- + +- Add the concept of buildmodes to mkarchiso, which allows for building more than the default .iso artifact + (sequentially) +- Add support to mkarchiso and both baseline and releng profiles for building a bootstrap image (a compressed + bootstrapped Arch Linux environment), by using the new buildmode `bootstrap` +- Add support to mkarchiso and both baseline and releng profiles for building artifacts required for netboot with iPXE + (optionally allowing codesigning on the artifacts), by using the new buildmode `netboot` +- Add qemu-guest-agent and virtualbox-guest-utils-nox to the releng profile and enable their services by default to + allow interaction between hypervisor and virtual machine if the installation medium is booted in a virtualized + environment + +Changed +------- + +- Always use the .sig file extension when signing the rootfs image, as that is how mkinitcpio-archiso expects it +- Fix for CI and run_archiso scripts to be compatible with QEMU >= 6.0 +- Increase robustness of CI by granting more time to reach the first prompt +- Change CI to build all available buildmodes of the baseline and releng profiles (baseline's netboot is currently + excluded due to a bug) +- Install all implicitly installed packages explicitly for the releng profile +- Install keyrings more generically when using pacman-init.service +- Consolidate CI scripts so that they may be shared between the archiso, arch-boxes and releng project in the future and + expose their configuration with the help of environment variables + +[53] - 2021-05-01 +================= + +Added +----- + +- Add ISO name to grubenv +- Add further metrics to CI, so that number of packages and further image sizes can be tracked +- Add IMAGE_ID and IMAGE_VERSION to /etc/os-release + +Changed +------- + +- Revert to an invalid GPT for greater hardware compatibility +- Fix CI scripts and initcpio script to comply with stricter shellcheck +- Fix an issue where writing to /etc/machine-id might override a file outside of the build directory +- Change gzip flags, so that compressed files are created reproducibly +- Increase default serial baud rate to 115200 +- Remove deprecated documentation and format existing documentation + +[52] - 2021-04-01 +================= + +Added +----- + +- Add usbmuxd support +- Add EROFS support (as an experimental alternative to squashfs) +- Add creation of zsync control file for delta downloads +- Add sof-firmware for additional soundcard support +- Add support for recursively setting file permissions on folders using profiledef.sh +- Add support for mobile broadband devices with the help of modemmanager +- Add information on PGP signatures of tags +- Add archinstall support + +Changed +------- + +- Remove haveged +- Fix various things in relation to gitlab CI +- Change systemd-networkd files to more generically setup networkds for devices +- Fix the behavior of the `script=` kernel commandline parameter to follow redirects +- Change the amount of mirrors checked by reflector to 20 to speed up availability of the mirrorlist + +[51] - 2021-02-01 +================= + +Added +----- + +- VNC support for `run_archiso` +- SSH enabled by default in baseline and releng profiles +- Add cloud-init support to baseline and releng profiles +- Add simple port forwarding to `run_archiso` to allow testing of SSH +- Add support for loading cloud-init user data images to `run_archiso` +- Add version information to images generated with `mkarchiso` +- Use pacman hooks for things previously done in `customize_airootfs.sh` (e.g. generating locale, uncommenting mirror + list) +- Add network setup for the baseline profile +- Add scripts for CI to build the baseline and releng profiles automatically + +Changed +------- + +- Change upstream URL in vendored profiles to archlinux.org +- Reduce the amount of sed calls in mkarchiso +- Fix typos in `mkarchiso` +- mkinitcpio-archiso: Remove resolv.conf before copy to circumvent its use +- Remove `customize_airootfs.sh` from the vendored profiles +- Support overriding more variables in `profiledef.sh` and refactor their use in `mkarchiso` +- Cleanup unused code in `run_archiso` diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..bffc49d --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,26 @@ +============ +Contributing +============ + +These are the contribution guidelines for archiso. +All contributions fall under the terms of the GPL-3.0-or-later (see `LICENSE <LICENSE>`_). + +Editorconfig +============ + +A top-level editorconfig file is provided. Please configure your text editor to use it. + +Linting +======= + +All ash and bash scripts are linted using shellcheck: + + .. code:: bash + + make lint + +Testing +======= + +Contributors are expected to test their contributions by building the releng profile and running the resulting image +using `run_archiso <scripts/run_archiso.sh>`_. @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. @@ -1,47 +1,36 @@ -V=$(shell git describe --exact-match) - -INSTALL_FILES=$(wildcard archiso/initcpio/install/*) -HOOKS_FILES=$(wildcard archiso/initcpio/hooks/*) -SCRIPT_FILES=$(wildcard archiso/initcpio/script/*) - -INSTALL_DIR=$(DESTDIR)/usr/lib/initcpio/install -HOOKS_DIR=$(DESTDIR)/usr/lib/initcpio/hooks -SCRIPT_DIR=$(DESTDIR)/usr/lib/initcpio +# +# SPDX-License-Identifier: GPL-3.0-or-later -DOC_FILES=$(wildcard docs/*) - -DOC_DIR=$(DESTDIR)/usr/share/doc/archiso +PREFIX ?= /usr/local +BIN_DIR=$(DESTDIR)$(PREFIX)/bin +DOC_DIR=$(DESTDIR)$(PREFIX)/share/doc/archiso +PROFILE_DIR=$(DESTDIR)$(PREFIX)/share/archiso +DOC_FILES=$(wildcard docs/*) $(wildcard *.rst) +SCRIPT_FILES=$(wildcard archiso/*) $(wildcard scripts/*.sh) $(wildcard .gitlab/ci/*.sh) \ + $(wildcard configs/*/profiledef.sh) $(wildcard configs/*/airootfs/usr/local/bin/*) all: -check: - shellcheck -s bash archiso/mkarchiso \ - scripts/run_archiso.sh \ - $(INSTALL_FILES) \ - $(wildcard configs/*/build.sh) \ - configs/releng/airootfs/root/.automated_script.sh \ - configs/releng/airootfs/usr/local/bin/choose-mirror - shellcheck -s dash $(HOOKS_FILES) $(SCRIPT_FILES) +check: shellcheck -install: install-program install-initcpio install-examples install-doc +shellcheck: + shellcheck -s bash $(SCRIPT_FILES) -install-program: - install -D -m 755 archiso/mkarchiso $(DESTDIR)/usr/bin/mkarchiso +install: install-scripts install-profiles install-doc -install-initcpio: - install -d $(SCRIPT_DIR) $(HOOKS_DIR) $(INSTALL_DIR) - install -m 755 -t $(SCRIPT_DIR) $(SCRIPT_FILES) - install -m 644 -t $(HOOKS_DIR) $(HOOKS_FILES) - install -m 644 -t $(INSTALL_DIR) $(INSTALL_FILES) +install-scripts: + install -vDm 755 archiso/mkarchiso -t "$(BIN_DIR)/" + install -vDm 755 scripts/run_archiso.sh "$(BIN_DIR)/run_archiso" -install-examples: - install -d -m 755 $(DESTDIR)/usr/share/archiso/ - cp -a --no-preserve=ownership configs $(DESTDIR)/usr/share/archiso/ +install-profiles: + install -d -m 755 $(PROFILE_DIR) + cp -a --no-preserve=ownership configs $(PROFILE_DIR)/ install-doc: - install -d $(DOC_DIR) - install -m 644 -t $(DOC_DIR) $(DOC_FILES) + install -vDm 644 $(DOC_FILES) -t $(DOC_DIR) + +V=$(shell git describe --exact-match) dist: git archive --format=tar --prefix=archiso32-$(V)/ $(V) | gzip -9 > archiso32-$(V).tar.gz @@ -50,4 +39,4 @@ dist: upload: scp archiso32-$(V).tar.gz archiso32-$(V).tar.gz.sig sources.archlinux32.org:sources/ -.PHONY: check install install-program install-initcpio install-examples install-doc dist upload +.PHONY: check install install-doc install-profiles install-scripts shellcheck dist upload diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..62cea01 --- /dev/null +++ b/README.rst @@ -0,0 +1,184 @@ +======= +archiso +======= + +The archiso project features scripts and configuration templates to build installation media (*.iso* images and +*.tar.gz* bootstrap images) as well as netboot artifacts for BIOS and UEFI based systems on the x86_64 architecture. +Currently creating the images is only supported on Arch Linux but may work on other operating systems as well. + +Requirements +============ + +The following packages need to be installed to be able to create an image with the included scripts: + +* arch-install-scripts +* awk +* dosfstools +* e2fsprogs +* erofs-utils (optional) +* findutils +* gzip +* libarchive +* libisoburn +* mtools +* openssl +* pacman +* sed +* squashfs-tools + +For running the images in a virtualized test environment the following packages are required: + +* edk2-ovmf +* qemu + +For linting the shell scripts the following package is required: + +* shellcheck + +Profiles +======== + +Archiso comes with two profiles: **baseline** and **releng**. While both can serve as starting points for creating +custom live media, **releng** is used to create the monthly installation medium. +They can be found below `configs/baseline/ <configs/baseline/>`_ and `configs/releng/ <configs/releng/>`_ +(respectively). Both profiles are defined by files to be placed into overlays (e.g. airootfs → the image's ``/``). + +Read `README.profile.rst <docs/README.profile.rst>`_ to learn more about how to create profiles. + +Create images +============= + +Usually the archiso tools are installed as a package. However, it is also possible to clone this repository and create +images without installing archiso system-wide. + +As filesystems are created and various mount actions have to be done when creating an image, **root** is required to run +the scripts. + +When archiso is installed system-wide and the modification of a profile is desired, it is necessary to copy it to a +writeable location, as ``/usr/share/archiso`` is tracked by the package manager and only writeable by root (changes will +be lost on update). + +The examples below will assume an unmodified profile in a system location (unless noted otherwise). + +It is advised to consult the help output of **mkarchiso**: + +.. code:: sh + + mkarchiso -h + +Create images with packaged archiso +----------------------------------- + +.. code:: sh + + mkarchiso -w path/to/work_dir -o path/to/out_dir path/to/profile + +Create images with local clone +------------------------------ + +Clone this repository and run: + +.. code:: sh + + ./archiso/mkarchiso -w path/to/work_dir -o path/to/out_dir path/to/profile + +Testing +======= + +The convenience script **run_archiso** is provided to boot into the medium using qemu. +It is advised to consult its help output: + +.. code:: sh + + run_archiso -h + +Run the following to boot the iso using BIOS: + +.. code:: sh + + run_archiso -i path/to/an/arch.iso + +Run the following to boot the iso using UEFI: + +.. code:: sh + + run_archiso -u -i path/to/an/arch.iso + +The script can of course also be executed from this repository: + + +.. code:: sh + + ./scripts/run_archiso.sh -i path/to/an/arch.iso + +Installation +============ + +To install archiso system-wide use the included ``Makefile``: + +.. code:: sh + + make install + +Optional features + +The iso image contains a GRUB environment block holding the iso name and version. This allows to +boot the iso image from GRUB with a version specific cow directory to mitigate overlay clashes. + +.. code:: sh + + loopback loop archlinux.iso + load_env -f (loop)/arch/grubenv + linux (loop)/arch/boot/x86_64/vmlinuz-linux ... \ + cow_directory=${NAME}/${VERSION} ... + initrd (loop)/arch/boot/x86_64/initramfs-linux-lts.img + +Contribute +========== + +Development of archiso takes place on Arch Linux' Gitlab: https://gitlab.archlinux.org/archlinux/archiso. + +Please read our distribution-wide `Code of Conduct <https://wiki.archlinux.org/title/Code_of_conduct>`_ before +contributing, to understand what actions will and will not be tolerated. + +Read our `contributing guide <CONTRIBUTING.rst>`_ to learn more about how to provide fixes or improvements for the code +base. + +Discussion around archiso takes place on the `arch-releng mailing list +<https://lists.archlinux.org/listinfo/arch-releng>`_ and in `#archlinux-releng +<ircs://irc.libera.chat/archlinux-releng>`_ on `Libera Chat <https://libera.chat/>`_. + +All past and present authors of archiso are listed in `AUTHORS <AUTHORS.rst>`_. + +Releases +======== + +`Releases of archiso <https://gitlab.archlinux.org/archlinux/archiso/-/tags>`_ are created by their current maintainers + +- `David Runge <https://gitlab.archlinux.org/dvzrv>`_ (``C7E7849466FE2358343588377258734B41C31549``) +- `nl6720 <https://gitlab.archlinux.org/nl6720>`_ (``BB8E6F1B81CF0BB301D74D1CBF425A01E68B38EF``) + +Tags are signed using respective PGP keys. + +To verify a tag, first import the relevant PGP key(s): + +.. code:: sh + + gpg --auto-key-locate wkd --search-keys dvzrv@archlinux.org + +or + +.. code:: sh + + gpg --auto-key-locate keyserver --recv-keys BB8E6F1B81CF0BB301D74D1CBF425A01E68B38EF + +Afterwards a tag can be verified from a clone of this repository: + +.. code:: sh + + git verify-tag <tag> + +License +======= + +Archiso is licensed under the terms of the **GPL-3.0-or-later** (see `LICENSE <LICENSE>`_). diff --git a/archiso/initcpio/hooks/archiso b/archiso/initcpio/hooks/archiso deleted file mode 100644 index 7f2f9a7..0000000 --- a/archiso/initcpio/hooks/archiso +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/ash - -# args: source, newroot, mountpoint -_mnt_dmsnapshot() { - local img="${1}" - local newroot="${2}" - local mnt="${3}" - local img_fullname="${img##*/}"; - local img_name="${img_fullname%%.*}" - local dm_snap_name="${dm_snap_prefix}_${img_name}" - local ro_dev ro_dev_size rw_dev - - ro_dev="$(losetup --find --show --read-only -- "${img}")" - echo "${ro_dev}" >> /run/archiso/used_block_devices - ro_dev_size="$(blockdev --getsz -- "${ro_dev}")" - - if [ "${cow_persistent}" = "P" ]; then - if [ -f "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" ]; then - msg ":: Found '/run/archiso/cowspace/${cow_directory}/${img_name}.cow', using as persistent." - else - msg ":: Creating '/run/archiso/cowspace/${cow_directory}/${img_name}.cow' as persistent." - truncate -s "${cow_spacesize}" "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" - fi - else - if [ -f "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" ]; then - msg ":: Found '/run/archiso/cowspace/${cow_directory}/${img_name}.cow' but non-persistent requested, removing." - rm -f "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" - fi - msg ":: Creating '/run/archiso/cowspace/${cow_directory}/${img_name}.cow' as non-persistent." - truncate -s "${cow_spacesize}" "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" - fi - - rw_dev="$(losetup --find --show "/run/archiso/cowspace/${cow_directory}/${img_name}.cow")" - echo "${rw_dev}" >> /run/archiso/used_block_devices - - dmsetup create "${dm_snap_name}" --table \ - "0 ${ro_dev_size} snapshot ${ro_dev} ${rw_dev} ${cow_persistent} ${cow_chunksize}" - - if [ "${cow_persistent}" != "P" ]; then - rm -f "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" - fi - - _mnt_dev "/dev/mapper/${dm_snap_name}" "${newroot}${mnt}" "-w" "defaults" - readlink -f "/dev/mapper/${dm_snap_name}" >> /run/archiso/used_block_devices -} - -# args: source, newroot, mountpoint -_mnt_overlayfs() { - local src="${1}" - local newroot="${2}" - local mnt="${3}" - mkdir -p "/run/archiso/cowspace/${cow_directory}/upperdir" "/run/archiso/cowspace/${cow_directory}/workdir" - mount -t overlay -o \ - "lowerdir=${src},upperdir=/run/archiso/cowspace/${cow_directory}/upperdir,workdir=/run/archiso/cowspace/${cow_directory}/workdir" \ - airootfs "${newroot}${mnt}" -} - - -# args: /path/to/image_file, mountpoint -_mnt_sfs() { - local img="${1}" - local mnt="${2}" - local img_fullname="${img##*/}" - local sfs_dev - - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ "${copytoram}" = "y" ]; then - msg -n ":: Copying squashfs image to RAM..." - if ! cp -- "${img}" "/run/archiso/copytoram/${img_fullname}" ; then - echo "ERROR: while copy '${img}' to '/run/archiso/copytoram/${img_fullname}'" - launch_interactive_shell - fi - img="/run/archiso/copytoram/${img_fullname}" - msg "done." - fi - sfs_dev="$(losetup --find --show --read-only -- "${img}")" - echo "${sfs_dev}" >> /run/archiso/used_block_devices - _mnt_dev "${sfs_dev}" "${mnt}" "-r" "defaults" -} - -# args: device, mountpoint, flags, opts -_mnt_dev() { - local dev="${1}" - local mnt="${2}" - local flg="${3}" - local opts="${4}" - - mkdir -p "${mnt}" - - msg ":: Mounting '${dev}' to '${mnt}'" - - while ! poll_device "${dev}" 30; do - echo "ERROR: '${dev}' device did not show up after 30 seconds..." - echo " Falling back to interactive prompt" - echo " You can try to fix the problem manually, log out when you are finished" - launch_interactive_shell - done - - if mount -o "${opts}" "${flg}" "${dev}" "${mnt}"; then - msg ":: Device '${dev}' mounted successfully." - else - echo "ERROR; Failed to mount '${dev}'" - echo " Falling back to interactive prompt" - echo " You can try to fix the problem manually, log out when you are finished" - launch_interactive_shell - fi -} - -_verify_checksum() { - local _status - cd "/run/archiso/bootmnt/${archisobasedir}/${arch}" || exit 1 - sha512sum -c airootfs.sha512 > /tmp/checksum.log 2>&1 - _status=$? - cd -- "${OLDPWD}" || exit 1 - return "${_status}" -} - -_verify_signature() { - local _status - cd "/run/archiso/bootmnt/${archisobasedir}/${arch}" || exit 1 - gpg --homedir /gpg --status-fd 1 --verify airootfs.sfs.sig 2>/dev/null | grep -qE '^\[GNUPG:\] GOODSIG' - _status=$? - cd -- "${OLDPWD}" || exit 1 - return ${_status} -} - -run_hook() { - [ -z "${arch}" ] && arch="$(uname -m)" - [ -z "${copytoram_size}" ] && copytoram_size="75%" - [ -z "${archisobasedir}" ] && archisobasedir="arch" - [ -z "${dm_snap_prefix}" ] && dm_snap_prefix="arch" - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - [ -z "${archisodevice}" ] && archisodevice="/dev/disk/by-label/${archisolabel}" - [ -z "${cow_spacesize}" ] && cow_spacesize="256M" - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ -n "${cow_label}" ]; then - cow_device="/dev/disk/by-label/${cow_label}" - [ -z "${cow_persistent}" ] && cow_persistent="P" - elif [ -n "${cow_device}" ]; then - [ -z "${cow_persistent}" ] && cow_persistent="P" - else - cow_persistent="N" - fi - - [ -z "${cow_flags}" ] && cow_flags="defaults" - [ -z "${cow_directory}" ] && cow_directory="persistent_${archisolabel}/${arch}" - [ -z "${cow_chunksize}" ] && cow_chunksize="8" - - # set mount handler for archiso - export mount_handler="archiso_mount_handler" -} - -# This function is called normally from init script, but it can be called -# as chain from other mount handlers. -# args: /path/to/newroot -archiso_mount_handler() { - local newroot="${1}" - - if ! mountpoint -q "/run/archiso/bootmnt"; then - _mnt_dev "${archisodevice}" "/run/archiso/bootmnt" "-r" "defaults" - if [ "${copytoram}" != "y" ]; then - readlink -f "${archisodevice}" >> /run/archiso/used_block_devices - fi - fi - - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ "${checksum}" = "y" ]; then - if [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sha512" ]; then - msg -n ":: Self-test requested, please wait..." - if _verify_checksum; then - msg "done. Checksum is OK, continue booting." - else - echo "ERROR: one or more files are corrupted" - echo "see /tmp/checksum.log for details" - launch_interactive_shell - fi - else - echo "ERROR: checksum=y option specified but ${archisobasedir}/${arch}/airootfs.sha512 not found" - launch_interactive_shell - fi - fi - - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ "${verify}" = "y" ]; then - if [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs.sig" ]; then - msg -n ":: Signature verification requested, please wait..." - if _verify_signature; then - msg "done. Signature is OK, continue booting." - else - echo "ERROR: one or more files are corrupted" - launch_interactive_shell - fi - else - echo "ERROR: verify=y option specified but ${archisobasedir}/${arch}/airootfs.sfs.sig not found" - launch_interactive_shell - fi - fi - - if [ "${copytoram}" = "y" ]; then - msg ":: Mounting /run/archiso/copytoram (tmpfs) filesystem, size=${copytoram_size}" - mkdir -p /run/archiso/copytoram - mount -t tmpfs -o "size=${copytoram_size}",mode=0755 copytoram /run/archiso/copytoram - fi - - if [ -n "${cow_device}" ]; then - _mnt_dev "${cow_device}" "/run/archiso/cowspace" "-r" "${cow_flags}" - readlink -f "${cow_device}" >> /run/archiso/used_block_devices - mount -o remount,rw "/run/archiso/cowspace" - else - msg ":: Mounting /run/archiso/cowspace (tmpfs) filesystem, size=${cow_spacesize}..." - mkdir -p /run/archiso/cowspace - mount -t tmpfs -o "size=${cow_spacesize}",mode=0755 cowspace /run/archiso/cowspace - fi - mkdir -p "/run/archiso/cowspace/${cow_directory}" - chmod 0700 "/run/archiso/cowspace/${cow_directory}" - - _mnt_sfs "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs" "/run/archiso/sfs/airootfs" - if [ -f "/run/archiso/sfs/airootfs/airootfs.img" ]; then - _mnt_dmsnapshot "/run/archiso/sfs/airootfs/airootfs.img" "${newroot}" "/" - else - _mnt_overlayfs "/run/archiso/sfs/airootfs" "${newroot}" "/" - fi - - if [ "${copytoram}" = "y" ]; then - umount -d /run/archiso/bootmnt - fi -} - -# vim: set ft=sh: diff --git a/archiso/initcpio/hooks/archiso_loop_mnt b/archiso/initcpio/hooks/archiso_loop_mnt deleted file mode 100644 index 2c607f5..0000000 --- a/archiso/initcpio/hooks/archiso_loop_mnt +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/ash - -run_hook () { - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - [ -n "${img_label}" ] && img_dev="/dev/disk/by-label/${img_label}" - [ -z "${img_flags}" ] && img_flags="defaults" - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ -n "${img_dev}" ] && [ -n "${img_loop}" ]; then - export mount_handler="archiso_loop_mount_handler" - fi -} - -archiso_loop_mount_handler () { - newroot="${1}" - - local _dev_loop - - msg ":: Setup a loop device from ${img_loop} located at device ${img_dev}" - _mnt_dev "${img_dev}" "/run/archiso/img_dev" "-r" "${img_flags}" - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ "${copytoram}" != "y" ]; then - readlink -f "${img_dev}" >> /run/archiso/used_block_devices - fi - - if _dev_loop=$(losetup --find --show --read-only "/run/archiso/img_dev/${img_loop}"); then - export archisodevice="${_dev_loop}" - else - echo "ERROR: Setting loopback device for file '/run/archiso/img_dev/${img_loop}'" - launch_interactive_shell - fi - - archiso_mount_handler "${newroot}" - - if [ "${copytoram}" = "y" ]; then - losetup -d "${_dev_loop}" 2>/dev/null - umount /run/archiso/img_dev - fi -} - -# vim: set ft=sh: diff --git a/archiso/initcpio/hooks/archiso_pxe_common b/archiso/initcpio/hooks/archiso_pxe_common deleted file mode 100644 index bf8e883..0000000 --- a/archiso/initcpio/hooks/archiso_pxe_common +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/ash - -run_hook () { - # Do *not* declare 'bootif_dev' local! We need it in run_latehook(). - local i net_mac bootif_mac - local DNSDOMAIN HOSTNAME IPV4DNS0 IPV4DNS1 ROOTSERVER - # These variables will be parsed from /tmp/net-*.conf generated by ipconfig - # shellcheck disable=SC2034 - local DEVICE IPV4ADDR IPV4BROADCAST IPV4NETMASK IPV4GATEWAY NISDOMAIN ROOTPATH filename - - if [ -n "${ip}" ]; then - if [ -n "${BOOTIF}" ]; then - bootif_mac="${BOOTIF#01-}" - # shellcheck disable=SC2169 - # ash supports bash-like string replacment - bootif_mac="${bootif_mac//-/:}" - for i in /sys/class/net/*/address; do - read -r net_mac < "${i}" - if [ "${bootif_mac}" = "${net_mac}" ]; then - bootif_dev=${i#/sys/class/net/} - bootif_dev=${bootif_dev%/address} - break - fi - done - if [ "${ip}" = "dhcp" ]; then - ip=":::::${bootif_dev}:dhcp" - else - ip="${ip}::${bootif_dev}" - fi - fi - - # setup network and save some values - if ! ipconfig -t 20 "ip=${ip}"; then - echo "ERROR; Failed to configure network" - echo " Falling back to interactive prompt" - echo " You can try to fix the problem manually, log out when you are finished" - launch_interactive_shell - fi - - # shellcheck disable=SC1090 - # ipconfig generates these files - . /tmp/net-*.conf - - export pxeserver="${ROOTSERVER}" - - # setup DNS resolver - if [ "${IPV4DNS0}" != "0.0.0.0" ]; then - echo "# added by archiso_pxe_common hook" > /etc/resolv.conf - echo "nameserver ${IPV4DNS0}" >> /etc/resolv.conf - fi - if [ "${IPV4DNS1}" != "0.0.0.0" ]; then - echo "nameserver ${IPV4DNS1}" >> /etc/resolv.conf - fi - if [ -n "${DNSDOMAIN}" ]; then - echo "search ${DNSDOMAIN}" >> /etc/resolv.conf - echo "domain ${DNSDOMAIN}" >> /etc/resolv.conf - fi - fi -} - -run_latehook () { - if [ -n "${ip}" ]; then - [ -z "${copy_resolvconf}" ] && copy_resolvconf="y" - - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ "${copytoram}" = "y" ]; then - if [ -n "${bootif_dev}" ]; then - ip addr flush dev "${bootif_dev}" - ip link set "${bootif_dev}" down - fi - elif [ "${copy_resolvconf}" != "n" ] && [ -f /etc/resolv.conf ]; then - cp /etc/resolv.conf /new_root/etc/resolv.conf - fi - fi -} - -# vim: set ft=sh: diff --git a/archiso/initcpio/hooks/archiso_pxe_http b/archiso/initcpio/hooks/archiso_pxe_http deleted file mode 100644 index bf2f5f4..0000000 --- a/archiso/initcpio/hooks/archiso_pxe_http +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/ash - -run_hook() { - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ -n "${ip}" ] && [ -n "${archiso_http_srv}" ]; then - - # booting with http is always copy-to-ram, so set here to make sure - # addresses are flushed and interface is set down - export copytoram="y" - - archiso_http_srv=$(eval echo "${archiso_http_srv}") - [ -z "${archiso_http_spc}" ] && archiso_http_spc="75%" - - export mount_handler="archiso_pxe_http_mount_handler" - fi -} - -# Fetch a file with CURL -# -# $1 URL -# $2 Destination directory inside httpspace/${archisobasedir} -_curl_get() { - local _url="${1}" - local _dst="${2}" - - msg ":: Downloading '${_url}'" - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if ! curl -L -f -o "/run/archiso/httpspace/${archisobasedir}${_dst}/${_url##*/}" --create-dirs "${_url}"; then - echo "ERROR: Downloading '${_url}'" - echo " Falling back to interactive prompt" - echo " You can try to fix the problem manually, log out when you are finished" - launch_interactive_shell - fi -} - -archiso_pxe_http_mount_handler () { - newroot="${1}" - - msg ":: Mounting /run/archiso/httpspace (tmpfs) filesystem, size='${archiso_http_spc}'" - mkdir -p "/run/archiso/httpspace" - mount -t tmpfs -o size="${archiso_http_spc}",mode=0755 httpspace "/run/archiso/httpspace" - - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - _curl_get "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.sfs" "/${arch}" - - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ "${checksum}" = "y" ]; then - _curl_get "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.sha512" "/${arch}" - fi - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ "${verify}" = "y" ]; then - _curl_get "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.sfs.sig" "/${arch}" - fi - - mkdir -p "/run/archiso/bootmnt" - mount -o bind /run/archiso/httpspace /run/archiso/bootmnt - - archiso_mount_handler "${newroot}" -} - -# vim: set ft=sh: diff --git a/archiso/initcpio/hooks/archiso_pxe_nbd b/archiso/initcpio/hooks/archiso_pxe_nbd deleted file mode 100644 index 4ccbcbf..0000000 --- a/archiso/initcpio/hooks/archiso_pxe_nbd +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/ash - -run_earlyhook() { - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ -n "${ip}" ] && [ -n "${archiso_nbd_srv}" ]; then - # Module autoloading like with loop devices does not work, doing manually... - modprobe nbd 2> /dev/null - fi -} - -run_hook() { - if [ -n "${ip}" ] && [ -n "${archiso_nbd_srv}" ]; then - - archiso_nbd_srv=$(eval echo "${archiso_nbd_srv}") - [ -z "${archiso_nbd_name}" ] && archiso_nbd_name="archiso" - - export mount_handler="archiso_pxe_nbd_mount_handler" - fi -} - -archiso_pxe_nbd_mount_handler () { - newroot="${1}" - - msg ":: Waiting for boot device..." - while ! poll_device /dev/nbd0 30; do - echo "ERROR: boot device didn't show up after 30 seconds..." - echo " Falling back to interactive prompt" - echo " You can try to fix the problem manually, log out when you are finished" - launch_interactive_shell - done - - msg ":: Setup NBD from ${archiso_nbd_srv} at /dev/nbd0" - if [ "${copytoram}" != "n" ]; then - nbd-client "${archiso_nbd_srv}" -N "${archiso_nbd_name}" /dev/nbd0 - copytoram="y" - else - nbd-client "${archiso_nbd_srv}" -N "${archiso_nbd_name}" -systemd-mark -persist /dev/nbd0 - fi - - export archisodevice=/dev/nbd0 - - archiso_mount_handler "${newroot}" - - if [ "${copytoram}" = "y" ]; then - msg ":: Disconnect NBD from ${archiso_nbd_srv} at /dev/nbd0" - nbd-client -d /dev/nbd0 - fi -} - -# vim: set ft=sh: diff --git a/archiso/initcpio/hooks/archiso_pxe_nfs b/archiso/initcpio/hooks/archiso_pxe_nfs deleted file mode 100644 index be1e4c3..0000000 --- a/archiso/initcpio/hooks/archiso_pxe_nfs +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/ash - -run_hook() { - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ -n "${ip}" ] && [ -n "${archiso_nfs_srv}" ]; then - - archiso_nfs_srv=$(eval echo "${archiso_nfs_srv}") - - export mount_handler="archiso_nfs_mount_handler" - fi -} - -archiso_nfs_mount_handler() { - local mount_status - newroot="${1}" - mkdir -p "/run/archiso/bootmnt" - msg ":: Mounting '${archiso_nfs_srv}'" - # shellcheck disable=SC2154 - # defined via initcpio's parse_cmdline() - if [ -n "${archiso_nfs_opt}" ]; then - nfsmount -o "${archiso_nfs_opt}" "${archiso_nfs_srv}" "/run/archiso/bootmnt" - mount_status=$? - else - nfsmount "${archiso_nfs_srv}" "/run/archiso/bootmnt" - mount_status=$? - fi - if [ $mount_status -gt 0 ]; then - echo "ERROR: Mounting '${archiso_nfs_srv}'" - echo " Falling back to interactive prompt" - echo " You can try to fix the problem manually, log out when you are finished" - launch_interactive_shell - fi - - if [ "${copytoram}" != "n" ]; then - copytoram="y" - fi - - archiso_mount_handler "${newroot}" -} - -# vim: set ft=sh: diff --git a/archiso/initcpio/hooks/archiso_shutdown b/archiso/initcpio/hooks/archiso_shutdown deleted file mode 100644 index db8fb33..0000000 --- a/archiso/initcpio/hooks/archiso_shutdown +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/ash - -run_cleanuphook() { - rm -rf /usr/lib/modules - cp -ax / /run/initramfs -} - -# vim: set ft=sh: diff --git a/archiso/initcpio/install/archiso b/archiso/initcpio/install/archiso deleted file mode 100644 index a12104e..0000000 --- a/archiso/initcpio/install/archiso +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -build() { - add_module "cdrom" - add_module "loop" - add_module "dm-snapshot" - add_module "overlay" - - add_runscript - - add_binary /usr/lib/udev/cdrom_id - add_binary blockdev - add_binary dmsetup - add_binary losetup - add_binary mountpoint - add_binary truncate - add_binary gpg - add_binary grep - - add_file /usr/lib/udev/rules.d/60-cdrom_id.rules - add_file /usr/lib/udev/rules.d/10-dm.rules - add_file /usr/lib/udev/rules.d/95-dm-notify.rules - add_file /usr/lib/initcpio/udev/11-dm-initramfs.rules /usr/lib/udev/rules.d/11-dm-initramfs.rules - if [[ $ARCHISO_GNUPG_FD ]]; then - mkdir -p "$BUILDROOT/gpg" - gpg --homedir "$BUILDROOT/gpg" --import <& "$ARCHISO_GNUPG_FD" - fi -} diff --git a/archiso/initcpio/install/archiso_kms b/archiso/initcpio/install/archiso_kms deleted file mode 100644 index 48832ff..0000000 --- a/archiso/initcpio/install/archiso_kms +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -build() { - add_module "amdgpu" - add_module "radeon" - add_module "nouveau" - add_module "i915" - add_module "mgag200" - add_module "via-agp" - add_module "sis-agp" - add_module "intel-agp" - - if [[ $(uname -m) == i686 ]]; then - add_module "amd64-agp" - add_module "ati-agp" - add_module "sworks-agp" - add_module "ali-agp" - add_module "amd-k7-agp" - add_module "nvidia-agp" - add_module "efficeon-agp" - fi -} - -help() { - cat << HELPEOF -Adds all common KMS drivers to the initramfs image. -HELPEOF -} diff --git a/archiso/initcpio/install/archiso_loop_mnt b/archiso/initcpio/install/archiso_loop_mnt deleted file mode 100644 index 4a5824d..0000000 --- a/archiso/initcpio/install/archiso_loop_mnt +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -build() { - add_runscript -} - -help() { -cat<<HELPEOF - This hook loads the necessary modules for boot via loop device. -HELPEOF -} diff --git a/archiso/initcpio/install/archiso_pxe_common b/archiso/initcpio/install/archiso_pxe_common deleted file mode 100644 index da5f6b6..0000000 --- a/archiso/initcpio/install/archiso_pxe_common +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -build() { - add_checked_modules -f "(irda|phy|wimax|wireless|ppp_|plip|pppoe)" "/drivers/net/" - - add_runscript - - add_binary /usr/lib/initcpio/ipconfig /bin/ipconfig - - # Add hosts support files+dns - add_symlink /usr/lib/libnss_files.so.2 "$(readlink /usr/lib/libnss_files.so.2)" - add_binary "$(readlink -f /usr/lib/libnss_files.so.2)" - add_symlink /usr/lib/libnss_dns.so.2 "$(readlink /usr/lib/libnss_dns.so.2)" - add_binary "$(readlink -f /usr/lib/libnss_dns.so.2)" - - add_dir /etc - echo "hosts: files dns" > "$BUILDROOT/etc/nsswitch.conf" -} - -help() { -cat<<HELPEOF - This hook loads the necessary modules for boot via PXE. -HELPEOF -} diff --git a/archiso/initcpio/install/archiso_pxe_http b/archiso/initcpio/install/archiso_pxe_http deleted file mode 100644 index 3353eb7..0000000 --- a/archiso/initcpio/install/archiso_pxe_http +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -build() { - add_runscript - - add_binary curl - - add_file "$(readlink -f /etc/ssl/certs/ca-certificates.crt)" /etc/ssl/certs/ca-certificates.crt -} - -help() { -cat<<HELPEOF - This hook loads the necessary modules for boot via PXE and HTTP. -HELPEOF -} diff --git a/archiso/initcpio/install/archiso_pxe_nbd b/archiso/initcpio/install/archiso_pxe_nbd deleted file mode 100644 index 9fe3fdd..0000000 --- a/archiso/initcpio/install/archiso_pxe_nbd +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -build() { - add_module "nbd" - - add_runscript - - add_binary nbd-client -} - -help() { -cat<<HELPEOF - This hook loads the necessary modules for boot via PXE and NBD. -HELPEOF -} diff --git a/archiso/initcpio/install/archiso_pxe_nfs b/archiso/initcpio/install/archiso_pxe_nfs deleted file mode 100644 index fa4e548..0000000 --- a/archiso/initcpio/install/archiso_pxe_nfs +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -build() { - add_module "nfs" - - add_runscript - - add_binary /usr/lib/initcpio/nfsmount /bin/nfsmount -} - -help() { - cat <<HELPEOF - This hook loads the necessary modules for boot via PXE and NFS. -HELPEOF -} diff --git a/archiso/initcpio/install/archiso_shutdown b/archiso/initcpio/install/archiso_shutdown deleted file mode 100644 index 1051d1b..0000000 --- a/archiso/initcpio/install/archiso_shutdown +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -build() { - add_binary cp - - add_runscript - - add_file /usr/lib/initcpio/archiso_shutdown /shutdown -} - -help() { - cat <<HELPEOF -This hook will create a shutdown initramfs in /run/initramfs -that we can pivot to on shutdown in order to unmount / and -and other mount points, dm-snapshot and loopback devices. -Mostly useful for persistent dm-snapshot. -HELPEOF -} diff --git a/archiso/initcpio/script/archiso_shutdown b/archiso/initcpio/script/archiso_shutdown deleted file mode 100644 index 4a0c7dc..0000000 --- a/archiso/initcpio/script/archiso_shutdown +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/ash - -# /oldroot depends on things inside /oldroot/run/archiso... -mkdir /oldrun -mount -n --move /oldroot/run /oldrun - -# Unmount all mounts now. -umount "$(mount | awk '$3 ~/^\/oldroot/ {print $3}' | sort -r)" - -# Remove all dm-snapshot devices. -dmsetup remove_all - -# Remove all loopback devices. -for _lup in $(grep ^/dev/loop /oldrun/archiso/used_block_devices | tac); do - if ! losetup -d -- "${_lup}" 2> /dev/null; then - umount -d -- "${_lup}" - fi -done - -# Unmount the space used to store *.cow. -umount /oldrun/archiso/cowspace - -# Unmount boot device if needed (no copytoram=y used) -if [ ! -d /oldrun/archiso/copytoram ]; then - if [ -d /oldrun/archiso/img_dev ]; then - umount /oldrun/archiso/img_dev - else - umount /oldrun/archiso/bootmnt - fi -fi - -# reboot / poweroff / halt, depending on the argument passed by init -# if something invalid is passed, we halt -case "$1" in - reboot|poweroff|halt) "$1" -f ;; - *) halt -f;; -esac - -# vim: set ft=sh: diff --git a/archiso/mkarchiso b/archiso/mkarchiso index 7b65cf6..63c2364 100755 --- a/archiso/mkarchiso +++ b/archiso/mkarchiso @@ -1,30 +1,63 @@ -#!/bin/bash +#!/usr/bin/env bash +# +# SPDX-License-Identifier: GPL-3.0-or-later set -e -u -export LANG=C +# Control the environment +umask 0022 +export LC_ALL="C" +[[ -v SOURCE_DATE_EPOCH ]] || printf -v SOURCE_DATE_EPOCH '%(%s)T' -1 +export SOURCE_DATE_EPOCH + +# Set application name from the script's file name +app_name="${0##*/}" -app_name=${0##*/} +# pass architecture via environment arch=${arch:-$(uname -m)} + +# Define global variables. All of them will be overwritten later pkg_list=() -run_cmd="" -quiet="y" -pacman_conf="/etc/pacman.conf" -iso_label="ARCH_$(date +%Y%m)" -iso_publisher="Arch Linux <http://www.archlinux.org>" -iso_application="Arch Linux Live/Rescue CD" -install_dir="arch" -work_dir="work" -out_dir="out" -sfs_mode="sfs" -sfs_comp="xz" -gpg_key= +bootstrap_pkg_list=() +quiet="" +work_dir="" +out_dir="" +gpg_key="" +gpg_sender="" +iso_name="" +iso_label="" +iso_publisher="" +iso_application="" +iso_version="" +install_dir="" +arch="" +pacman_conf="" +packages="" +bootstrap_packages="" +pacstrap_dir="" +buildmodes=() +bootmodes=() +airootfs_image_type="" +airootfs_image_tool_options=() +cert_list=() +sign_netboot_artifacts="" +declare -A file_permissions=() +# adapted from GRUB_EARLY_INITRD_LINUX_STOCK in https://git.savannah.gnu.org/cgit/grub.git/tree/util/grub-mkconfig.in +readonly ucodes=('intel-uc.img' 'intel-ucode.img' 'amd-uc.img' 'amd-ucode.img' 'early_ucode.cpio' 'microcode.cpio') + # Show an INFO message # $1: message string _msg_info() { local _msg="${1}" - echo "[mkarchiso] INFO: ${_msg}" + [[ "${quiet}" == "y" ]] || printf '[%s] INFO: %s\n' "${app_name}" "${_msg}" +} + +# Show a WARNING message +# $1: message string +_msg_warning() { + local _msg="${1}" + printf '[%s] WARNING: %s\n' "${app_name}" "${_msg}" >&2 } # Show an ERROR message then exit with status @@ -33,377 +66,1256 @@ _msg_info() { _msg_error() { local _msg="${1}" local _error=${2} - echo - echo "[mkarchiso] ERROR: ${_msg}" - echo - if [[ ${_error} -gt 0 ]]; then + printf '[%s] ERROR: %s\n' "${app_name}" "${_msg}" >&2 + if (( _error > 0 )); then exit "${_error}" fi } -_chroot_init() { - mkdir -p ${work_dir}/airootfs - _pacman base syslinux +# Show help usage, with an exit status. +# $1: exit status number. +_usage() { + IFS='' read -r -d '' usagetext <<ENDUSAGETEXT || true +usage: ${app_name} [options] <profile_dir> + options: + -A <application> Set an application name for the ISO + Default: '${iso_application}' + -C <file> pacman configuration file. + Default: '${pacman_conf}' + -D <install_dir> Set an install_dir. All files will by located here. + Default: '${install_dir}' + NOTE: Max 8 characters, use only [a-z0-9] + -L <label> Set the ISO volume label + Default: '${iso_label}' + -P <publisher> Set the ISO publisher + Default: '${iso_publisher}' + -c [cert ..] Provide certificates for codesigning of netboot artifacts + Multiple files are provided as quoted, space delimited list. + The first file is considered as the signing certificate, + the second as the key. + -g <gpg_key> Set the PGP key ID to be used for signing the rootfs image. + Passed to gpg as the value for --default-key + -G <mbox> Set the PGP signer (must include an email address) + Passed to gpg as the value for --sender + -h This message + -m [mode ..] Build mode(s) to use (valid modes are: 'bootstrap', 'iso' and 'netboot'). + Multiple build modes are provided as quoted, space delimited list. + -o <out_dir> Set the output directory + Default: '${out_dir}' + -p [package ..] Package(s) to install. + Multiple packages are provided as quoted, space delimited list. + -v Enable verbose output + -w <work_dir> Set the working directory + Default: '${work_dir}' + + profile_dir: Directory of the archiso profile to build +ENDUSAGETEXT + printf '%s' "${usagetext}" + exit "${1}" } -_chroot_run() { - eval arch-chroot ${work_dir}/airootfs "${run_cmd}" +# Shows configuration options. +_show_config() { + local build_date + printf -v build_date '%(%FT%R%z)T' "${SOURCE_DATE_EPOCH}" + _msg_info "${app_name} configuration settings" + _msg_info " Architecture: ${arch}" + _msg_info " Working directory: ${work_dir}" + _msg_info " Installation directory: ${install_dir}" + _msg_info " Build date: ${build_date}" + _msg_info " Output directory: ${out_dir}" + _msg_info " Current build mode: ${buildmode}" + _msg_info " Build modes: ${buildmodes[*]}" + _msg_info " GPG key: ${gpg_key:-None}" + _msg_info " GPG signer: ${gpg_sender:-None}" + _msg_info "Code signing certificates: ${cert_list[*]:-None}" + _msg_info " Profile: ${profile}" + _msg_info "Pacman configuration file: ${pacman_conf}" + _msg_info " Image file name: ${image_name:-None}" + _msg_info " ISO volume label: ${iso_label}" + _msg_info " ISO publisher: ${iso_publisher}" + _msg_info " ISO application: ${iso_application}" + _msg_info " Boot modes: ${bootmodes[*]:-None}" + _msg_info " Packages File: ${buildmode_packages}" + _msg_info " Packages: ${buildmode_pkg_list[*]}" } -_mount_airootfs() { - trap "_umount_airootfs" EXIT HUP INT TERM - mkdir -p "${work_dir}/mnt/airootfs" - _msg_info "Mounting '${work_dir}/airootfs.img' on '${work_dir}/mnt/airootfs'" - mount "${work_dir}/airootfs.img" "${work_dir}/mnt/airootfs" +# Cleanup airootfs +_cleanup_pacstrap_dir() { + _msg_info "Cleaning up in pacstrap location..." + + # Delete all files in /boot + [[ -d "${pacstrap_dir}/boot" ]] && find "${pacstrap_dir}/boot" -mindepth 1 -delete + # Delete pacman database sync cache files (*.tar.gz) + [[ -d "${pacstrap_dir}/var/lib/pacman" ]] && find "${pacstrap_dir}/var/lib/pacman" -maxdepth 1 -type f -delete + # Delete pacman database sync cache + [[ -d "${pacstrap_dir}/var/lib/pacman/sync" ]] && find "${pacstrap_dir}/var/lib/pacman/sync" -delete + # Delete pacman package cache + [[ -d "${pacstrap_dir}/var/cache/pacman/pkg" ]] && find "${pacstrap_dir}/var/cache/pacman/pkg" -type f -delete + # Delete all log files, keeps empty dirs. + [[ -d "${pacstrap_dir}/var/log" ]] && find "${pacstrap_dir}/var/log" -type f -delete + # Delete all temporary files and dirs + [[ -d "${pacstrap_dir}/var/tmp" ]] && find "${pacstrap_dir}/var/tmp" -mindepth 1 -delete + # Delete package pacman related files. + find "${work_dir}" \( -name '*.pacnew' -o -name '*.pacsave' -o -name '*.pacorig' \) -delete + # Create an empty /etc/machine-id + rm -f -- "${pacstrap_dir}/etc/machine-id" + printf '' > "${pacstrap_dir}/etc/machine-id" + _msg_info "Done!" } -_umount_airootfs() { - _msg_info "Unmounting '${work_dir}/mnt/airootfs'" - umount -d "${work_dir}/mnt/airootfs" +# Create a squashfs image and place it in the ISO 9660 file system. +# $@: options to pass to mksquashfs +_run_mksquashfs() { + local mksquashfs_options=() image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" + rm -f -- "${image_path}" + [[ ! "${quiet}" == "y" ]] || mksquashfs_options+=('-no-progress' '-quiet') + mksquashfs "$@" "${image_path}" -noappend "${airootfs_image_tool_options[@]}" "${mksquashfs_options[@]}" +} + +# Create an ext4 image containing the root file system and pack it inside a squashfs image. +# Save the squashfs image on the ISO 9660 file system. +_mkairootfs_ext4+squashfs() { + local ext4_hash_seed mkfs_ext4_options=() + [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 + + _msg_info "Creating ext4 image of 32 GiB and copying '${pacstrap_dir}/' to it..." + + ext4_hash_seed="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 \ + --name "${SOURCE_DATE_EPOCH} ext4 hash seed")" + mkfs_ext4_options=( + '-d' "${pacstrap_dir}" + '-O' '^has_journal,^resize_inode' + '-E' "lazy_itable_init=0,root_owner=0:0,hash_seed=${ext4_hash_seed}" + '-m' '0' + '-F' + '-U' 'clear' + ) + [[ ! "${quiet}" == "y" ]] || mkfs_ext4_options+=('-q') + rm -f -- "${pacstrap_dir}.img" + E2FSPROGS_FAKE_TIME="${SOURCE_DATE_EPOCH}" mkfs.ext4 "${mkfs_ext4_options[@]}" -- "${pacstrap_dir}.img" 32G + tune2fs -c 0 -i 0 -- "${pacstrap_dir}.img" > /dev/null _msg_info "Done!" - rmdir "${work_dir}/mnt/airootfs" - trap - EXIT HUP INT TERM + + install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" + _msg_info "Creating SquashFS image, this may take some time..." + _run_mksquashfs "${pacstrap_dir}.img" + _msg_info "Done!" + rm -- "${pacstrap_dir}.img" } -# Show help usage, with an exit status. -# $1: exit status number. -_usage () -{ - echo "usage ${app_name} [options] command <command options>" - echo " general options:" - echo " -p PACKAGE(S) Package(s) to install, can be used multiple times" - echo " -r <command> Run <command> inside airootfs" - echo " -C <file> Config file for pacman." - echo " Default: '${pacman_conf}'" - echo " -L <label> Set a label for the disk" - echo " Default: '${iso_label}'" - echo " -P <publisher> Set a publisher for the disk" - echo " Default: '${iso_publisher}'" - echo " -A <application> Set an application name for the disk" - echo " Default: '${iso_application}'" - echo " -D <install_dir> Set an install_dir. All files will by located here." - echo " Default: '${install_dir}'" - echo " NOTE: Max 8 characters, use only [a-z0-9]" - echo " -w <work_dir> Set the working directory" - echo " Default: '${work_dir}'" - echo " -o <out_dir> Set the output directory" - echo " Default: '${out_dir}'" - echo " -s <sfs_mode> Set SquashFS image mode (img or sfs)" - echo " img: prepare airootfs.sfs for dm-snapshot usage" - echo " sfs: prepare airootfs.sfs for overlayfs usage" - echo " Default: ${sfs_mode}" - echo " -c <comp_type> Set SquashFS compression type (gzip, lzma, lzo, xz, zstd)" - echo " Default: '${sfs_comp}'" - echo " -v Enable verbose output" - echo " -h This message" - echo " commands:" - echo " init" - echo " Make base layout and install base group" - echo " install" - echo " Install all specified packages (-p)" - echo " run" - echo " run command specified by -r" - echo " prepare" - echo " build all images" - echo " pkglist" - echo " make a pkglist.txt of packages installed on airootfs" - echo " iso <image name>" - echo " build an iso image from the working dir" - exit "${1}" +# Create a squashfs image containing the root file system and saves it on the ISO 9660 file system. +_mkairootfs_squashfs() { + [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 + + install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" + _msg_info "Creating SquashFS image, this may take some time..." + _run_mksquashfs "${pacstrap_dir}" } -# Shows configuration according to command mode. -# $1: init | install | run | prepare | iso -_show_config () { - local _mode="$1" - echo - _msg_info "Configuration settings" - _msg_info " Command: ${command_name}" - _msg_info " Architecture: ${arch}" - _msg_info " Working directory: ${work_dir}" - _msg_info " Installation directory: ${install_dir}" - case "${_mode}" in - init) - _msg_info " Pacman config file: ${pacman_conf}" - ;; - install) - _msg_info " Pacman config file: ${pacman_conf}" - _msg_info " Packages: ${pkg_list[*]}" - ;; - run) - _msg_info " Run command: ${run_cmd}" - ;; - prepare) - ;; - pkglist) - ;; - iso) - _msg_info " Image name: ${img_name}" - _msg_info " Disk label: ${iso_label}" - _msg_info " Disk publisher: ${iso_publisher}" - _msg_info " Disk application: ${iso_application}" - ;; - esac - echo +# Create an EROFS image containing the root file system and saves it on the ISO 9660 file system. +_mkairootfs_erofs() { + local fsuuid mkfs_erofs_options=() + [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 + + install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" + local image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" + rm -f -- "${image_path}" + [[ ! "${quiet}" == "y" ]] || mkfs_erofs_options+=('--quiet') + # Generate reproducible file system UUID from SOURCE_DATE_EPOCH + fsuuid="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 --name "${SOURCE_DATE_EPOCH}")" + mkfs_erofs_options+=('-U' "${fsuuid}" "${airootfs_image_tool_options[@]}") + _msg_info "Creating EROFS image, this may take some time..." + mkfs.erofs "${mkfs_erofs_options[@]}" -- "${image_path}" "${pacstrap_dir}" + _msg_info "Done!" } -# Install desired packages to airootfs -_pacman () -{ - _msg_info "Installing packages to '${work_dir}/airootfs/'..." +# Create checksum file for the rootfs image. +_mkchecksum() { + _msg_info "Creating checksum file for self-test..." + cd -- "${isofs_dir}/${install_dir}/${arch}" + if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then + sha512sum airootfs.sfs > airootfs.sha512 + elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then + sha512sum airootfs.erofs > airootfs.sha512 + fi + cd -- "${OLDPWD}" + _msg_info "Done!" +} - if [[ "${quiet}" = "y" ]]; then - pacstrap -C "${pacman_conf}" -c -G -M "${work_dir}/airootfs" "$@" &> /dev/null - else - pacstrap -C "${pacman_conf}" -c -G -M "${work_dir}/airootfs" "$@" +# GPG sign the root file system image. +_mksignature() { + local airootfs_image_filename gpg_options=() + _msg_info "Signing rootfs image..." + if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then + airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" + elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then + airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" fi + rm -f -- "${airootfs_image_filename}.sig" + # Add gpg sender option if the value is provided + [[ -z "${gpg_sender}" ]] || gpg_options+=('--sender' "${gpg_sender}") + # always use the .sig file extension, as that is what mkinitcpio-archiso's hooks expect + gpg --batch --no-armor --no-include-key-block --output "${airootfs_image_filename}.sig" --detach-sign \ + --default-key "${gpg_key}" "${gpg_options[@]}" "${airootfs_image_filename}" + _msg_info "Done!" +} - _msg_info "Packages installed successfully!" +# Helper function to run functions only one time. +# $1: function name +_run_once() { + if [[ ! -e "${work_dir}/${run_once_mode}.${1}" ]]; then + "$1" + touch "${work_dir}/${run_once_mode}.${1}" + fi } -# Cleanup airootfs -_cleanup () { - _msg_info "Cleaning up what we can on airootfs..." +# Set up custom pacman.conf with custom cache and pacman hook directories. +_make_pacman_conf() { + local _cache_dirs _system_cache_dirs _profile_cache_dirs + _system_cache_dirs="$(pacman-conf CacheDir| tr '\n' ' ')" + _profile_cache_dirs="$(pacman-conf --config "${pacman_conf}" CacheDir| tr '\n' ' ')" - # Delete initcpio image(s) - if [[ -d "${work_dir}/airootfs/boot" ]]; then - find "${work_dir}/airootfs/boot" -type f -name '*.img' -delete + # Only use the profile's CacheDir, if it is not the default and not the same as the system cache dir. + if [[ "${_profile_cache_dirs}" != "/var/cache/pacman/pkg" ]] && \ + [[ "${_system_cache_dirs}" != "${_profile_cache_dirs}" ]]; then + _cache_dirs="${_profile_cache_dirs}" + else + _cache_dirs="${_system_cache_dirs}" fi - # Delete kernel(s) - if [[ -d "${work_dir}/airootfs/boot" ]]; then - find "${work_dir}/airootfs/boot" -type f -name 'vmlinuz*' -delete + + _msg_info "Copying custom pacman.conf to work directory..." + _msg_info "Using pacman CacheDir: ${_cache_dirs}" + # take the profile pacman.conf and strip all settings that would break in chroot when using pacman -r + # append CacheDir and HookDir to [options] section + # HookDir is *always* set to the airootfs' override directory + # see `man 8 pacman` for further info + pacman-conf --config "${pacman_conf}" | \ + sed "/CacheDir/d;/DBPath/d;/HookDir/d;/LogFile/d;/RootDir/d;/\[options\]/a CacheDir = ${_cache_dirs} + /\[options\]/a HookDir = ${pacstrap_dir}/etc/pacman.d/hooks/" > "${work_dir}/${buildmode}.pacman.conf" +} + +# Prepare working directory and copy custom root file system files. +_make_custom_airootfs() { + local passwd=() + local filename permissions + + install -d -m 0755 -o 0 -g 0 -- "${pacstrap_dir}" + + if [[ -d "${profile}/airootfs" ]]; then + _msg_info "Copying custom airootfs files..." + cp -af --no-preserve=ownership,mode -- "${profile}/airootfs/." "${pacstrap_dir}" + # Set ownership and mode for files and directories + for filename in "${!file_permissions[@]}"; do + IFS=':' read -ra permissions <<< "${file_permissions["${filename}"]}" + # Prevent file path traversal outside of $pacstrap_dir + if [[ "$(realpath -q -- "${pacstrap_dir}${filename}")" != "${pacstrap_dir}"* ]]; then + _msg_error "Failed to set permissions on '${pacstrap_dir}${filename}'. Outside of valid path." 1 + # Warn if the file does not exist + elif [[ ! -e "${pacstrap_dir}${filename}" ]]; then + _msg_warning "Cannot change permissions of '${pacstrap_dir}${filename}'. The file or directory does not exist." + else + if [[ "${filename: -1}" == "/" ]]; then + chown -fhR -- "${permissions[0]}:${permissions[1]}" "${pacstrap_dir}${filename}" + chmod -fR -- "${permissions[2]}" "${pacstrap_dir}${filename}" + else + chown -fh -- "${permissions[0]}:${permissions[1]}" "${pacstrap_dir}${filename}" + chmod -f -- "${permissions[2]}" "${pacstrap_dir}${filename}" + fi + fi + done + _msg_info "Done!" fi - # Delete pacman database sync cache files (*.tar.gz) - if [[ -d "${work_dir}/airootfs/var/lib/pacman" ]]; then - find "${work_dir}/airootfs/var/lib/pacman" -maxdepth 1 -type f -delete +} + +# Install desired packages to the root file system +_make_packages() { + _msg_info "Installing packages to '${pacstrap_dir}/'..." + + if [[ -n "${gpg_key}" ]]; then + exec {ARCHISO_GNUPG_FD}<>"${work_dir}/pubkey.gpg" + export ARCHISO_GNUPG_FD fi - # Delete pacman database sync cache - if [[ -d "${work_dir}/airootfs/var/lib/pacman/sync" ]]; then - find "${work_dir}/airootfs/var/lib/pacman/sync" -delete + + # Unset TMPDIR to work around https://bugs.archlinux.org/task/70580 + if [[ "${quiet}" = "y" ]]; then + env -u TMPDIR pacstrap -C "${work_dir}/${buildmode}.pacman.conf" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" &> /dev/null + else + env -u TMPDIR pacstrap -C "${work_dir}/${buildmode}.pacman.conf" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" fi - # Delete pacman package cache - if [[ -d "${work_dir}/airootfs/var/cache/pacman/pkg" ]]; then - find "${work_dir}/airootfs/var/cache/pacman/pkg" -type f -delete + + if [[ -n "${gpg_key}" ]]; then + exec {ARCHISO_GNUPG_FD}<&- + unset ARCHISO_GNUPG_FD fi - # Delete all log files, keeps empty dirs. - if [[ -d "${work_dir}/airootfs/var/log" ]]; then - find "${work_dir}/airootfs/var/log" -type f -delete + + _msg_info "Done! Packages installed successfully." +} + +# Customize installation. +_make_customize_airootfs() { + local passwd=() + + if [[ -e "${profile}/airootfs/etc/passwd" ]]; then + _msg_info "Copying /etc/skel/* to user homes..." + while IFS=':' read -a passwd -r; do + # Only operate on UIDs in range 1000–59999 + (( passwd[2] >= 1000 && passwd[2] < 60000 )) || continue + # Skip invalid home directories + [[ "${passwd[5]}" == '/' ]] && continue + [[ -z "${passwd[5]}" ]] && continue + # Prevent path traversal outside of $pacstrap_dir + if [[ "$(realpath -q -- "${pacstrap_dir}${passwd[5]}")" == "${pacstrap_dir}"* ]]; then + if [[ ! -d "${pacstrap_dir}${passwd[5]}" ]]; then + install -d -m 0750 -o "${passwd[2]}" -g "${passwd[3]}" -- "${pacstrap_dir}${passwd[5]}" + fi + cp -dnRT --preserve=mode,timestamps,links -- "${pacstrap_dir}/etc/skel/." "${pacstrap_dir}${passwd[5]}" + chmod -f 0750 -- "${pacstrap_dir}${passwd[5]}" + chown -hR -- "${passwd[2]}:${passwd[3]}" "${pacstrap_dir}${passwd[5]}" + else + _msg_error "Failed to set permissions on '${pacstrap_dir}${passwd[5]}'. Outside of valid path." 1 + fi + done < "${profile}/airootfs/etc/passwd" + _msg_info "Done!" fi - # Delete all temporary files and dirs - if [[ -d "${work_dir}/airootfs/var/tmp" ]]; then - find "${work_dir}/airootfs/var/tmp" -mindepth 1 -delete + + if [[ -e "${pacstrap_dir}/root/customize_airootfs.sh" ]]; then + _msg_info "Running customize_airootfs.sh in '${pacstrap_dir}' chroot..." + _msg_warning "customize_airootfs.sh is deprecated! Support for it will be removed in a future archiso version." + chmod -f -- +x "${pacstrap_dir}/root/customize_airootfs.sh" + # Unset TMPDIR to work around https://bugs.archlinux.org/task/70580 + eval -- env -u TMPDIR arch-chroot "${pacstrap_dir}" "/root/customize_airootfs.sh" + rm -- "${pacstrap_dir}/root/customize_airootfs.sh" + _msg_info "Done! customize_airootfs.sh run successfully." fi - # Delete package pacman related files. - find "${work_dir}" \( -name "*.pacnew" -o -name "*.pacsave" -o -name "*.pacorig" \) -delete +} + +# Set up boot loaders +_make_bootmodes() { + local bootmode + for bootmode in "${bootmodes[@]}"; do + _run_once "_make_bootmode_${bootmode}" + done +} + +# Copy kernel and initramfs to ISO 9660 +_make_boot_on_iso9660() { + local ucode_image + _msg_info "Preparing kernel and initramfs for the ISO 9660 file system..." + install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/${arch}" + install -m 0644 -- "${pacstrap_dir}/boot/initramfs-"*".img" "${isofs_dir}/${install_dir}/boot/${arch}/" + install -m 0644 -- "${pacstrap_dir}/boot/vmlinuz-"* "${isofs_dir}/${install_dir}/boot/${arch}/" + + for ucode_image in "${ucodes[@]}"; do + if [[ -e "${pacstrap_dir}/boot/${ucode_image}" ]]; then + install -m 0644 -- "${pacstrap_dir}/boot/${ucode_image}" "${isofs_dir}/${install_dir}/boot/" + if [[ -e "${pacstrap_dir}/usr/share/licenses/${ucode_image%.*}/" ]]; then + install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/licenses/${ucode_image%.*}/" + install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/${ucode_image%.*}/"* \ + "${isofs_dir}/${install_dir}/boot/licenses/${ucode_image%.*}/" + fi + fi + done _msg_info "Done!" } -# Makes a ext4 filesystem inside a SquashFS from a source directory. -_mkairootfs_img () { - if [[ ! -e "${work_dir}/airootfs" ]]; then - _msg_error "The path '${work_dir}/airootfs' does not exist" 1 +# Prepare syslinux for booting from MBR (isohybrid) +_make_bootmode_bios.syslinux.mbr() { + _msg_info "Setting up SYSLINUX for BIOS booting from a disk..." + install -d -m 0755 -- "${isofs_dir}/syslinux" + for _cfg in "${profile}/syslinux/"*.cfg; do + sed "s|%ARCHISO_LABEL%|${iso_label}|g; + s|%INSTALL_DIR%|${install_dir}|g; + s|%ARCH%|${arch}|g" \ + "${_cfg}" > "${isofs_dir}/syslinux/${_cfg##*/}" + done + if [[ -e "${profile}/syslinux/splash.png" ]]; then + install -m 0644 -- "${profile}/syslinux/splash.png" "${isofs_dir}/syslinux/" fi + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/"*.c32 "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/lpxelinux.0" "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/memdisk" "${isofs_dir}/syslinux/" - _msg_info "Creating ext4 image of 32GiB..." - truncate -s 32G "${work_dir}/airootfs.img" - local _qflag="" - if [[ "${quiet}" == "y" ]]; then - _qflag="-q" + _run_once _make_boot_on_iso9660 + + if [[ -e "${isofs_dir}/syslinux/hdt.c32" ]]; then + install -d -m 0755 -- "${isofs_dir}/syslinux/hdt" + if [[ -e "${pacstrap_dir}/usr/share/hwdata/pci.ids" ]]; then + gzip -cn9 "${pacstrap_dir}/usr/share/hwdata/pci.ids" > \ + "${isofs_dir}/syslinux/hdt/pciids.gz" + fi + find "${pacstrap_dir}/usr/lib/modules" -name 'modules.alias' -print -exec gzip -cn9 '{}' ';' -quit > \ + "${isofs_dir}/syslinux/hdt/modalias.gz" + fi + + # Add other aditional/extra files to ${install_dir}/boot/ + if [[ -e "${pacstrap_dir}/boot/memtest86+/memtest.bin" ]]; then + # rename for PXE: https://wiki.archlinux.org/title/Syslinux#Using_memtest + install -m 0644 -- "${pacstrap_dir}/boot/memtest86+/memtest.bin" "${isofs_dir}/${install_dir}/boot/memtest" + install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/licenses/memtest86+/" + install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/common/GPL2/license.txt" \ + "${isofs_dir}/${install_dir}/boot/licenses/memtest86+/" + fi + _msg_info "Done! SYSLINUX set up for BIOS booting from a disk successfully." +} + +# Prepare syslinux for El-Torito booting +_make_bootmode_bios.syslinux.eltorito() { + _msg_info "Setting up SYSLINUX for BIOS booting from an optical disc..." + install -d -m 0755 -- "${isofs_dir}/syslinux" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isolinux.bin" "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isohdpfx.bin" "${isofs_dir}/syslinux/" + + # ISOLINUX and SYSLINUX installation is shared + _run_once _make_bootmode_bios.syslinux.mbr + + _msg_info "Done! SYSLINUX set up for BIOS booting from an optical disc successfully." +} + +# Copy kernel and initramfs to FAT image +_make_boot_on_fat() { + local ucode_image all_ucode_images=() + _msg_info "Preparing kernel and initramfs for the FAT file system..." + mmd -i "${work_dir}/efiboot.img" \ + "::/${install_dir}" "::/${install_dir}/boot" "::/${install_dir}/boot/${arch}" + mcopy -i "${work_dir}/efiboot.img" "${pacstrap_dir}/boot/vmlinuz-"* \ + "${pacstrap_dir}/boot/initramfs-"*".img" "::/${install_dir}/boot/${arch}/" + for ucode_image in "${ucodes[@]}"; do + if [[ -e "${pacstrap_dir}/boot/${ucode_image}" ]]; then + all_ucode_images+=("${pacstrap_dir}/boot/${ucode_image}") + fi + done + if (( ${#all_ucode_images[@]} )); then + mcopy -i "${work_dir}/efiboot.img" "${all_ucode_images[@]}" "::/${install_dir}/boot/" fi - mkfs.ext4 ${_qflag} -O ^has_journal,^resize_inode -E lazy_itable_init=0 -m 0 -F "${work_dir}/airootfs.img" - tune2fs -c 0 -i 0 "${work_dir}/airootfs.img" &> /dev/null - _msg_info "Done!" - _mount_airootfs - _msg_info "Copying '${work_dir}/airootfs/' to '${work_dir}/mnt/airootfs/'..." - cp -aT "${work_dir}/airootfs/" "${work_dir}/mnt/airootfs/" - chown root:root "${work_dir}/mnt/airootfs/" _msg_info "Done!" - _umount_airootfs - mkdir -p "${work_dir}/iso/${install_dir}/${arch}" - _msg_info "Creating SquashFS image, this may take some time..." - if [[ "${quiet}" = "y" ]]; then - mksquashfs "${work_dir}/airootfs.img" "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend \ - -comp "${sfs_comp}" -no-progress &> /dev/null +} + +# Create a FAT image (efiboot.img) which will serve as the EFI system partition +# $1: image size in bytes +_make_efibootimg() { + local imgsize="0" + + # Convert from bytes to KiB and round up to the next full MiB with an additional MiB for reserved sectors. + imgsize="$(awk 'function ceil(x){return int(x)+(x>int(x))} + function byte_to_kib(x){return x/1024} + function mib_to_kib(x){return x*1024} + END {print mib_to_kib(ceil((byte_to_kib($1)+1024)/1024))}' <<< "${1}" + )" + # The FAT image must be created with mkfs.fat not mformat, as some systems have issues with mformat made images: + # https://lists.gnu.org/archive/html/grub-devel/2019-04/msg00099.html + rm -f -- "${work_dir}/efiboot.img" + _msg_info "Creating FAT image of size: ${imgsize} KiB..." + if [[ "${quiet}" == "y" ]]; then + # mkfs.fat does not have a -q/--quiet option, so redirect stdout to /dev/null instead + # https://github.com/dosfstools/dosfstools/issues/103 + mkfs.fat -C -n ARCHISO_EFI "${work_dir}/efiboot.img" "${imgsize}" > /dev/null else - mksquashfs "${work_dir}/airootfs.img" "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend \ - -comp "${sfs_comp}" -no-progress + mkfs.fat -C -n ARCHISO_EFI "${work_dir}/efiboot.img" "${imgsize}" + fi + + # Create the default/fallback boot path in which a boot loaders will be placed later. + mmd -i "${work_dir}/efiboot.img" ::/EFI ::/EFI/BOOT +} + +# Prepare system-boot for booting when written to a disk (isohybrid) +_make_bootmode_uefi-x64.systemd-boot.esp() { + local _file efiboot_imgsize + local _available_ucodes=() + _msg_info "Setting up systemd-boot for UEFI booting..." + + for _file in "${ucodes[@]}"; do + if [[ -e "${pacstrap_dir}/boot/${_file}" ]]; then + _available_ucodes+=("${pacstrap_dir}/boot/${_file}") + fi + done + # Calculate the required FAT image size in bytes + efiboot_imgsize="$(du -bc \ + "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \ + "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" \ + "${profile}/efiboot/" \ + "${pacstrap_dir}/boot/vmlinuz-"* \ + "${pacstrap_dir}/boot/initramfs-"*".img" \ + "${_available_ucodes[@]}" \ + 2>/dev/null | awk 'END { print $1 }')" + # Create a FAT image for the EFI system partition + _make_efibootimg "$efiboot_imgsize" + + # Copy systemd-boot EFI binary to the default/fallback boot path + mcopy -i "${work_dir}/efiboot.img" \ + "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI + + # Copy systemd-boot configuration files + mmd -i "${work_dir}/efiboot.img" ::/loader ::/loader/entries + mcopy -i "${work_dir}/efiboot.img" "${profile}/efiboot/loader/loader.conf" ::/loader/ + for _conf in "${profile}/efiboot/loader/entries/"*".conf"; do + sed "s|%ARCHISO_LABEL%|${iso_label}|g; + s|%INSTALL_DIR%|${install_dir}|g; + s|%ARCH%|${arch}|g" \ + "${_conf}" | mcopy -i "${work_dir}/efiboot.img" - "::/loader/entries/${_conf##*/}" + done + + # shellx64.efi is picked up automatically when on / + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then + mcopy -i "${work_dir}/efiboot.img" \ + "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ::/shellx64.efi + fi + + # Copy kernel and initramfs to FAT image. + # systemd-boot can only access files from the EFI system partition it was launched from. + _make_boot_on_fat + + _msg_info "Done! systemd-boot set up for UEFI booting successfully." +} + +# Prepare system-boot for El Torito booting +_make_bootmode_uefi-x64.systemd-boot.eltorito() { + # El Torito UEFI boot requires an image containing the EFI system partition. + # uefi-x64.systemd-boot.eltorito has the same requirements as uefi-x64.systemd-boot.esp + _run_once _make_bootmode_uefi-x64.systemd-boot.esp + + # Additionally set up system-boot in ISO 9660. This allows creating a medium for the live environment by using + # manual partitioning and simply copying the ISO 9660 file system contents. + # This is not related to El Torito booting and no firmware uses these files. + _msg_info "Preparing an /EFI directory for the ISO 9660 file system..." + install -d -m 0755 -- "${isofs_dir}/EFI/BOOT" + + # Copy systemd-boot EFI binary to the default/fallback boot path + install -m 0644 -- "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \ + "${isofs_dir}/EFI/BOOT/BOOTx64.EFI" + + # Copy systemd-boot configuration files + install -d -m 0755 -- "${isofs_dir}/loader/entries" + install -m 0644 -- "${profile}/efiboot/loader/loader.conf" "${isofs_dir}/loader/" + for _conf in "${profile}/efiboot/loader/entries/"*".conf"; do + sed "s|%ARCHISO_LABEL%|${iso_label}|g; + s|%INSTALL_DIR%|${install_dir}|g; + s|%ARCH%|${arch}|g" \ + "${_conf}" > "${isofs_dir}/loader/entries/${_conf##*/}" + done + + # edk2-shell based UEFI shell + # shellx64.efi is picked up automatically when on / + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then + install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" "${isofs_dir}/shellx64.efi" fi + _msg_info "Done!" - rm "${work_dir}/airootfs.img" } -# Makes a SquashFS filesystem from a source directory. -_mkairootfs_sfs () { - if [[ ! -e "${work_dir}/airootfs" ]]; then - _msg_error "The path '${work_dir}/airootfs' does not exist" 1 +_validate_requirements_bootmode_bios.syslinux.mbr() { + # bios.syslinux.mbr requires bios.syslinux.eltorito + # shellcheck disable=SC2076 + if [[ ! " ${bootmodes[*]} " =~ ' bios.syslinux.eltorito ' ]]; then + (( validation_error=validation_error+1 )) + _msg_error "Using 'bios.syslinux.mbr' boot mode without 'bios.syslinux.eltorito' is not supported." 0 fi - mkdir -p "${work_dir}/iso/${install_dir}/${arch}" - _msg_info "Creating SquashFS image, this may take some time..." - if [[ "${quiet}" = "y" ]]; then - mksquashfs "${work_dir}/airootfs" "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend \ - -comp "${sfs_comp}" -no-progress &> /dev/null + # Check if the syslinux package is in the package list + # shellcheck disable=SC2076 + if [[ ! " ${pkg_list[*]} " =~ ' syslinux ' ]]; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': The 'syslinux' package is missing from the package list!" 0 + fi + + # Check if syslinux configuration files exist + if [[ ! -d "${profile}/syslinux" ]]; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': The '${profile}/syslinux' directory is missing!" 0 else - mksquashfs "${work_dir}/airootfs" "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend \ - -comp "${sfs_comp}" -no-progress + local cfgfile + for cfgfile in "${profile}/syslinux/"*'.cfg'; do + if [[ -e "${cfgfile}" ]]; then + break + else + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': No configuration file found in '${profile}/syslinux/'!" 0 + fi + done + fi + + # Check for optional packages + # shellcheck disable=SC2076 + if [[ ! " ${pkg_list[*]} " =~ ' memtest86+ ' ]]; then + _msg_info "Validating '${bootmode}': 'memtest86+' is not in the package list. Memmory testing will not be available from syslinux." fi - _msg_info "Done!" } -_mkchecksum () { - _msg_info "Creating checksum file for self-test..." - cd "${work_dir}/iso/${install_dir}/${arch}" - sha512sum airootfs.sfs > airootfs.sha512 - cd "${OLDPWD}" +_validate_requirements_bootmode_bios.syslinux.eltorito() { + # bios.syslinux.eltorito has the exact same requirements as bios.syslinux.mbr + _validate_requirements_bootmode_bios.syslinux.mbr +} + +_validate_requirements_bootmode_uefi-x64.systemd-boot.esp() { + # Check if mkfs.fat is available + if ! command -v mkfs.fat &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': mkfs.fat is not available on this host. Install 'dosfstools'!" 0 + fi + + # Check if mmd and mcopy are available + if ! { command -v mmd &> /dev/null && command -v mcopy &> /dev/null; }; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': mmd and/or mcopy are not available on this host. Install 'mtools'!" 0 + fi + + # Check if systemd-boot configuration files exist + if [[ ! -d "${profile}/efiboot/loader/entries" ]]; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': The '${profile}/efiboot/loader/entries' directory is missing!" 0 + else + if [[ ! -e "${profile}/efiboot/loader/loader.conf" ]]; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': File '${profile}/efiboot/loader/loader.conf' not found!" 0 + fi + local conffile + for conffile in "${profile}/efiboot/loader/entries/"*'.conf'; do + if [[ -e "${conffile}" ]]; then + break + else + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': No configuration file found in '${profile}/efiboot/loader/entries/'!" 0 + fi + done + fi + + # Check for optional packages + # shellcheck disable=SC2076 + if [[ ! " ${pkg_list[*]} " =~ ' edk2-shell ' ]]; then + _msg_info "'edk2-shell' is not in the package list. The ISO will not contain a bootable UEFI shell." + fi +} + +_validate_requirements_bootmode_uefi-x64.systemd-boot.eltorito() { + # uefi-x64.systemd-boot.eltorito has the exact same requirements as uefi-x64.systemd-boot.esp + _validate_requirements_bootmode_uefi-x64.systemd-boot.esp +} + +# Build airootfs filesystem image +_prepare_airootfs_image() { + _run_once "_mkairootfs_${airootfs_image_type}" + _mkchecksum + if [[ -n "${gpg_key}" ]]; then + _mksignature + fi +} + +# export build artifacts for netboot +_export_netboot_artifacts() { + _msg_info "Exporting netboot artifacts..." + install -d -m 0755 "${out_dir}" + cp -a -- "${isofs_dir}/${install_dir}/" "${out_dir}/" _msg_info "Done!" + du -hs -- "${out_dir}/${install_dir}" } -_mksignature () { - _msg_info "Creating signature file..." - cd "${work_dir}/iso/${install_dir}/${arch}" - gpg --detach-sign --default-key "${gpg_key}" airootfs.sfs - cd "${OLDPWD}" +# sign build artifacts for netboot +_sign_netboot_artifacts() { + local _file _dir + local _files_to_sign=() + _msg_info "Signing netboot artifacts..." + _dir="${isofs_dir}/${install_dir}/boot/" + for _file in "${ucodes[@]}"; do + if [[ -e "${_dir}${_file}" ]]; then + _files_to_sign+=("${_dir}${_file}") + fi + done + for _file in "${_files_to_sign[@]}" "${_dir}${arch}/vmlinuz-"* "${_dir}${arch}/initramfs-"*.img; do + openssl cms \ + -sign \ + -binary \ + -noattr \ + -in "${_file}" \ + -signer "${cert_list[0]}" \ + -inkey "${cert_list[1]}" \ + -outform DER \ + -out "${_file}".ipxe.sig + done _msg_info "Done!" } -command_pkglist () { - _show_config pkglist +_validate_requirements_airootfs_image_type_squashfs() { + if ! command -v mksquashfs &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${airootfs_image_type}': mksquashfs is not available on this host. Install 'squashfs-tools'!" 0 + fi +} - _msg_info "Creating a list of installed packages on live-enviroment..." - pacman -Q --sysroot "${work_dir}/airootfs" > \ - "${work_dir}/iso/${install_dir}/pkglist.${arch}.txt" - _msg_info "Done!" +_validate_requirements_airootfs_image_type_ext4+squashfs() { + if ! { command -v mkfs.ext4 &> /dev/null && command -v tune2fs &> /dev/null; }; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${airootfs_image_type}': mkfs.ext4 and/or tune2fs is not available on this host. Install 'e2fsprogs'!" 0 + fi + _validate_requirements_airootfs_image_type_squashfs +} +_validate_requirements_airootfs_image_type_erofs() { + if ! command -v mkfs.erofs &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${airootfs_image_type}': mkfs.erofs is not available on this host. Install 'erofs-utils'!" 0 + fi } -# Create an ISO9660 filesystem from "iso" directory. -command_iso () { - local _iso_efi_boot_args=() +_validate_common_requirements_buildmode_all() { + if ! command -v pacman &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': pacman is not available on this host. Install 'pacman'!" 0 + fi + if ! command -v find &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': find is not available on this host. Install 'findutils'!" 0 + fi + if ! command -v gzip &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': gzip is not available on this host. Install 'gzip'!" 0 + fi +} + +_validate_requirements_buildmode_bootstrap() { + local bootstrap_pkg_list_from_file=() + + # Check if packages for the bootstrap image are specified + if [[ -e "${bootstrap_packages}" ]]; then + mapfile -t bootstrap_pkg_list_from_file < \ + <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${bootstrap_packages}") + bootstrap_pkg_list+=("${bootstrap_pkg_list_from_file[@]}") + if (( ${#bootstrap_pkg_list_from_file[@]} < 1 )); then + (( validation_error=validation_error+1 )) + _msg_error "No package specified in '${bootstrap_packages}'." 0 + fi + else + (( validation_error=validation_error+1 )) + _msg_error "Bootstrap packages file '${bootstrap_packages}' does not exist." 0 + fi + + _validate_common_requirements_buildmode_all + if ! command -v bsdtar &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': bsdtar is not available on this host. Install 'libarchive'!" 0 + fi +} + +_validate_common_requirements_buildmode_iso_netboot() { + local bootmode + local pkg_list_from_file=() - if [[ ! -f "${work_dir}/iso/isolinux/isolinux.bin" ]]; then - _msg_error "The file '${work_dir}/iso/isolinux/isolinux.bin' does not exist." 1 + # Check if the package list file exists and read packages from it + if [[ -e "${packages}" ]]; then + mapfile -t pkg_list_from_file < <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${packages}") + pkg_list+=("${pkg_list_from_file[@]}") + if (( ${#pkg_list_from_file[@]} < 1 )); then + (( validation_error=validation_error+1 )) + _msg_error "No package specified in '${packages}'." 0 + fi + else + (( validation_error=validation_error+1 )) + _msg_error "Packages file '${packages}' does not exist." 0 fi - if [[ ! -f "${work_dir}/iso/isolinux/isohdpfx.bin" ]]; then - _msg_error "The file '${work_dir}/iso/isolinux/isohdpfx.bin' does not exist." 1 + + # Check if the specified airootfs_image_type is supported + if typeset -f "_mkairootfs_${airootfs_image_type}" &> /dev/null; then + if typeset -f "_validate_requirements_airootfs_image_type_${airootfs_image_type}" &> /dev/null; then + "_validate_requirements_airootfs_image_type_${airootfs_image_type}" + else + _msg_warning "Function '_validate_requirements_airootfs_image_type_${airootfs_image_type}' does not exist. Validating the requirements of '${airootfs_image_type}' airootfs image type will not be possible." + fi + else + (( validation_error=validation_error+1 )) + _msg_error "Unsupported image type: '${airootfs_image_type}'" 0 fi +} - # If exists, add an EFI "El Torito" boot image (FAT filesystem) to ISO-9660 image. - if [[ -f "${work_dir}/iso/EFI/archiso/efiboot.img" ]]; then - _iso_efi_boot_args+=( +_validate_requirements_buildmode_iso() { + _validate_common_requirements_buildmode_iso_netboot + _validate_common_requirements_buildmode_all + # Check if the specified bootmodes are supported + if (( ${#bootmodes[@]} < 1 )); then + (( validation_error=validation_error+1 )) + _msg_error "No boot modes specified in '${profile}/profiledef.sh'." 0 + fi + for bootmode in "${bootmodes[@]}"; do + if typeset -f "_make_bootmode_${bootmode}" &> /dev/null; then + if typeset -f "_validate_requirements_bootmode_${bootmode}" &> /dev/null; then + "_validate_requirements_bootmode_${bootmode}" + else + _msg_warning "Function '_validate_requirements_bootmode_${bootmode}' does not exist. Validating the requirements of '${bootmode}' boot mode will not be possible." + fi + else + (( validation_error=validation_error+1 )) + _msg_error "${bootmode} is not a valid boot mode!" 0 + fi + done + + if ! command -v awk &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': awk is not available on this host. Install 'awk'!" 0 + fi +} + +_validate_requirements_buildmode_netboot() { + local _override_cert_list=() + + if [[ "${sign_netboot_artifacts}" == "y" ]]; then + # Check if the certificate files exist + for _cert in "${cert_list[@]}"; do + if [[ -e "${_cert}" ]]; then + _override_cert_list+=("$(realpath -- "${_cert}")") + else + (( validation_error=validation_error+1 )) + _msg_error "File '${_cert}' does not exist." 0 + fi + done + cert_list=("${_override_cert_list[@]}") + # Check if there are at least two certificate files + if (( ${#cert_list[@]} < 2 )); then + (( validation_error=validation_error+1 )) + _msg_error "Two certificates are required for codesigning, but '${cert_list[*]}' is provided." 0 + fi + fi + _validate_common_requirements_buildmode_iso_netboot + _validate_common_requirements_buildmode_all + if ! command -v openssl &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': openssl is not available on this host. Install 'openssl'!" 0 + fi +} + +# SYSLINUX El Torito +_add_xorrisofs_options_bios.syslinux.eltorito() { + xorrisofs_options+=( + # El Torito boot image for x86 BIOS + '-eltorito-boot' 'syslinux/isolinux.bin' + # El Torito boot catalog file + '-eltorito-catalog' 'syslinux/boot.cat' + # Required options to boot with ISOLINUX + '-no-emul-boot' '-boot-load-size' '4' '-boot-info-table' + ) +} + +# SYSLINUX MBR (isohybrid) +_add_xorrisofs_options_bios.syslinux.mbr() { + xorrisofs_options+=( + # SYSLINUX MBR bootstrap code; does not work without "-eltorito-boot syslinux/isolinux.bin" + '-isohybrid-mbr' "${isofs_dir}/syslinux/isohdpfx.bin" + # When GPT is used, create an additional partition in the MBR (besides 0xEE) for sectors 0–1 (MBR + # bootstrap code area) and mark it as bootable + # May allow booting on some systems + # https://wiki.archlinux.org/title/Partitioning#Tricking_old_BIOS_into_booting_from_GPT + '--mbr-force-bootable' + # Move the first partition away from the start of the ISO to match the expectations of partition editors + # May allow booting on some systems + # https://dev.lovelyhq.com/libburnia/libisoburn/src/branch/master/doc/partition_offset.wiki + '-partition_offset' '16' + ) +} + +# systemd-boot in an attached EFI system partition +_add_xorrisofs_options_uefi-x64.systemd-boot.esp() { + # Move the first partition away from the start of the ISO, otherwise the GPT will not be valid and ISO 9660 + # partition will not be mountable + # shellcheck disable=SC2076 + [[ " ${xorrisofs_options[*]} " =~ ' -partition_offset ' ]] || xorrisofs_options+=('-partition_offset' '16') + # Attach efiboot.img as a second partition and set its partition type to "EFI system partition" + xorrisofs_options+=('-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${work_dir}/efiboot.img") + # Ensure GPT is used as some systems do not support UEFI booting without it + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then + # A valid GPT prevents BIOS booting on some systems, instead use an invalid GPT (without a protective MBR). + # The attached partition will have the EFI system partition type code in MBR, but in the invalid GPT it will + # have a Microsoft basic partition type code. + if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' ]]; then + # If '-isohybrid-gpt-basdat' is specified before '-e', then the appended EFI system partition will have the + # EFI system partition type ID/GUID in both MBR and GPT. If '-isohybrid-gpt-basdat' is specified after '-e', + # the appended EFI system partition will have the Microsoft basic data type GUID in GPT. + if [[ ! " ${xorrisofs_options[*]} " =~ ' -isohybrid-gpt-basdat ' ]]; then + xorrisofs_options+=('-isohybrid-gpt-basdat') + fi + fi + else + # Use valid GPT if BIOS booting support will not be required + xorrisofs_options+=('-appended_part_as_gpt') + fi +} + +# systemd-boot via El Torito +_add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' ]]; then + # systemd-boot in an attached EFI system partition via El Torito + xorrisofs_options+=( + # Start a new El Torito boot entry for UEFI '-eltorito-alt-boot' + # Set the second partition as the El Torito UEFI boot image + '-e' '--interval:appended_partition_2:all::' + # Boot image is not emulating floppy or hard disk; required for all known boot loaders + '-no-emul-boot' + ) + # A valid GPT prevents BIOS booting on some systems, use an invalid GPT instead. + if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then + # If '-isohybrid-gpt-basdat' is specified before '-e', then the appended EFI system partition will have the + # EFI system partition type ID/GUID in both MBR and GPT. If '-isohybrid-gpt-basdat' is specified after '-e', + # the appended EFI system partition will have the Microsoft basic data type GUID in GPT. + if [[ ! " ${xorrisofs_options[*]} " =~ ' -isohybrid-gpt-basdat ' ]]; then + xorrisofs_options+=('-isohybrid-gpt-basdat') + fi + fi + else + # The ISO will not contain a GPT partition table, so to be able to reference efiboot.img, place it as a + # file inside the ISO 9660 file system + install -d -m 0755 -- "${isofs_dir}/EFI/archiso" + cp -a -- "${work_dir}/efiboot.img" "${isofs_dir}/EFI/archiso/efiboot.img" + # systemd-boot in an embedded efiboot.img via El Torito + xorrisofs_options+=( + # Start a new El Torito boot entry for UEFI + '-eltorito-alt-boot' + # Set efiboot.img as the El Torito UEFI boot image '-e' 'EFI/archiso/efiboot.img' + # Boot image is not emulating floppy or hard disk; required for all known boot loaders '-no-emul-boot' - '-isohybrid-gpt-basdat' ) fi + # Specify where to save the El Torito boot catalog file in case it is not already set by bios.syslinux.eltorito + # shellcheck disable=SC2076 + [[ " ${bootmodes[*]} " =~ ' bios.' ]] || xorrisofs_options+=('-eltorito-catalog' 'EFI/boot.cat') +} - _show_config iso +# Build bootstrap image +_build_bootstrap_image() { + local _bootstrap_parent + _bootstrap_parent="$(dirname -- "${pacstrap_dir}")" + + [[ -d "${out_dir}" ]] || install -d -- "${out_dir}" + + cd -- "${_bootstrap_parent}" + + _msg_info "Creating bootstrap image..." + bsdtar -cf - "root.${arch}" | gzip -cn9 > "${out_dir}/${image_name}" + _msg_info "Done!" + du -h -- "${out_dir}/${image_name}" + cd -- "${OLDPWD}" +} + +# Build ISO +_build_iso_image() { + local xorriso_options=() xorrisofs_options=() + local bootmode + + [[ -d "${out_dir}" ]] || install -d -- "${out_dir}" - mkdir -p "${out_dir}" - _msg_info "Creating ISO image..." - local _qflag="" if [[ "${quiet}" == "y" ]]; then - xorriso -as mkisofs -quiet \ + # The when xorriso is run in mkisofs compatibility mode (xorrisofs), the mkisofs option -quiet is interpreted + # too late (e.g. messages about SOURCE_DATE_EPOCH still get shown). + # Instead use native xorriso option to silence the output. + xorriso_options=('-report_about' 'SORRY' "${xorriso_options[@]}") + fi + + # Add required xorrisofs options for each boot mode + for bootmode in "${bootmodes[@]}"; do + typeset -f "_add_xorrisofs_options_${bootmode}" &> /dev/null && "_add_xorrisofs_options_${bootmode}" + done + + rm -f -- "${out_dir}/${image_name}" + _msg_info "Creating ISO image..." + xorriso "${xorriso_options[@]}" -as mkisofs \ -iso-level 3 \ -full-iso9660-filenames \ + -joliet \ + -joliet-long \ + -rational-rock \ -volid "${iso_label}" \ -appid "${iso_application}" \ -publisher "${iso_publisher}" \ - -preparer "prepared by mkarchiso" \ - -eltorito-boot isolinux/isolinux.bin \ - -eltorito-catalog isolinux/boot.cat \ - -no-emul-boot -boot-load-size 4 -boot-info-table \ - -isohybrid-mbr "${work_dir}/iso/isolinux/isohdpfx.bin" \ - "${_iso_efi_boot_args[@]}" \ - -output "${out_dir}/${img_name}" \ - "${work_dir}/iso/" + -preparer "prepared by ${app_name}" \ + "${xorrisofs_options[@]}" \ + -output "${out_dir}/${image_name}" \ + "${isofs_dir}/" + _msg_info "Done!" + du -h -- "${out_dir}/${image_name}" +} + +# Read profile's values from profiledef.sh +_read_profile() { + if [[ -z "${profile}" ]]; then + _msg_error "No profile specified!" 1 + fi + if [[ ! -d "${profile}" ]]; then + _msg_error "Profile '${profile}' does not exist!" 1 + elif [[ ! -e "${profile}/profiledef.sh" ]]; then + _msg_error "Profile '${profile}' is missing 'profiledef.sh'!" 1 else - xorriso -as mkisofs \ - -iso-level 3 \ - -full-iso9660-filenames \ - -volid "${iso_label}" \ - -appid "${iso_application}" \ - -publisher "${iso_publisher}" \ - -preparer "prepared by mkarchiso" \ - -eltorito-boot isolinux/isolinux.bin \ - -eltorito-catalog isolinux/boot.cat \ - -no-emul-boot -boot-load-size 4 -boot-info-table \ - -isohybrid-mbr "${work_dir}/iso/isolinux/isohdpfx.bin" \ - "${_iso_efi_boot_args[@]}" \ - -output "${out_dir}/${img_name}" \ - "${work_dir}/iso/" + cd -- "${profile}" + + # Source profile's variables + # shellcheck source=configs/releng/profiledef.sh + . "${profile}/profiledef.sh" + + # Resolve paths of files that are expected to reside in the profile's directory + [[ -n "$arch" ]] || arch="$(uname -m)" + [[ -n "$packages" ]] || packages="${profile}/packages.${arch}" + packages="$(realpath -- "${packages}")" + pacman_conf="$(realpath -- "${pacman_conf}")" + + # Resolve paths of files that may reside in the profile's directory + if [[ -z "$bootstrap_packages" ]] && [[ -e "${profile}/bootstrap_packages.${arch}" ]]; then + bootstrap_packages="${profile}/bootstrap_packages.${arch}" + bootstrap_packages="$(realpath -- "${bootstrap_packages}")" + pacman_conf="$(realpath -- "${pacman_conf}")" + fi + + cd -- "${OLDPWD}" fi - _msg_info "Done! | $(ls -sh "${out_dir}/${img_name}")" } -# create airootfs.sfs filesystem, and push it in "iso" directory. -command_prepare () { - _show_config prepare +# Validate set options +_validate_options() { + local validation_error=0 _buildmode - _cleanup - if [[ "${sfs_mode}" == "sfs" ]]; then - _mkairootfs_sfs - else - _mkairootfs_img + _msg_info "Validating options..." + + # Check if pacman configuration file exists + if [[ ! -e "${pacman_conf}" ]]; then + (( validation_error=validation_error+1 )) + _msg_error "File '${pacman_conf}' does not exist." 0 fi - _mkchecksum - if [[ "${gpg_key}" ]]; then - _mksignature + + # Check if the specified buildmodes are supported + for _buildmode in "${buildmodes[@]}"; do + if typeset -f "_build_buildmode_${_buildmode}" &> /dev/null; then + if typeset -f "_validate_requirements_buildmode_${_buildmode}" &> /dev/null; then + "_validate_requirements_buildmode_${_buildmode}" + else + _msg_warning "Function '_validate_requirements_buildmode_${_buildmode}' does not exist. Validating the requirements of '${_buildmode}' build mode will not be possible." + fi + else + (( validation_error=validation_error+1 )) + _msg_error "${_buildmode} is not a valid build mode!" 0 + fi + done + + if (( validation_error )); then + _msg_error "${validation_error} errors were encountered while validating the profile. Aborting." 1 + fi + _msg_info "Done!" +} + +# Set defaults and, if present, overrides from mkarchiso command line option parameters +_set_overrides() { + # Set variables that have command line overrides + [[ ! -v override_buildmodes ]] || buildmodes=("${override_buildmodes[@]}") + if (( ${#buildmodes[@]} < 1 )); then + buildmodes+=('iso') + fi + if [[ -v override_work_dir ]]; then + work_dir="$override_work_dir" + elif [[ -z "$work_dir" ]]; then + work_dir='./work' + fi + work_dir="$(realpath -- "$work_dir")" + if [[ -v override_out_dir ]]; then + out_dir="$override_out_dir" + elif [[ -z "$out_dir" ]]; then + out_dir='./out' + fi + out_dir="$(realpath -- "$out_dir")" + if [[ -v override_pacman_conf ]]; then + pacman_conf="$override_pacman_conf" + elif [[ -z "$pacman_conf" ]]; then + pacman_conf="/etc/pacman.conf" + fi + pacman_conf="$(realpath -- "$pacman_conf")" + [[ ! -v override_pkg_list ]] || pkg_list+=("${override_pkg_list[@]}") + # TODO: allow overriding bootstrap_pkg_list + if [[ -v override_iso_label ]]; then + iso_label="$override_iso_label" + elif [[ -z "$iso_label" ]]; then + iso_label="${app_name^^}" + fi + if [[ -v override_iso_publisher ]]; then + iso_publisher="$override_iso_publisher" + elif [[ -z "$iso_publisher" ]]; then + iso_publisher="${app_name}" + fi + if [[ -v override_iso_application ]]; then + iso_application="$override_iso_application" + elif [[ -z "$iso_application" ]]; then + iso_application="${app_name} iso" + fi + if [[ -v override_install_dir ]]; then + install_dir="$override_install_dir" + elif [[ -z "$install_dir" ]]; then + install_dir="${app_name}" + fi + [[ ! -v override_gpg_key ]] || gpg_key="$override_gpg_key" + [[ ! -v override_gpg_sender ]] || gpg_sender="$override_gpg_sender" + if [[ -v override_cert_list ]]; then + sign_netboot_artifacts="y" + fi + [[ ! -v override_cert_list ]] || cert_list+=("${override_cert_list[@]}") + if [[ -v override_quiet ]]; then + quiet="$override_quiet" + elif [[ -z "$quiet" ]]; then + quiet="y" + fi + + # Set variables that do not have overrides + [[ -n "$airootfs_image_type" ]] || airootfs_image_type="squashfs" + [[ -n "$iso_name" ]] || iso_name="${app_name}" +} + +_export_gpg_publickey() { + rm -f -- "${work_dir}/pubkey.gpg" + gpg --batch --no-armor --output "${work_dir}/pubkey.gpg" --export "${gpg_key}" +} + +_make_version() { + local _os_release + + _msg_info "Creating version files..." + # Write version file to system installation dir + rm -f -- "${pacstrap_dir}/version" + printf '%s\n' "${iso_version}" > "${pacstrap_dir}/version" + + if [[ "${buildmode}" == @("iso"|"netboot") ]]; then + install -d -m 0755 -- "${isofs_dir}/${install_dir}" + # Write version file to ISO 9660 + printf '%s\n' "${iso_version}" > "${isofs_dir}/${install_dir}/version" + # Write grubenv with version information to ISO 9660 + printf '%.1024s' "$(printf '# GRUB Environment Block\nNAME=%s\nVERSION=%s\n%s' \ + "${iso_name}" "${iso_version}" "$(printf '%0.1s' "#"{1..1024})")" \ + > "${isofs_dir}/${install_dir}/grubenv" + fi + + # Append IMAGE_ID & IMAGE_VERSION to os-release + _os_release="$(realpath -- "${pacstrap_dir}/etc/os-release")" + if [[ ! -e "${pacstrap_dir}/etc/os-release" && -e "${pacstrap_dir}/usr/lib/os-release" ]]; then + _os_release="$(realpath -- "${pacstrap_dir}/usr/lib/os-release")" fi + if [[ "${_os_release}" != "${pacstrap_dir}"* ]]; then + _msg_warning "os-release file '${_os_release}' is outside of valid path." + else + [[ ! -e "${_os_release}" ]] || sed -i '/^IMAGE_ID=/d;/^IMAGE_VERSION=/d' "${_os_release}" + printf 'IMAGE_ID=%s\nIMAGE_VERSION=%s\n' "${iso_name}" "${iso_version}" >> "${_os_release}" + fi + _msg_info "Done!" +} + +_make_pkglist() { + _msg_info "Creating a list of installed packages on live-enviroment..." + case "${buildmode}" in + "bootstrap") + pacman -Q --sysroot "${pacstrap_dir}" > "${pacstrap_dir}/pkglist.${arch}.txt" + ;; + "iso"|"netboot") + install -d -m 0755 -- "${isofs_dir}/${install_dir}" + pacman -Q --sysroot "${pacstrap_dir}" > "${isofs_dir}/${install_dir}/pkglist.${arch}.txt" + ;; + esac + _msg_info "Done!" } -# Install packages on airootfs. -# A basic check to avoid double execution/reinstallation is done via hashing package names. -command_install () { - if [[ ! -f "${pacman_conf}" ]]; then - _msg_error "Pacman config file '${pacman_conf}' does not exist" 1 +# build the base for an ISO and/or a netboot target +_build_iso_base() { + local run_once_mode="base" + local buildmode_packages="${packages}" + # Set the package list to use + local buildmode_pkg_list=("${pkg_list[@]}") + # Set up essential directory paths + pacstrap_dir="${work_dir}/${arch}/airootfs" + isofs_dir="${work_dir}/iso" + + # Create working directory + [[ -d "${work_dir}" ]] || install -d -- "${work_dir}" + # Write build date to file or if the file exists, read it from there + if [[ -e "${work_dir}/build_date" ]]; then + SOURCE_DATE_EPOCH="$(<"${work_dir}/build_date")" + else + printf '%s\n' "$SOURCE_DATE_EPOCH" > "${work_dir}/build_date" fi - if [[ "${#pkg_list[@]}" -eq 0 ]]; then - _msg_error "Packages must be specified" 0 - _usage 1 + [[ "${quiet}" == "y" ]] || _show_config + _run_once _make_pacman_conf + [[ -z "${gpg_key}" ]] || _run_once _export_gpg_publickey + _run_once _make_custom_airootfs + _run_once _make_packages + _run_once _make_version + _run_once _make_customize_airootfs + _run_once _make_pkglist + if [[ "${buildmode}" == 'netboot' ]]; then + _run_once _make_boot_on_iso9660 + else + _make_bootmodes fi + _run_once _cleanup_pacstrap_dir + _run_once _prepare_airootfs_image +} - _show_config install +# Build the bootstrap buildmode +_build_buildmode_bootstrap() { + local image_name="${iso_name}-bootstrap-${iso_version}-${arch}.tar.gz" + local run_once_mode="${buildmode}" + local buildmode_packages="${bootstrap_packages}" + # Set the package list to use + local buildmode_pkg_list=("${bootstrap_pkg_list[@]}") - _pacman "${pkg_list[@]}" + # Set up essential directory paths + pacstrap_dir="${work_dir}/${arch}/bootstrap/root.${arch}" + [[ -d "${work_dir}" ]] || install -d -- "${work_dir}" + install -d -m 0755 -o 0 -g 0 -- "${pacstrap_dir}" + + [[ "${quiet}" == "y" ]] || _show_config + _run_once _make_pacman_conf + _run_once _make_packages + _run_once _make_version + _run_once _make_pkglist + _run_once _cleanup_pacstrap_dir + _run_once _build_bootstrap_image } -command_init() { - _show_config init - _chroot_init +# Build the netboot buildmode +_build_buildmode_netboot() { + local run_once_mode="${buildmode}" + + _build_iso_base + if [[ -v cert_list ]]; then + _run_once _sign_netboot_artifacts + fi + _run_once _export_netboot_artifacts } -command_run() { - _show_config run - _chroot_run +# Build the ISO buildmode +_build_buildmode_iso() { + local image_name="${iso_name}-${iso_version}-${arch}.iso" + local run_once_mode="${buildmode}" + _build_iso_base + _run_once _build_iso_image } -if [[ "${EUID}" -ne 0 ]]; then - _msg_error "This script must be run as root." 1 -fi +# build all buildmodes +_build() { + local buildmode + local run_once_mode="build" -umask 0022 + for buildmode in "${buildmodes[@]}"; do + _run_once "_build_buildmode_${buildmode}" + done +} -while getopts 'p:r:C:L:P:A:D:w:o:s:c:g:vh' arg; do +while getopts 'c:p:C:L:P:A:D:w:m:o:g:G:vh?' arg; do case "${arg}" in - p) - read -r -a opt_pkg_list <<< "${OPTARG}" - pkg_list+=("${opt_pkg_list[@]}") - ;; - r) run_cmd="${OPTARG}" ;; - C) pacman_conf="${OPTARG}" ;; - L) iso_label="${OPTARG}" ;; - P) iso_publisher="${OPTARG}" ;; - A) iso_application="${OPTARG}" ;; - D) install_dir="${OPTARG}" ;; - w) work_dir="${OPTARG}" ;; - o) out_dir="${OPTARG}" ;; - s) sfs_mode="${OPTARG}" ;; - c) sfs_comp="${OPTARG}" ;; - g) gpg_key="${OPTARG}" ;; - v) quiet="n" ;; + p) read -r -a override_pkg_list <<< "${OPTARG}" ;; + C) override_pacman_conf="${OPTARG}" ;; + L) override_iso_label="${OPTARG}" ;; + P) override_iso_publisher="${OPTARG}" ;; + A) override_iso_application="${OPTARG}" ;; + D) override_install_dir="${OPTARG}" ;; + c) read -r -a override_cert_list <<< "${OPTARG}" ;; + w) override_work_dir="${OPTARG}" ;; + m) read -r -a override_buildmodes <<< "${OPTARG}" ;; + o) override_out_dir="${OPTARG}" ;; + g) override_gpg_key="${OPTARG}" ;; + G) override_gpg_sender="${OPTARG}" ;; + v) override_quiet="n" ;; h|?) _usage 0 ;; *) _msg_error "Invalid argument '${arg}'" 0 @@ -414,40 +1326,21 @@ done shift $((OPTIND - 1)) -if [[ $# -lt 1 ]]; then - _msg_error "No command specified" 0 +if (( $# < 1 )); then + _msg_error "No profile specified" 0 _usage 1 fi -command_name="${1}" - -case "${command_name}" in - init) - command_init - ;; - install) - command_install - ;; - run) - command_run - ;; - prepare) - command_prepare - ;; - pkglist) - command_pkglist - ;; - iso) - if [[ $# -lt 2 ]]; then - _msg_error "No image specified" 0 - _usage 1 - fi - img_name="${2}" - command_iso - ;; - *) - _msg_error "Invalid command name '${command_name}'" 0 - _usage 1 - ;; -esac + +if (( EUID != 0 )); then + _msg_error "${app_name} must be run as root." 1 +fi + +# get the absolute path representation of the first non-option argument +profile="$(realpath -- "${1}")" + +_read_profile +_set_overrides +_validate_options +_build # vim:ts=4:sw=4:et: diff --git a/configs/baseline/airootfs/etc/mkinitcpio.conf b/configs/baseline/airootfs/etc/mkinitcpio.conf new file mode 100644 index 0000000..34b1a06 --- /dev/null +++ b/configs/baseline/airootfs/etc/mkinitcpio.conf @@ -0,0 +1,67 @@ +# vim:set ft=sh +# MODULES +# The following modules are loaded before any boot hooks are +# run. Advanced users may wish to specify all system modules +# in this array. For instance: +# MODULES=(piix ide_disk reiserfs) +MODULES=() + +# BINARIES +# This setting includes any additional binaries a given user may +# wish into the CPIO image. This is run last, so it may be used to +# override the actual binaries included by a given hook +# BINARIES are dependency parsed, so you may safely ignore libraries +BINARIES=() + +# FILES +# This setting is similar to BINARIES above, however, files are added +# as-is and are not parsed in any way. This is useful for config files. +FILES=() + +# HOOKS +# This is the most important setting in this file. The HOOKS control the +# modules and scripts added to the image, and what happens at boot time. +# Order is important, and it is recommended that you do not change the +# order in which HOOKS are added. Run 'mkinitcpio -H <hook name>' for +# help on a given hook. +# 'base' is _required_ unless you know precisely what you are doing. +# 'udev' is _required_ in order to automatically load modules +# 'filesystems' is _required_ unless you specify your fs modules in MODULES +# Examples: +## This setup specifies all modules in the MODULES setting above. +## No raid, lvm2, or encrypted root is needed. +# HOOKS=(base) +# +## This setup will autodetect all modules for your system and should +## work as a sane default +# HOOKS=(base udev autodetect block filesystems) +# +## This setup will generate a 'full' image which supports most systems. +## No autodetection is done. +# HOOKS=(base udev block filesystems) +# +## This setup assembles a pata mdadm array with an encrypted root FS. +## Note: See 'mkinitcpio -H mdadm' for more information on raid devices. +# HOOKS=(base udev block mdadm encrypt filesystems) +# +## This setup loads an lvm2 volume group on a usb device. +# HOOKS=(base udev block lvm2 filesystems) +# +## NOTE: If you have /usr on a separate partition, you MUST include the +# usr, fsck and shutdown hooks. +HOOKS=(base udev modconf archiso block filesystems) + +# COMPRESSION +# Use this to compress the initramfs image. By default, gzip compression +# is used. Use 'cat' to create an uncompressed image. +#COMPRESSION="gzip" +#COMPRESSION="bzip2" +#COMPRESSION="lzma" +#COMPRESSION="xz" +#COMPRESSION="lzop" +#COMPRESSION="lz4" +#COMPRESSION="zstd" + +# COMPRESSION_OPTIONS +# Additional options for the compressor +#COMPRESSION_OPTIONS=() diff --git a/configs/baseline/airootfs/etc/mkinitcpio.d/linux.preset b/configs/baseline/airootfs/etc/mkinitcpio.d/linux.preset new file mode 100644 index 0000000..9f67184 --- /dev/null +++ b/configs/baseline/airootfs/etc/mkinitcpio.d/linux.preset @@ -0,0 +1,8 @@ +# mkinitcpio preset file for the 'linux' package on archiso + +PRESETS=('archiso') + +ALL_kver='/boot/vmlinuz-linux' +ALL_config='/etc/mkinitcpio.conf' + +archiso_image="/boot/initramfs-linux.img" diff --git a/configs/baseline/airootfs/etc/ssh/sshd_config b/configs/baseline/airootfs/etc/ssh/sshd_config new file mode 100644 index 0000000..93f7d63 --- /dev/null +++ b/configs/baseline/airootfs/etc/ssh/sshd_config @@ -0,0 +1,116 @@ +# $OpenBSD: sshd_config,v 1.104 2021/07/02 05:11:21 dtucker Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/bin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +#Port 22 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_ecdsa_key +#HostKey /etc/ssh/ssh_host_ed25519_key + +# Ciphers and keying +#RekeyLimit default none + +# Logging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin yes +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#PubkeyAuthentication yes + +# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +# but this is overridden so installations will only check .ssh/authorized_keys +AuthorizedKeysFile .ssh/authorized_keys + +#AuthorizedPrincipalsFile none + +#AuthorizedKeysCommand none +#AuthorizedKeysCommandUser nobody + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +#PermitEmptyPasswords no + +# Change to no to disable s/key passwords +#KbdInteractiveAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the KbdInteractiveAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via KbdInteractiveAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and KbdInteractiveAuthentication to 'no'. +UsePAM yes + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes +PrintMotd no # pam does that +#PrintLastLog yes +#TCPKeepAlive yes +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS no +#PidFile /run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +#Banner none + +# override default of no subsystems +Subsystem sftp /usr/lib/ssh/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# PermitTTY no +# ForceCommand cvs server diff --git a/configs/releng/airootfs/etc/systemd/network/20-wireless.network b/configs/baseline/airootfs/etc/systemd/network/20-ethernet.network index e1d624c..e8842f2 100644 --- a/configs/releng/airootfs/etc/systemd/network/20-wireless.network +++ b/configs/baseline/airootfs/etc/systemd/network/20-ethernet.network @@ -1,10 +1,7 @@ [Match] -Name=wlp* -Name=wlan* +Name=en* +Name=eth* [Network] DHCP=yes IPv6PrivacyExtensions=yes - -[DHCP] -RouteMetric=1024 diff --git a/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-config.service b/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-config.service new file mode 120000 index 0000000..ebc50f0 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-config.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/cloud-config.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-final.service b/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-final.service new file mode 120000 index 0000000..80fa3c8 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-final.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/cloud-final.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init-local.service b/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init-local.service new file mode 120000 index 0000000..dd8e9f1 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init-local.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/cloud-init-local.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init.service b/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init.service new file mode 120000 index 0000000..24c7a26 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/cloud-init.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/qemu-guest-agent.service b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/qemu-guest-agent.service new file mode 120000 index 0000000..8e3ff80 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/qemu-guest-agent.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/qemu-guest-agent.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/sshd.service b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/sshd.service new file mode 120000 index 0000000..d21ebd9 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/sshd.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/sshd.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/systemd-networkd.service b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/systemd-networkd.service new file mode 120000 index 0000000..4c158e6 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/systemd-networkd.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-networkd.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/systemd-resolved.service b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/systemd-resolved.service new file mode 120000 index 0000000..4f6ae34 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/systemd-resolved.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-resolved.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/vboxservice.service b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/vboxservice.service new file mode 120000 index 0000000..cb2d560 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/vboxservice.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/vboxservice.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service b/configs/baseline/airootfs/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service new file mode 120000 index 0000000..7d6ad92 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-networkd-wait-online.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/sockets.target.wants/systemd-networkd.socket b/configs/baseline/airootfs/etc/systemd/system/sockets.target.wants/systemd-networkd.socket new file mode 120000 index 0000000..51942c8 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/sockets.target.wants/systemd-networkd.socket @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-networkd.socket
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/systemd-networkd-wait-online.service.d/wait-for-only-one-interface.conf b/configs/baseline/airootfs/etc/systemd/system/systemd-networkd-wait-online.service.d/wait-for-only-one-interface.conf new file mode 100644 index 0000000..c9f9bce --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/systemd-networkd-wait-online.service.d/wait-for-only-one-interface.conf @@ -0,0 +1,6 @@ +# Allow systemd-networkd-wait-online to succeed with one interface, otherwise, if multiple network interfaces exist, +# network-online.target gets needlessly delayed. +# See https://wiki.archlinux.org/title/systemd-networkd#systemd-networkd-wait-online +[Service] +ExecStart= +ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --any diff --git a/configs/baseline/bootstrap_packages.x86_64 b/configs/baseline/bootstrap_packages.x86_64 new file mode 100644 index 0000000..64966d0 --- /dev/null +++ b/configs/baseline/bootstrap_packages.x86_64 @@ -0,0 +1,2 @@ +arch-install-scripts +base diff --git a/configs/baseline/build.sh b/configs/baseline/build.sh deleted file mode 100755 index f2f3922..0000000 --- a/configs/baseline/build.sh +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env bash - -set -e -u - -iso_name=archlinux -iso_label="ARCH_$(date +%Y%m)" -iso_version=$(date +%Y.%m.%d) -install_dir=arch -arch=$(uname -m) -work_dir=work -out_dir=out - -script_path="$( cd -P "$( dirname "$(readlink -f "$0")" )" && pwd )" - -umask 0022 - -# Helper function to run make_*() only one time per architecture. -run_once() { - if [[ ! -e "${work_dir}/build.${1}_${arch}" ]]; then - "$1" - touch "${work_dir}/build.${1}_${arch}" - fi -} - -# Setup custom pacman.conf with current cache directories. -make_pacman_conf() { - local _cache_dirs - _cache_dirs=("$(pacman -v 2>&1 | grep '^Cache Dirs:' | sed 's/Cache Dirs:\s*//g')") - sed -r "s|^#?\\s*CacheDir.+|CacheDir = $(echo -n "${_cache_dirs[@]}")|g" \ - "${script_path}/pacman.conf" > "${work_dir}/pacman.conf" -} - -# Prepare working directory and copy custom airootfs files (airootfs) -make_custom_airootfs() { - local _airootfs="${work_dir}/airootfs" - mkdir -p -- "${_airootfs}" - - if [[ -d "${script_path}/airootfs" ]]; then - cp -af --no-preserve=ownership -- "${script_path}/airootfs/." "${_airootfs}" - [[ -e "${_airootfs}/etc/shadow" ]] && chmod -f 0400 -- "${_airootfs}/etc/shadow" - [[ -e "${_airootfs}/etc/gshadow" ]] && chmod -f 0400 -- "${_airootfs}/etc/gshadow" - fi -} - -# Packages (airootfs) -make_packages() { - mkarchiso -v -w "${work_dir}" -C "${work_dir}/pacman.conf" -D "${install_dir}" \ - -p "$(grep -h -v '^#' "${script_path}/packages.x86_64"| sed ':a;N;$!ba;s/\n/ /g')" install -} - -# Copy mkinitcpio archiso hooks and build initramfs (airootfs) -make_setup_mkinitcpio() { - mkdir -p "${work_dir}/airootfs/etc/initcpio/hooks" - mkdir -p "${work_dir}/airootfs/etc/initcpio/install" - cp /usr/lib/initcpio/hooks/archiso "${work_dir}/airootfs/etc/initcpio/hooks" - cp /usr/lib/initcpio/install/archiso "${work_dir}/airootfs/etc/initcpio/install" - cp "${script_path}/mkinitcpio.conf" "${work_dir}/airootfs/etc/mkinitcpio-archiso.conf" - mkarchiso -v -w "${work_dir}" -D "${install_dir}" \ - -r 'mkinitcpio -c /etc/mkinitcpio-archiso.conf -k /boot/vmlinuz-linux -g /boot/archiso.img' run -} - -# Prepare ${install_dir}/boot/ -make_boot() { - mkdir -p "${work_dir}/iso/${install_dir}/boot/${arch}" - cp "${work_dir}/airootfs/boot/archiso.img" "${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img" - cp "${work_dir}/airootfs/boot/vmlinuz-linux" "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz" -} - -# Prepare /${install_dir}/boot/syslinux -make_syslinux() { - mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux" - sed "s|%ARCHISO_LABEL%|${iso_label}|g; - s|%INSTALL_DIR%|${install_dir}|g; - s|%ARCH%|${arch}|g" "${script_path}/syslinux/syslinux.cfg" > \ - "${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg" - cp "${work_dir}/airootfs/usr/lib/syslinux/bios/ldlinux.c32" "${work_dir}/iso/${install_dir}/boot/syslinux/" - cp "${work_dir}/airootfs/usr/lib/syslinux/bios/menu.c32" "${work_dir}/iso/${install_dir}/boot/syslinux/" - cp "${work_dir}/airootfs/usr/lib/syslinux/bios/libutil.c32" "${work_dir}/iso/${install_dir}/boot/syslinux/" -} - -# Prepare /isolinux -make_isolinux() { - mkdir -p "${work_dir}/iso/isolinux" - sed "s|%INSTALL_DIR%|${install_dir}|g" "${script_path}/isolinux/isolinux.cfg" > \ - "${work_dir}/iso/isolinux/isolinux.cfg" - cp "${work_dir}/airootfs/usr/lib/syslinux/bios/isolinux.bin" "${work_dir}/iso/isolinux/" - cp "${work_dir}/airootfs/usr/lib/syslinux/bios/isohdpfx.bin" "${work_dir}/iso/isolinux/" - cp "${work_dir}/airootfs/usr/lib/syslinux/bios/ldlinux.c32" "${work_dir}/iso/isolinux/" -} - -# Build airootfs filesystem image -make_prepare() { - mkarchiso -v -w "${work_dir}" -D "${install_dir}" prepare -} - -# Build ISO -make_iso() { - mkarchiso -v -w "${work_dir}" -D "${install_dir}" -L "${iso_label}" -o "${out_dir}" iso \ - "${iso_name}-${iso_version}-${arch}.iso" -} - -run_once make_custom_airootfs -run_once make_pacman_conf -run_once make_packages -run_once make_setup_mkinitcpio -run_once make_boot -run_once make_syslinux -run_once make_isolinux -run_once make_prepare -run_once make_iso diff --git a/configs/baseline/efiboot/loader/entries/01-archiso-x86_64-linux.conf b/configs/baseline/efiboot/loader/entries/01-archiso-x86_64-linux.conf new file mode 100644 index 0000000..11624b6 --- /dev/null +++ b/configs/baseline/efiboot/loader/entries/01-archiso-x86_64-linux.conf @@ -0,0 +1,4 @@ +title Arch Linux (x86_64, UEFI) +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img +options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% diff --git a/configs/baseline/efiboot/loader/entries/02-archiso-x86_64-ram-linux.conf b/configs/baseline/efiboot/loader/entries/02-archiso-x86_64-ram-linux.conf new file mode 100644 index 0000000..d66f5a6 --- /dev/null +++ b/configs/baseline/efiboot/loader/entries/02-archiso-x86_64-ram-linux.conf @@ -0,0 +1,4 @@ +title Arch Linux (x86_64, UEFI) Copy to RAM +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img +options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram diff --git a/configs/baseline/efiboot/loader/loader.conf b/configs/baseline/efiboot/loader/loader.conf new file mode 100644 index 0000000..17110fa --- /dev/null +++ b/configs/baseline/efiboot/loader/loader.conf @@ -0,0 +1,2 @@ +timeout 3 +default 01-archiso-x86_64-linux.conf diff --git a/configs/baseline/isolinux/isolinux.cfg b/configs/baseline/isolinux/isolinux.cfg deleted file mode 100644 index 33e8b65..0000000 --- a/configs/baseline/isolinux/isolinux.cfg +++ /dev/null @@ -1,6 +0,0 @@ -PATH /%INSTALL_DIR%/boot/syslinux/ -DEFAULT loadconfig - -LABEL loadconfig - CONFIG /%INSTALL_DIR%/boot/syslinux/syslinux.cfg - APPEND /%INSTALL_DIR%/ diff --git a/configs/baseline/mkinitcpio.conf b/configs/baseline/mkinitcpio.conf deleted file mode 100644 index 279eccb..0000000 --- a/configs/baseline/mkinitcpio.conf +++ /dev/null @@ -1 +0,0 @@ -HOOKS=(base udev archiso block filesystems) diff --git a/configs/baseline/packages.x86_64 b/configs/baseline/packages.x86_64 index d3ad7bf..0a64120 100644 --- a/configs/baseline/packages.x86_64 +++ b/configs/baseline/packages.x86_64 @@ -1,4 +1,10 @@ base +cloud-init linux mkinitcpio +mkinitcpio-archiso +openssh +pv +qemu-guest-agent syslinux +virtualbox-guest-utils-nox diff --git a/configs/baseline/pacman.conf b/configs/baseline/pacman.conf index bbca42f..5ee6c1e 100644 --- a/configs/baseline/pacman.conf +++ b/configs/baseline/pacman.conf @@ -31,10 +31,11 @@ Architecture = auto # Misc options #UseSyslog #Color -#TotalDownload +#NoProgressBar # We cannot check disk space from within a chroot environment #CheckSpace #VerbosePkgLists +ParallelDownloads = 5 # By default, pacman accepts packages signed by keys that its local keyring # trusts (see pacman-key and its man page), as well as unsigned packages. diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh new file mode 100644 index 0000000..d376516 --- /dev/null +++ b/configs/baseline/profiledef.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2034 + +iso_name="archlinux-baseline" +iso_label="ARCH_$(date +%Y%m)" +iso_publisher="Arch Linux <https://archlinux.org>" +iso_application="Arch Linux baseline" +iso_version="$(date +%Y.%m.%d)" +install_dir="arch" +buildmodes=('iso') +bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' 'uefi-x64.systemd-boot.esp' 'uefi-x64.systemd-boot.eltorito') +arch="x86_64" +pacman_conf="pacman.conf" +airootfs_image_type="erofs" +airootfs_image_tool_options=('-zlz4hc,12') +file_permissions=( + ["/etc/shadow"]="0:0:400" +) diff --git a/configs/baseline/syslinux/syslinux-linux.cfg b/configs/baseline/syslinux/syslinux-linux.cfg new file mode 100644 index 0000000..6bfd0c3 --- /dev/null +++ b/configs/baseline/syslinux/syslinux-linux.cfg @@ -0,0 +1,11 @@ +LABEL arch +MENU LABEL Arch Linux (x86_64, BIOS) +LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% + +LABEL arch-ram +MENU LABEL Arch Linux (x86_64, BIOS) Copy to RAM +LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram diff --git a/configs/baseline/syslinux/syslinux.cfg b/configs/baseline/syslinux/syslinux.cfg index 4f7ce4d..561ac7c 100644 --- a/configs/baseline/syslinux/syslinux.cfg +++ b/configs/baseline/syslinux/syslinux.cfg @@ -1,12 +1,9 @@ -UI boot/syslinux/menu.c32 +SERIAL 0 115200 +UI menu.c32 MENU TITLE Arch Linux MENU CLEAR DEFAULT arch TIMEOUT 30 -LABEL arch -MENU LABEL Arch Linux -LINUX boot/%ARCH%/vmlinuz -INITRD boot/%ARCH%/archiso.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% +INCLUDE syslinux-linux.cfg diff --git a/configs/releng/airootfs/etc/fstab b/configs/releng/airootfs/etc/fstab deleted file mode 100644 index e69de29..0000000 --- a/configs/releng/airootfs/etc/fstab +++ /dev/null diff --git a/configs/releng/airootfs/etc/machine-id b/configs/releng/airootfs/etc/machine-id deleted file mode 100644 index e69de29..0000000 --- a/configs/releng/airootfs/etc/machine-id +++ /dev/null diff --git a/configs/releng/airootfs/etc/mkinitcpio.conf b/configs/releng/airootfs/etc/mkinitcpio.conf new file mode 100644 index 0000000..f57dbdd --- /dev/null +++ b/configs/releng/airootfs/etc/mkinitcpio.conf @@ -0,0 +1,67 @@ +# vim:set ft=sh +# MODULES +# The following modules are loaded before any boot hooks are +# run. Advanced users may wish to specify all system modules +# in this array. For instance: +# MODULES=(piix ide_disk reiserfs) +MODULES=() + +# BINARIES +# This setting includes any additional binaries a given user may +# wish into the CPIO image. This is run last, so it may be used to +# override the actual binaries included by a given hook +# BINARIES are dependency parsed, so you may safely ignore libraries +BINARIES=() + +# FILES +# This setting is similar to BINARIES above, however, files are added +# as-is and are not parsed in any way. This is useful for config files. +FILES=() + +# HOOKS +# This is the most important setting in this file. The HOOKS control the +# modules and scripts added to the image, and what happens at boot time. +# Order is important, and it is recommended that you do not change the +# order in which HOOKS are added. Run 'mkinitcpio -H <hook name>' for +# help on a given hook. +# 'base' is _required_ unless you know precisely what you are doing. +# 'udev' is _required_ in order to automatically load modules +# 'filesystems' is _required_ unless you specify your fs modules in MODULES +# Examples: +## This setup specifies all modules in the MODULES setting above. +## No raid, lvm2, or encrypted root is needed. +# HOOKS=(base) +# +## This setup will autodetect all modules for your system and should +## work as a sane default +# HOOKS=(base udev autodetect block filesystems) +# +## This setup will generate a 'full' image which supports most systems. +## No autodetection is done. +# HOOKS=(base udev block filesystems) +# +## This setup assembles a pata mdadm array with an encrypted root FS. +## Note: See 'mkinitcpio -H mdadm' for more information on raid devices. +# HOOKS=(base udev block mdadm encrypt filesystems) +# +## This setup loads an lvm2 volume group on a usb device. +# HOOKS=(base udev block lvm2 filesystems) +# +## NOTE: If you have /usr on a separate partition, you MUST include the +# usr, fsck and shutdown hooks. +HOOKS=(base udev modconf memdisk archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs archiso_kms block filesystems keyboard) + +# COMPRESSION +# Use this to compress the initramfs image. By default, gzip compression +# is used. Use 'cat' to create an uncompressed image. +#COMPRESSION="gzip" +#COMPRESSION="bzip2" +#COMPRESSION="lzma" +COMPRESSION="xz" +#COMPRESSION="lzop" +#COMPRESSION="lz4" +#COMPRESSION="zstd" + +# COMPRESSION_OPTIONS +# Additional options for the compressor +#COMPRESSION_OPTIONS=() diff --git a/configs/releng/airootfs/etc/mkinitcpio.d/linux.preset b/configs/releng/airootfs/etc/mkinitcpio.d/linux.preset new file mode 100644 index 0000000..9f67184 --- /dev/null +++ b/configs/releng/airootfs/etc/mkinitcpio.d/linux.preset @@ -0,0 +1,8 @@ +# mkinitcpio preset file for the 'linux' package on archiso + +PRESETS=('archiso') + +ALL_kver='/boot/vmlinuz-linux' +ALL_config='/etc/mkinitcpio.conf' + +archiso_image="/boot/initramfs-linux.img" diff --git a/configs/releng/airootfs/etc/motd b/configs/releng/airootfs/etc/motd index 417b050..1ddc9c3 100644 --- a/configs/releng/airootfs/etc/motd +++ b/configs/releng/airootfs/etc/motd @@ -1,8 +1,9 @@ To install [38;2;23;147;209mArch Linux[0m follow the installation guide: -https://wiki.archlinux.org/index.php/Installation_guide +https://wiki.archlinux.org/title/Installation_guide For Wi-Fi, authenticate to the wireless network using the [35miwctl[0m utility. -Ethernet and Wi-Fi connections using DHCP should work automatically. +For mobile broadband (WWAN) modems, connect with the [35mmmcli[0m utility. +Ethernet, WLAN and WWAN interfaces using DHCP should work automatically. After connecting to the internet, the installation guide can be accessed via the convenience script [35mInstallation_guide[0m. diff --git a/configs/releng/airootfs/etc/pacman.d/hooks/40-locale-gen.hook b/configs/releng/airootfs/etc/pacman.d/hooks/40-locale-gen.hook new file mode 100644 index 0000000..82dd199 --- /dev/null +++ b/configs/releng/airootfs/etc/pacman.d/hooks/40-locale-gen.hook @@ -0,0 +1,13 @@ +# remove from airootfs! +[Trigger] +Operation = Install +Type = Package +Target = glibc + +[Action] +Description = Uncommenting en_US.UTF-8 locale and running locale-gen... +When = PostTransaction +Depends = glibc +Depends = sed +Depends = sh +Exec = /bin/sh -c "sed -i 's/#\(en_US\.UTF-8\)/\1/' /etc/locale.gen && locale-gen" diff --git a/configs/releng/airootfs/etc/pacman.d/hooks/uncomment-mirrors.hook b/configs/releng/airootfs/etc/pacman.d/hooks/uncomment-mirrors.hook new file mode 100644 index 0000000..342aa95 --- /dev/null +++ b/configs/releng/airootfs/etc/pacman.d/hooks/uncomment-mirrors.hook @@ -0,0 +1,13 @@ +# remove from airootfs! +[Trigger] +Operation = Install +Operation = Upgrade +Type = Package +Target = pacman-mirrorlist + +[Action] +Description = Uncommenting all mirrors in /etc/pacman.d/mirrorlist... +When = PostTransaction +Depends = pacman-mirrorlist +Depends = sed +Exec = /usr/bin/sed -i "s/#Server/Server/g" /etc/pacman.d/mirrorlist diff --git a/configs/releng/airootfs/etc/pacman.d/hooks/zzzz99-remove-custom-hooks-from-airootfs.hook b/configs/releng/airootfs/etc/pacman.d/hooks/zzzz99-remove-custom-hooks-from-airootfs.hook new file mode 100644 index 0000000..8dfb943 --- /dev/null +++ b/configs/releng/airootfs/etc/pacman.d/hooks/zzzz99-remove-custom-hooks-from-airootfs.hook @@ -0,0 +1,18 @@ +# remove from airootfs! +# As a workaround for https://bugs.archlinux.org/task/49347 , remove pacman hooks specific to the ISO build process. +# If not, they would be used when pacstrap is run in the live environment. + +[Trigger] +Operation = Install +Operation = Upgrade +Operation = Remove +Type = Package +Target = * + +[Action] +Description = Work around FS#49347 by removing custom pacman hooks that are only required during ISO build... +When = PostTransaction +Depends = sh +Depends = coreutils +Depends = grep +Exec = /bin/sh -c "rm -- $(grep -Frl 'remove from airootfs' /etc/pacman.d/hooks/)" diff --git a/configs/releng/airootfs/etc/ssh/sshd_config b/configs/releng/airootfs/etc/ssh/sshd_config new file mode 100644 index 0000000..93f7d63 --- /dev/null +++ b/configs/releng/airootfs/etc/ssh/sshd_config @@ -0,0 +1,116 @@ +# $OpenBSD: sshd_config,v 1.104 2021/07/02 05:11:21 dtucker Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/bin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +#Port 22 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_ecdsa_key +#HostKey /etc/ssh/ssh_host_ed25519_key + +# Ciphers and keying +#RekeyLimit default none + +# Logging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin yes +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#PubkeyAuthentication yes + +# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +# but this is overridden so installations will only check .ssh/authorized_keys +AuthorizedKeysFile .ssh/authorized_keys + +#AuthorizedPrincipalsFile none + +#AuthorizedKeysCommand none +#AuthorizedKeysCommandUser nobody + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +#PermitEmptyPasswords no + +# Change to no to disable s/key passwords +#KbdInteractiveAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the KbdInteractiveAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via KbdInteractiveAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and KbdInteractiveAuthentication to 'no'. +UsePAM yes + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes +PrintMotd no # pam does that +#PrintLastLog yes +#TCPKeepAlive yes +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS no +#PidFile /run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +#Banner none + +# override default of no subsystems +Subsystem sftp /usr/lib/ssh/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# PermitTTY no +# ForceCommand cvs server diff --git a/configs/releng/airootfs/etc/systemd/network/20-ethernet.network b/configs/releng/airootfs/etc/systemd/network/20-ethernet.network index 37878b0..f2a7d60 100644 --- a/configs/releng/airootfs/etc/systemd/network/20-ethernet.network +++ b/configs/releng/airootfs/etc/systemd/network/20-ethernet.network @@ -6,5 +6,13 @@ Name=eth* DHCP=yes IPv6PrivacyExtensions=yes -[DHCP] -RouteMetric=512 +# systemd-networkd does not set per-interface-type default route metrics +# https://github.com/systemd/systemd/issues/17698 +# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband. +# Use values from NetworkManager. From nm_device_get_route_metric_default in +# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c +[DHCPv4] +RouteMetric=100 + +[IPv6AcceptRA] +RouteMetric=100 diff --git a/configs/releng/airootfs/etc/systemd/network/20-wlan.network b/configs/releng/airootfs/etc/systemd/network/20-wlan.network new file mode 100644 index 0000000..601d5b8 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/network/20-wlan.network @@ -0,0 +1,17 @@ +[Match] +Name=wl* + +[Network] +DHCP=yes +IPv6PrivacyExtensions=yes + +# systemd-networkd does not set per-interface-type default route metrics +# https://github.com/systemd/systemd/issues/17698 +# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband. +# Use values from NetworkManager. From nm_device_get_route_metric_default in +# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c +[DHCPv4] +RouteMetric=600 + +[IPv6AcceptRA] +RouteMetric=600 diff --git a/configs/releng/airootfs/etc/systemd/network/20-wwan.network b/configs/releng/airootfs/etc/systemd/network/20-wwan.network new file mode 100644 index 0000000..9104c24 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/network/20-wwan.network @@ -0,0 +1,17 @@ +[Match] +Name=ww* + +[Network] +DHCP=yes +IPv6PrivacyExtensions=yes + +# systemd-networkd does not set per-interface-type default route metrics +# https://github.com/systemd/systemd/issues/17698 +# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband. +# Use values from NetworkManager. From nm_device_get_route_metric_default in +# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c +[DHCPv4] +RouteMetric=700 + +[IPv6AcceptRA] +RouteMetric=700 diff --git a/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-config.service b/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-config.service new file mode 120000 index 0000000..ebc50f0 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-config.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/cloud-config.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-final.service b/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-final.service new file mode 120000 index 0000000..80fa3c8 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-final.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/cloud-final.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init-local.service b/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init-local.service new file mode 120000 index 0000000..dd8e9f1 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init-local.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/cloud-init-local.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init.service b/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init.service new file mode 120000 index 0000000..24c7a26 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/cloud-init.target.wants/cloud-init.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/cloud-init.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.ModemManager1.service b/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.ModemManager1.service new file mode 120000 index 0000000..dcf7c8e --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.ModemManager1.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/ModemManager.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/default.target b/configs/releng/airootfs/etc/systemd/system/default.target deleted file mode 120000 index d321622..0000000 --- a/configs/releng/airootfs/etc/systemd/system/default.target +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/systemd/system/multi-user.target
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/livecd-alsa-unmuter.service b/configs/releng/airootfs/etc/systemd/system/livecd-alsa-unmuter.service new file mode 100644 index 0000000..03db4b9 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/livecd-alsa-unmuter.service @@ -0,0 +1,13 @@ +[Unit] +Description=Unmute All Sound Card Controls For Use With The Live Arch Environment +# This needs to run after the audio device becomes available. +Wants=systemd-udev-settle.service +After=systemd-udev-settle.service sound.target +ConditionKernelCommandLine=accessibility=on + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/livecd-sound -u + +[Install] +WantedBy=sound.target diff --git a/configs/releng/airootfs/etc/systemd/system/livecd-talk.service b/configs/releng/airootfs/etc/systemd/system/livecd-talk.service new file mode 100644 index 0000000..b38df22 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/livecd-talk.service @@ -0,0 +1,20 @@ +[Unit] +Description=Screen reader service +After=livecd-alsa-unmuter.service +Before=getty@tty1.service +ConditionKernelCommandLine=accessibility=on + +[Service] +Type=oneshot +TTYPath=/dev/tty13 +ExecStartPre=/usr/bin/chvt 13 +ExecStart=/usr/local/bin/livecd-sound -p +ExecStartPost=/usr/bin/chvt 1 +ExecStartPost=systemctl start espeakup.service +StandardInput=tty +TTYVHangup=yes +TTYVTDisallocate=yes +RemainAfterExit=true + +[Install] +WantedBy=multi-user.target diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/ModemManager.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/ModemManager.service new file mode 120000 index 0000000..dcf7c8e --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/ModemManager.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/ModemManager.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/livecd-talk.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/livecd-talk.service new file mode 120000 index 0000000..b917481 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/livecd-talk.service @@ -0,0 +1 @@ +/etc/systemd/system/livecd-talk.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/qemu-guest-agent.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/qemu-guest-agent.service new file mode 120000 index 0000000..8e3ff80 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/qemu-guest-agent.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/qemu-guest-agent.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/reflector.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/reflector.service index f5071ce..d372729 120000 --- a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/reflector.service +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/reflector.service @@ -1 +1 @@ -../reflector.service
\ No newline at end of file +/usr/lib/systemd/system/reflector.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/sshd.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/sshd.service new file mode 120000 index 0000000..d21ebd9 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/sshd.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/sshd.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/vboxservice.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/vboxservice.service new file mode 120000 index 0000000..cb2d560 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/vboxservice.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/vboxservice.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/pacman-init.service b/configs/releng/airootfs/etc/systemd/system/pacman-init.service index 6bc9aa0..77704e4 100644 --- a/configs/releng/airootfs/etc/systemd/system/pacman-init.service +++ b/configs/releng/airootfs/etc/systemd/system/pacman-init.service @@ -1,7 +1,5 @@ [Unit] Description=Initializes Pacman keyring -Wants=haveged.service -After=haveged.service Requires=etc-pacman.d-gnupg.mount After=etc-pacman.d-gnupg.mount diff --git a/configs/releng/airootfs/etc/systemd/system/reflector.service b/configs/releng/airootfs/etc/systemd/system/reflector.service deleted file mode 100644 index f7a88f2..0000000 --- a/configs/releng/airootfs/etc/systemd/system/reflector.service +++ /dev/null @@ -1,41 +0,0 @@ -[Unit] -Description=pacman mirrorlist update -Wants=network-online.target -After=network-online.target nss-lookup.target -ConditionKernelCommandLine=!mirror - -[Service] -Type=oneshot -ExecStart=/usr/bin/reflector --protocol https --age 1 --sort rate --save /etc/pacman.d/mirrorlist -Restart=on-failure -RestartSec=10 -CacheDirectory=reflector -CapabilityBoundingSet=~CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER CAP_NET_ADMIN CAP_SYS_TIME CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE CAP_KILL CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SYS_NICE CAP_SYS_RESOURCE CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_SYS_BOOT CAP_LINUX_IMMUTABLE CAP_IPC_LOCK CAP_SYS_CHROOT CAP_BLOCK_SUSPEND CAP_LEASE CAP_SYS_PACCT CAP_SYS_TTY_CONFIG CAP_WAKE_ALARM -Environment=XDG_CACHE_HOME=/var/cache/reflector -LockPersonality=true -MemoryDenyWriteExecute=true -NoNewPrivileges=true -PrivateDevices=true -PrivateTmp=true -PrivateUsers=true -ProtectClock=true -ProtectControlGroups=true -ProtectHome=true -ProtectHostname=true -ProtectKernelTunables=true -ProtectKernelLogs=true -ProtectKernelModules=true -ProtectSystem=strict -ReadWritePaths=/etc/pacman.d/mirrorlist -RemoveIPC=true -RestrictAddressFamilies=~AF_AX25 AF_IPX AF_APPLETALK AF_X25 AF_DECnet AF_KEY AF_NETLINK AF_PACKET AF_RDS AF_PPPOX AF_LLC AF_IB AF_MPLS AF_CAN AF_TIPC AF_BLUETOOTH AF_ALG AF_VSOCK AF_KCM AF_UNIX AF_XDP -RestrictNamespaces=true -RestrictRealtime=true -RestrictSUIDSGID=true -SystemCallArchitectures=native -SystemCallFilter=@system-service -SystemCallFilter=~@resources @privileged -UMask=177 - -[Install] -WantedBy=multi-user.target diff --git a/configs/releng/airootfs/etc/systemd/system/reflector.service.d/archiso.conf b/configs/releng/airootfs/etc/systemd/system/reflector.service.d/archiso.conf new file mode 100644 index 0000000..de6664d --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/reflector.service.d/archiso.conf @@ -0,0 +1,6 @@ +[Unit] +ConditionKernelCommandLine=!mirror + +[Service] +Restart=on-failure +RestartSec=10 diff --git a/configs/releng/airootfs/etc/systemd/system/sound.target.wants/livecd-alsa-unmuter.service b/configs/releng/airootfs/etc/systemd/system/sound.target.wants/livecd-alsa-unmuter.service new file mode 120000 index 0000000..98c0fc8 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/sound.target.wants/livecd-alsa-unmuter.service @@ -0,0 +1 @@ +../livecd-alsa-unmuter.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/systemd-networkd-wait-online.service.d/wait-for-only-one-interface.conf b/configs/releng/airootfs/etc/systemd/system/systemd-networkd-wait-online.service.d/wait-for-only-one-interface.conf index c875311..c9f9bce 100644 --- a/configs/releng/airootfs/etc/systemd/system/systemd-networkd-wait-online.service.d/wait-for-only-one-interface.conf +++ b/configs/releng/airootfs/etc/systemd/system/systemd-networkd-wait-online.service.d/wait-for-only-one-interface.conf @@ -1,3 +1,6 @@ +# Allow systemd-networkd-wait-online to succeed with one interface, otherwise, if multiple network interfaces exist, +# network-online.target gets needlessly delayed. +# See https://wiki.archlinux.org/title/systemd-networkd#systemd-networkd-wait-online [Service] ExecStart= ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --any diff --git a/configs/releng/airootfs/etc/xdg/reflector/reflector.conf b/configs/releng/airootfs/etc/xdg/reflector/reflector.conf new file mode 100644 index 0000000..9a72b0d --- /dev/null +++ b/configs/releng/airootfs/etc/xdg/reflector/reflector.conf @@ -0,0 +1,6 @@ +# Reflector configuration file for the systemd service. + +--save /etc/pacman.d/mirrorlist +--protocol https +--latest 20 +--sort rate diff --git a/configs/releng/airootfs/root/.automated_script.sh b/configs/releng/airootfs/root/.automated_script.sh index ed3a924..52c47e6 100755 --- a/configs/releng/airootfs/root/.automated_script.sh +++ b/configs/releng/airootfs/root/.automated_script.sh @@ -16,7 +16,7 @@ automated_script () script="$(script_cmdline)" if [[ -n "${script}" && ! -x /tmp/startup_script ]]; then if [[ "${script}" =~ ^((http|https|ftp)://) ]]; then - curl "${script}" --retry-connrefused -s -o /tmp/startup_script >/dev/null + curl "${script}" --location --retry-connrefused --retry 10 -s -o /tmp/startup_script >/dev/null rt=$? else cp "${script}" /tmp/startup_script diff --git a/configs/releng/airootfs/root/.zlogin b/configs/releng/airootfs/root/.zlogin index f598e43..0fb119d 100644 --- a/configs/releng/airootfs/root/.zlogin +++ b/configs/releng/airootfs/root/.zlogin @@ -1 +1,6 @@ +# fix for screen readers +if grep -Fq 'accessibility=' /proc/cmdline &> /dev/null; then + setopt SINGLE_LINE_ZLE +fi + ~/.automated_script.sh diff --git a/configs/releng/airootfs/root/customize_airootfs.sh b/configs/releng/airootfs/root/customize_airootfs.sh deleted file mode 100755 index 5c98fd6..0000000 --- a/configs/releng/airootfs/root/customize_airootfs.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -e -u - -sed -i 's/#\(en_US\.UTF-8\)/\1/' /etc/locale.gen -locale-gen - -cp -aT /etc/skel/ /root/ - -sed -i 's/#\(PermitRootLogin \).\+/\1yes/' /etc/ssh/sshd_config -sed -i "s/#Server/Server/g" /etc/pacman.d/mirrorlist diff --git a/configs/releng/airootfs/usr/local/bin/Installation_guide b/configs/releng/airootfs/usr/local/bin/Installation_guide index cd38645..4266754 100755 --- a/configs/releng/airootfs/usr/local/bin/Installation_guide +++ b/configs/releng/airootfs/usr/local/bin/Installation_guide @@ -1,3 +1,5 @@ #!/bin/sh +# +# SPDX-License-Identifier: GPL-3.0-or-later -exec lynx 'https://wiki.archlinux.org/index.php/Installation_guide' +exec lynx 'https://wiki.archlinux.org/title/Installation_guide' diff --git a/configs/releng/airootfs/usr/local/bin/choose-mirror b/configs/releng/airootfs/usr/local/bin/choose-mirror index 0ae0806..b021945 100755 --- a/configs/releng/airootfs/usr/local/bin/choose-mirror +++ b/configs/releng/airootfs/usr/local/bin/choose-mirror @@ -1,4 +1,6 @@ #!/bin/bash +# +# SPDX-License-Identifier: GPL-3.0-or-later get_cmdline() { local param diff --git a/configs/releng/airootfs/usr/local/bin/livecd-sound b/configs/releng/airootfs/usr/local/bin/livecd-sound new file mode 100755 index 0000000..baae0d2 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/livecd-sound @@ -0,0 +1,248 @@ +#!/usr/bin/env bash +# +# SPDX-License-Identifier: GPL-3.0-or-later + +usage() { + cat <<- _EOF_ + live cd sound helper script. + Usage: livecdsound [OPTION] + OPTIONS + -u, --unmute unmute all sound cards + -p, --pick select a card for speetch output + -h, --help Show this usage message + +_EOF_ +} + +bugout () { + printf "/usr/local/bin/livecdsound: programming error" + stat_fail +} + +echo_card_indices() +{ + if [ -f /proc/asound/cards ] ; then + sed -n -e's/^[[:space:]]*\([0-7]\)[[:space:]].*/\1/p' /proc/asound/cards + fi +} + +# The following functions try to set many controls. +# No card has all the controls and so some of the attempts are bound to fail. +# Because of this, the functions can't return useful status values. + +# $1 <card id> +# $2 <control> +# $3 <level> +unmute_and_set_level(){ + { [ "$3" ] &&[ "$2" ] && [ "$1" ] ; } || bugout + systemd-cat -t "livecdsound" printf "Setting: %s on card: %s to %s\n" "$2" "$1" "$3" + systemd-cat -t "livecdsound" amixer -c "$1" set "$2" "$3" unmute + return 0 +} + +# $1 <card id> +# $2 <control> +mute_and_zero_level() +{ + { [ "$1" ] && [ "$2" ] ; } || bugout + systemd-cat -t "livecdsound" printf "Muting control: %s on card: %s\n" "$2" "$1" + systemd-cat -t "livecdsound" amixer -c "$1" set "$2" "0%" mute + return 0 +} + +# $1 <card ID> +# $2 <control> +# $3 "on" | "off" +switch_control() +{ + { [ "$3" ] && [ "$1" ] ; } || bugout + systemd-cat -t "livecdsound" printf "Switching control: %s on card: %s to %s\n" "$2" "$1" "$3" + systemd-cat -t "livecdsound" amixer -c "$1" set "$2" "$3" + return 0 +} + +# $1 <card ID> +sanify_levels_on_card() +{ + unmute_and_set_level "$1" "Front" "80%" + unmute_and_set_level "$1" "Master" "80%" + unmute_and_set_level "$1" "Master Mono" "80%" + unmute_and_set_level "$1" "Master Digital" "80%" # E.g., cs4237B + unmute_and_set_level "$1" "Playback" "80%" + unmute_and_set_level "$1" "Headphone" "100%" + unmute_and_set_level "$1" "PCM" "80%" + unmute_and_set_level "$1" "PCM,1" "80%" # E.g., ess1969 + unmute_and_set_level "$1" "DAC" "80%" # E.g., envy24, cs46xx + unmute_and_set_level "$1" "DAC,0" "80%" # E.g., envy24 + unmute_and_set_level "$1" "DAC,1" "80%" # E.g., envy24 + unmute_and_set_level "$1" "Synth" "80%" + unmute_and_set_level "$1" "CD" "80%" + unmute_and_set_level "$1" "PC Speaker" "100%" + + mute_and_zero_level "$1" "Mic" + mute_and_zero_level "$1" "IEC958" # Ubuntu #19648 + + # Intel P4P800-MX + switch_control "$1" "Master Playback Switch" on + switch_control "$1" "Master Surround" on + + # Trident/YMFPCI/emu10k1: + unmute_and_set_level "$1" "Wave" "80%" + unmute_and_set_level "$1" "Music" "80%" + unmute_and_set_level "$1" "AC97" "80%" + + # DRC: + unmute_and_set_level "$1" "Dynamic Range Compression" "80%" + + # Required for HDA Intel (hda-intel): + unmute_and_set_level "$1" "Front" "80%" + + # Required for SB Live 7.1/24-bit (ca0106): + unmute_and_set_level "$1" "Analog Front" "80%" + + # Required at least for Via 823x hardware on DFI K8M800-MLVF Motherboard + switch_control "$1" "IEC958 Capture Monitor" off + + # Required for hardware allowing toggles for AC97 through IEC958, + # valid values are 0, 1, 2, 3. Needs to be set to 0 for PCM1. + unmute_and_set_level "$1" "IEC958 Playback AC97-SPSA" "0" + + # Required for newer Via hardware + unmute_and_set_level "$1" "VIA DXS,0" "80%" + unmute_and_set_level "$1" "VIA DXS,1" "80%" + unmute_and_set_level "$1" "VIA DXS,2" "80%" + unmute_and_set_level "$1" "VIA DXS,3" "80%" + + # Required on some notebooks with ICH4: + switch_control "$1" "Headphone Jack Sense" off + switch_control "$1" "Line Jack Sense" off + + # Some machines need one or more of these to be on; + # others need one or more of these to be off: + + switch_control "$1" "Audigy Analog/Digital Output Jack" on + switch_control "$1" "SB Live Analog/Digital Output Jack" on + + # D1984 -- Thinkpad T61/X61 + switch_control "$1" "Speaker" on + switch_control "$1" "Headphone" on + + # HDA-Intel w/ "Digital" capture mixer (See Ubuntu #193823) + unmute_and_set_level "$1" "Digital" "80%" + + return 0 +} + +# $1 <card ID> | "all" +sanify_levels() +{ + local ttsdml_returnstatus=0 + local card + case "$1" in + all) + for card in $(echo_card_indices) ; do + sanify_levels_on_card "$card" || ttsdml_returnstatus=1 + done + ;; + *) + sanify_levels_on_card "$1" || ttsdml_returnstatus=1 + ;; + esac + return $ttsdml_returnstatus +} + +# List all cards that *should* be usable for PCM audio. In my experience, +# the console speaker (handled by the pcsp driver) isn't a suitable playback +# device, so we'll exclude it. +list_non_pcsp_cards() +{ + for card in $(echo_card_indices); do + local cardfile="/proc/asound/card${card}/id" + if [ -r "$cardfile" ] && [ -f "$cardfile" ] && \ + [ "$(cat "$cardfile")" != pcsp ]; then + echo "$card" + fi + done +} + +# Properly initialize the sound card so that we have audio at boot. +unmute_all_cards() +{ + sanify_levels all +} + +is_numeric() { + local str=$1 + [[ "$str" =~ ^[0-9]+$ ]] +} + +set_default_card() { + local card=$1 + sed -e "s/%card%/$card/g" < /usr/local/share/livecd-sound/asound.conf.in \ + > /etc/asound.conf +} + +play_on_card() { + local card=$1 file=$2 + aplay -q "-Dplughw:$card,0" "$file" +} + +# If there are multiple usable sound cards, prompt the user to choose one, +# using auditory feedback. +pick_a_card() +{ + set -f + usable_cards="$(list_non_pcsp_cards)" + num_usable_cards="$(wc -w <<< "$usable_cards")" + + if [ "$num_usable_cards" -eq 1 ]; then + systemd-cat -t "livecdsound" printf "Only one sound card is detected\n" + exit 0 + fi + systemd-cat -t "livecdsound" printf "multiple sound cards detected\n" + for card in $usable_cards; do + if ! is_numeric "$card"; then + continue + fi + play_on_card "$card" /usr/share/livecd-sounds/pick-a-card.wav& + done + wait + sleep 1 + for card in $usable_cards; do + if ! is_numeric "$card"; then + continue + fi + play_on_card "$card" /usr/share/livecd-sounds/beep.wav + if read -r -t 10; then + systemd-cat -t "livecdsound" printf "Selecting %s sound card as default\n" "$card" + set_default_card "$card" + break + fi +done +} + +if [[ $# -eq 0 ]]; then + echo "error: No argument passed." + exit 1 +fi +while [[ "${1}" != "" ]]; do + case ${1} in + -h|--help) + usage + exit + ;; + -u|--unmute) + systemd-cat -t "livecdsound" printf "Unmuting all cards" + unmute_all_cards + ;; + -p|--pick) + pick_a_card + ;; + *) + echo "error: Unsupported argument" + usage + exit 1 + ;; + esac + shift +done diff --git a/configs/releng/airootfs/usr/local/share/livecd-sound/asound.conf.in b/configs/releng/airootfs/usr/local/share/livecd-sound/asound.conf.in new file mode 100644 index 0000000..3f9c7aa --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/livecd-sound/asound.conf.in @@ -0,0 +1,3 @@ +Defaults node +defaults.ctl.card %card%; +defaults.pcm.card %card%; diff --git a/configs/releng/bootstrap_packages.i686 b/configs/releng/bootstrap_packages.i686 new file mode 100644 index 0000000..64966d0 --- /dev/null +++ b/configs/releng/bootstrap_packages.i686 @@ -0,0 +1,2 @@ +arch-install-scripts +base diff --git a/configs/releng/bootstrap_packages.x86_64 b/configs/releng/bootstrap_packages.x86_64 new file mode 100644 index 0000000..64966d0 --- /dev/null +++ b/configs/releng/bootstrap_packages.x86_64 @@ -0,0 +1,2 @@ +arch-install-scripts +base diff --git a/configs/releng/efiboot/loader/entries/01-archiso-x86_64-linux.conf b/configs/releng/efiboot/loader/entries/01-archiso-x86_64-linux.conf new file mode 100644 index 0000000..d59262f --- /dev/null +++ b/configs/releng/efiboot/loader/entries/01-archiso-x86_64-linux.conf @@ -0,0 +1,6 @@ +title Arch Linux install medium (x86_64, UEFI) +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +initrd /%INSTALL_DIR%/boot/intel-ucode.img +initrd /%INSTALL_DIR%/boot/amd-ucode.img +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img +options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% diff --git a/configs/releng/efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf b/configs/releng/efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf new file mode 100644 index 0000000..06f5466 --- /dev/null +++ b/configs/releng/efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf @@ -0,0 +1,6 @@ +title Arch Linux install medium (x86_64, UEFI) with speech +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +initrd /%INSTALL_DIR%/boot/intel-ucode.img +initrd /%INSTALL_DIR%/boot/amd-ucode.img +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img +options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% accessibility=on diff --git a/configs/releng/efiboot/loader/entries/03-archiso-x86_64-ram-linux.conf b/configs/releng/efiboot/loader/entries/03-archiso-x86_64-ram-linux.conf new file mode 100644 index 0000000..9c7a51a --- /dev/null +++ b/configs/releng/efiboot/loader/entries/03-archiso-x86_64-ram-linux.conf @@ -0,0 +1,6 @@ +title Arch Linux install medium (x86_64, UEFI, Copy to RAM) +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +initrd /%INSTALL_DIR%/boot/intel-ucode.img +initrd /%INSTALL_DIR%/boot/amd-ucode.img +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img +options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram diff --git a/configs/releng/efiboot/loader/entries/archiso-x86_64-cd.conf b/configs/releng/efiboot/loader/entries/archiso-x86_64-cd.conf deleted file mode 100644 index 7f5c81b..0000000 --- a/configs/releng/efiboot/loader/entries/archiso-x86_64-cd.conf +++ /dev/null @@ -1,6 +0,0 @@ -title Arch Linux install medium (x86_64, UEFI) -linux /EFI/archiso/vmlinuz.efi -initrd /EFI/archiso/intel_ucode.img -initrd /EFI/archiso/amd_ucode.img -initrd /EFI/archiso/archiso.img -options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% diff --git a/configs/releng/efiboot/loader/entries/archiso-x86_64-usb.conf b/configs/releng/efiboot/loader/entries/archiso-x86_64-usb.conf deleted file mode 100644 index e1d156a..0000000 --- a/configs/releng/efiboot/loader/entries/archiso-x86_64-usb.conf +++ /dev/null @@ -1,6 +0,0 @@ -title Arch Linux install medium (x86_64, UEFI) -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz -initrd /%INSTALL_DIR%/boot/intel_ucode.img -initrd /%INSTALL_DIR%/boot/amd_ucode.img -initrd /%INSTALL_DIR%/boot/x86_64/archiso.img -options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% diff --git a/configs/releng/efiboot/loader/loader.conf b/configs/releng/efiboot/loader/loader.conf index 9a0049c..ae63487 100644 --- a/configs/releng/efiboot/loader/loader.conf +++ b/configs/releng/efiboot/loader/loader.conf @@ -1,2 +1,2 @@ -timeout 3 -default archiso-x86_64.conf +timeout 15 +default 01-archiso-x86_64-linux.conf diff --git a/configs/releng/isolinux/isolinux.cfg b/configs/releng/isolinux/isolinux.cfg deleted file mode 100644 index 10fd285..0000000 --- a/configs/releng/isolinux/isolinux.cfg +++ /dev/null @@ -1,6 +0,0 @@ -PATH /%INSTALL_DIR%/boot/syslinux/ -DEFAULT loadconfig - -LABEL loadconfig - CONFIG /%INSTALL_DIR%/boot/syslinux/archiso.cfg - APPEND /%INSTALL_DIR%/ diff --git a/configs/releng/mkinitcpio.conf b/configs/releng/mkinitcpio.conf deleted file mode 100644 index c04f1dc..0000000 --- a/configs/releng/mkinitcpio.conf +++ /dev/null @@ -1,2 +0,0 @@ -HOOKS=(base udev memdisk archiso_shutdown archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs archiso_kms block filesystems keyboard) -COMPRESSION="xz" diff --git a/configs/releng/packages.i686 b/configs/releng/packages.i686 index e69de29..1a3b0b1 100644 --- a/configs/releng/packages.i686 +++ b/configs/releng/packages.i686 @@ -0,0 +1,121 @@ +alsa-utils +amd-ucode +arch-install-scripts +archinstall +b43-fwcutter +base +bind-tools +brltty +broadcom-wl +btrfs-progs +clonezilla +cloud-init +crda +cryptsetup +darkhttpd +ddrescue +dhclient +dhcpcd +diffutils +dmraid +dnsmasq +dosfstools +e2fsprogs +edk2-shell +efibootmgr +espeakup +ethtool +exfatprogs +f2fs-tools +fatresize +fsarchiver +gnu-netcat +gpart +gpm +gptfdisk +grml-zsh-config +grub +hdparm +intel-ucode +ipw2100-fw +ipw2200-fw +irssi +iw +iwd +jfsutils +kitty-terminfo +less +lftp +libfido2 +libusb-compat +linux +linux-atm +linux-firmware +livecd-sounds +lsscsi +lvm2 +lynx +man-db +man-pages +mc +mdadm +memtest86+ +mkinitcpio +mkinitcpio-archiso +mkinitcpio-nfs-utils +modemmanager +mtools +nano +nbd +ndisc6 +nfs-utils +nilfs-utils +nmap +ntfs-3g +nvme-cli +openconnect +openssh +openvpn +partclone +parted +partimage +pcsclite +ppp +pptpclient +pv +qemu-guest-agent +refind +reflector +reiserfsprogs +rp-pppoe +rsync +rxvt-unicode-terminfo +screen +sdparm +sg3_utils +smartmontools +sof-firmware +squashfs-tools +sudo +syslinux +systemd-resolvconf +tcpdump +terminus-font +testdisk +tmux +tpm2-tss +udftools +usb_modeswitch +usbmuxd +usbutils +vim +virtualbox-guest-utils-nox +vpnc +wireless-regdb +wireless_tools +wpa_supplicant +wvdial +xfsprogs +xl2tpd +zsh +pcmciautils diff --git a/configs/releng/packages.both b/configs/releng/packages.x86_64 index 1cfd724..9079c06 100644 --- a/configs/releng/packages.both +++ b/configs/releng/packages.x86_64 @@ -1,12 +1,17 @@ +alsa-utils amd-ucode arch-install-scripts +archinstall b43-fwcutter base bind-tools +brltty broadcom-wl btrfs-progs clonezilla +cloud-init crda +cryptsetup darkhttpd ddrescue dhclient @@ -15,28 +20,38 @@ diffutils dmraid dnsmasq dosfstools +e2fsprogs +edk2-shell efibootmgr +espeakup ethtool -exfat-utils +exfatprogs f2fs-tools +fatresize fsarchiver gnu-netcat +gpart gpm gptfdisk grml-zsh-config -haveged +grub hdparm intel-ucode ipw2100-fw ipw2200-fw irssi +iw iwd jfsutils kitty-terminfo +less lftp +libfido2 +libusb-compat linux linux-atm linux-firmware +livecd-sounds lsscsi lvm2 lynx @@ -46,7 +61,9 @@ mc mdadm memtest86+ mkinitcpio +mkinitcpio-archiso mkinitcpio-nfs-utils +modemmanager mtools nano nbd @@ -62,26 +79,37 @@ openvpn partclone parted partimage +pcsclite ppp pptpclient +pv +qemu-guest-agent +refind reflector reiserfsprogs rp-pppoe rsync rxvt-unicode-terminfo +screen sdparm sg3_utils smartmontools +sof-firmware +squashfs-tools sudo syslinux systemd-resolvconf tcpdump terminus-font -termite-terminfo testdisk +tmux +tpm2-tss +udftools usb_modeswitch +usbmuxd usbutils vim +virtualbox-guest-utils-nox vpnc wireless-regdb wireless_tools diff --git a/configs/releng/pacman.conf b/configs/releng/pacman.conf index bbca42f..5296707 100644 --- a/configs/releng/pacman.conf +++ b/configs/releng/pacman.conf @@ -31,10 +31,11 @@ Architecture = auto # Misc options #UseSyslog #Color -#TotalDownload +#NoProgressBar # We cannot check disk space from within a chroot environment #CheckSpace #VerbosePkgLists +ParallelDownloads = 5 # By default, pacman accepts packages signed by keys that its local keyring # trusts (see pacman-key and its man page), as well as unsigned packages. @@ -73,16 +74,16 @@ LocalFileSigLevel = Optional #Include = /etc/pacman.d/mirrorlist [core] -Include = /etc/pacman.d/mirrorlist +Include = /etc/pacman.d/mirrorlist32 [extra] -Include = /etc/pacman.d/mirrorlist +Include = /etc/pacman.d/mirrorlist32 #[community-testing] #Include = /etc/pacman.d/mirrorlist [community] -Include = /etc/pacman.d/mirrorlist +Include = /etc/pacman.d/mirrorlist32 # If you want to run 32 bit applications on your x86_64 system, # enable the multilib repositories as required here. diff --git a/configs/releng/profiledef.sh b/configs/releng/profiledef.sh new file mode 100644 index 0000000..e8fdf55 --- /dev/null +++ b/configs/releng/profiledef.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2034 + +iso_name="archlinux32" +iso_label="ARCH_$(date +%Y%m)" +iso_publisher="Arch Linux <https://archlinux.org>" +iso_application="Arch Linux Live/Rescue CD" +iso_version="$(date +%Y.%m.%d)" +install_dir="arch" +buildmodes=('iso') +bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito') +arch="i686" +pacman_conf="pacman.conf" +airootfs_image_type="squashfs" +airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M') +file_permissions=( + ["/etc/shadow"]="0:0:400" + ["/root"]="0:0:750" + ["/root/.automated_script.sh"]="0:0:755" + ["/usr/local/bin/choose-mirror"]="0:0:755" + ["/usr/local/bin/Installation_guide"]="0:0:755" + ["/usr/local/bin/livecd-sound"]="0:0:755" +) diff --git a/configs/releng/syslinux/archiso.cfg b/configs/releng/syslinux/archiso.cfg deleted file mode 100644 index 40d8b34..0000000 --- a/configs/releng/syslinux/archiso.cfg +++ /dev/null @@ -1,11 +0,0 @@ -DEFAULT select - -LABEL select -COM32 boot/syslinux/whichsys.c32 -APPEND -pxe- pxe -sys- sys -iso- sys - -LABEL pxe -CONFIG boot/syslinux/archiso_pxe.cfg - -LABEL sys -CONFIG boot/syslinux/archiso_sys.cfg diff --git a/configs/releng/syslinux/archiso_head.cfg b/configs/releng/syslinux/archiso_head.cfg index a915d34..1154f78 100644 --- a/configs/releng/syslinux/archiso_head.cfg +++ b/configs/releng/syslinux/archiso_head.cfg @@ -1,7 +1,7 @@ -SERIAL 0 38400 -UI boot/syslinux/vesamenu.c32 +SERIAL 0 115200 +UI vesamenu.c32 MENU TITLE Arch Linux -MENU BACKGROUND boot/syslinux/splash.png +MENU BACKGROUND splash.png MENU WIDTH 78 MENU MARGIN 4 @@ -25,3 +25,4 @@ MENU COLOR msg07 37;40 #90ffffff #a0000000 std MENU COLOR tabmsg 31;40 #30ffffff #00000000 std MENU CLEAR +MENU IMMEDIATE diff --git a/configs/releng/syslinux/archiso_pxe-linux.cfg b/configs/releng/syslinux/archiso_pxe-linux.cfg new file mode 100644 index 0000000..4310ff8 --- /dev/null +++ b/configs/releng/syslinux/archiso_pxe-linux.cfg @@ -0,0 +1,32 @@ +LABEL arch32_nbd +TEXT HELP +Boot the Arch Linux install medium using NBD. +It allows you to install Arch Linux or perform system maintenance. +ENDTEXT +MENU LABEL Arch Linux install medium (i686, NBD) +LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/i686/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% archiso_nbd_srv=${pxeserver} checksum verify +SYSAPPEND 3 + +LABEL arch32_nfs +TEXT HELP +Boot the Arch Linux live medium using NFS. +It allows you to install Arch Linux or perform system maintenance. +ENDTEXT +MENU LABEL Arch Linux install medium (i686, NFS) +LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/i686/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archiso_nfs_srv=${pxeserver}:/run/archiso/bootmnt checksum verify +SYSAPPEND 3 + +LABEL arch32_http +TEXT HELP +Boot the Arch Linux live medium using HTTP. +It allows you to install Arch Linux or perform system maintenance. +ENDTEXT +MENU LABEL Arch Linux install medium (i686, HTTP) +LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/i686/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archiso_http_srv=http://${pxeserver}/ checksum verify +SYSAPPEND 3 diff --git a/configs/releng/syslinux/archiso_pxe.cfg b/configs/releng/syslinux/archiso_pxe.cfg index b0e66e8..b4c9a80 100644 --- a/configs/releng/syslinux/archiso_pxe.cfg +++ b/configs/releng/syslinux/archiso_pxe.cfg @@ -1,36 +1,5 @@ -INCLUDE boot/syslinux/archiso_head.cfg +INCLUDE archiso_head.cfg -LABEL arch32_nbd -TEXT HELP -Boot the Arch Linux (i686) live medium (Using NBD). -It allows you to install Arch Linux or perform system maintenance. -ENDTEXT -MENU LABEL Boot Arch Linux (i686) (NBD) -LINUX boot/i686/vmlinuz -INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/i686/archiso.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% archiso_nbd_srv=${pxeserver} -SYSAPPEND 3 +INCLUDE archiso_pxe-linux.cfg -LABEL arch32_nfs -TEXT HELP -Boot the Arch Linux (i686) live medium (Using NFS). -It allows you to install Arch Linux or perform system maintenance. -ENDTEXT -MENU LABEL Boot Arch Linux (i686) (NFS) -LINUX boot/i686/vmlinuz -INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/i686/archiso.img -APPEND archisobasedir=%INSTALL_DIR% archiso_nfs_srv=${pxeserver}:/run/archiso/bootmnt -SYSAPPEND 3 - -LABEL arch32_http -TEXT HELP -Boot the Arch Linux (i686) live medium (Using HTTP). -It allows you to install Arch Linux or perform system maintenance. -ENDTEXT -MENU LABEL Boot Arch Linux (i686) (HTTP) -LINUX boot/i686/vmlinuz -INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/i686/archiso.img -APPEND archisobasedir=%INSTALL_DIR% archiso_http_srv=http://${pxeserver}/ -SYSAPPEND 3 - -INCLUDE boot/syslinux/archiso_tail.cfg +INCLUDE archiso_tail.cfg diff --git a/configs/releng/syslinux/archiso_sys-linux.cfg b/configs/releng/syslinux/archiso_sys-linux.cfg new file mode 100644 index 0000000..6bff367 --- /dev/null +++ b/configs/releng/syslinux/archiso_sys-linux.cfg @@ -0,0 +1,31 @@ +LABEL arch32 +TEXT HELP +Boot the Arch Linux install medium on BIOS. +It allows you to install Arch Linux or perform system maintenance. +ENDTEXT +MENU LABEL Arch Linux install medium (i686, BIOS) +LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/i686/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% + +# Accessibility boot option +LABEL arch32speech +TEXT HELP +Boot the Arch Linux install medium on BIOS with speakup screen reader. +It allows you to install Arch Linux or perform system maintenance with speech feedback. +ENDTEXT +MENU LABEL Arch Linux install medium (i686, BIOS) with ^speech +LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/i686/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% accessibility=on + +# Copy to RAM boot option +LABEL arch32ram +TEXT HELP +Boot the Arch Linux install medium on BIOS with Copy-to-RAM option +It allows you to install Arch Linux or perform system maintenance. +ENDTEXT +MENU LABEL Arch Linux install medium (i686, BIOS, Copy to RAM) +LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/i686/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram diff --git a/configs/releng/syslinux/archiso_sys.cfg b/configs/releng/syslinux/archiso_sys.cfg index 62bba0b..dc1a6eb 100644 --- a/configs/releng/syslinux/archiso_sys.cfg +++ b/configs/releng/syslinux/archiso_sys.cfg @@ -1,13 +1,8 @@ -INCLUDE boot/syslinux/archiso_head.cfg +INCLUDE archiso_head.cfg -LABEL arch32 -TEXT HELP -Boot the Arch Linux (i686) live medium. -It allows you to install Arch Linux or perform system maintenance. -ENDTEXT -MENU LABEL Boot Arch Linux (i686) -LINUX boot/i686/vmlinuz -INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/i686/archiso.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% +DEFAULT arch32 +TIMEOUT 150 -INCLUDE boot/syslinux/archiso_tail.cfg +INCLUDE archiso_sys-linux.cfg + +INCLUDE archiso_tail.cfg diff --git a/configs/releng/syslinux/archiso_tail.cfg b/configs/releng/syslinux/archiso_tail.cfg index 34b6c5b..e5339a2 100644 --- a/configs/releng/syslinux/archiso_tail.cfg +++ b/configs/releng/syslinux/archiso_tail.cfg @@ -4,19 +4,19 @@ Boot an existing operating system. Press TAB to edit the disk and partition number to boot. ENDTEXT MENU LABEL Boot existing OS -COM32 boot/syslinux/chain.c32 +COM32 chain.c32 APPEND hd0 0 # http://www.memtest.org/ LABEL memtest MENU LABEL Run Memtest86+ (RAM test) -LINUX boot/memtest +LINUX /%INSTALL_DIR%/boot/memtest # http://hdt-project.org/ LABEL hdt MENU LABEL Hardware Information (HDT) -COM32 boot/syslinux/hdt.c32 -APPEND modules_alias=boot/syslinux/hdt/modalias.gz pciids=boot/syslinux/hdt/pciids.gz +COM32 hdt.c32 +APPEND modules_alias=hdt/modalias.gz pciids=hdt/pciids.gz LABEL reboot TEXT HELP @@ -24,7 +24,7 @@ Reboot computer. The computer's firmware must support APM. ENDTEXT MENU LABEL Reboot -COM32 boot/syslinux/reboot.c32 +COM32 reboot.c32 LABEL poweroff TEXT HELP @@ -32,4 +32,4 @@ Power off computer. The computer's firmware must support APM. ENDTEXT MENU LABEL Power Off -COM32 boot/syslinux/poweroff.c32 +COM32 poweroff.c32 diff --git a/configs/releng/syslinux/syslinux.cfg b/configs/releng/syslinux/syslinux.cfg index 3ee98de..cbda72f 100644 --- a/configs/releng/syslinux/syslinux.cfg +++ b/configs/releng/syslinux/syslinux.cfg @@ -1,5 +1,11 @@ -DEFAULT loadconfig +DEFAULT select -LABEL loadconfig - CONFIG archiso.cfg - APPEND ../../ +LABEL select +COM32 whichsys.c32 +APPEND -pxe- pxe -sys- sys -iso- sys + +LABEL pxe +CONFIG archiso_pxe.cfg + +LABEL sys +CONFIG archiso_sys.cfg diff --git a/docs/README.altbootmethods b/docs/README.altbootmethods deleted file mode 100644 index beb6f0d..0000000 --- a/docs/README.altbootmethods +++ /dev/null @@ -1,113 +0,0 @@ -INDEX ------ - -* Alternative boot methods (configs/releng) - * ISO in loopback mode - * ISO in memdisk mode - * Network booting (PXE) [first stage] - * DHCP + TFTP - * DHCP + HTTP - * HTTP/NFS/NBD [second stage] - - - -*** Alternative boot methods (configs/releng) - -ISO images names consist of: archlinux-<YYYY>.<MM>.<DD>-i686.iso - -Where: - <YYYY> Year - <MM> Month - <DD> Day - - -** ISO in loopback mode. - -Note: Described method is for using with GRUB2. - GRUB2 is installed on target media and archlinux-<YYYY>.<MM>.<DD>-i686.iso - is at path <TARGET-PATH> on disk <D> and partition <P>, - where filesystem is labeled as <TARGET-FS-LABEL>. - -menuentry "Arch Linux (i686)" { - set isofile="/<TARGET-PATH>/archlinux-<YYYY>.<MM>.<DD>-i686.iso" - loopback loop (hd<D>,<P>)$isofile - linux (loop)/arch/boot/i686/vmlinuz img_label=<TARGET-FS-LABEL> img_loop=$isofile - initrd (loop)/arch/boot/i686/archiso.img -} - - -** ISO in memdisk mode. - -Note: Described method is for using with SYSLINUX. Anyway MEMDISK from SYSLINUX can work - with other bootloaders. - SYSLINUX is installed on target media and archlinux-<YYYY>.<MM>.<DD>-i686.iso - is at path <TARGET-PATH>. - On 32-bit systems, is needed to pass vmalloc=nnM to the kernel, where nn is the size - of the ISO image plus 64 MiB (or 128 MiB). - - -LABEL arch_x32 - LINUX memdisk - INITRD /<TARGET-PATH>/archlinux-<YYYY>.<MM>.<DD>-i686.iso - APPEND iso - - -** Network booting (PXE). - -All ISOs are ready to act as PXE server, some manual steps are needed -to setup the desired PXE boot mode. -Alternatively it is possible to use an existing PXE server following the same logic. -Note: Setup network first, adjust IP adresses, and respect all slashes "/". - -First stage is for loading kernel and initramfs via PXE, two methods described here: - -* DHCP + TFTP - -Note: All NIC firmwares should support this. - -# dnsmasq --port=0 \ - --enable-tftp \ - --tftp-root=/run/archiso/bootmnt \ - --dhcp-range=192.168.0.2,192.168.0.254,86400 \ - --dhcp-boot=/arch/boot/syslinux/lpxelinux.0 \ - --dhcp-option-force=209,boot/syslinux/archiso.cfg \ - --dhcp-option-force=210,/arch/ - -* DHCP + HTTP - -Note: Not all NIC firmware supports HTTP and DNS (if domain name is used). - At least this works with iPXE and gPXE. - -# dnsmasq --port=0 \ - --dhcp-range=192.168.0.2,192.168.0.254,86400 \ - --dhcp-boot=http://192.168.0.7/arch/boot/syslinux/lpxelinux.0 \ - --dhcp-option-force=209,boot/syslinux/archiso.cfg \ - --dhcp-option-force=210,http://192.168.0.7/arch/ - - -Once the kernel is started from PXE, SquashFS files and other misc files -inside "arch" directory must be loaded (second stage). One of the following -methods can be used to serve the rest of live-medium. - -* HTTP - -# darkhttpd /run/archiso/bootmnt - - -* NFS - -# echo "/run/archiso/bootmnt 192.168.0.*(ro,no_subtree_check,no_root_squash)" >> /etc/exports -# systemctl start nfs-server.service - - -* NBD - -Note: Adjust ARCH_201703 as needed. - -# cat << EOF > /tmp/nbd-server.conf -[generic] -[archiso] - readonly = true - exportname = /dev/disk/by-label/ARCH_201703 -EOF -# nbd-server -C /tmp/nbd-server.conf diff --git a/docs/README.bootparams b/docs/README.bootparams deleted file mode 100644 index bcafc0e..0000000 --- a/docs/README.bootparams +++ /dev/null @@ -1,141 +0,0 @@ -INDEX ------ - -* Boot parameters (initramfs stage) - * hooks/archiso - * hooks/archiso_pxe_common - * hooks/archiso_pxe_nbd - * hooks/archiso_pxe_http - * hooks/archiso_pxe_nfs - * hooks/archiso_loop_mnt - -* Boot parameters (configs/releng) - * scripts/choose-mirror - - -*** Boot parameters (initramfs stage) - -** hooks/archiso - -* archisolabel= Set the filesystem label where archiso files reside. - Default: (unset) -* archisodevice= Set the device node where archiso medium is located. - Default: "/dev/disk/by-label/${archisolabel}" -* archisobasedir= Set the base directory where all files reside. - Default: "arch" -* copytoram= If set to "y" or just "copytoram" without arguments, - all SquashFS are copied to "RAM". - Default: (unset) -* checksum= If set to "y" or just "checksum" without arguments, - performs a self-test of all files inside ${install_dir}, - and continue booting if ok. - Default: (unset) -* cow_label= Set the filesystem label where COW file (for dm-snapshot) - or upperdir/workdir files (for overlayfs) must be stored. - Default: (unset) -* cow_device= Like cow_label= but using device node. - Default: (unset) or "/dev/disk/by-label/${cow_label}" -* cow_flags= Set extra mount options, e.g. for btrfs subvolumes. - Default: defaults -* cow_directory= Set a directory inside ${cow_device}. - Default: "/persistent_${archisolabel}/${arch}" -* cow_persistent= Set if snapshot is persistent "P" or non-persistent "N". - Only used for dm-snapshot mode, ignored for overlayfs. - Default: "N" (if no ${cow_device} is used) otherwise "P". -* cow_spacesize= Set the size for COW space (tmpfs). Valid for both - dm-snapshot and overlayfs mode. - The argument is an integer and optional unit. - Units are M,G (powers of 1024). - Default: "256M" -* cow_chunksize= Set chunksize used for dm-snapshot. This is number - of 512 byte blocks to write at once. - Default: "8" -* copytoram_size= Set the size of tmpfs. This space is used for - airootfs.sfs image if copytoram=y. - Size is in bytes (suffix with "k", "m" and "g") or - in percentage of available RAM. - Default: "75%" -* dm_snap_prefix= Set a prefix for dm-snapshot node names. - Only used for dm-snapshot mode, ignored for overlayfs. - Default: "arch" -* arch= Force an architecture type (i686 | x86_64). - Do not set it for normal operations. - Default: (architecture of running kernel) - - -** hooks/archiso_pxe_common - -* ip= This parameter is setup automatically by PXELINUX - when option "SYSAPPEND" is set to 1 or 2 in config. - ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask> - Default: (set via PXE server) -* BOOTIF= This parameter is setup automatically by PXELINUX - when option "SYSAPPEND" is set to 2 or 3 in config. - BOOTIF=<hardware-address-of-boot-interface> - Default: (set via PXELINUX) -* copy_resolvconf= Copy /etc/resolv.conf from initramfs to live-enviroment. - Set to "n" to skip them. - Default: "y" - - -** hooks/archiso_pxe_nbd - -* archiso_nbd_name= Set NBD export name used by the server. - Default: archiso -* archiso_nbd_srv= Set an IP address where NBD reside. - If ${pxeserver} is used, PXE IP will be used. - Default: (unset) - - -** hooks/archiso_pxe_http - -* archiso_http_srv= Set an HTTP URL (must end with /) where ${archisobasedir} - is found with all *.sfs files. - In the IP/domain part if ${pxeserver} is used, use PXE IP. - Default: (unset) -* archiso_http_spc= Set the size of tmpfs where *.sfs files are downloaded. - Default: "75%" - - -** hooks/archiso_pxe_nfs - -* archiso_nfs_srv= Set the NFS-IP:/path of the server - In the IP part if ${pxeserver} is used, PXE IP will be used. - Default: (unset) -* archiso_nfs_opt= Set NFS mount options separated by comma. - Default: (unset, see below) - These are the implicit options: - port = as given by server portmap daemon - rsize = 1024 - wsize = 1024 - timeo = 7 - retrans = 3 - acregmin = 3 - acregmax = 60 - acdirmin = 30 - acdirmax = 60 - flags = hard, nointr, noposix, cto, ac - - -** hooks/archiso_loop_mnt - -* img_label= Set the filesystem label where archiso-image.iso. - Default: (unset) -* img_dev= Device where archiso-image.iso reside. - Default: (unset) or "/dev/disk/by-label/${img_label}" -* img_flags= Set extra mount options, e.g. for btrfs subvolumes. - Default: defaults -* img_loop= Full path where archiso-image.iso is located on ${img_dev} - Default: (unset) - - - -*** Boot parameters (configs/releng) - -** scripts/choose-mirror - -* mirror= Takes a mirror URL and creates a new mirrorlist. - When setting mirror=auto, the mirror is taken from - archiso_http_srv= in order to keep using the mirror - selected in the netboot menu. - Default: (unset) diff --git a/docs/README.build b/docs/README.build deleted file mode 100644 index efa78d0..0000000 --- a/docs/README.build +++ /dev/null @@ -1,68 +0,0 @@ -INDEX ------ - -* Build requirements -* Building the most basic Arch Linux live media. (configs/baseline) -* Building official Arch Linux live media. (configs/releng) - - - -*** Build requirements - -** For mkarchiso script needs these packages (build host): - + arch-install-scripts for pacstrap/arch-chroot - + edk2-shell for UEFI shell - + squashfs-tools for mksquashfs - + libisoburn for xorriso - + btrfs-progs for mkfs.btrfs (optional) - -** For configs/releng build.sh needs theses packages (build host): - + dosfstools for mkfs.fat - + lynx for fetching the latest installation guide - -** For these hooks needs these packages (on target airootfs) -* archiso - + (none) -* archiso_loop_mnt - + (none) -* archiso_pxe_common - + mkinitcpio-nfs-utils for ipconfig -* archiso_pxe_nbd - + nbd for nbd-client -* archiso_pxe_http - + curl for curl -* archiso_pxe_nfs - + mkinitcpio-nfs-utils for nfsmount -* archiso_shutdown - + (none) - - -*** Building the most basic Arch Linux live media. (configs/baseline) - -* Install needed packages. - # pacman -S git make arch-install-scripts squashfs-tools libisoburn --needed - -* Install archiso. - # git clone git://projects.archlinux.org/archiso.git - # make -C archiso install - -* Build a basic iso. - # /usr/share/archiso/configs/baseline/build.sh - -Note: If you want to customize, just see the configs/releng directory which is -used to build official images with much more things. - - -*** Building official Arch Linux live media. (configs/releng) - -* Install needed packages. - # pacman -S git make arch-install-scripts squashfs-tools libisoburn dosfstools lynx --needed - -* Install archiso. - # git clone git://projects.archlinux.org/archiso.git - # make -C archiso install - -* Build them! - # /usr/share/archiso/configs/releng/build.sh - -Note: See build.sh -h for more options. This only runs on x86_64. diff --git a/docs/README.knownissues b/docs/README.knownissues deleted file mode 100644 index 3a94764..0000000 --- a/docs/README.knownissues +++ /dev/null @@ -1,12 +0,0 @@ -*** Know issues - -** (1) On shutdown lots of messages from systemd like: - - "Could not unmount /run/archiso/<ABC>: Device or resource busy" - "Could not delete loopback /dev/loop<N>: Device or resource busy" - This is not a real issue since, all mounted filesystem, loopback devices - and device mapper devices made by archiso will be "free" on "shutdown tmpfs" - (A.K.A deinitramfs), build at initramfs by [archiso_shutdown] initcpio hook. - Proper shutdown is mostly important when persistent is used. - - diff --git a/docs/README.profile.rst b/docs/README.profile.rst new file mode 100644 index 0000000..c93228d --- /dev/null +++ b/docs/README.profile.rst @@ -0,0 +1,163 @@ +======= +profile +======= + +An archiso profile consists of several configuration files and a directory for files to be added to the resulting image. + +.. code:: plaintext + + profile/ + ├── airootfs/ + ├── efiboot/ + ├── syslinux/ + ├── bootstrap_packages.arch + ├── packages.arch + ├── pacman.conf + └── profiledef.sh + +The required files and directories are explained in the following sections. + +profiledef.sh +============= + +This file describes several attributes of the resulting image and is a place for customization to the general behavior +of the image. + +The image file is constructed from some of the variables in ``profiledef.sh``: ``<iso_name>-<iso_version>-<arch>.iso`` +(e.g. ``archlinux-202010-x86_64.iso``). + +* ``iso_name``: The first part of the name of the resulting image (defaults to ``mkarchiso``) +* ``iso_label``: The ISO's volume label (defaults to ``MKARCHISO``) +* ``iso_publisher``: A free-form string that states the publisher of the resulting image (defaults to ``mkarchiso``) +* ``iso_application``: A free-form string that states the application (i.e. its use-case) of the resulting image (defaults + to ``mkarchiso iso``) +* ``iso_version``: A string that states the version of the resulting image (defaults to ``""``) +* ``install_dir``: A string (maximum eight characters long, which **must** consist of ``[a-z0-9]``) that states the + directory on the resulting image into which all files will be installed (defaults to ``mkarchiso``) +* ``buildmodes``: An optional list of strings, that state the build modes that the profile uses. Only the following are + understood: + + - ``bootstrap``: Build a compressed file containing a minimal system to bootstrap from + - ``iso``: Build a bootable ISO image (implicit default, if no ``buildmodes`` are set) + - ``netboot``: Build artifacts required for netboot using iPXE +* ``bootmodes``: A list of strings, that state the supported boot modes of the resulting image. Only the following are + understood: + + - ``bios.syslinux.mbr``: Syslinux for x86 BIOS booting from a disk + - ``bios.syslinux.eltorito``: Syslinux for x86 BIOS booting from an optical disc + - ``uefi-x64.systemd-boot.esp``: systemd-boot for x86_64 UEFI booting from a disk + - ``uefi-x64.systemd-boot.eltorito``: systemd-boot for x86_64 UEFI booting from an optical disc + Note that BIOS El Torito boot mode must always be listed before UEFI El Torito boot mode. +* ``arch``: The architecture (e.g. ``x86_64``) to build the image for. This is also used to resolve the name of the packages + file (e.g. ``packages.x86_64``) +* ``pacman_conf``: The ``pacman.conf`` to use to install packages to the work directory when creating the image (defaults to + the host's ``/etc/pacman.conf``) +* ``airootfs_image_type``: The image type to create. The following options are understood (defaults to ``squashfs``): + + - ``squashfs``: Create a squashfs image directly from the airootfs work directory + - ``ext4+squashfs``: Create an ext4 partition, copy the airootfs work directory to it and create a squashfs image from it + - ``erofs``: Create an EROFS image for the airootfs work directory +* ``airootfs_image_tool_options``: An array of options to pass to the tool to create the airootfs image. ``mksquashfs`` and + ``mkfs.erofs`` are supported. See ``mksquashfs --help`` or ``mkfs.erofs --help`` for all possible options +* ``file_permissions``: An associative array that lists files and/or directories who need specific ownership or + permissions. The array's keys contain the path and the value is a colon separated list of owner UID, owner GID and + access mode. E.g. ``file_permissions=(["/etc/shadow"]="0:0:400")``. When directories are listed with a trailing backslash (``/``) **all** files and directories contained within the listed directory will have the same owner UID, owner GID, and access mode applied recursively. + +bootstrap_packages.arch +======================= + +All packages to be installed into the environment of a bootstrap image have to be listed in an architecture specific +file (e.g. ``bootstrap_packages.x86_64``), which resides top-level in the profile. + +Packages have to be listed one per line. Lines starting with a ``#`` and blank lines are ignored. + +This file is required when generating bootstrap images using the ``bootstrap`` build mode. + +packages.arch +============= + +All packages to be installed into the environment of an ISO image have to be listed in an architecture specific file +(e.g. ``packages.x86_64``), which resides top-level in the profile. + +Packages have to be listed one per line. Lines starting with a ``#`` and blank lines are ignored. + + .. note:: + + The **mkinitcpio** and **mkinitcpio-archiso** packages are mandatory (see `#30 + <https://gitlab.archlinux.org/archlinux/archiso/-/issues/30>`_). + +This file is required when generating ISO images using the ``iso`` or ``netboot`` build modes. + +pacman.conf +=========== + +A configuration for pacman is required per profile. + +Some configuration options will not be used or will be modified: + +* ``CacheDir``: the profile's option is **only** used if it is not the default (i.e. ``/var/cache/pacman/pkg``) and if it is + not the same as the system's option. In all other cases the system's pacman cache is used. +* ``HookDir``: it is **always** set to the ``/etc/pacman.d/hooks`` directory in the work directory's airootfs to allow + modification via the profile and ensure interoparability with hosts using dracut (see `#73 + <https://gitlab.archlinux.org/archlinux/archiso/-/issues/73>`_) +* ``RootDir``: it is **always** removed, as setting it explicitely otherwise refers to the host's root filesystem (see + ``man 8 pacman`` for further information on the ``-r`` option used by ``pacstrap``) +* ``LogFile``: it is **always** removed, as setting it explicitely otherwise refers to the host's pacman log file (see + ``man 8 pacman`` for further information on the ``-r`` option used by ``pacstrap``) +* ``DBPath``: it is **always** removed, as setting it explicitely otherwise refers to the host's pacman database (see + ``man 8 pacman`` for further information on the ``-r`` option used by ``pacstrap``) + +airootfs +======== + +This optional directory may contain files and directories that will be copied to the work directory of the resulting +image's root filesystem. +The files are copied before packages are being installed to work directory location. +Ownership and permissions of files and directories from the profile's ``airootfs`` directory are not preserved. The mode +will be ``644`` for files and ``755`` for directories, all of them will be owned by root. To set custom ownership and/or +permissions, use ``file_permissions`` in ``profiledef.sh``. + +With this overlay structure it is possible to e.g. create users and set passwords for them, by providing +``airootfs/etc/passwd``, ``airootfs/etc/shadow``, ``airootfs/etc/gshadow`` (see ``man 5 passwd``, ``man 5 shadow`` and ``man 5 gshadow`` respectively). +If user home directories exist in the profile's ``airootfs``, their ownership and (and top-level) permissions will be +altered according to the provided information in the password file. + +Boot loader configuration +========================= + +A profile may contain configuration for several boot loaders. These reside in specific top-level directories, which are +explained in the following subsections. + +The following *custom template identifiers* are understood and will be replaced according to the assignments of the +respective variables in ``profiledef.sh``: + +* ``%ARCHISO_LABEL%``: Set this using the ``iso_label`` variable in ``profiledef.sh``. +* ``%INSTALL_DIR%``: Set this using the ``iso_label`` variable in ``profiledef.sh``. +* ``%ARCH%``: Set this using the ``arch`` variable in ``profiledef.sh``. + + +efiboot +------- + +This directory is mandatory when the ``uefi-x64.systemd-boot.esp`` or ``uefi-x64.systemd-boot.eltorito`` bootmodes are +selected in ``profiledef.sh``. It contains configuration for `systemd-boot +<https://www.freedesktop.org/wiki/Software/systemd/systemd-boot/>`_. + + .. note:: + + The directory is a top-level representation of the systemd-boot configuration directories and files found in the + root of an EFI system partition. + +The *custom template identifiers* are **only** understood in the boot loader entry `.conf` files (i.e. **not** in +``loader.conf``). + +syslinux +-------- + +This directory is mandatory when the ``bios.syslinux.mbr`` or the ``bios.syslinux.eltorito`` bootmodes are selected in +``profiledef.sh``. +It contains configuration files for `syslinux <https://wiki.syslinux.org/wiki/index.php?title=SYSLINUX>`_ or `isolinux +<https://wiki.syslinux.org/wiki/index.php?title=ISOLINUX>`_ , or `pxelinux +<https://wiki.syslinux.org/wiki/index.php?title=PXELINUX>`_ used in the resuling image. + +The *custom template identifiers* are understood in all `.cfg` files in this directory. diff --git a/docs/README.transfer b/docs/README.transfer index 2bb2b3d..aed5f92 100644 --- a/docs/README.transfer +++ b/docs/README.transfer @@ -13,7 +13,7 @@ INDEX *** Transfer ISO image to target medium (configs/releng) -ISO images names consist of: archlinux-<YYYY>.<MM>.<DD>-i686.iso +ISO images names consist of: archlinux32-<YYYY>.<MM>.<DD>-i686.iso Where: <YYYY> Year @@ -34,7 +34,7 @@ Nomeclature: 1) Write it directly using your favorite recording program. -# cdrecord dev=<B>,<T>,<L> -dao archlinux-<YYYY>.<MM>.<DD>-i686.iso +# cdrecord dev=<B>,<T>,<L> -dao archlinux32-<YYYY>.<MM>.<DD>-i686.iso ** To -> USB Flash Drive (USB-key) / Memory card (SD) / @@ -53,8 +53,8 @@ Nomeclature: (example: /dev/sdx1) <MNT-TARGET-N>: Mount point path where <DEV-TARGET-N> is mounted (example: /mnt/sdx/1) -<ISO-SOURCE>: Path to the ISO file archlinux-<YYYY>.<MM>.<DD>-i686.iso - (example: ~/archlinux-2017.03.01-i686.iso) +<ISO-SOURCE>: Path to the ISO file archlinux32-<YYYY>.<MM>.<DD>-i686.iso + (example: ~/archlinux32-2017.03.01-i686.iso) <FS-LABEL>: Represents the filesystem label of the <ISO-SOURCE> (example: ARCH_201703) diff --git a/scripts/run_archiso.sh b/scripts/run_archiso.sh index 210246c..6ddce15 100755 --- a/scripts/run_archiso.sh +++ b/scripts/run_archiso.sh @@ -15,117 +15,131 @@ set -eu print_help() { - cat << EOF + local usagetext + IFS='' read -r -d '' usagetext <<EOF || true Usage: run_archiso [options] Options: - -b set boot type to 'bios' (default) + -a set accessibility support using brltty + -b set boot type to 'BIOS' (default) + -d set image type to hard disk instead of optical disc -h print help -i [image] image to boot into - -s use secure boot (only relevant when using UEFI) - -u set boot type to 'uefi' + -s use Secure Boot (only relevant when using UEFI) + -u set boot type to 'UEFI' + -v use VNC display (instead of default SDL) + -c [image] attach an additional optical disc image (e.g. for cloud-init) Example: Run an image using UEFI: $ run_archiso -u -i archiso-2020.05.23-x86_64.iso EOF + printf '%s' "${usagetext}" } cleanup_working_dir() { - if [ -d "${working_dir}" ]; then - rm -rf "${working_dir}" + if [[ -d "${working_dir}" ]]; then + rm -rf -- "${working_dir}" fi } copy_ovmf_vars() { - if [ ! -f /usr/share/edk2-ovmf/x64/OVMF_VARS.fd ]; then - echo "ERROR: OVMF_VARS.fd not found. Install edk2-ovmf." + if [[ ! -f '/usr/share/edk2-ovmf/x64/OVMF_VARS.fd' ]]; then + printf 'ERROR: %s\n' "OVMF_VARS.fd not found. Install edk2-ovmf." exit 1 fi - cp -av /usr/share/edk2-ovmf/x64/OVMF_VARS.fd "${working_dir}" + cp -av -- '/usr/share/edk2-ovmf/x64/OVMF_VARS.fd' "${working_dir}/" } check_image() { - if [ -z "$image" ]; then - echo "ERROR: Image name can not be empty." + if [[ -z "$image" ]]; then + printf 'ERROR: %s\n' "Image name can not be empty." exit 1 fi - if [ ! -f "$image" ]; then - echo "ERROR: Image file ($image) does not exist." + if [[ ! -f "$image" ]]; then + printf 'ERROR: %s\n' "Image file (${image}) does not exist." exit 1 fi } run_image() { - [ "$boot_type" == "bios" ] && run_image_using_bios - [ "$boot_type" == "uefi" ] && run_image_using_uefi -} + if [[ "$boot_type" == 'uefi' ]]; then + copy_ovmf_vars + if [[ "${secure_boot}" == 'on' ]]; then + printf '%s\n' 'Using Secure Boot' + local ovmf_code='/usr/share/edk2-ovmf/x64/OVMF_CODE.secboot.fd' + else + local ovmf_code='/usr/share/edk2-ovmf/x64/OVMF_CODE.fd' + fi + qemu_options+=( + '-drive' "if=pflash,format=raw,unit=0,file=${ovmf_code},read-only=on" + '-drive' "if=pflash,format=raw,unit=1,file=${working_dir}/OVMF_VARS.fd" + '-global' "driver=cfi.pflash01,property=secure,value=${secure_boot}" + ) + fi -run_image_using_bios() { - qemu-system-x86_64 \ - -boot order=d,menu=on,reboot-timeout=5000 \ - -m size=3072,slots=0,maxmem=$((3072*1024*1024)) \ - -k en \ - -name archiso,process=archiso_0 \ - -drive file="${image}",media=cdrom,readonly=on,if=virtio \ - -display sdl \ - -vga virtio \ - -device virtio-net-pci,netdev=net0 -netdev user,id=net0 \ - -enable-kvm \ - -no-reboot -} + if [[ "${accessibility}" == 'on' ]]; then + qemu_options+=( + '-chardev' 'braille,id=brltty' + '-device' 'usb-braille,id=usbbrl,chardev=brltty' + ) + fi -run_image_using_uefi() { - local ovmf_code=/usr/share/edk2-ovmf/x64/OVMF_CODE.fd - local secure_boot_state=off - copy_ovmf_vars - if [ "${secure_boot}" == "yes" ]; then - echo "Using Secure Boot" - ovmf_code=/usr/share/edk2-ovmf/x64/OVMF_CODE.secboot.fd - secure_boot_state=on + if [[ -n "${oddimage}" ]]; then + qemu_options+=( + '-device' 'scsi-cd,bus=scsi0.0,drive=cdrom1' + '-drive' "id=cdrom1,if=none,format=raw,media=cdrom,read-only=on,file=${oddimage}" + ) fi + qemu-system-x86_64 \ -boot order=d,menu=on,reboot-timeout=5000 \ - -m size=3072,slots=0,maxmem=$((3072*1024*1024)) \ - -k en \ + -m "size=3072,slots=0,maxmem=$((3072*1024*1024))" \ + -k en-us \ -name archiso,process=archiso_0 \ - -drive file="${image}",media=cdrom,readonly=on,if=virtio \ - -drive if=pflash,format=raw,unit=0,file="${ovmf_code}",readonly \ - -drive if=pflash,format=raw,unit=1,file="${working_dir}/OVMF_VARS.fd" \ - -machine type=q35,smm=on,accel=kvm \ - -global driver=cfi.pflash01,property=secure,value="${secure_boot_state}" \ - -global ICH9-LPC.disable_s3=1 \ - -display sdl \ + -device virtio-scsi-pci,id=scsi0 \ + -device "scsi-${mediatype%rom},bus=scsi0.0,drive=${mediatype}0" \ + -drive "id=${mediatype}0,if=none,format=raw,media=${mediatype/hd/disk},read-only=on,file=${image}" \ + -display "${display}" \ -vga virtio \ - -device virtio-net-pci,netdev=net0 -netdev user,id=net0 \ + -audiodev pa,id=snd0 \ + -device ich9-intel-hda \ + -device hda-output,audiodev=snd0 \ + -device virtio-net-pci,romfile=,netdev=net0 -netdev user,id=net0,hostfwd=tcp::60022-:22 \ + -machine type=q35,smm=on,accel=kvm,usb=on,pcspk-audiodev=snd0 \ + -global ICH9-LPC.disable_s3=1 \ -enable-kvm \ + "${qemu_options[@]}" \ + -serial stdio \ -no-reboot } -set_image() { - if [ -z "$image" ]; then - echo "ERROR: Image name can not be empty." - exit 1 - fi - if [ ! -f "$image" ]; then - echo "ERROR: Image ($image) does not exist." - exit 1 - fi - image="$1" -} - -image="" -boot_type="bios" -secure_boot="no" -working_dir="$(mktemp -d)" +image='' +oddimage='' +accessibility='' +boot_type='bios' +mediatype='cdrom' +secure_boot='off' +display='sdl' +qemu_options=() +working_dir="$(mktemp -dt run_archiso.XXXXXXXXXX)" trap cleanup_working_dir EXIT -if [ ${#@} -gt 0 ]; then - while getopts 'bhi:su' flag; do - case "${flag}" in +if (( ${#@} > 0 )); then + while getopts 'abc:dhi:suv' flag; do + case "$flag" in + a) + accessibility='on' + ;; b) - boot_type=bios + boot_type='bios' + ;; + c) + oddimage="$OPTARG" + ;; + d) + mediatype='hd' ;; h) print_help @@ -135,13 +149,17 @@ if [ ${#@} -gt 0 ]; then image="$OPTARG" ;; u) - boot_type=uefi + boot_type='uefi' ;; s) - secure_boot=yes + secure_boot='on' + ;; + v) + display='none' + qemu_options+=(-vnc 'vnc=0.0.0.0:0,vnc=[::]:0') ;; *) - echo "Error: Wrong option. Try 'run_archiso -h'." + printf '%s\n' "Error: Wrong option. Try 'run_archiso -h'." exit 1 ;; esac |