diff options
83 files changed, 2204 insertions, 1139 deletions
diff --git a/.editorconfig b/.editorconfig index 7bc540f..6ef3c82 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,6 +16,10 @@ charset = utf-8 indent_style = space indent_size = 4 max_line_length = 120 +# for shfmt +switch_case_indent = true +binary_next_line = true + [*.{yml,yaml}] end_of_line = lf @@ -32,3 +36,6 @@ trim_trailing_whitespace = true charset = utf-8 indent_style = space indent_size = 2 + +[Makefile] +indent_style = tab @@ -3,5 +3,10 @@ parabolaiso-*.tar.gz* work/ out/ *.iso +*.img +*.cer +*.crt +*.key +*.pem user-data meta-data diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..2c099c2 --- /dev/null +++ b/.mailmap @@ -0,0 +1,17 @@ +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 P. <megver83@parabola.nu> <megver83@hyperbola.info> +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/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..75aca74 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,11 @@ +# Suggest explicitly using -n in `[ $var ]` +enable=avoid-nullary-conditions + +# Suggest 'command -v' instead of 'which' +enable=deprecate-which + +# Suggest quoting variables without metacharacters +enable=quote-safe-variables + +# Require [[ and warn about [ in Bash/Ksh +enable=require-double-brackets diff --git a/AUTHORS.rst b/AUTHORS.rst index 9dc5520..f3da577 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -2,36 +2,60 @@ Archiso Authors =============== +* 2hexed <2hexed@protonmail.com> * Aaron Griffin <aaron@archlinux.org> * Adam Purkrt <adam@purkrt.net> * Alexander Epaneshnikov <aarnaarn2@gmail.com> +* Alexander Speshilov <speshuric@gmail.com> +* Anton Hvornum <anton@hvornum.se> +* Antonio V <crazysnob@live.it> * 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> +* Darren Ng <un1gfn@gmail.com> * David Runge <dvzrv@archlinux.org> * David Thurstenson <thurstylark@gmail.com> * Dieter Plaetinck <dieter@plaetinck.be> * Eli Schwartz <eschwartz@archlinux.org> +* Eric Toombs <567-ewtoombs@users.noreply.gitlab.archlinux.org> * Florian Pritz <bluewind@xinu.at> +* Francois Dupoux <fdupoux@users.sourceforge.net> * Gerardo Exequiel Pozzi <vmlinuz386@gmail.com> * Gerhard Brauer <gerbra@archlinux.de> +* Giancarlo Razzolini <grazzolini@archlinux.org> +* Howard Hicks <deimosian@gmail.com> * James Sitegen <jamesm.sitegen@gmail.com> +* Jonathan Liu <net147@gmail.com> +* Jonathon Fernyhough <jonathon@m2x.dev> * Justin Kromlinger <hashworks@archlinux.org> * Keshav Amburay <the.ridikulus.rat@gmail.com> +* Kristian Klausen <kristian@klausen.dk> * Loui Chang <louipc.ist@gmail.com> * Lukas Fleischer <archlinux@cryptocrack.de> * Martin Damian Fernandez <martin.damian.fernandez@gmail.com> +* Michael Gilchrist <michaelgilch@gmail.com> * Michael Vorburger <mike@vorburger.ch> +* Pellegrino Prevete <pellegrinoprevete@gmail.com> * Pierre Schmitz <pierre@archlinux.de> * Sean Enck <enckse@voidedtech.com> * Simo Leone <simo@archlinux.org> +* Simon Wilper <sxw@chronowerks.de> +* Sorin Pânca <sorin.panca@gmail.com> * Steffen Bönigk <boenki@gmx.de> * Sven-Hendrik Haase <svenstaro@gmail.com> * Thomas Bächler <thomas@archlinux.org> +* Tobias Powalowski <tpowa@archlinux.org> +* Tom Yan <tom.ty89@gmail.com> * Yu Li-Yu <afg984@gmail.com> +* Zig Globulin <zig@zigsystem.com> +* hayao <hayao@fascode.net> +* mono wock <aaronleemorrison@protonmail.com> * nl6720 <nl6720@gmail.com> +* plain linen <bcdedit@hotmail.com> +* shivanandvp <shivanandvp.oss@gmail.com> +* weltio weltio <weltio@web.de> * Øyvind Heggstad <heggstad@gmail.com> =================== @@ -39,11 +63,11 @@ Parabolaiso Authors =================== * Andreas Grapentin <andreas@grapentin.org> -* André Fabian Silva Delgado <emulatorman@parabola.nu> +* André Fabian Silva Delgado <emulatorman@hyperbola.info> * David P <megver83@parabola.nu> * Drtan Samos <drtan@lavabit.com> * Esteban Carnevale <alfplayer@mailoo.org> * Jorge Lopez <jorginho@riseup.net> * bill-auger <mr.j.spam.me@gmail.com> * chandan <cks071g2@gmail.com> -* Márcio Alexandre Silva Delgado <coadde@parabola.nu> +* Márcio Alexandre Silva Delgado <coadde@hyperbola.info> diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5f7c39d..b2f9dc3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,382 @@ Changelog ######### +[XX] - YYYY-MM-DD +================= + +Added +----- + +Changed +------- + +Deprecated +---------- + +Fixed +----- + +Removed +------- + +[74] - 2023-12-21 +================= + +Added +----- + +- Add bcachefs-tools to releng for access to bcachefs userspace tools. +- Add tftp as a valid protocol for downloading automated boot script. + +Changed +------- + +- Set ``RequiredForOnline=routable`` in systemd-networkd configuration files to improve the chances that the network + really is *online* when ``network-online.target`` is reached. + +Fixed +----- + +- Add missing replacement for the UUID variable in systemd-boot configuration files on ISO 9660. + +[73] - 2023-09-29 +================= + +Added +----- + +- Add bolt to releng for authorizing and otherwise managing Thunderbolt and USB4 devices. +- Add ``uefi-ia32.systemd-boot.esp`` and ``uefi-ia32.systemd-boot.eltorito`` boot modes that use systemd-boot for IA32 + UEFI. The boot modes of baseline and releng are not changed. +- Add GRUB configuration file ``/boot/grub/loopback.cfg`` to the releng and baseline profiles. It sets the necessary + boot parameters required for booting the ISO image as a file on a file system. + +Fixed +----- + +- Add ``/etc/localtime`` to the baseline profile to ensure the ISO can be booted successfully without triggering + questions from systemd-firstboot. + +[72] - 2023-08-29 +================= + +Added +----- + +- Add tpm2-tools to releng to allow clearing, creating and reading keys on the TPM. +- Add sequoia-sq and openpgp-card-tools as additional tooling for working with OpenPGP certificates and smartcards. + +Changed +------- + +- Moved custom ``mkinitcpio.conf`` files to ``/etc/mkinitcpio.conf.d/parabolaiso.conf``. +- Mount ``/etc/pacman.d/gnupg`` on tmpfs with option ``noswap`` instead of using ramfs. This ensures there is a limit to + the file system size. +- Enable systemd-networkd's support for IPv6 Privacy Extensions globally instead of per-connection. +- Moved custom ``sshd_config`` files to ``/ssh/sshd_config.d/10-parabolaiso.conf`` +- Use pcsclite for interfacing with smartcards, since both gnupg and opgpcard support it. + +Fixed +----- + +- Sign the root file system image only once. +- Make sure xorriso does not read its configuration files to prevent interference and unintended behavior. + +[71] - 2023-05-28 +================= + +Added +----- + +- Added classes for Memtest86+ and UEFI Shell menuentries. +- Add foot-terminfo and wezterm-terminfo packages to releng to support terminal emulators using them. E.g. when + installing via SSH. +- Add a new ``-r`` option to ``mkparabolaiso`` that deletes the working directly after the build. +- Add support for mDNS announce and resolve. + +Changed +------- + +- Increase EROFS compression for the baseline profile by using an extreme LZMA compression level and enabling the + experimental compressed fragments and data deduplication features. +- Identify the ISO volume via a UUID instead of a file system label in all boot loader configuration files. +- Update ``pacman.conf`` to match the one shipped with pacman 6.0.2-7 (from Arch) which removes the community repository. + +Fixed +----- + +- Wait for ``network-online.target`` to become active before trying to download the script passed via the ``script=`` + boot parameter. +- Subdirectories from ``grub/`` are copied to the ISO. +- Modify the commandline options to a ``cp`` command in ``mkparabolaiso`` so that the entire script does not exit with + failure when a custom ``.bashrc`` file is supplied with the parabolaiso configuration. This fix was needed after + **GNU Coreutils** recently changed the behaviour of the ``-n`` (or ``--no-clobber``) commandline option to the ``cp`` + command. +- Ensure ``SOURCE_DATE_EPOCH`` is read from the ``build_date`` file before ``profiledef.sh`` is sourced to ensure the + variable has a correct value when used inside ``profiledef.sh``. + + +[70] - 2023-02-27 +================= + +Added +----- + +- Support *file system transposition* to simplify boot medium preparation for UEFI boot via extracting the ISO image + contents to a drive. ``grub.cfg`` does not hardcode the ISO volume label anymore, instead GRUB will search for volume + with a ``/boot/grub/YYYY-mm-dd-HH-MM-SS-00.uuid`` file on it. +- Preload GRUB's NTFS modules for UEFI that allegedly have native NTFS support. GRUB's exFAT and UDF modules are also + preloaded in case someone finds them useful. + +Changed +------- + +- Identify the ISO volume via a UUID instead of a file system label to avoid collisions of multiple ISOs created in the + same month. +- Honor ``SOURCE_DATE_EPOCH`` in the ``date`` command used by ``profiledef.sh`` of the shipped profiles. +- Do not duplicate ``grub.cfg`` in both ISO 9660 and the EFI system partition / El Torito image. GRUB will search for + the ISO volume and load the ``grub.cfg`` from there. +- Moved GRUB files on ISO 9660 from ``/EFI/BOOT/`` to a boot-platform neutral place ``/boot/grub/``. This does not apply + to the EFI binaries that remain in the default/fallback boot path. +- Move ``grubenv`` to ``/boot/grub/grubenv`` on ISO 9660 so that it is together with the rest of GRUB-specific files. + Additionally write more variables in it. The previous ``/${install_dir}/grubenv`` (``/parabola/grubenv`` for releng) + is deprecated and a future parabolaiso release will not create this file anymore. +- Moved syslinux directory from ``/syslinux/`` to ``/boot/syslinux/`` to keep most boot loader files in ``/boot/``. +- Update ``README.transfer`` documentation and convert it to reStructuredText. +- Use ``console`` as grub's ``terminal_output``, as ``gfxterm`` leads to a blank screen on some hardware. + +Removed +------- + +- Do not place memtest86+ in netboot artifacts. + +[69] - 2022-12-24 +================= + +Added +----- + +- Add Memtest86+ to x86_64 UEFI GRUB boot menu. + +Changed +------- + +- Check if the GPG public key file was successfully placed in the work directory before trying to use it. +- Open the file descriptors for code signing certificates and GPG public key as read only. Nothing from the within the + ``pacstrap`` invoked chroot should ever be allowed to write outside of it. +- Error out early if any of the code signing certificate files passed with option ``-c`` do not exist. +- Use LZMA compressed EROFS image for the baseline profile. Now that xz 5.4 is out and erofs-utils is built with LZMA + support, using a higher compression is possible. +- Add ``/etc/machine-id`` with special value ``uninitialized``. The final id is generated at boot time, and systemd's + first-boot mechanim (see ``First Boot Semantics`` in ``machine-id(5)``) applies. No functional change unless that + ``ConditionFirstBoot=yes`` is true and passive unit ``first-boot-complete.target`` activates for ordering. + +[68] - 2022-10-30 +================= + +Changed +------- + +- Do not explicitly enable ``qemu-guest-agent.service`` as it will be started by a udev rule. +- Remove existing signature (``.sig``) files and do not sign them when signing netboot artifacts. This is mostly + applicable when re-running ``mkparabolaiso`` after a failure. +- Replace ``parabolaiso_kms`` with ``kms`` in ``mkinitcpio.conf``. The hook is available in mkinitcpio since version 32. + +[67] - 2022-09-25 +================= + +Added +----- + +- The ability to generate rootfs signatures using openssl CMS module if ``-c`` is given. + +Changed +------- + +- Order ``pacman-init.service`` before ``archlinux-keyring-wkd-sync.service`` since + ``archlinux-keyring-wkd-sync.service`` needs an initialized pacman keyring. +- Order ``pacman-init.service`` after ``time-sync.target`` since ``pacman-init.service`` may otherwise create local + signatures that are not valid on target systems after installation. + +[66] - 2022-08-28 +================= + +Added +----- + +- Add ``efibootimg`` to ``mkarchiso`` to abstract the FAT image path. +- Unset ``LANGUAGE`` since ``LC_ALL=C.UTF-8``, unlike ``LC_ALL=C``, does not override ``LANGUAGE``. +- Copy all files from the ``grub`` directory to ISO9660 and the FAT image, not just only ``grub.cfg``. +- Touching ``/usr/lib/clock-epoch`` to to help ``systemd`` with screwed or broken RTC. + +Changed +------- + +- Disable GRUB's shim_lock verifier and preload more modules. This allows reusing the GRUB EFI binaries when repacking + the ISO to support Secure Boot with custom signatures. + +[65] - 2022-06-30 +================= + +Added +----- + +- Configure the locale for the baseline profile to ``C.UTF-8`` so that a UTF-8 locale is used. +- Add ``uefi-x64.grub.esp`` and ``uefi-x64.grub.eltorito`` boot mode to support x86_64 UEFI boot on x86_64 machines. +- Use ``mkfs.erofs``'s ``ztailpacking`` option in the baseline profile to reduce the image size. + +Changed +------- + +- Change the releng profile's locale from ``en_US.UTF-8`` to ``C.UTF-8``. +- Set ``LC_ALL`` to ``C.UTF-8`` instead of ``C`` in mkparabolaiso since it is now available and non-UTF-8 locales should be + avoided. + +Removed +------- + +- Remove the custom pacman hook that ran ``locale-gen`` on glibc install from the releng profile. The used locale now + ships with the glibc package itself. +- Remove "Copy to RAM" boot entries since the ``parabolaiso`` mkinitcpio hook enables it automatically when there is enough + free RAM. +- Drop parabolaiso rEFInd support in favor of upstream archiso GRUB EFI bootmode. + +[64] - 2022-05-30 +================= + +Added +----- + +- Add ``uefi-ia32.grub.esp`` boot mode to support IA32 UEFI boot on x86_64 machines. +- Add GRUB configuration files to profiles. +- Add accessible ``copytoram`` entry. +- Enable beeps in systemd-boot menu. + +Changed +------- + +- Fix systemd-boot menu entry sorting by using the ``sort-key`` option. + +[63] - 2022-04-30 +================= + +Added +----- + +- Add dmidecode to the list of packages in the releng profile. +- Add open-iscsi to the list of packages in the releng profile to allow installing Parabola on an iSCSI target. +- Add hyperv to the list of packages and enable its services to provide better integration with the + Hyper-V hypervisor. + +Changed +------- + +- Mount /etc/pacman.d/gnupg on ramfs instead of tmpfs to ensure its contents never land in swap. +- Configure reflector to return only mirrors that support both IPv4 and IPv6. + +[62.1] - 2022-04-05 +=================== + +Removed +------- + +- Easter egg + +[62] - 2022-03-31 +================= + +Changed +------- + +- Fix the PXE support. PXELINUX was having trouble finding the kernel and initrds. Now, archiso forces syslinux to + interpret all TFTP paths as absolute. That seems to have solved the issue. +- Disable systemd-gpt-auto-generator, which we do not need, in both baseline and releng profiles. It avoids the error + message about it failing during boot. +- Register qemu-arm-static if it is not already, rather than suggesting installing an extra package. + +[61] - 2022-01-31 +================= + +Added +----- + +- Add documentation to systemd-networkd configuration files +- Add information about the use of changelog and merge requests to the contributing guidelines + +Changed +------- + +- Fix an issue where mkparabolaiso is failing to raise an error when the ``mmd`` and ``mcopy`` commands are not found +- Fix an issue where the architecture detection in mkparabolaiso fails due to an unset ``arch`` variable in the profile + +Removed +------- + +[60] - 2021-12-28 +================= + +Added +----- + +Changed +------- + +- Show a more descriptive message when no code signing certificate is used + +Removed +------- + +- Remove unused parabolaiso_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 +- Add armv7h support for bootstrap buildmode + +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 +- Borrow some code from librechroot to correctly validate binfmt +- Do not check if qemu-user-static is installed, just check for qemu-user-static-binfmt as it will pull it as dependency + +Removed +------- + +- Remove all files related to ``mkinitcpio`` integration, as they now live in + https://gitlab.archlinux.org/archlinux/mkinitcpio/mkinitcpio-archiso + [57] - 2021-07-30 ================= diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 53ee73a..9ad94ad 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -19,6 +19,28 @@ All ash and bash scripts are linted using shellcheck: make lint +Changelog +========= + +When adding, changing or removing something in a merge request, add a sentence to the `CHANGELOG.rst <CHANGELOG.rst>`_ +explaining it. +The changelog entry needs to be added to the unreleased section at the top, as that section is used for the next +release. + +Merge requests and signed commits +================================= + +Merge requests are not required to contain signed commits (using ``git commit -S`` - see `man 1 git-commit +<https://man.archlinux.org/man/git-commit.1>`_). +The project maintainers may rebase a given merge request branch at their discretion (if possible), which may remove +signed commits. + +The tip of the project's default branch is required to be a signed commit by the project maintainers. +For external contributors this means, that their merge request will be merged using ``--no-ff`` (see `man 1 git-merge +<https://man.archlinux.org/man/git-merge.1>`_) in a signed merge commit, while contributions by the project maintainers +may be merged using ``--ff`` when the top-most commit of the source branch is signed by a valid PGP key of the given +maintainer. + Testing ======= @@ -18,6 +18,7 @@ The following packages need to be installed to be able to create an image with t * e2fsprogs * erofs-utils (optional) * findutils +* grub * gzip * libarchive * libisoburn @@ -127,8 +128,9 @@ The iso image contains a GRUB environment block holding the iso name and version boot the iso image from GRUB with a version specific cow directory to mitigate overlay clashes. .. code:: sh + loopback loop parabola.iso - load_env -f (loop)/parabola/grubenv + load_env -f (loop)/boot/grub/grubenv linux (loop)/parabola/boot/x86_64/vmlinuz-linux-libre ... \ cow_directory=parabola/${VERSION} ... initrd (loop)/parabola/boot/x86_64/initramfs-linux-libre-lts.img @@ -150,16 +152,23 @@ All past and present authors of parabolaiso are listed in `AUTHORS <AUTHORS.rst> Releases ======== -`Releases of parabolaiso <https://git.parabola.nu/parabolaiso.git/refs/tags>`_ are created by its current maintainer -`David P <https://www.parabola.nu/people/hackers/#megver83>`_. Tags are signed using the PGP key with the ID -``6DB9C4B4F0D8C0DC432CF6E4227CA7C556B2BA78``. +`Releases of parabolaiso <https://git.parabola.nu/parabolaiso.git/refs/tags>`_ are created by their current maintainers + +- `David P <https://www.parabola.nu/people/hackers/#megver83>`_ (``6DB9C4B4F0D8C0DC432CF6E4227CA7C556B2BA78``) + +Tags are signed using respective PGP keys. -To verify a tag, first import the relevant PGP key: +To verify a tag, first import the relevant PGP key(s): .. code:: sh gpg --auto-key-locate wkd --search-keys megver83@parabola.nu +or + +.. code:: sh + + gpg --auto-key-locate keyserver --recv-keys 6DB9C4B4F0D8C0DC432CF6E4227CA7C556B2BA78 Afterwards a tag can be verified from a clone of this repository: diff --git a/configs/baseline/airootfs/etc/locale.conf b/configs/baseline/airootfs/etc/locale.conf new file mode 100644 index 0000000..f9c983c --- /dev/null +++ b/configs/baseline/airootfs/etc/locale.conf @@ -0,0 +1 @@ +LANG=C.UTF-8 diff --git a/configs/baseline/airootfs/etc/localtime b/configs/baseline/airootfs/etc/localtime Binary files differnew file mode 100644 index 0000000..91558be --- /dev/null +++ b/configs/baseline/airootfs/etc/localtime diff --git a/configs/baseline/airootfs/etc/mkinitcpio.conf b/configs/baseline/airootfs/etc/mkinitcpio.conf deleted file mode 100644 index 9a851c9..0000000 --- a/configs/baseline/airootfs/etc/mkinitcpio.conf +++ /dev/null @@ -1,67 +0,0 @@ -# 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 parabolaiso 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.conf.d/parabolaiso.conf b/configs/baseline/airootfs/etc/mkinitcpio.conf.d/parabolaiso.conf new file mode 100644 index 0000000..9d4877e --- /dev/null +++ b/configs/baseline/airootfs/etc/mkinitcpio.conf.d/parabolaiso.conf @@ -0,0 +1 @@ +HOOKS=(base udev modconf parabolaiso block filesystems) diff --git a/configs/baseline/airootfs/etc/mkinitcpio.d/linux-libre.preset b/configs/baseline/airootfs/etc/mkinitcpio.d/linux-libre.preset index 625a03d..282bcde 100644 --- a/configs/baseline/airootfs/etc/mkinitcpio.d/linux-libre.preset +++ b/configs/baseline/airootfs/etc/mkinitcpio.d/linux-libre.preset @@ -3,6 +3,6 @@ PRESETS=('parabolaiso') ALL_kver='/boot/vmlinuz-linux-libre' -ALL_config='/etc/mkinitcpio.conf' +parabolaiso_config='/etc/mkinitcpio.conf.d/parabolaiso.conf' parabolaiso_image="/boot/initramfs-linux-libre.img" diff --git a/configs/baseline/airootfs/etc/ssh/sshd_config b/configs/baseline/airootfs/etc/ssh/sshd_config deleted file mode 100644 index 93f7d63..0000000 --- a/configs/baseline/airootfs/etc/ssh/sshd_config +++ /dev/null @@ -1,116 +0,0 @@ -# $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/baseline/airootfs/etc/ssh/sshd_config.d/10-parabolaiso.conf b/configs/baseline/airootfs/etc/ssh/sshd_config.d/10-parabolaiso.conf new file mode 100644 index 0000000..6ea7b41 --- /dev/null +++ b/configs/baseline/airootfs/etc/ssh/sshd_config.d/10-parabolaiso.conf @@ -0,0 +1,3 @@ +# Allow root login using password authentication +PasswordAuthentication yes +PermitRootLogin yes diff --git a/configs/baseline/airootfs/etc/systemd/network.conf.d/ipv6-privacy-extensions.conf b/configs/baseline/airootfs/etc/systemd/network.conf.d/ipv6-privacy-extensions.conf new file mode 100644 index 0000000..0e9ceb4 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/network.conf.d/ipv6-privacy-extensions.conf @@ -0,0 +1,2 @@ +[Network] +IPv6PrivacyExtensions=yes diff --git a/configs/baseline/airootfs/etc/systemd/network/20-ethernet.network b/configs/baseline/airootfs/etc/systemd/network/20-ethernet.network index e8842f2..0e4287b 100644 --- a/configs/baseline/airootfs/etc/systemd/network/20-ethernet.network +++ b/configs/baseline/airootfs/etc/systemd/network/20-ethernet.network @@ -1,7 +1,13 @@ [Match] +# Matching with "Type=ether" causes issues with containers because it also matches virtual Ethernet interfaces (veth*). +# See https://bugs.archlinux.org/task/70892 +# Instead match by globbing the network interface name. Name=en* Name=eth* +[Link] +RequiredForOnline=routable + [Network] DHCP=yes -IPv6PrivacyExtensions=yes +MulticastDNS=yes diff --git a/configs/baseline/airootfs/etc/systemd/resolved.conf.d/parabolaiso.conf b/configs/baseline/airootfs/etc/systemd/resolved.conf.d/parabolaiso.conf new file mode 100644 index 0000000..5d64185 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/resolved.conf.d/parabolaiso.conf @@ -0,0 +1,4 @@ +# Default systemd-resolved configuration for parabolaiso + +[Resolve] +MulticastDNS=yes diff --git a/configs/baseline/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator b/configs/baseline/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator new file mode 120000 index 0000000..dc1dc0c --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator @@ -0,0 +1 @@ +/dev/null
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_fcopy_daemon.service b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_fcopy_daemon.service new file mode 120000 index 0000000..20ac7b2 --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_fcopy_daemon.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/hv_fcopy_daemon.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_kvp_daemon.service b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_kvp_daemon.service new file mode 120000 index 0000000..a7eac4a --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_kvp_daemon.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/hv_kvp_daemon.service
\ No newline at end of file diff --git a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_vss_daemon.service b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_vss_daemon.service new file mode 120000 index 0000000..eae19ef --- /dev/null +++ b/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/hv_vss_daemon.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/hv_vss_daemon.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 deleted file mode 120000 index 8e3ff80..0000000 --- a/configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/qemu-guest-agent.service +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/systemd/system/qemu-guest-agent.service
\ No newline at end of file diff --git a/configs/baseline/efiboot/loader/entries/01-parabolaiso-x86_64-linux-libre.conf b/configs/baseline/efiboot/loader/entries/01-parabolaiso-x86_64-linux-libre.conf index e89de03..dcfa3a9 100644 --- a/configs/baseline/efiboot/loader/entries/01-parabolaiso-x86_64-linux-libre.conf +++ b/configs/baseline/efiboot/loader/entries/01-parabolaiso-x86_64-linux-libre.conf @@ -1,4 +1,4 @@ title Parabola GNU/Linux-libre (x86_64, UEFI) linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -options parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% +options parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% diff --git a/configs/baseline/efiboot/loader/entries/02-parabolaiso-x86_64-ram-linux-libre.conf b/configs/baseline/efiboot/loader/entries/02-parabolaiso-x86_64-ram-linux-libre.conf deleted file mode 100644 index 630af00..0000000 --- a/configs/baseline/efiboot/loader/entries/02-parabolaiso-x86_64-ram-linux-libre.conf +++ /dev/null @@ -1,4 +0,0 @@ -title Parabola GNU/Linux-libre (x86_64, UEFI) Copy to RAM -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -options parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% copytoram diff --git a/configs/baseline/grub/grub.cfg b/configs/baseline/grub/grub.cfg new file mode 100644 index 0000000..540ba68 --- /dev/null +++ b/configs/baseline/grub/grub.cfg @@ -0,0 +1,104 @@ +# Load partition table and file system modules +insmod part_gpt +insmod part_msdos +insmod fat +insmod iso9660 +insmod ntfs +insmod ntfscomp +insmod exfat +insmod udf + +# Use graphics-mode output +if loadfont "${prefix}/fonts/unicode.pf2" ; then + insmod all_video + set gfxmode="auto" + terminal_input console + terminal_output console +fi + +# Enable serial console +insmod serial +insmod usbserial_common +insmod usbserial_ftdi +insmod usbserial_pl2303 +insmod usbserial_usbdebug +if serial --unit=0 --speed=115200; then + terminal_input --append serial + terminal_output --append serial +fi + +# Search for the ISO volume +if [ -z "${PARABOLAISO_UUID}" ]; then + if [ -z "${PARABOLAISO_HINT}" ]; then + regexp --set=1:PARABOLAISO_HINT '^\(([^)]+)\)' "${cmdpath}" + fi + search --no-floppy --set=root --file '%PARABOLAISO_SEARCH_FILENAME%' --hint "${PARABOLAISO_HINT}" + probe --set PARABOLAISO_UUID --fs-uuid "${root}" +fi + +# Get a human readable platform identifier +if [ "${grub_platform}" == 'efi' ]; then + parabolaiso_platform='UEFI' + if [ "${grub_cpu}" == 'x86_64' ]; then + parabolaiso_platform="x64 ${parabolaiso_platform}" + elif [ "${grub_cpu}" == 'i386' ]; then + parabolaiso_platform="IA32 ${parabolaiso_platform}" + else + parabolaiso_platform="${grub_cpu} ${parabolaiso_platform}" + fi +elif [ "${grub_platform}" == 'pc' ]; then + parabolaiso_platform='BIOS' +else + parabolaiso_platform="${grub_cpu} ${grub_platform}" +fi + +# Set default menu entry +default=parabola +timeout=15 +timeout_style=menu + +# Menu entries + +menuentry "Parabola GNU/Linux-libre (%ARCH%, ${parabolaiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'parabola' { + set gfxpayload=keep + linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-libre parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=${PARABOLAISO_UUID} + initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-libre.img +} + +if [ "${grub_platform}" == 'efi' -a "${grub_cpu}" == 'x86_64' -a -f '/boot/memtest86+/memtest.efi' ]; then + menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class gnu --class tool { + set gfxpayload=800x600,1024x768 + linux /boot/memtest86+/memtest.efi + } +fi +if [ "${grub_platform}" == 'pc' -a -f '/boot/memtest86+/memtest' ]; then + menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class gnu --class tool { + set gfxpayload=800x600,1024x768 + linux /boot/memtest86+/memtest + } +fi +if [ "${grub_platform}" == 'efi' ]; then + if [ "${grub_cpu}" == 'x86_64' -a -f '/shellx64.efi' ]; then + menuentry 'UEFI Shell' { + chainloader /shellx64.efi + } + elif [ "${grub_cpu}" == "i386" -a -f '/shellia32.efi' ]; then + menuentry 'UEFI Shell' { + chainloader /shellia32.efi + } + fi + + menuentry 'UEFI Firmware Settings' --id 'uefi-firmware' { + fwsetup + } +fi + +menuentry 'System shutdown' --class shutdown --class poweroff { + echo 'System shutting down...' + halt +} + +menuentry 'System restart' --class reboot --class restart { + echo 'System rebooting...' + reboot +} diff --git a/configs/baseline/grub/loopback.cfg b/configs/baseline/grub/loopback.cfg new file mode 100644 index 0000000..149c879 --- /dev/null +++ b/configs/baseline/grub/loopback.cfg @@ -0,0 +1,73 @@ +# https://www.supergrubdisk.org/wiki/Loopback.cfg + +# Search for the ISO volume +search --no-floppy --set=parabolaiso_img_dev --file "${iso_path}" +probe --set parabolaiso_img_dev_uuid --fs-uuid "${parabolaiso_img_dev}" + +# Get a human readable platform identifier +if [ "${grub_platform}" == 'efi' ]; then + parabolaiso_platform='UEFI' + if [ "${grub_cpu}" == 'x86_64' ]; then + parabolaiso_platform="x64 ${parabolaiso_platform}" + elif [ "${grub_cpu}" == 'i386' ]; then + parabolaiso_platform="IA32 ${parabolaiso_platform}" + else + parabolaiso_platform="${grub_cpu} ${parabolaiso_platform}" + fi +elif [ "${grub_platform}" == 'pc' ]; then + parabolaiso_platform='BIOS' +else + parabolaiso_platform="${grub_cpu} ${grub_platform}" +fi + +# Set default menu entry +default=parabola +timeout=15 +timeout_style=menu + + +# Menu entries + +menuentry "Parabola GNU/Linux-libre (%ARCH%, ${parabolaiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'parabola' { + set gfxpayload=keep + linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-libre parabolaisobasedir=%INSTALL_DIR% img_dev=UUID=${parabolaiso_img_dev_uuid} img_loop="${iso_path}" + initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-libre.img +} + +if [ "${grub_platform}" == 'efi' -a "${grub_cpu}" == 'x86_64' -a -f '/boot/memtest86+/memtest.efi' ]; then + menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class gnu --class tool { + set gfxpayload=800x600,1024x768 + linux /boot/memtest86+/memtest.efi + } +fi +if [ "${grub_platform}" == 'pc' -a -f '/boot/memtest86+/memtest' ]; then + menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class gnu --class tool { + set gfxpayload=800x600,1024x768 + linux /boot/memtest86+/memtest + } +fi +if [ "${grub_platform}" == 'efi' ]; then + if [ "${grub_cpu}" == 'x86_64' -a -f '/shellx64.efi' ]; then + menuentry 'UEFI Shell' { + chainloader /shellx64.efi + } + elif [ "${grub_cpu}" == "i386" -a -f '/shellia32.efi' ]; then + menuentry 'UEFI Shell' { + chainloader /shellia32.efi + } + fi + + menuentry 'UEFI Firmware Settings' --id 'uefi-firmware' { + fwsetup + } +fi + +menuentry 'System shutdown' --class shutdown --class poweroff { + echo 'System shutting down...' + halt +} + +menuentry 'System restart' --class reboot --class restart { + echo 'System rebooting...' + reboot +} diff --git a/configs/baseline/packages.x86_64 b/configs/baseline/packages.x86_64 index 92d9da2..23eb008 100644 --- a/configs/baseline/packages.x86_64 +++ b/configs/baseline/packages.x86_64 @@ -1,5 +1,6 @@ base cloud-init +hyperv linux-libre mkinitcpio mkinitcpio-parabolaiso diff --git a/configs/baseline/pacman.conf b/configs/baseline/pacman.conf index 7bcfccb..59821bc 100644 --- a/configs/baseline/pacman.conf +++ b/configs/baseline/pacman.conf @@ -77,21 +77,12 @@ LocalFileSigLevel = Optional [libre] Include = /etc/pacman.d/mirrorlist -#[testing] -#Include = /etc/pacman.d/mirrorlist - [core] Include = /etc/pacman.d/mirrorlist [extra] Include = /etc/pacman.d/mirrorlist -#[community-testing] -#Include = /etc/pacman.d/mirrorlist - -[community] -Include = /etc/pacman.d/mirrorlist - #[pcr-testing] #Include = /etc/pacman.d/mirrorlist diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh index 19b003a..7c35814 100644 --- a/configs/baseline/profiledef.sh +++ b/configs/baseline/profiledef.sh @@ -2,17 +2,19 @@ # shellcheck disable=SC2034 iso_name="parabola-baseline" -iso_label="PARA_$(date +%Y%m)" +iso_label="PARA_$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y%m)" iso_publisher="Parabola GNU/Linux-libre <https://parabola.nu>" iso_application="Parabola GNU/Linux-libre baseline" -iso_version="$(date +%Y.%m.%d)" +iso_version="$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y.%m.%d)" install_dir="parabola" buildmodes=('iso') -bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' 'uefi-x64.systemd-boot.esp' 'uefi-x64.systemd-boot.eltorito') +bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' + 'uefi-ia32.grub.esp' 'uefi-x64.systemd-boot.esp' + 'uefi-ia32.grub.eltorito' 'uefi-x64.systemd-boot.eltorito') arch="x86_64" pacman_conf="pacman.conf" airootfs_image_type="erofs" -airootfs_image_tool_options=('-zlz4hc,12') +airootfs_image_tool_options=('-zlzma,109' -E 'ztailpacking,fragments,dedupe') file_permissions=( ["/etc/shadow"]="0:0:400" ) diff --git a/configs/baseline/syslinux/syslinux-linux-libre.cfg b/configs/baseline/syslinux/syslinux-linux-libre.cfg index 47ac1e7..458bfe4 100644 --- a/configs/baseline/syslinux/syslinux-linux-libre.cfg +++ b/configs/baseline/syslinux/syslinux-linux-libre.cfg @@ -2,10 +2,4 @@ LABEL parabola MENU LABEL Parabola GNU/Linux-libre (x86_64, BIOS) LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-libre INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% - -LABEL parabola-ram -MENU LABEL Parabola GNU/Linux-libre (x86_64, BIOS) Copy to RAM -LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-libre -INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% copytoram +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% diff --git a/configs/releng/airootfs/etc/locale.conf b/configs/releng/airootfs/etc/locale.conf index 01ec548..f9c983c 100644 --- a/configs/releng/airootfs/etc/locale.conf +++ b/configs/releng/airootfs/etc/locale.conf @@ -1 +1 @@ -LANG=en_US.UTF-8 +LANG=C.UTF-8 diff --git a/configs/releng/airootfs/etc/mkinitcpio.conf b/configs/releng/airootfs/etc/mkinitcpio.conf deleted file mode 100644 index 34645b9..0000000 --- a/configs/releng/airootfs/etc/mkinitcpio.conf +++ /dev/null @@ -1,67 +0,0 @@ -# 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 parabolaiso_shutdown parabolaiso parabolaiso_loop_mnt parabolaiso_pxe_common parabolaiso_pxe_nbd parabolaiso_pxe_http parabolaiso_pxe_nfs parabolaiso_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.conf.d/parabolaiso.conf b/configs/releng/airootfs/etc/mkinitcpio.conf.d/parabolaiso.conf new file mode 100644 index 0000000..26c74ea --- /dev/null +++ b/configs/releng/airootfs/etc/mkinitcpio.conf.d/parabolaiso.conf @@ -0,0 +1,2 @@ +HOOKS=(base udev modconf kms memdisk parabolaiso parabolaiso_loop_mnt parabolaiso_pxe_common parabolaiso_pxe_nbd parabolaiso_pxe_http parabolaiso_pxe_nfs block filesystems keyboard) +COMPRESSION="xz" diff --git a/configs/releng/airootfs/etc/mkinitcpio.d/linux-libre.preset b/configs/releng/airootfs/etc/mkinitcpio.d/linux-libre.preset index 625a03d..282bcde 100644 --- a/configs/releng/airootfs/etc/mkinitcpio.d/linux-libre.preset +++ b/configs/releng/airootfs/etc/mkinitcpio.d/linux-libre.preset @@ -3,6 +3,6 @@ PRESETS=('parabolaiso') ALL_kver='/boot/vmlinuz-linux-libre' -ALL_config='/etc/mkinitcpio.conf' +parabolaiso_config='/etc/mkinitcpio.conf.d/parabolaiso.conf' parabolaiso_image="/boot/initramfs-linux-libre.img" diff --git a/configs/releng/airootfs/etc/motd b/configs/releng/airootfs/etc/motd index e94c5c5..fdd42e0 100644 --- a/configs/releng/airootfs/etc/motd +++ b/configs/releng/airootfs/etc/motd @@ -7,3 +7,5 @@ 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. + +[41m [41m [41m [40m [44m [40m [41m [46m [45m [41m [46m [43m [41m [44m [45m [40m [44m [40m [41m [44m [41m [41m [46m [42m [41m [44m [43m [41m [45m [40m [40m [44m [40m [41m [44m [42m [41m [46m [44m [41m [46m [47m [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 deleted file mode 100644 index 82dd199..0000000 --- a/configs/releng/airootfs/etc/pacman.d/hooks/40-locale-gen.hook +++ /dev/null @@ -1,13 +0,0 @@ -# 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/ssh/sshd_config b/configs/releng/airootfs/etc/ssh/sshd_config deleted file mode 100644 index 93f7d63..0000000 --- a/configs/releng/airootfs/etc/ssh/sshd_config +++ /dev/null @@ -1,116 +0,0 @@ -# $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/ssh/sshd_config.d/10-parabolaiso.conf b/configs/releng/airootfs/etc/ssh/sshd_config.d/10-parabolaiso.conf new file mode 100644 index 0000000..6ea7b41 --- /dev/null +++ b/configs/releng/airootfs/etc/ssh/sshd_config.d/10-parabolaiso.conf @@ -0,0 +1,3 @@ +# Allow root login using password authentication +PasswordAuthentication yes +PermitRootLogin yes diff --git a/configs/releng/airootfs/etc/systemd/network.conf.d/ipv6-privacy-extensions.conf b/configs/releng/airootfs/etc/systemd/network.conf.d/ipv6-privacy-extensions.conf new file mode 100644 index 0000000..0e9ceb4 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/network.conf.d/ipv6-privacy-extensions.conf @@ -0,0 +1,2 @@ +[Network] +IPv6PrivacyExtensions=yes diff --git a/configs/releng/airootfs/etc/systemd/network/20-ethernet.network b/configs/releng/airootfs/etc/systemd/network/20-ethernet.network index 0ac5028..d3a3271 100644 --- a/configs/releng/airootfs/etc/systemd/network/20-ethernet.network +++ b/configs/releng/airootfs/etc/systemd/network/20-ethernet.network @@ -1,10 +1,16 @@ [Match] -Type=en* -Type=eth* +# Matching with "Type=ether" causes issues with containers because it also matches virtual Ethernet interfaces (veth*). +# See https://bugs.archlinux.org/task/70892 +# Instead match by globbing the network interface name. +Name=en* +Name=eth* + +[Link] +RequiredForOnline=routable [Network] DHCP=yes -IPv6PrivacyExtensions=yes +MulticastDNS=yes # systemd-networkd does not set per-interface-type default route metrics # https://github.com/systemd/systemd/issues/17698 diff --git a/configs/releng/airootfs/etc/systemd/network/20-wlan.network b/configs/releng/airootfs/etc/systemd/network/20-wlan.network index 601d5b8..8b70a95 100644 --- a/configs/releng/airootfs/etc/systemd/network/20-wlan.network +++ b/configs/releng/airootfs/etc/systemd/network/20-wlan.network @@ -1,9 +1,12 @@ [Match] Name=wl* +[Link] +RequiredForOnline=routable + [Network] DHCP=yes -IPv6PrivacyExtensions=yes +MulticastDNS=yes # systemd-networkd does not set per-interface-type default route metrics # https://github.com/systemd/systemd/issues/17698 diff --git a/configs/releng/airootfs/etc/systemd/network/20-wwan.network b/configs/releng/airootfs/etc/systemd/network/20-wwan.network index 55dadc2..6e1c8dd 100644 --- a/configs/releng/airootfs/etc/systemd/network/20-wwan.network +++ b/configs/releng/airootfs/etc/systemd/network/20-wwan.network @@ -1,9 +1,11 @@ [Match] -Type=ww* +Name=ww* + +[Link] +RequiredForOnline=routable [Network] DHCP=yes -IPv6PrivacyExtensions=yes # systemd-networkd does not set per-interface-type default route metrics # https://github.com/systemd/systemd/issues/17698 @@ -11,7 +13,7 @@ IPv6PrivacyExtensions=yes # 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=2048 +RouteMetric=700 [IPv6AcceptRA] RouteMetric=700 diff --git a/configs/releng/airootfs/etc/systemd/resolved.conf.d/parabolaiso.conf b/configs/releng/airootfs/etc/systemd/resolved.conf.d/parabolaiso.conf new file mode 100644 index 0000000..5d64185 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/resolved.conf.d/parabolaiso.conf @@ -0,0 +1,4 @@ +# Default systemd-resolved configuration for parabolaiso + +[Resolve] +MulticastDNS=yes diff --git a/configs/releng/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator b/configs/releng/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator new file mode 120000 index 0000000..dc1dc0c --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator @@ -0,0 +1 @@ +/dev/null
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.timesync1.service b/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.timesync1.service new file mode 120000 index 0000000..cd00411 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.timesync1.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-timesyncd.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/etc-pacman.d-gnupg.mount b/configs/releng/airootfs/etc/systemd/system/etc-pacman.d-gnupg.mount index 4eab551..038961e 100644 --- a/configs/releng/airootfs/etc/systemd/system/etc-pacman.d-gnupg.mount +++ b/configs/releng/airootfs/etc/systemd/system/etc-pacman.d-gnupg.mount @@ -5,4 +5,4 @@ Description=Temporary /etc/pacman.d/gnupg directory What=tmpfs Where=/etc/pacman.d/gnupg Type=tmpfs -Options=mode=0755 +Options=mode=0755,noswap diff --git a/configs/releng/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf b/configs/releng/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf index d1d8474..b9d22eb 100644 --- a/configs/releng/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf +++ b/configs/releng/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf @@ -1,3 +1,3 @@ [Service] ExecStart= -ExecStart=-/sbin/agetty --autologin root --noclear %I 38400 linux +ExecStart=-/sbin/agetty -o '-p -f -- \\u' --noclear --autologin root - $TERM diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_fcopy_daemon.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_fcopy_daemon.service new file mode 120000 index 0000000..20ac7b2 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_fcopy_daemon.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/hv_fcopy_daemon.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_kvp_daemon.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_kvp_daemon.service new file mode 120000 index 0000000..a7eac4a --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_kvp_daemon.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/hv_kvp_daemon.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_vss_daemon.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_vss_daemon.service new file mode 120000 index 0000000..eae19ef --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/hv_vss_daemon.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/hv_vss_daemon.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 deleted file mode 120000 index 8e3ff80..0000000 --- a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/qemu-guest-agent.service +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/systemd/system/qemu-guest-agent.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 b18f7f8..b824884 100644 --- a/configs/releng/airootfs/etc/systemd/system/pacman-init.service +++ b/configs/releng/airootfs/etc/systemd/system/pacman-init.service @@ -1,7 +1,9 @@ [Unit] Description=Initializes Pacman keyring Requires=etc-pacman.d-gnupg.mount -After=etc-pacman.d-gnupg.mount +After=etc-pacman.d-gnupg.mount time-sync.target +BindsTo=etc-pacman.d-gnupg.mount +Before=archlinux-keyring-wkd-sync.service [Service] Type=oneshot diff --git a/configs/releng/airootfs/etc/systemd/system/sockets.target.wants/pcscd.socket b/configs/releng/airootfs/etc/systemd/system/sockets.target.wants/pcscd.socket new file mode 120000 index 0000000..3897c63 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/sockets.target.wants/pcscd.socket @@ -0,0 +1 @@ +/usr/lib/systemd/system/pcscd.socket
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-time-wait-sync.service b/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-time-wait-sync.service new file mode 120000 index 0000000..cabf28b --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-time-wait-sync.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-time-wait-sync.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service b/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service new file mode 120000 index 0000000..cd00411 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-timesyncd.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/xdg/reflector/reflector.conf b/configs/releng/airootfs/etc/xdg/reflector/reflector.conf index 9a72b0d..7c830d2 100644 --- a/configs/releng/airootfs/etc/xdg/reflector/reflector.conf +++ b/configs/releng/airootfs/etc/xdg/reflector/reflector.conf @@ -1,6 +1,8 @@ # Reflector configuration file for the systemd service. --save /etc/pacman.d/mirrorlist +--ipv4 +--ipv6 --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 5c0c316..0d95012 100755 --- a/configs/releng/airootfs/root/.automated_script.sh +++ b/configs/releng/airootfs/root/.automated_script.sh @@ -1,22 +1,29 @@ #!/usr/bin/env bash -script_cmdline () -{ +script_cmdline() { local param - for param in $(< /proc/cmdline); do + for param in $(</proc/cmdline); do case "${param}" in - script=*) echo "${param#*=}" ; return 0 ;; + script=*) + echo "${param#*=}" + return 0 + ;; esac done } -automated_script () -{ +automated_script() { local script rt script="$(script_cmdline)" if [[ -n "${script}" && ! -x /tmp/startup_script ]]; then - if [[ "${script}" =~ ^((http|https|ftp)://) ]]; then - curl "${script}" --location --retry-connrefused -s -o /tmp/startup_script >/dev/null + if [[ "${script}" =~ ^((http|https|ftp|tftp)://) ]]; then + # there's no synchronization for network availability before executing this script + printf '%s: waiting for network-online.target\n' "$0" + until systemctl --quiet is-active network-online.target; do + sleep 1 + done + printf '%s: downloading %s\n' "$0" "${script}" + curl "${script}" --location --retry-connrefused --retry 10 -s -o /tmp/startup_script rt=$? else cp "${script}" /tmp/startup_script @@ -24,6 +31,9 @@ automated_script () fi if [[ ${rt} -eq 0 ]]; then chmod +x /tmp/startup_script + printf '%s: executing automated script\n' "$0" + # note that script is executed when other services (like pacman-init) may be still in progress, please + # synchronize to "systemctl is-system-running --wait" when your script depends on other services /tmp/startup_script fi fi diff --git a/configs/releng/airootfs/root/.gnupg/scdaemon.conf b/configs/releng/airootfs/root/.gnupg/scdaemon.conf new file mode 100644 index 0000000..e1f3d1f --- /dev/null +++ b/configs/releng/airootfs/root/.gnupg/scdaemon.conf @@ -0,0 +1,4 @@ +disable-ccid +disable-pinpad +pcsc-driver /usr/lib/libpcsclite.so +pcsc-shared diff --git a/configs/releng/airootfs/root/.zlogin b/configs/releng/airootfs/root/.zlogin index 0fb119d..bf6bc8f 100644 --- a/configs/releng/airootfs/root/.zlogin +++ b/configs/releng/airootfs/root/.zlogin @@ -1,5 +1,5 @@ # fix for screen readers -if grep -Fq 'accessibility=' /proc/cmdline &> /dev/null; then +if grep -Fqa 'accessibility=' /proc/cmdline &> /dev/null; then setopt SINGLE_LINE_ZLE fi diff --git a/configs/releng/airootfs/usr/local/bin/choose-mirror b/configs/releng/airootfs/usr/local/bin/choose-mirror index e8f8254..2f881e4 100755 --- a/configs/releng/airootfs/usr/local/bin/choose-mirror +++ b/configs/releng/airootfs/usr/local/bin/choose-mirror @@ -4,21 +4,22 @@ get_cmdline() { local param - for param in $(< /proc/cmdline); do + for param in $(</proc/cmdline); do case "${param}" in - $1=*) echo "${param##*=}"; - return 0 - ;; + "${1}="*) + echo "${param##*=}" + return 0 + ;; esac done } -mirror=$(get_cmdline mirror) -[[ $mirror = auto ]] && mirror=$(get_cmdline parabolaiso_http_srv) -[[ $mirror ]] || exit 0 +mirror="$(get_cmdline mirror)" +[[ "$mirror" == 'auto' ]] && mirror="$(get_cmdline parabolaiso_http_srv)" +[[ -n "$mirror" ]] || exit 0 mv /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.orig -cat >/etc/pacman.d/mirrorlist << EOF +cat >/etc/pacman.d/mirrorlist <<EOF # # Parabola GNU/Linux-libre repository mirrorlist # Generated by parabolaiso diff --git a/configs/releng/airootfs/usr/local/bin/livecd-sound b/configs/releng/airootfs/usr/local/bin/livecd-sound index baae0d2..b92fcf2 100755 --- a/configs/releng/airootfs/usr/local/bin/livecd-sound +++ b/configs/releng/airootfs/usr/local/bin/livecd-sound @@ -3,7 +3,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later usage() { - cat <<- _EOF_ + cat <<-_EOF_ live cd sound helper script. Usage: livecdsound [OPTION] OPTIONS @@ -14,14 +14,13 @@ usage() { _EOF_ } -bugout () { +bugout() { printf "/usr/local/bin/livecdsound: programming error" stat_fail } -echo_card_indices() -{ - if [ -f /proc/asound/cards ] ; then +echo_card_indices() { + if [[ -f /proc/asound/cards ]]; then sed -n -e's/^[[:space:]]*\([0-7]\)[[:space:]].*/\1/p' /proc/asound/cards fi } @@ -33,8 +32,8 @@ echo_card_indices() # $1 <card id> # $2 <control> # $3 <level> -unmute_and_set_level(){ - { [ "$3" ] &&[ "$2" ] && [ "$1" ] ; } || bugout +unmute_and_set_level() { + [[ -n "$3" && -n "$2" && -n "$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 @@ -42,9 +41,8 @@ unmute_and_set_level(){ # $1 <card id> # $2 <control> -mute_and_zero_level() -{ - { [ "$1" ] && [ "$2" ] ; } || bugout +mute_and_zero_level() { + [[ -n "$1" && -n "$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 @@ -53,17 +51,15 @@ mute_and_zero_level() # $1 <card ID> # $2 <control> # $3 "on" | "off" -switch_control() -{ - { [ "$3" ] && [ "$1" ] ; } || bugout +switch_control() { + [[ -n "$3" && -n "$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() -{ +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%" @@ -134,94 +130,89 @@ sanify_levels_on_card() } # $1 <card ID> | "all" -sanify_levels() -{ +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 - ;; + 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 + 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() -{ +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 + 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() -{ +unmute_all_cards() { sanify_levels all } is_numeric() { - local str=$1 + 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 + 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 + 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() -{ +pick_a_card() { set -f usable_cards="$(list_non_pcsp_cards)" - num_usable_cards="$(wc -w <<< "$usable_cards")" + num_usable_cards="$(wc -w <<<"$usable_cards")" - if [ "$num_usable_cards" -eq 1 ]; then + if (( num_usable_cards == 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 + 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& + play_on_card "$card" /usr/share/livecd-sounds/pick-a-card.wav & done wait sleep 1 - for card in $usable_cards; do + 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 + 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 +if (( $# == 0 )); then echo "error: No argument passed." exit 1 fi diff --git a/configs/releng/efiboot/loader/entries/01-parabolaiso-x86_64-linux-libre.conf b/configs/releng/efiboot/loader/entries/01-parabolaiso-x86_64-linux-libre.conf index 760ce9a..1af7867 100644 --- a/configs/releng/efiboot/loader/entries/01-parabolaiso-x86_64-linux-libre.conf +++ b/configs/releng/efiboot/loader/entries/01-parabolaiso-x86_64-linux-libre.conf @@ -1,4 +1,5 @@ -title Parabola GNU/Linux-libre install medium (x86_64, UEFI) -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -options parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% +title Parabola GNU/Linux-libre install medium (x86_64, UEFI) +sort-key 01 +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img +options parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% diff --git a/configs/releng/efiboot/loader/entries/02-parabolaiso-x86_64-speech-linux-libre.conf b/configs/releng/efiboot/loader/entries/02-parabolaiso-x86_64-speech-linux-libre.conf index 3ebef25..3bb7725 100644 --- a/configs/releng/efiboot/loader/entries/02-parabolaiso-x86_64-speech-linux-libre.conf +++ b/configs/releng/efiboot/loader/entries/02-parabolaiso-x86_64-speech-linux-libre.conf @@ -1,4 +1,5 @@ -title Parabola GNU/Linux-libre install medium (x86_64, UEFI) with speech -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -options parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% accessibility=on +title Parabola GNU/Linux-libre install medium (x86_64, UEFI) with speech +sort-key 02 +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img +options parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% accessibility=on diff --git a/configs/releng/efiboot/loader/entries/03-parabolaiso-x86_64-ram-linux-libre.conf b/configs/releng/efiboot/loader/entries/03-parabolaiso-x86_64-ram-linux-libre.conf deleted file mode 100644 index 40fd971..0000000 --- a/configs/releng/efiboot/loader/entries/03-parabolaiso-x86_64-ram-linux-libre.conf +++ /dev/null @@ -1,4 +0,0 @@ -title Parabola GNU/Linux-libre install medium (x86_64, UEFI, Copy to RAM) -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -options parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% copytoram diff --git a/configs/releng/efiboot/loader/loader.conf b/configs/releng/efiboot/loader/loader.conf index 8a5b018..8e31f03 100644 --- a/configs/releng/efiboot/loader/loader.conf +++ b/configs/releng/efiboot/loader/loader.conf @@ -1,2 +1,3 @@ timeout 15 default 01-parabolaiso-x86_64-linux-libre.conf +beep on diff --git a/configs/releng/grub/grub.cfg b/configs/releng/grub/grub.cfg new file mode 100644 index 0000000..4266ef3 --- /dev/null +++ b/configs/releng/grub/grub.cfg @@ -0,0 +1,87 @@ +# Load partition table and file system modules +insmod part_gpt +insmod part_msdos +insmod fat +insmod iso9660 +insmod ntfs +insmod ntfscomp +insmod exfat +insmod udf + +# Use graphics-mode output +insmod all_video +insmod font +if loadfont "${prefix}/fonts/unicode.pf2" ; then + set gfxmode="auto" + terminal_input console + terminal_output console +fi + +# Enable serial console +if serial --unit=0 --speed=115200; then + terminal_input --append serial + terminal_output --append serial +fi + +# Search for the ISO volume +if [ -z "${PARABOLAISO_UUID}" ]; then + if [ -z "${PARABOLAISO_HINT}" ]; then + regexp --set=1:PARABOLAISO_HINT '^\(([^)]+)\)' "${cmdpath}" + fi + search --no-floppy --set=root --file '%PARABOLAISO_SEARCH_FILENAME%' --hint "${PARABOLAISO_HINT}" + probe --set PARABOLAISO_UUID --fs-uuid "${root}" +fi + +# Set default menu entry +default=parabola +timeout=15 +timeout_style=menu + +# GRUB init tune for accessibility +play 600 988 1 1319 4 + +# Menu entries + +menuentry "Parabola GNU/Linux-libre install medium (x86_64, UEFI)" --class arch --class gnu-linux --class gnu --class os --id 'parabola' { + set gfxpayload=keep + linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=${PARABOLAISO_UUID} + initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img +} + +menuentry "Parabola GNU/Linux-libre install medium with speakup screen reader (x86_64, UEFI)" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'parabola-accessibility' { + set gfxpayload=keep + linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=${PARABOLAISO_UUID} accessibility=on + initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img +} + +if [ "${grub_platform}" == "efi" ]; then + if [ "${grub_cpu}" == "x86_64" ]; then + menuentry "Run Memtest86+ (RAM test)" --class memtest86 --class memtest --class gnu --class tool { + set gfxpayload=800x600,1024x768 + linux /boot/memtest86+/memtest.efi + } + menuentry "UEFI Shell" --class efi { + insmod chain + chainloader /shellx64.efi + } + elif [ "${grub_cpu}" == "i386" ]; then + menuentry "UEFI Shell" --class efi { + insmod chain + chainloader /shellia32.efi + } + fi + + menuentry 'UEFI Firmware Settings' --id 'uefi-firmware' { + fwsetup + } +fi + +menuentry "System shutdown" --class shutdown --class poweroff { + echo "System shutting down..." + halt +} + +menuentry "System restart" --class reboot --class restart { + echo "System rebooting..." + reboot +} diff --git a/configs/releng/grub/loopback.cfg b/configs/releng/grub/loopback.cfg new file mode 100644 index 0000000..6ac328c --- /dev/null +++ b/configs/releng/grub/loopback.cfg @@ -0,0 +1,80 @@ +# https://www.supergrubdisk.org/wiki/Loopback.cfg + +# Search for the ISO volume +search --no-floppy --set=parabolaiso_img_dev --file "${iso_path}" +probe --set parabolaiso_img_dev_uuid --fs-uuid "${parabolaiso_img_dev}" + +# Get a human readable platform identifier +if [ "${grub_platform}" == 'efi' ]; then + parabolaiso_platform='UEFI' + if [ "${grub_cpu}" == 'x86_64' ]; then + parabolaiso_platform="x64 ${parabolaiso_platform}" + elif [ "${grub_cpu}" == 'i386' ]; then + parabolaiso_platform="IA32 ${parabolaiso_platform}" + else + parabolaiso_platform="${grub_cpu} ${parabolaiso_platform}" + fi +elif [ "${grub_platform}" == 'pc' ]; then + parabolaiso_platform='BIOS' +else + parabolaiso_platform="${grub_cpu} ${grub_platform}" +fi + +# Set default menu entry +default=parabola +timeout=15 +timeout_style=menu + + +# Menu entries + +menuentry "Parabola GNU/Linux-libre install medium (%ARCH%, ${parabolaiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'parabola' { + set gfxpayload=keep + linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-libre parabolaisobasedir=%INSTALL_DIR% img_dev=UUID=${parabolaiso_img_dev_uuid} img_loop="${iso_path}" + initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-libre.img +} + +menuentry "Parabola GNU/Linux-libre install medium with speakup screen reader (%ARCH%, ${parabolaiso_platform})" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'parabola-accessibility' { + set gfxpayload=keep + linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-libre parabolaisobasedir=%INSTALL_DIR% img_dev=UUID=${parabolaiso_img_dev_uuid} img_loop="${iso_path}" accessibility=on + initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-libre.img +} + + +if [ "${grub_platform}" == 'efi' -a "${grub_cpu}" == 'x86_64' -a -f '/boot/memtest86+/memtest.efi' ]; then + menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class memtest --class gnu --class tool { + set gfxpayload=800x600,1024x768 + linux /boot/memtest86+/memtest.efi + } +fi +if [ "${grub_platform}" == 'pc' -a -f '/boot/memtest86+/memtest' ]; then + menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class memtest --class gnu --class tool { + set gfxpayload=800x600,1024x768 + linux /boot/memtest86+/memtest + } +fi +if [ "${grub_platform}" == 'efi' ]; then + if [ "${grub_cpu}" == 'x86_64' -a -f '/shellx64.efi' ]; then + menuentry 'UEFI Shell' --class efi { + chainloader /shellx64.efi + } + elif [ "${grub_cpu}" == "i386" -a -f '/shellia32.efi' ]; then + menuentry 'UEFI Shell' --class efi { + chainloader /shellia32.efi + } + fi + + menuentry 'UEFI Firmware Settings' --id 'uefi-firmware' { + fwsetup + } +fi + +menuentry 'System shutdown' --class shutdown --class poweroff { + echo 'System shutting down...' + halt +} + +menuentry 'System restart' --class reboot --class restart { + echo 'System rebooting...' + reboot +} diff --git a/configs/releng/packages.both b/configs/releng/packages.both index ba01e84..9828871 100644 --- a/configs/releng/packages.both +++ b/configs/releng/packages.both @@ -1,35 +1,40 @@ alsa-utils arch-install-scripts -archinstall base -bind-tools +bcachefs-tools +bind +bolt brltty btrfs-progs cloud-init -crda cryptsetup darkhttpd ddrescue dhclient dhcpcd diffutils +dmidecode dmraid dnsmasq dosfstools e2fsprogs +edk2-shell efibootmgr espeakup ethtool exfatprogs f2fs-tools fatresize +foot-terminfo fsarchiver gnu-netcat gpart gpm gptfdisk grml-zsh-config +grub hdparm +hyperv irssi iw iwd @@ -51,6 +56,7 @@ man-pages mc mdadm memtest86+ +memtest86+-efi mkinitcpio mkinitcpio-parabolaiso mkinitcpio-nfs-utils @@ -61,10 +67,11 @@ nbd ndisc6 nfs-utils nilfs-utils -nmap ntfs-3g nvme-cli +open-iscsi openconnect +openpgp-card-tools openssh openvpn partclone @@ -75,16 +82,17 @@ ppp pptpclient pv qemu-guest-agent +refind reflector reiserfsprogs rp-pppoe rsync rxvt-unicode-terminfo screen +sequoia-sq sdparm sg3_utils smartmontools -sof-firmware squashfs-tools sudo syslinux @@ -93,6 +101,7 @@ tcpdump terminus-font testdisk tmux +tpm2-tools tpm2-tss udftools usb_modeswitch @@ -100,6 +109,7 @@ usbmuxd usbutils vim vpnc +wezterm-terminfo wireless-regdb wireless_tools wpa_supplicant diff --git a/configs/releng/packages.x86_64 b/configs/releng/packages.x86_64 deleted file mode 100644 index 4cfa070..0000000 --- a/configs/releng/packages.x86_64 +++ /dev/null @@ -1 +0,0 @@ -edk2-shell diff --git a/configs/releng/pacman.conf b/configs/releng/pacman.conf index 79a8f69..4469abc 100644 --- a/configs/releng/pacman.conf +++ b/configs/releng/pacman.conf @@ -76,21 +76,12 @@ LocalFileSigLevel = Optional [libre] Include = /etc/pacman.d/mirrorlist -#[testing] -#Include = /etc/pacman.d/mirrorlist - [core] Include = /etc/pacman.d/mirrorlist [extra] Include = /etc/pacman.d/mirrorlist -#[community-testing] -#Include = /etc/pacman.d/mirrorlist - -[community] -Include = /etc/pacman.d/mirrorlist - #[pcr-testing] #Include = /etc/pacman.d/mirrorlist diff --git a/configs/releng/profiledef.sh b/configs/releng/profiledef.sh index 8ca837f..5ac639e 100644 --- a/configs/releng/profiledef.sh +++ b/configs/releng/profiledef.sh @@ -2,13 +2,15 @@ # shellcheck disable=SC2034 iso_name="parabola" -iso_label="PARA_$(date +%Y%m)" +iso_label="PARA_$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y%m)" iso_publisher="Parabola GNU/Linux-libre <https://parabola.nu>" iso_application="Parabola GNU/Linux-libre Live/Rescue CD" -iso_version="$(date +%Y.%m.%d)" +iso_version="$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y.%m.%d)" install_dir="parabola" buildmodes=('iso') -bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' 'uefi-x64.systemd-boot.esp' 'uefi-x64.systemd-boot.eltorito') +bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' + 'uefi-ia32.grub.esp' 'uefi-x64.systemd-boot.esp' + 'uefi-ia32.grub.eltorito' 'uefi-x64.systemd-boot.eltorito') arch="dual" pacman_conf="pacman.conf" airootfs_image_type="squashfs" @@ -17,6 +19,7 @@ file_permissions=( ["/etc/shadow"]="0:0:400" ["/root"]="0:0:750" ["/root/.automated_script.sh"]="0:0:755" + ["/root/.gnupg"]="0:0:700" ["/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/parabolaiso_head.cfg b/configs/releng/syslinux/parabolaiso_head.cfg index 591097e..4f56858 100644 --- a/configs/releng/syslinux/parabolaiso_head.cfg +++ b/configs/releng/syslinux/parabolaiso_head.cfg @@ -12,7 +12,7 @@ MENU CMDLINEROW 14 MENU HELPMSGROW 16 MENU HELPMSGENDROW 29 -# Refer to http://syslinux.zytor.com/wiki/index.php/Doc/menu +# Refer to https://wiki.syslinux.org/wiki/index.php/Comboot/menu.c32 MENU COLOR border 35;40 #ff777caa #a0000000 std MENU COLOR title 1;35;40 #ff777caa #a0000000 std diff --git a/configs/releng/syslinux/parabolaiso_pxe32-linux-libre.cfg b/configs/releng/syslinux/parabolaiso_pxe32-linux-libre.cfg index 9e0bb0e..fa629f1 100644 --- a/configs/releng/syslinux/parabolaiso_pxe32-linux-libre.cfg +++ b/configs/releng/syslinux/parabolaiso_pxe32-linux-libre.cfg @@ -4,9 +4,9 @@ Boot the Parabola GNU/Linux-libre (i686) live medium (Using NBD). It allows you to install Parabola GNU/Linux-libre or perform system maintenance. ENDTEXT MENU LABEL Boot Parabola GNU/Linux-libre (i686) (NBD) -LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre -INITRD /%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% parabolaiso_nbd_srv=${pxeserver} checksum verify +LINUX ::/%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre +INITRD ::/%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% parabolaiso_nbd_srv=${pxeserver} cms_verify=y SYSAPPEND 3 LABEL parabola32_nfs @@ -15,9 +15,9 @@ Boot the Parabola GNU/Linux-libre (i686) live medium (Using NFS). It allows you to install Parabola GNU/Linux-libre or perform system maintenance. ENDTEXT MENU LABEL Boot Parabola GNU/Linux-libre (i686) (NFS) -LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre -INITRD /%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaiso_nfs_srv=${pxeserver}:/run/parabolaiso/bootmnt checksum verify +LINUX ::/%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre +INITRD ::/%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaiso_nfs_srv=${pxeserver}:/run/parabolaiso/bootmnt cms_verify=y SYSAPPEND 3 LABEL parabola32_http @@ -26,7 +26,7 @@ Boot the Parabola GNU/Linux-libre (i686) live medium (Using HTTP). It allows you to install Parabola GNU/Linux-libre or perform system maintenance. ENDTEXT MENU LABEL Boot Parabola GNU/Linux-libre (i686) (HTTP) -LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre -INITRD /%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaiso_http_srv=http://${pxeserver}/ checksum verify +LINUX ::/%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre +INITRD ::/%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaiso_http_srv=http://${pxeserver}/ cms_verify=y SYSAPPEND 3 diff --git a/configs/releng/syslinux/parabolaiso_pxe64-linux-libre.cfg b/configs/releng/syslinux/parabolaiso_pxe64-linux-libre.cfg index 71e70c5..44531ab 100644 --- a/configs/releng/syslinux/parabolaiso_pxe64-linux-libre.cfg +++ b/configs/releng/syslinux/parabolaiso_pxe64-linux-libre.cfg @@ -4,9 +4,9 @@ Boot the Parabola GNU/Linux-libre (x86_64) live medium (Using NBD). It allows you to install Parabola GNU/Linux-libre or perform system maintenance. ENDTEXT MENU LABEL Boot Parabola GNU/Linux-libre (x86_64) (NBD) -LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre -INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% parabolaiso_nbd_srv=${pxeserver} checksum verify +LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre +INITRD ::/%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% parabolaiso_nbd_srv=${pxeserver} cms_verify=y SYSAPPEND 3 LABEL parabola64_nfs @@ -15,9 +15,9 @@ Boot the Parabola GNU/Linux-libre (x86_64) live medium (Using NFS). It allows you to install Parabola GNU/Linux-libre or perform system maintenance. ENDTEXT MENU LABEL Boot Parabola GNU/Linux-libre (x86_64) (NFS) -LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre -INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaiso_nfs_srv=${pxeserver}:/run/parabolaiso/bootmnt checksum verify +LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre +INITRD ::/%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaiso_nfs_srv=${pxeserver}:/run/parabolaiso/bootmnt cms_verify=y SYSAPPEND 3 LABEL parabola64_http @@ -26,7 +26,7 @@ Boot the Parabola GNU/Linux-libre (x86_64) live medium (Using HTTP). It allows you to install Parabola GNU/Linux-libre or perform system maintenance. ENDTEXT MENU LABEL Boot Parabola GNU/Linux-libre (x86_64) (HTTP) -LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre -INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaiso_http_srv=http://${pxeserver}/ checksum verify +LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre +INITRD ::/%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaiso_http_srv=http://${pxeserver}/ cms_verify=y SYSAPPEND 3 diff --git a/configs/releng/syslinux/parabolaiso_sys32-linux-libre.cfg b/configs/releng/syslinux/parabolaiso_sys32-linux-libre.cfg index 4f0acb1..d15cac6 100644 --- a/configs/releng/syslinux/parabolaiso_sys32-linux-libre.cfg +++ b/configs/releng/syslinux/parabolaiso_sys32-linux-libre.cfg @@ -8,7 +8,7 @@ ENDTEXT MENU LABEL Parabola GNU/Linux-libre install medium (i686, BIOS) LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre INITRD /%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% # Accessibility boot option LABEL parabola32speech @@ -19,7 +19,7 @@ ENDTEXT MENU LABEL Parabola GNU/Linux-libre install medium (i686, BIOS) with ^speech LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre INITRD /%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% accessibility=on +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% accessibility=on # Copy to RAM boot option LABEL parabola32ram @@ -30,4 +30,4 @@ ENDTEXT MENU LABEL Parabola GNU/Linux-libre install medium (i686, BIOS, Copy to RAM) LINUX /%INSTALL_DIR%/boot/i686/vmlinuz-linux-libre INITRD /%INSTALL_DIR%/boot/i686/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% copytoram +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% copytoram diff --git a/configs/releng/syslinux/parabolaiso_sys64-linux-libre.cfg b/configs/releng/syslinux/parabolaiso_sys64-linux-libre.cfg index cbf736e..9750687 100644 --- a/configs/releng/syslinux/parabolaiso_sys64-linux-libre.cfg +++ b/configs/releng/syslinux/parabolaiso_sys64-linux-libre.cfg @@ -6,7 +6,7 @@ ENDTEXT MENU LABEL Parabola GNU/Linux-libre install medium (x86_64, BIOS) LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% # Accessibility boot option LABEL parabola64speech @@ -17,15 +17,4 @@ ENDTEXT MENU LABEL Parabola GNU/Linux-libre install medium (x86_64, BIOS) with ^speech LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% accessibility=on - -# Copy to RAM boot option -LABEL parabola64ram -TEXT HELP -Boot the Parabola GNU/Linux-libre install medium on BIOS with Copy-to-RAM option -It allows you to install Parabola GNU/Linux-libre or perform system maintenance. -ENDTEXT -MENU LABEL Parabola GNU/Linux-libre install medium (x86_64, BIOS, Copy to RAM) -LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-libre -INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux-libre.img -APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisolabel=%PARABOLAISO_LABEL% copytoram +APPEND parabolaisobasedir=%INSTALL_DIR% parabolaisodevice=UUID=%PARABOLAISO_UUID% accessibility=on diff --git a/configs/releng/syslinux/parabolaiso_tail.cfg b/configs/releng/syslinux/parabolaiso_tail.cfg index e5339a2..dcbb413 100644 --- a/configs/releng/syslinux/parabolaiso_tail.cfg +++ b/configs/releng/syslinux/parabolaiso_tail.cfg @@ -7,12 +7,12 @@ MENU LABEL Boot existing OS COM32 chain.c32 APPEND hd0 0 -# http://www.memtest.org/ +# https://www.memtest.org/ LABEL memtest MENU LABEL Run Memtest86+ (RAM test) LINUX /%INSTALL_DIR%/boot/memtest -# http://hdt-project.org/ +# https://wiki.syslinux.org/wiki/index.php/Hdt_(Hardware_Detection_Tool) LABEL hdt MENU LABEL Hardware Information (HDT) COM32 hdt.c32 diff --git a/docs/README.profile.rst b/docs/README.profile.rst index a3dc954..ec76ede 100644 --- a/docs/README.profile.rst +++ b/docs/README.profile.rst @@ -10,6 +10,7 @@ A parabolaiso profile consists of several configuration files and a directory fo ├── airootfs/ ├── efiboot/ ├── syslinux/ + ├── grub/ ├── bootstrap_packages.arch ├── packages.arch ├── pacman.conf @@ -45,10 +46,14 @@ The image file is constructed from some of the variables in ``profiledef.sh``: ` - ``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 - - ``uefi-x64.refind.esp``: rEFInd for x86_64 UEFI booting from a disk - - ``uefi-x64.refind.eltorito``: rEFInd for x86_64 UEFI booting from an optical disc + - ``uefi-ia32.grub.esp``: GRUB for IA32 UEFI booting from a disk + - ``uefi-ia32.grub.eltorito``: GRUB for IA32 UEFI booting from an optical disc + - ``uefi-x64.grub.esp``: GRUB for x64 UEFI booting from a disk + - ``uefi-x64.grub.eltorito``: GRUB for x64 UEFI booting from an optical disc + - ``uefi-ia32.systemd-boot.esp``: systemd-boot for IA32 UEFI booting from a disk + - ``uefi-ia32.systemd-boot.eltorito``: systemd-boot for IA32UEFI booting from an optical disc + - ``uefi-x64.systemd-boot.esp``: systemd-boot for x64 UEFI booting from a disk + - ``uefi-x64.systemd-boot.eltorito``: systemd-boot for x64 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``) @@ -134,9 +139,16 @@ The following *custom template identifiers* are understood and will be replaced respective variables in ``profiledef.sh``: * ``%PARABOLAISO_LABEL%``: Set this using the ``iso_label`` variable in ``profiledef.sh``. -* ``%INSTALL_DIR%``: Set this using the ``iso_label`` variable in ``profiledef.sh``. +* ``%INSTALL_DIR%``: Set this using the ``install_dir`` variable in ``profiledef.sh``. * ``%ARCH%``: Set this using the ``arch`` variable in ``profiledef.sh``. +Additionally there are also *custom template identifiers* have harcoded values set by ``mkparabolaiso`` that cannot be +overridden: + +* ``%PARABOLAISO_UUID%``: the ISO 9660 modification date in UTC, i.e. its "UUID", +* ``%PARABOLAISO_SEARCH_FILENAME%``: file path on ISO 9660 that can be used by GRUB to find the ISO volume + (**for GRUB ``.cfg`` files only**). + efiboot ------- @@ -166,3 +178,16 @@ It contains configuration files for `syslinux <https://wiki.syslinux.org/wiki/in <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. + +grub +---- + +This directory is mandatory when any of the following bootmodes is used in ``profiledef.sh``: + +- ``uefi-ia32.grub.esp`` or +- ``uefi-ia32.grub.eltorito`` or +- ``uefi-x64.grub.esp`` or +- ``uefi-x64.grub.eltorito`` + +It contains configuration files for `GRUB <https://www.gnu.org/software/grub/>`_ +used in the resulting image. diff --git a/docs/README.transfer b/docs/README.transfer deleted file mode 100644 index 2cf28e3..0000000 --- a/docs/README.transfer +++ /dev/null @@ -1,133 +0,0 @@ -INDEX ------ - -* Transfer ISO file to target medium (configs/releng) - * To -> CD / DVD / BD - * To -> USB-key / SD / HDD / SSD - * PC-BIOS (MBR) - * PC-BIOS (ISOHYBRID-MBR) - * PC-EFI (GPT) [x86_64 only] - * PC-EFI (ISOHYBRID-GPT) [x86_64 only] - - - -*** Transfer ISO image to target medium (configs/releng) - -ISO images names consist of: parabola-<YYYY>.<MM>.<DD>-dual.iso - -Where: - <YYYY> Year - <MM> Month - <DD> Day - - -** To -> CD / DVD / BD - -Note: All ISO images are booteable on a PC-BIOS via "El Torito" in no-emulation mode, - All x86_64 ISO images are booteable on a PC-EFI via "El Torito" in no-emulation mode. - -Nomeclature: - <B> scsibus number - <T> target number - <L> lun number - (Note: see cdrecord -scanbus, for these numbers) - - -1) Write it directly using your favorite recording program. -# cdrecord dev=<B>,<T>,<L> -dao parabola-<YYYY>.<MM>.<DD>-dual.iso - - -** To -> USB Flash Drive (USB-key) / Memory card (SD) / - Hard-Disk Drive (HDD) / Solid-State Drive (SSD) - -Note: These steps are the general workflow, you can skip some of them, - using another filesystem if your bootloader supports it, - installing to another directory than "parabola/" or using more than - one partition. Just ensure that main boot params options - (parabolaisolabel= and parabolaisobasedir=) are set correctly according to your setup. - -Nomeclature: -<DEV-TARGET>: Device node of the drive where ISO contents should be copied - (example: /dev/sdx) -<DEV-TARGET-N>: Device node of the partition on <DEV-TARGET> - (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 parabola-<YYYY>.<MM>.<DD>-dual.iso - (example: ~/parabola-2012.07.22-dual.iso) -<FS-LABEL>: Represents the filesystem label of the <ISO-SOURCE> - (example: PARA_201302) - - -* PC-BIOS (MBR): - -Note: Using here a MBR partition mode as example, but GPT should also works - if machine firmware is not broken. - Just ensure that partition is set with attribute "2: legacy BIOS bootable" - and use gptmbr.bin instead of mbr.bin for syslinux. - -1) Create one partition entry in MBR and mark it as "active" (booteable). -Note: Type "b" for FAT32, "83" for EXTFS or "7" for NTFS. -# fdisk <DEV-TARGET> - -2) Create a FAT32, EXTFS or NTFS filesystem on such partition and setup a label. -Note: COW is not supported on NTFS. -# mkfs.fat -F 32 -n <FS-LABEL> <DEV-TARGET-N> -# mkfs.ext4 -L <FS-LABEL> <DEV-TARGET-N> -# mkfs.ntfs -L <FS-LABEL> <DEV-TARGET-N> - -3) Mount target filesystem. -# mount <DEV-TARGET-N> <MNT-TARGET-N> - -4) Extract ISO image on target filesystem. -# bsdtar -x --exclude=isolinux/ --exclude=EFI/ --exclude=loader/ -f <ISO-SOURCE> -C <MNT-TARGET-N> - -5) Install syslinux bootloader on target filesystem. -# extlinux -i <MNT-TARGET-N>/parabola/boot/syslinux - -6) Unmount target filesystem. -# umount <MNT-TARGET-N> - -7) Install syslinux MBR boot code on target drive. -# dd bs=440 count=1 conv=notrunc if=/usr/lib/syslinux/bios/mbr.bin of=<DEV-TARGET> - - -* PC-BIOS (ISOHYBRID-MBR): - -Note: This method is the most easily, quick and dirty, but is the most limited - if you want to use your target medium for other purposes. - If using this does not work, use PC-BIOS (MBR) method instead. - -1) Dump ISO file to target medium. -# dd if=<ISO-SOURCE> of=<DEV-TARGET> - - -* PC-EFI (GPT) [x86_64 only] - -Note: Using here a GPT partition mode as example, but MBR should also works - if machine firmware is not broken. - -1) Create one partition entry in GPT (of type "ef00") -# gdisk <DEV-TARGET> - -2) Create a FAT32 filesystem on such partition and setup a label. -# mkfs.fat -F 32 -n <FS-LABEL> <DEV-TARGET-N> - -3) Mount target filesystem. -# mount <DEV-TARGET-N> <MNT-TARGET-N> - -4) Extract ISO image on target filesystem. -# bsdtar -x --exclude=isolinux/ --exclude=EFI/parabolaiso/ --exclude=parabola/boot/syslinux/ -f <ISO-SOURCE> -C <MNT-TARGET-N> - -5) Unmount target filesystem. -# umount <MNT-TARGET-N> - - -* PC-EFI (ISOHYBRID-GPT) [x86_64 only] - -Note: This method is the most easily, quick and dirty, but is the most limited - if you want to use your target medium for other purposes. - If using this does not work, use PC-EFI (GPT) method instead. - -1) Dump ISO file to target medium. -# dd if=<ISO-SOURCE> of=<DEV-TARGET> diff --git a/docs/README.transfer.rst b/docs/README.transfer.rst new file mode 100644 index 0000000..c09b41d --- /dev/null +++ b/docs/README.transfer.rst @@ -0,0 +1,165 @@ +============================================== +Transfer ISO to target medium (configs/releng) +============================================== + +ISO images names consist of: ``parabola-YYYY.MM.DD-x86_64.iso``. + +Where: ``YYYY`` is the year, ``MM`` the month and ``DD`` the day. + +.. contents:: + +Burn to an optical disc +======================= + + .. note:: + All ISO images are BIOS and UEFI bootable via "El Torito" in no-emulation mode. + +Burn the ISO using your favorite disc burning program. + +For example: + +.. code:: sh + + xorriso -as cdrecord -v -sao dev=/dev/sr0 parabola-YYYY.MM.DD-x86_64.iso + +Write to an USB flash drive / memory card / hard disk drive / solid state drive / etc. +====================================================================================== + + .. tip:: + See https://wiki.archlinux.org/title/USB_flash_installation_medium for more detailed instructions. + +Nomeclature: + +``<DEV-TARGET>`` + Device node of the drive where ISO contents should be copied (example: ``/dev/sdx``). +``<DEV-TARGET-N>`` + Device node of the partition on ``<DEV-TARGET>`` (example: ``/dev/sdx1``). +``<FS-LABEL>`` + Represents the file system label of the ``parabola-YYYY.MM.DD-x86_64.iso`` (example: ``ARCH_201703``). + +ISOHYBRID (BIOS and UEFI) +------------------------- + + .. note:: + This method is the most easily, quick and dirty, but is the most limited if you want to use your target medium + for other purposes. If using this does not work, use the `File system transposition (UEFI only)`_ method instead. + +Directly write the ISO file to the target medium: + +.. code:: sh + + dd bs=4M if=parabola-YYYY.MM.DD-x86_64.iso of=<DEV-TARGET> conv=fsync oflag=direct status=progress + +File system transposition (UEFI only) +-------------------------------- + +This method extracts the contents of the ISO onto a prepared UEFI-bootable volume. + +If your drive is already partitioned and formatted, skip to the "Mount the target file system" step. + + .. note:: + Using MBR with one FAT formatted active partition is the most compatible method. + +1. Partition the drive with *fdisk*. + + .. code:: sh + + fdisk <DEV-TARGET> + + 1) Create a new MBR partition table with command ``o``. + + .. warning:: + This will destroy all data on the drive. + + 2) Create a new primary partition with command ``n`` and set its type code to ``0c`` with command ``t``. + + 3) Mark the partition as bootable with the ``a`` command. + + 4) Write the changes and exit with ``w``. + +2. Format the newly created partition to FAT32 + + .. code:: sh + + mkfs.fat -F 32 /dev/disk/by-id/<TARGET-DEVICE>-part1 + +3. Mount the target file system + + .. code:: sh + + mount <DEV-TARGET-N> /mnt + +4. Extract the ISO image on the target file system. + + .. code:: sh + + bsdtar -x --exclude=boot/syslinux/ -f parabola-YYYY.MM.DD-x86_64.iso -C /mnt + +5. Unmount the target file system. + + .. code:: sh + + umount /mnt + +Manual formatting (BIOS only) +----------------------------- + + .. note:: + These steps are the general workflow, you can skip some of them, using another file system if your boot loader + supports it, installing to another directory than ``arch/`` or using more than one partition. Just ensure that + main boot parameters (``archisolabel=`` and ``archisobasedir=``) are set correctly according to your setup. + + Using here a MBR partition mode as example, but GPT should also work if the machine firmware is not broken. Just + ensure that partition is set with attribute ``2: legacy BIOS bootable`` and use ``gptmbr.bin`` instead of + ``mbr.bin`` for syslinux. + +1) Create one partition entry in MBR and mark it as "active" (bootable). + + .. note:: + Type ``b`` for FAT32, ``83`` for EXTFS or ``7`` for NTFS. + + .. code:: sh + + fdisk <DEV-TARGET> + +2) Create a FAT32, EXTFS or NTFS file system on such partition and setup a label. + + .. note:: + COW is not supported on NTFS. + + .. code:: sh + + mkfs.fat -F 32 -n <FS-LABEL> <DEV-TARGET-N> + mkfs.ext4 -L <FS-LABEL> <DEV-TARGET-N> + mkfs.ntfs -L <FS-LABEL> <DEV-TARGET-N> + +3) Mount the target file system. + + .. code:: sh + + mount <DEV-TARGET-N> /mnt + +4) Extract the ISO image on the target file system. + + .. code:: sh + + bsdtar -x --exclude=boot/grub/ --exclude=EFI/ -f parabola-YYYY.MM.DD-x86_64.iso -C /mnt + +5) Install the syslinux boot loader on the target file system. + + .. code:: sh + + extlinux -i /mnt/boot/syslinux + +6) Unmount the target file system. + + .. code:: sh + + umount /mnt + +7) Install syslinux MBR boot code on the target drive. + + .. code:: sh + + dd bs=440 count=1 conv=notrunc if=/usr/lib/syslinux/bios/mbr.bin of=<DEV-TARGET> + diff --git a/parabolaiso/mkparabolaiso b/parabolaiso/mkparabolaiso index 9abbba4..3beb237 100755 --- a/parabolaiso/mkparabolaiso +++ b/parabolaiso/mkparabolaiso @@ -3,11 +3,18 @@ # SPDX-License-Identifier: GPL-3.0-or-later set -e -u +shopt -s extglob # Control the environment umask 0022 -export LC_ALL="C" -export SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-"$(date +%s)"}" +export LC_ALL="C.UTF-8" +if [[ -v LANGUAGE ]]; then + # LC_ALL=C.UTF-8, unlike LC_ALL=C, does not override LANGUAGE. + # See https://sourceware.org/bugzilla/show_bug.cgi?id=16621 and https://savannah.gnu.org/bugs/?62815 + unset LANGUAGE +fi +[[ -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##*/}" @@ -22,6 +29,7 @@ gpg_key="" gpg_sender="" iso_name="" iso_label="" +iso_uuid="" iso_publisher="" iso_application="" iso_version="" @@ -33,14 +41,15 @@ packages_dual="" bootstrap_packages="" bootstrap_packages_dual="" pacstrap_dir="" +declare -i rm_work_dir=0 buildmodes=() bootmodes=() airootfs_image_type="" airootfs_image_tool_options=() cert_list=() -sign_netboot_artifacts="" declare -A file_permissions=() - +efibootimg="" +efiboot_files=() # Show an INFO message # $1: message string @@ -78,14 +87,15 @@ usage: ${app_name} [options] <profile_dir> Default: '${iso_application}' -C <file> pacman configuration file. Default: '${pacman_conf}' - -D <install_dir> Set an install_dir. All files will by located here. + -D <install_dir> Set an install_dir. All files will be 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 + -c [cert ..] Provide certificates for codesigning of netboot artifacts as + well as the rootfs artifact. Multiple files are provided as quoted, space delimited list. The first file is considered as the signing certificate, the second as the key. @@ -100,6 +110,7 @@ usage: ${app_name} [options] <profile_dir> Default: '${out_dir}' -p [package ..] Package(s) to install. Multiple packages are provided as quoted, space delimited list. + -r Delete the working directory at the end. -v Enable verbose output -w <work_dir> Set the working directory Default: '${work_dir}' @@ -113,7 +124,7 @@ ENDUSAGETEXT # Shows configuration options. _show_config() { local build_date - build_date="$(date --utc --iso-8601=seconds -d "@${SOURCE_DATE_EPOCH}")" + 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}" @@ -124,14 +135,14 @@ _show_config() { _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[*]}" + _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[*]}" + _msg_info " Boot modes: ${bootmodes[*]:-None}" _msg_info " Packages File: ${buildmode_packages}" _msg_info " Packages: ${buildmode_pkg_list[*]}" if [[ "${arch}" == "dual" ]]; then @@ -158,9 +169,10 @@ _cleanup_pacstrap_dir() { [[ -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 + # Create /etc/machine-id with special value 'uninitialized': the final id is + # generated on first boot, systemd's first-boot mechanism applies (see machine-id(5)) rm -f -- "${pacstrap_dir}/etc/machine-id" - printf '' > "${pacstrap_dir}/etc/machine-id" + printf 'uninitialized\n' >"${pacstrap_dir}/etc/machine-id" _msg_info "Done!" } @@ -168,13 +180,10 @@ _cleanup_pacstrap_dir() { # Create a squashfs image and place it in the ISO 9660 file system. # $@: options to pass to mksquashfs _run_mksquashfs() { - local image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" + local mksquashfs_options=() image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" rm -f -- "${image_path}" - if [[ "${quiet}" == "y" ]]; then - mksquashfs "$@" "${image_path}" -noappend "${airootfs_image_tool_options[@]}" -no-progress > /dev/null - else - mksquashfs "$@" "${image_path}" -noappend "${airootfs_image_tool_options[@]}" - fi + [[ ! "${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. @@ -198,7 +207,7 @@ _mkairootfs_ext4+squashfs() { [[ ! "${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 + tune2fs -c 0 -i 0 -- "${pacstrap_dir}.img" >/dev/null _msg_info "Done!" install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" @@ -219,16 +228,18 @@ _mkairootfs_squashfs() { # Create an EROFS image containing the root file system and saves it on the ISO 9660 file system. _mkairootfs_erofs() { - local fsuuid + 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 -U "${fsuuid}" "${airootfs_image_tool_options[@]}" -- "${image_path}" "${pacstrap_dir}" + mkfs.erofs "${mkfs_erofs_options[@]}" -- "${image_path}" "${pacstrap_dir}" _msg_info "Done!" } @@ -237,27 +248,24 @@ _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 + sha512sum airootfs.sfs >airootfs.sha512 elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then - sha512sum airootfs.erofs > airootfs.sha512 + sha512sum airootfs.erofs >airootfs.sha512 fi cd -- "${OLDPWD}" _msg_info "Done!" } # GPG sign the root file system image. -_mksignature() { - local airootfs_image_filename gpg_options=() - _msg_info "Signing ${arch} 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 +_mk_pgp_signature() { + local gpg_options=() + local airootfs_image_filename="${1}" + _msg_info "Signing rootfs image using GPG..." + 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 + # always use the .sig file extension, as that is what mkinitcpio-parabolaiso'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!" @@ -275,35 +283,34 @@ _run_once() { # Helper function to run commands for the i686 and x86_64 architectures. # $@: commands to run in both architectures _run_dual() { + local architectures="${arch}" + local arch local cmd - if [[ "${arch}" == "dual" ]]; then - local arch - for arch in i686 x86_64; do - if [[ "${buildmode}" == "bootstrap" ]]; then - pacstrap_dir="${work_dir}/${arch}/bootstrap/root.${arch}" - else - pacstrap_dir="${work_dir}/${arch}/airootfs" - fi - for cmd in "$@"; do - ${cmd} - done - done - else + + if [[ "${architectures}" == "dual" ]]; then + architectures="i686 x86_64" + fi + + for arch in ${architectures}; do + pacstrap_dir="${work_dir}/${arch}/airootfs" + if [[ "${buildmode}" == "bootstrap" ]]; then + pacstrap_dir="${work_dir}/${arch}/bootstrap/root.${arch}" + fi for cmd in "$@"; do ${cmd} done - fi + done } # 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' ' ')" + _system_cache_dirs="$(pacman-conf CacheDir | tr '\n' ' ')" + _profile_cache_dirs="$(pacman-conf --config "${pacman_conf}" CacheDir | tr '\n' ' ')" # 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 + 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}" @@ -316,9 +323,9 @@ _make_pacman_conf() { # HookDir is *always* set to the airootfs' override directory # see `man 8 pacman` for further info sed "/Architecture/d;/\[options\]/a Architecture = ${arch}" "${pacman_conf}" | \ - pacman-conf --config /dev/stdin | \ - 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.${arch}" + pacman-conf --config /dev/stdin \ + | 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.${arch}" } # Prepare working directory and copy custom root file system files. @@ -329,11 +336,11 @@ _make_custom_airootfs() { install -d -m 0755 -o 0 -g 0 -- "${pacstrap_dir}" if [[ -d "${profile}/airootfs" ]]; then - _msg_info "Copying custom airootfs files..." + _msg_info "Copying custom ${arch} 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}"]}" + 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 @@ -361,32 +368,59 @@ _make_packages() { local buildmode_pkg_list_arch eval "buildmode_pkg_list_arch=(\${buildmode_pkg_list_${arch}[@]})" + if [[ -v gpg_publickey ]]; then + exec {PARABOLAISO_GNUPG_FD}<"$gpg_publickey" + export PARABOLAISO_GNUPG_FD + fi + if [[ -v cert_list[0] ]]; then + exec {PARABOLAISO_TLS_FD}<"${cert_list[0]}" + export PARABOLAISO_TLS_FD + fi + if [[ -v cert_list[2] ]]; then + exec {PARABOLAISO_TLSCA_FD}<"${cert_list[2]}" + export PARABOLAISO_TLSCA_FD + fi + + # Install the qemu-arm-static binary - if [[ "${arch}" == "armv7h" ]] && [[ ! "$(uname -m)" == armv7? ]]; then + if [[ "${arch}" == "armv7h" ]] && ! setarch armv7l /bin/true 2>/dev/null; then + # Make sure that qemu-static is set up with binfmt_misc + if [[ -z $(grep -l -xF \ + -e "interpreter /usr/bin/qemu-arm-static" \ + -r -- /proc/sys/fs/binfmt_misc 2>/dev/null \ + | xargs -r grep -xF 'enabled') ]]; then + # Register the qemu-arm-static as an ARM interpreter in the kernel (using binfmt_misc kernel module) + printf ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:' >/proc/sys/fs/binfmt_misc/register + fi install -d -m 0755 -- "${pacstrap_dir}/usr/bin" install -m 0755 -- /usr/bin/qemu-arm-static "${pacstrap_dir}/usr/bin" fi - if [[ -n "${gpg_key}" ]]; then - exec {PARABOLAISO_GNUPG_FD}<>"${work_dir}/pubkey.gpg" - export PARABOLAISO_GNUPG_FD - fi - # 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.${arch}" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" "${buildmode_pkg_list_arch[@]}" &> /dev/null + env -u TMPDIR pacstrap -C "${work_dir}/${buildmode}.pacman.conf.${arch}" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" "${buildmode_pkg_list_arch[@]}" &>/dev/null else env -u TMPDIR pacstrap -C "${work_dir}/${buildmode}.pacman.conf.${arch}" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" "${buildmode_pkg_list_arch[@]}" fi - if [[ -n "${gpg_key}" ]]; then + # Delete the qemu-arm-static binary + if [[ "${arch}" == "armv7h" ]] && ! setarch armv7l /bin/true 2>/dev/null; then + rm -f -- "${pacstrap_dir}/usr/bin/qemu-arm-static" + fi + + if [[ -v cert_list[0] ]]; then + exec {PARABOLAISO_TLS_FD}<&- + unset PARABOLAISO_TLS_FD + fi + if [[ -v cert_list[2] ]]; then + exec {PARABOLAISO_TLSCA_FD}<&- + unset PARABOLAISO_TLSCA_FD + fi + if [[ -v gpg_publickey ]]; then exec {PARABOLAISO_GNUPG_FD}<&- unset PARABOLAISO_GNUPG_FD fi - # Delete the qemu-arm-static binary - rm -f -- "${pacstrap_dir}/usr/bin/qemu-arm-static" - _msg_info "Done! Packages installed successfully." } @@ -407,13 +441,13 @@ _make_customize_airootfs() { 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]}" + cp -dRT --update=none --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" + done <"${profile}/airootfs/etc/passwd" _msg_info "Done!" fi @@ -434,6 +468,10 @@ _make_bootmodes() { for bootmode in "${bootmodes[@]}"; do _run_once "_make_bootmode_${bootmode}" done + + if [[ "${bootmodes[*]}" != *grub* ]]; then + _run_once _make_common_grubenv_and_loopbackcfg + fi } # Copy kernel and initramfs to ISO 9660 @@ -448,39 +486,39 @@ _make_boot_on_iso9660() { # 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" + install -d -m 0755 -- "${isofs_dir}/boot/syslinux" for _cfg in "${profile}/syslinux/"*.cfg; do sed "s|%PARABOLAISO_LABEL%|${iso_label}|g; + s|%PARABOLAISO_UUID%|${iso_uuid}|g; s|%INSTALL_DIR%|${install_dir}|g; s|%ARCH%|${arch}|g" \ - "${_cfg}" > "${isofs_dir}/syslinux/${_cfg##*/}" + "${_cfg}" >"${isofs_dir}/boot/syslinux/${_cfg##*/}" done if [[ -e "${profile}/syslinux/splash.png" ]]; then - install -m 0644 -- "${profile}/syslinux/splash.png" "${isofs_dir}/syslinux/" + install -m 0644 -- "${profile}/syslinux/splash.png" "${isofs_dir}/boot/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/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/"*.c32 "${isofs_dir}/boot/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/lpxelinux.0" "${isofs_dir}/boot/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/memdisk" "${isofs_dir}/boot/syslinux/" _run_dual '_run_once _make_boot_on_iso9660' - if [[ -e "${isofs_dir}/syslinux/hdt.c32" ]]; then - install -d -m 0755 -- "${isofs_dir}/syslinux/hdt" + if [[ -e "${isofs_dir}/boot/syslinux/hdt.c32" ]]; then + install -d -m 0755 -- "${isofs_dir}/boot/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" + "${isofs_dir}/boot/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" + "${isofs_dir}/boot/syslinux/hdt/modalias.gz" fi # Add other aditional/extra files to ${install_dir}/boot/ if [[ -e "${pacstrap_dir}/boot/memtest86+/memtest.bin" ]]; then + install -d -m 0755 -- "${isofs_dir}/boot/memtest86+/" # rename for PXE: https://wiki.parabola.nu/index.php/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+/" + install -m 0644 -- "${pacstrap_dir}/boot/memtest86+/memtest.bin" "${isofs_dir}/boot/memtest86+/memtest" + install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/common/GPL2/license.txt" "${isofs_dir}/boot/memtest86+/" fi _msg_info "Done! SYSLINUX set up for BIOS booting from a disk successfully." } @@ -488,9 +526,9 @@ _make_bootmode_bios.syslinux.mbr() { # 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/" + install -d -m 0755 -- "${isofs_dir}/boot/syslinux" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isolinux.bin" "${isofs_dir}/boot/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isohdpfx.bin" "${isofs_dir}/boot/syslinux/" # ISOLINUX and SYSLINUX installation is shared _run_once _make_bootmode_bios.syslinux.mbr @@ -501,9 +539,9 @@ _make_bootmode_bios.syslinux.eltorito() { # Copy kernel and initramfs to FAT image _make_boot_on_fat() { _msg_info "Preparing kernel and initramfs for the FAT file system..." - mmd -i "${work_dir}/efiboot.img" \ + mmd -i "${efibootimg}" \ "::/${install_dir}" "::/${install_dir}/boot" "::/${install_dir}/boot/x86_64" - mcopy -i "${work_dir}/efiboot.img" "${pacstrap_dir}/boot/vmlinuz-"* \ + mcopy -i "${efibootimg}" "${pacstrap_dir}/boot/vmlinuz-"* \ "${pacstrap_dir}/boot/initramfs-"*".img" "::/${install_dir}/boot/x86_64/" _msg_info "Done!" } @@ -511,117 +549,400 @@ _make_boot_on_fat() { # Create a FAT image (efiboot.img) which will serve as the EFI system partition # $1: image size in bytes _make_efibootimg() { - local imgsize="0" + local imgsize_kib="0" + local imgsize_bytes=${1} + + if (( imgsize_bytes < 2*1024*1024 )); then + _msg_info "Validating '${bootmode}': efiboot.img size is ${imgsize_bytes} bytes is less than 2 MiB! Bumping up to 2 MiB" + imgsize_bytes=$((2*1024*1024)) + fi # 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))} + imgsize_kib="$( + 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}" + END {print mib_to_kib(ceil((byte_to_kib($1)+1024)/1024))}' <<<"${imgsize_bytes}" )" # 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..." - mkfs.fat -C -n PARAISO_EFI "${work_dir}/efiboot.img" "${imgsize}" + rm -f -- "${efibootimg}" + _msg_info "Creating FAT image of size: ${imgsize_kib} 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 PARAISO_EFI "${efibootimg}" "${imgsize_kib}" >/dev/null + else + mkfs.fat -C -n PARAISO_EFI "${efibootimg}" "${imgsize_kib}" + 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 + mmd -i "${efibootimg}" ::/EFI ::/EFI/BOOT } -# Prepare system-boot for booting when written to a disk (isohybrid) -_make_bootmode_uefi-x64.systemd-boot.esp() { - local efiboot_imgsize - _msg_info "Setting up systemd-boot for UEFI booting..." +# Copy GRUB files to ISO 9660 which is used by both IA32 UEFI and x64 UEFI +_make_common_bootmode_grub_copy_to_isofs() { + local files_to_copy=() - # 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" \ - 2>/dev/null | awk 'END { print $1 }')" - # Create a FAT image for the EFI system partition - _make_efibootimg "$efiboot_imgsize" + files_to_copy+=("${work_dir}/grub/"*) + if compgen -G "${profile}/grub/!(*.cfg)" &>/dev/null; then + files_to_copy+=("${profile}/grub/"!(*.cfg)) + fi + install -d -m 0755 -- "${isofs_dir}/boot/grub" + cp -r --remove-destination -- "${files_to_copy[@]}" "${isofs_dir}/boot/grub/" +} - # 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 +# Prepare GRUB configuration files +_make_common_bootmode_grub_cfg() { + local _cfg search_filename - # 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 + install -d -- "${work_dir}/grub" + + # Create a /boot/grub/YYYY-mm-dd-HH-MM-SS-00.uuid file on ISO 9660. GRUB will search for it to find the ISO + # volume. This is similar to what grub-mkrescue does, except it places the file in /.disk/, but we opt to use a + # directory that does not start with a dot to avoid it being accidentally missed when copying the ISO's contents. + : >"${work_dir}/grub/${iso_uuid}.uuid" + search_filename="/boot/grub/${iso_uuid}.uuid" + + # Fill GRUB configuration files + for _cfg in "${profile}/grub/"*'.cfg'; do sed "s|%PARABOLAISO_LABEL%|${iso_label}|g; + s|%PARABOLAISO_UUID%|${iso_uuid}|g; s|%INSTALL_DIR%|${install_dir}|g; - s|%ARCH%|${arch}|g" \ - "${_conf}" | mcopy -i "${work_dir}/efiboot.img" - "::/loader/entries/${_conf##*/}" + s|%ARCH%|${arch}|g; + s|%PARABOLAISO_SEARCH_FILENAME%|${search_filename}|g" \ + "${_cfg}" >"${work_dir}/grub/${_cfg##*/}" done - # shellx64.efi is picked up automatically when on / + # Prepare grub.cfg that will be embedded inside the GRUB binaries + IFS='' read -r -d '' grubembedcfg <<'EOF' || true +if ! [ -d "$cmdpath" ]; then + # On some firmware, GRUB has a wrong cmdpath when booted from an optical disc. During El Torito boot, GRUB is + # launched from a case-insensitive FAT-formatted EFI system partition, but it seemingly cannot access that partition + # and sets cmdpath to the whole cd# device which has case-sensitive ISO 9660 + Rock Ridge + Joliet file systems. + # See https://gitlab.archlinux.org/archlinux/archiso/-/issues/183 and https://savannah.gnu.org/bugs/?62886 + if regexp --set=1:parabolaiso_bootdevice '^\(([^)]+)\)\/?[Ee][Ff][Ii]\/[Bb][Oo][Oo][Tt]\/?$' "${cmdpath}"; then + set cmdpath="(${parabolaiso_bootdevice})/EFI/BOOT" + set PARABOLAISO_HINT="${parabolaiso_bootdevice}" + fi +fi + +# Prepare a hint for the search command using the device in cmdpath +if [ -z "${PARABOLAISO_HINT}" ]; then + regexp --set=1:PARABOLAISO_HINT '^\(([^)]+)\)' "${cmdpath}" +fi + +# Search for the ISO volume +if search --no-floppy --set=parabolaiso_device --file '%PARABOLAISO_SEARCH_FILENAME%' --hint "${PARABOLAISO_HINT}"; then + set PARABOLAISO_HINT="${parabolaiso_device}" + if probe --set PARABOLAISO_UUID --fs-uuid "${PARABOLAISO_HINT}"; then + export PARABOLAISO_UUID + fi +else + echo "Could not find a volume with a '%PARABOLAISO_SEARCH_FILENAME%' file on it!" +fi + +# Load grub.cfg +if [ "${PARABOLAISO_HINT}" == 'memdisk' -o -z "${PARABOLAISO_HINT}" ]; then + echo 'Could not find the ISO volume!' +elif [ -e "(${PARABOLAISO_HINT})/boot/grub/grub.cfg" ]; then + export PARABOLAISO_HINT + set root="${PARABOLAISO_HINT}" + configfile "(${PARABOLAISO_HINT})/boot/grub/grub.cfg" +else + echo "File '(${PARABOLAISO_HINT})/boot/grub/grub.cfg' not found!" +fi +EOF + grubembedcfg="${grubembedcfg//'%PARABOLAISO_SEARCH_FILENAME%'/"${search_filename}"}" + printf '%s\n' "$grubembedcfg" >"${work_dir}/grub-embed.cfg" + + # Write grubenv + printf '%.1024s' \ + "$(printf '# GRUB Environment Block\nNAME=%s\nVERSION=%s\nPARABOLAISO_LABEL=%s\nINSTALL_DIR=%s\nARCH=%s\nPARABOLAISO_SEARCH_FILENAME=%s\n%s' \ + "${iso_name}" \ + "${iso_version}" \ + "${iso_label}" \ + "${install_dir}" \ + "${arch}" \ + "${search_filename}" \ + "$(printf '%0.1s' "#"{1..1024})")" \ + >"${work_dir}/grub/grubenv" +} + +# Create GRUB specific configuration files when GRUB is not used as a boot loader +_make_common_grubenv_and_loopbackcfg() { + local search_filename + + install -d -m 0755 -- "${isofs_dir}/boot/grub" + # Create a /boot/grub/YYYY-mm-dd-HH-MM-SS-00.uuid file on ISO 9660. GRUB will search for it to find the ISO + # volume. This is similar to what grub-mkrescue does, except it places the file in /.disk/, but we opt to use a + # directory that does not start with a dot to avoid it being accidentally missed when copying the ISO's contents. + search_filename="/boot/grub/${iso_uuid}.uuid" + : >"${isofs_dir}/${search_filename}" + + # Write grubenv + printf '%.1024s' \ + "$(printf '# GRUB Environment Block\nNAME=%s\nVERSION=%s\nPARABOLAISO_LABEL=%s\nINSTALL_DIR=%s\nARCH=%s\nPARABOLAISO_SEARCH_FILENAME=%s\n%s' \ + "${iso_name}" \ + "${iso_version}" \ + "${iso_label}" \ + "${install_dir}" \ + "${arch}" \ + "${search_filename}" \ + "$(printf '%0.1s' "#"{1..1024})")" \ + >"${isofs_dir}/boot/grub/grubenv" + + # Copy loopback.cfg to /boot/grub/ on ISO 9660 + if [[ -e "${profile}/grub/loopback.cfg" ]]; then + sed "s|%PARABOLAISO_LABEL%|${iso_label}|g; + s|%PARABOLAISO_UUID%|${iso_uuid}|g; + s|%INSTALL_DIR%|${install_dir}|g; + s|%ARCH%|${arch}|g; + s|%PARABOLAISO_SEARCH_FILENAME%|${search_filename}|g" \ + "${profile}/grub/loopback.cfg" >"${isofs_dir}/boot/grub/loopback.cfg" + fi +} + +_make_bootmode_uefi-ia32.grub.esp() { + local grubmodules=() + + # Prepare configuration files + _run_once _make_common_bootmode_grub_cfg + + # Create EFI binary + # Module list from https://bugs.archlinux.org/task/71382#comment202911 + grubmodules=(all_video at_keyboard boot btrfs cat chain configfile echo efifwsetup efinet exfat ext2 f2fs fat font \ + gfxmenu gfxterm gzio halt hfsplus iso9660 jpeg keylayouts linux loadenv loopback lsefi lsefimmap \ + minicmd normal ntfs ntfscomp part_apple part_gpt part_msdos png read reboot regexp search \ + search_fs_file search_fs_uuid search_label serial sleep tpm udf usb usbserial_common usbserial_ftdi \ + usbserial_pl2303 usbserial_usbdebug video xfs zstd) + grub-mkstandalone -O i386-efi \ + --modules="${grubmodules[*]}" \ + --locales="en@quot" \ + --themes="" \ + --disable-shim-lock \ + -o "${work_dir}/BOOTIA32.EFI" "boot/grub/grub.cfg=${work_dir}/grub-embed.cfg" + # Add GRUB to the list of files used to calculate the required FAT image size. + efiboot_files+=("${work_dir}/BOOTIA32.EFI" + "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi") + + if [[ " ${bootmodes[*]} " =~ uefi-x64.systemd-boot.esp ]]; then + # TODO: Remove this branch. + _run_once _make_bootmode_uefi-x64.systemd-boot.esp + elif [[ " ${bootmodes[*]} " =~ uefi-x64.grub.esp ]]; then + _run_once _make_bootmode_uefi-x64.grub.esp + else + efiboot_imgsize="$(du -bcs -- "${efiboot_files[@]}" 2>/dev/null | awk 'END { print $1 }')" + # Create a FAT image for the EFI system partition + _make_efibootimg "$efiboot_imgsize" + fi + + # Copy GRUB EFI binary to the default/fallback boot path + mcopy -i "${efibootimg}" "${work_dir}/BOOTIA32.EFI" ::/EFI/BOOT/BOOTIA32.EFI + + # Copy GRUB files + _run_once _make_common_bootmode_grub_copy_to_isofs + + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ]]; then + mcopy -i "${efibootimg}" "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ::/shellia32.efi + fi + + _msg_info "Done! GRUB set up for UEFI booting successfully." +} + +# Prepare GRUB for El Torito booting +_make_bootmode_uefi-ia32.grub.eltorito() { + # El Torito UEFI boot requires an image containing the EFI system partition. + # uefi-ia32.grub.eltorito has the same requirements as uefi-ia32.grub.esp + _run_once _make_bootmode_uefi-ia32.grub.esp + + # Prepare configuration files + _run_once _make_common_bootmode_grub_cfg + + # Additionally set up systemd-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 GRUB EFI binary to the default/fallback boot path + install -m 0644 -- "${work_dir}/BOOTIA32.EFI" "${isofs_dir}/EFI/BOOT/BOOTIA32.EFI" + + # Copy GRUB configuration files + _run_once _make_common_bootmode_grub_copy_to_isofs + + # edk2-shell based UEFI shell + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ]]; then + install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" "${isofs_dir}/shellia32.efi" + fi + + _msg_info "Done!" +} + +_make_bootmode_uefi-x64.grub.esp() { + local grubmodules=() + + # Prepare configuration files + _run_once _make_common_bootmode_grub_cfg + + # Create EFI binary + # Module list from https://bugs.archlinux.org/task/71382#comment202911 + grubmodules=(all_video at_keyboard boot btrfs cat chain configfile echo efifwsetup efinet ext2 f2fs fat font \ + gfxmenu gfxterm gzio halt hfsplus iso9660 jpeg keylayouts linux loadenv loopback lsefi lsefimmap \ + minicmd normal part_apple part_gpt part_msdos png read reboot regexp search search_fs_file \ + search_fs_uuid search_label serial sleep tpm usb usbserial_common usbserial_ftdi usbserial_pl2303 \ + usbserial_usbdebug video xfs zstd) + grub-mkstandalone -O x86_64-efi \ + --modules="${grubmodules[*]}" \ + --locales="en@quot" \ + --themes="" \ + --disable-shim-lock \ + -o "${work_dir}/BOOTx64.EFI" "boot/grub/grub.cfg=${work_dir}/grub-embed.cfg" + # Add GRUB to the list of files used to calculate the required FAT image size. + efiboot_files+=("${work_dir}/BOOTx64.EFI" + "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi") + + efiboot_imgsize="$(du -bcs -- "${efiboot_files[@]}" 2>/dev/null | awk 'END { print $1 }')" + + # Create a FAT image for the EFI system partition + _make_efibootimg "$efiboot_imgsize" + + # Copy GRUB EFI binary to the default/fallback boot path + mcopy -i "${efibootimg}" "${work_dir}/BOOTx64.EFI" ::/EFI/BOOT/BOOTx64.EFI + + # Copy GRUB files + _run_once _make_common_bootmode_grub_copy_to_efibootimg + 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 + mcopy -i "${efibootimg}" "${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 + # Add other aditional/extra files to ${install_dir}/boot/ + if [[ -e "${pacstrap_dir}/boot/memtest86+/memtest.efi" ]]; then + install -d -m 0755 -- "${isofs_dir}/boot/memtest86+/" + install -m 0644 -- "${pacstrap_dir}/boot/memtest86+/memtest.efi" "${isofs_dir}/boot/memtest86+/memtest.efi" + install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/common/GPL2/license.txt" "${isofs_dir}/boot/memtest86+/" + fi + + _msg_info "Done! GRUB set up for UEFI booting successfully." +} + +# Prepare GRUB for El Torito booting +_make_bootmode_uefi-x64.grub.eltorito() { + # El Torito UEFI boot requires an image containing the EFI system partition. + # uefi-x64.grub.eltorito has the same requirements as uefi-x64.grub.esp + _run_once _make_bootmode_uefi-x64.grub.esp + + # Prepare configuration files + _run_once _make_common_bootmode_grub_cfg + + # Additionally set up systemd-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 GRUB EFI binary to the default/fallback boot path + install -m 0644 -- "${work_dir}/BOOTx64.EFI" "${isofs_dir}/EFI/BOOT/BOOTx64.EFI" + + # Copy GRUB files + _run_once _make_common_bootmode_grub_copy_to_isofs + + # edk2-shell based UEFI shell + 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! systemd-boot set up for UEFI booting successfully." + _msg_info "Done!" } -# Prepare rEFInd for booting when written to a disk (isohybrid) -_make_bootmode_uefi-x64.refind.esp() { - local efiboot_imgsize - _msg_info "Setting up rEFInd for UEFI booting..." +_make_common_bootmode_systemd-boot() { + local _file efiboot_imgsize # Calculate the required FAT image size in bytes - efiboot_imgsize="$(du -bc \ - "${pacstrap_dir}/usr/share/refind/refind_x64.efi" \ - "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" \ - "${profile}/efiboot/" \ - "${pacstrap_dir}/boot/vmlinuz-"* \ - "${pacstrap_dir}/boot/initramfs-"*".img" \ - 2>/dev/null | awk 'END { print $1 }')" + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' || " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' ]]; then + efiboot_files+=("${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" + "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi") + fi + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-ia32.systemd-boot.esp ' || " ${bootmodes[*]} " =~ ' uefi-ia32.systemd-boot.eltorito ' ]]; then + efiboot_files+=("${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootia32.efi" + "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi") + fi + efiboot_files+=("${work_dir}/loader/" + "${pacstrap_dir}/boot/vmlinuz-"* + "${pacstrap_dir}/boot/initramfs-"*".img") + efiboot_imgsize="$(du -bcs -- "${efiboot_files[@]}" 2>/dev/null | awk 'END { print $1 }')" # Create a FAT image for the EFI system partition _make_efibootimg "$efiboot_imgsize" +} - # Copy rEFInd EFI binary to the default/fallback boot path - mcopy -i "${work_dir}/efiboot.img" \ - "${pacstrap_dir}/usr/share/refind/refind_x64.efi" ::/EFI/BOOT/BOOTx64.EFI +_make_common_bootmode_systemd-boot_conf() { + local _conf - # Copy rEFInd configuration files - mmd -i "${work_dir}/efiboot.img" ::/EFI/BOOT/entries - mcopy -i "${work_dir}/efiboot.img" "${profile}/efiboot/EFI/BOOT/refind.conf" ::/EFI/BOOT/ - for _conf in "${profile}/efiboot/EFI/BOOT/entries/"*".conf"; do + install -d -m 0755 -- "${work_dir}/loader" "${work_dir}/loader/entries" + + install -m 0644 -- "${profile}/efiboot/loader/loader.conf" "${work_dir}/loader" + for _conf in "${profile}/efiboot/loader/entries/"*".conf"; do sed "s|%PARABOLAISO_LABEL%|${iso_label}|g; + s|%PARABOLAISO_UUID%|${iso_uuid}|g; s|%INSTALL_DIR%|${install_dir}|g; s|%ARCH%|${arch}|g" \ - "${_conf}" | mcopy -i "${work_dir}/efiboot.img" - "::/EFI/BOOT/entries/${_conf##*/}" + "${_conf}" >"${work_dir}/loader/entries/${_conf##*/}" done +} + +# Copy systemd-boot configuration files to ISO 9660 +_make_common_bootmode_systemd-boot_conf.isofs() { + cp -r --remove-destination -- "${work_dir}/loader" "${isofs_dir}/" +} + +# Copy systemd-boot configuration files to FAT image +_make_common_bootmode_systemd-boot_conf.esp() { + mcopy -i "${efibootimg}" -s "${work_dir}/loader" ::/ +} + +# Prepare systemd-boot for booting when written to a disk (isohybrid) +_make_bootmode_uefi-x64.systemd-boot.esp() { + _msg_info "Setting up systemd-boot for x64 UEFI booting..." + + # Prepare configuration files + _run_once _make_common_bootmode_systemd-boot_conf + + # Prepare a FAT image for the EFI system partition + _run_once _make_common_bootmode_systemd-boot + + # Copy systemd-boot EFI binary to the default/fallback boot path + mcopy -i "${efibootimg}" \ + "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI + + # Copy systemd-boot configuration files + _run_once _make_common_bootmode_systemd-boot_conf.esp # 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" \ + mcopy -i "${efibootimg}" \ "${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 + _run_once _make_boot_on_fat - _msg_info "Done! rEFInd set up for UEFI booting successfully." + _msg_info "Done! systemd-boot set up for x64 UEFI booting successfully." } -# Prepare system-boot for El Torito booting +# Prepare systemd-boot for El Torito booting _make_bootmode_uefi-x64.systemd-boot.eltorito() { + # Prepare configuration files + _run_once _make_common_bootmode_systemd-boot_conf + # 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 + # Additionally set up systemd-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..." @@ -632,14 +953,7 @@ _make_bootmode_uefi-x64.systemd-boot.eltorito() { "${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|%PARABOLAISO_LABEL%|${iso_label}|g; - s|%INSTALL_DIR%|${install_dir}|g; - s|%ARCH%|${arch}|g" \ - "${_conf}" > "${isofs_dir}/loader/entries/${_conf##*/}" - done + _run_once _make_common_bootmode_systemd-boot_conf.isofs # edk2-shell based UEFI shell # shellx64.efi is picked up automatically when on / @@ -650,36 +964,60 @@ _make_bootmode_uefi-x64.systemd-boot.eltorito() { _msg_info "Done!" } -# Prepare rEFInd for El Torito booting -_make_bootmode_uefi-x64.refind.eltorito() { +_make_bootmode_uefi-ia32.systemd-boot.esp() { + _msg_info "Setting up systemd-boot for IA32 UEFI booting..." + + # Prepare configuration files + _run_once _make_common_bootmode_systemd-boot_conf + + # Prepare a FAT image for the EFI system partition + _run_once _make_common_bootmode_systemd-boot + + # Copy systemd-boot EFI binary to the default/fallback boot path + mcopy -i "${efibootimg}" \ + "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootia32.efi" ::/EFI/BOOT/BOOTIA32.EFI + + # Copy systemd-boot configuration files + _run_once _make_common_bootmode_systemd-boot_conf.esp + + # shellia32.efi is picked up automatically when on / + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ]]; then + mcopy -i "${efibootimg}" \ + "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ::/shellia32.efi + fi + + # Copy kernel and initramfs to FAT image. + # systemd-boot can only access files from the EFI system partition it was launched from. + _run_once _make_boot_on_fat + + _msg_info "Done! systemd-boot set up for IA32 UEFI booting successfully." +} + +_make_bootmode_uefi-ia32.systemd-boot.eltorito() { + # Prepare configuration files + _run_once _make_common_bootmode_systemd-boot_conf + # El Torito UEFI boot requires an image containing the EFI system partition. - # uefi-x64.refind.eltorito has the same requirements as uefi-x64.refind.esp - _run_once _make_bootmode_uefi-x64.refind.esp + # uefi-ia32.systemd-boot.eltorito has the same requirements as uefi-ia32.systemd-boot.esp + _run_once _make_bootmode_uefi-ia32.systemd-boot.esp - # Additionally set up rEFInd in ISO 9660. This allows creating a medium for the live environment by using + # Additionally set up systemd-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 rEFInd EFI binary to the default/fallback boot path - install -m 0644 -- "${pacstrap_dir}/usr/share/refind/refind_x64.efi" \ - "${isofs_dir}/EFI/BOOT/BOOTx64.EFI" + # Copy systemd-boot EFI binary to the default/fallback boot path + install -m 0644 -- "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootia32.efi" \ + "${isofs_dir}/EFI/BOOT/BOOTIA32.EFI" - # Copy rEFInd configuration files - install -d -m 0755 -- "${isofs_dir}/EFI/BOOT/entries" - install -m 0644 -- "${profile}/efiboot/EFI/BOOT/refind.conf" "${isofs_dir}/EFI/BOOT/" - for _conf in "${profile}/efiboot/EFI/BOOT/entries/"*".conf"; do - sed "s|%PARABOLAISO_LABEL%|${iso_label}|g; - s|%INSTALL_DIR%|${install_dir}|g; - s|%ARCH%|${arch}|g" \ - "${_conf}" > "${isofs_dir}/EFI/BOOT/entries/${_conf##*/}" - done + # Copy systemd-boot configuration files + _run_once _make_common_bootmode_systemd-boot_conf.isofs # 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" + # shellia32.efi is picked up automatically when on / + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ]]; then + install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" "${isofs_dir}/shellia32.efi" fi _msg_info "Done!" @@ -728,15 +1066,16 @@ _validate_requirements_bootmode_bios.syslinux.eltorito() { _validate_requirements_bootmode_bios.syslinux.mbr } -_validate_requirements_bootmode_uefi-x64.systemd-boot.esp() { +_validate_requirements_common_systemd-boot() { # Check if mkfs.fat is available - if ! command -v mkfs.fat &> /dev/null; then + 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 + 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 @@ -761,78 +1100,150 @@ _validate_requirements_bootmode_uefi-x64.systemd-boot.esp() { fi # Check for optional packages - if [[ "${arch}" == "dual" ]]; then - # shellcheck disable=SC2154 - if [[ ! " ${pkg_list_x86_64[*]} " =~ ' edk2-shell ' ]]; then - _msg_info "'edk2-shell' is not in the x86_64 package list. The ISO will not contain a bootable UEFI shell." - fi + # 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.esp() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-x64.grub.esp!" 0 + fi + _validate_requirements_common_systemd-boot +} + +_validate_requirements_bootmode_uefi-x64.systemd-boot.eltorito() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.grub.eltorito ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-x64.grub.eltorito!" 0 + fi + + # uefi-x64.systemd-boot.eltorito has the exact same requirements as uefi-x64.systemd-boot.esp + _validate_requirements_bootmode_uefi-x64.systemd-boot.esp +} + +_validate_requirements_bootmode_uefi-ia32.systemd-boot.esp() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-ia32.grub.esp ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-ia32.grub.esp!" 0 + fi + + _validate_requirements_common_systemd-boot +} + +_validate_requirements_bootmode_uefi-ia32.systemd-boot.eltorito() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-ia32.grub.eltorito ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-ia32.grub.eltorito!" 0 + fi + + # uefi-ia32.systemd-boot.eltorito has the exact same requirements as uefi-ia32.systemd-boot.esp + _validate_requirements_bootmode_uefi-x64.systemd-boot.esp +} + +_validate_requirements_bootmode_uefi-ia32.grub.esp() { + # Check if GRUB is available + if ! command -v grub-mkstandalone &>/dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': grub-install is not available on this host. Install 'grub'!" 0 + fi + + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' ]]; then + _validate_requirements_bootmode_uefi-x64.systemd-boot.esp + elif [[ " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' ]]; then + _validate_requirements_bootmode_uefi-x64.grub.esp else - 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 + _msg_error "Validating '${bootmode}': requires one of bootmode uefi-x64.systemd-boot.esp or uefi-x64.grub.esp" 0 fi } -_validate_requirements_bootmode_uefi-x64.refind.esp() { - # Check if mkfs.fat is available - if ! command -v mkfs.fat &> /dev/null; then +_validate_requirements_bootmode_uefi-ia32.grub.eltorito() { + # uefi-ia32.grub.eltorito has the exact same requirements as uefi-ia32.grub.esp + _validate_requirements_bootmode_uefi-ia32.grub.esp +} + +_validate_requirements_bootmode_uefi-x64.grub.esp() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-x64.systemd-boot.esp!" 0 + fi + + # Check if GRUB is available + if ! command -v grub-mkstandalone &>/dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': grub-install is not available on this host. Install 'grub'!" 0 + fi + + # 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 + if ! { command -v mmd &>/dev/null && command -v mcopy &>/dev/null; }; then _msg_error "Validating '${bootmode}': mmd and/or mcopy are not available on this host. Install 'mtools'!" 0 fi - # Check if rEFInd configuration files exist - if [[ ! -d "${profile}/efiboot/EFI/BOOT/entries" ]]; then + # Check if GRUB configuration files exist + if [[ ! -d "${profile}/grub" ]]; then (( validation_error=validation_error+1 )) - _msg_error "Validating '${bootmode}': The '${profile}/efiboot/EFI/BOOT/entries' directory is missing!" 0 + _msg_error "Validating '${bootmode}': The '${profile}/grub' directory is missing!" 0 else - if [[ ! -e "${profile}/efiboot/EFI/BOOT/refind.conf" ]]; then + if [[ ! -e "${profile}/grub/grub.cfg" ]]; then (( validation_error=validation_error+1 )) - _msg_error "Validating '${bootmode}': File '${profile}/efiboot/EFI/BOOT/refind.conf' not found!" 0 + _msg_error "Validating '${bootmode}': File '${profile}/grub/grub.cfg' not found!" 0 fi local conffile - for conffile in "${profile}/efiboot/EFI/BOOT/entries/"*'.conf'; do + for conffile in "${profile}/grub/"*'.cfg'; do if [[ -e "${conffile}" ]]; then break else (( validation_error=validation_error+1 )) - _msg_error "Validating '${bootmode}': No configuration file found in '${profile}/efiboot/EFI/BOOT/entries/'!" 0 + _msg_error "Validating '${bootmode}': No configuration file found in '${profile}/grub/'!" 0 fi done fi # Check for optional packages - if [[ "${arch}" == "dual" ]]; then - if [[ ! " ${pkg_list_x86_64[*]} " =~ ' edk2-shell ' ]]; then - _msg_info "'edk2-shell' is not in the x86_64 package list. The ISO will not contain a bootable UEFI shell." - fi - else - 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 + # 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 + # shellcheck disable=SC2076 + if [[ ! " ${pkg_list[*]} " =~ ' memtest86+-efi ' ]]; then + _msg_info "Validating '${bootmode}': 'memtest86+-efi' is not in the package list. Memory testing will not be available from GRUB." 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 -} - -_validate_requirements_bootmode_uefi-x64.refind.eltorito() { - # uefi-x64.refind.eltorito has the exact same requirements as uefi-x64.refind.esp - _validate_requirements_bootmode_uefi-x64.refind.esp +_validate_requirements_bootmode_uefi-x64.grub.eltorito() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-x64.systemd-boot.eltorito!" 0 + fi + # uefi-x64.grub.eltorito has the exact same requirements as uefi-x64.grub.esp + _validate_requirements_bootmode_uefi-x64.grub.esp } # Build airootfs filesystem image _prepare_airootfs_image() { _run_once "_mkairootfs_${airootfs_image_type}" _mkchecksum + + 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 + if [[ -n "${gpg_key}" ]]; then - _mksignature + _mk_pgp_signature "${airootfs_image_filename}" + fi + if [[ -v cert_list ]]; then + _cms_sign_artifact "${airootfs_image_filename}" fi } @@ -841,8 +1252,38 @@ _export_netboot_artifacts() { _msg_info "Exporting netboot artifacts..." install -d -m 0755 "${out_dir}" cp -a -- "${isofs_dir}/${install_dir}/" "${out_dir}/" + + # Remove grubenv since it serves no purpose in netboot artifacts + rm -f -- "${out_dir}/${install_dir}/grubenv" + + _msg_info "Done!" + du -hs -- "${out_dir}/${install_dir}" +} + +_cms_sign_artifact() { + local artifact="${1}" + local openssl_flags=( + "-sign" + "-binary" + "-nocerts" + "-noattr" + "-outform" "DER" "-out" "${artifact}.cms.sig" + "-in" "${artifact}" + "-signer" "${cert_list[0]}" + "-inkey" "${cert_list[1]}" + ) + + if (( ${#cert_list[@]} > 2 )); then + openssl_flags+=("-certfile" "${cert_list[2]}") + fi + + _msg_info "Signing ${artifact} image using openssl cms..." + + rm -f -- "${artifact}.cms.sig" + + openssl cms "${openssl_flags[@]}" + _msg_info "Done!" - du -h -- "${out_dir}/${install_dir}" } # sign build artifacts for netboot @@ -851,7 +1292,8 @@ _sign_netboot_artifacts() { local _files_to_sign=() _msg_info "Signing netboot artifacts..." _dir="${isofs_dir}/${install_dir}/boot/" - for _file in "${_files_to_sign[@]}" "${_dir}${arch}/vmlinuz-"* "${_dir}${arch}/initramfs-"*.img; do + for _file in "${_files_to_sign[@]}" "${_dir}${arch}/vmlinuz-"!(*.sig) "${_dir}${arch}/initramfs-"*.img; do + rm -f -- "${_file}".ipxe.sig openssl cms \ -sign \ -binary \ @@ -866,14 +1308,14 @@ _sign_netboot_artifacts() { } _validate_requirements_airootfs_image_type_squashfs() { - if ! command -v mksquashfs &> /dev/null; then + 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 } _validate_requirements_airootfs_image_type_ext4+squashfs() { - if ! { command -v mkfs.ext4 &> /dev/null && command -v tune2fs &> /dev/null; }; then + 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 @@ -881,79 +1323,194 @@ _validate_requirements_airootfs_image_type_ext4+squashfs() { } _validate_requirements_airootfs_image_type_erofs() { - if ! command -v mkfs.erofs; then + if ! command -v mkfs.erofs &>/dev/nul; 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 } -_validate_requirements_buildmode_all() { - if ! command -v pacman &> /dev/null; then +_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 + 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 + 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() { - _validate_requirements_buildmode_all - if ! command -v bsdtar &> /dev/null; then + local bootstrap_pkg_list_from_file=() + + if [[ "${arch}" == "dual" ]]; then + # Check if packages for the bootstrap image are specified for each architecture + for bootstrap_packages in ${bootstrap_packages_dual}; do + if [[ "${bootstrap_packages##*/}" == "bootstrap_packages.both" ]]; then + 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 + elif [[ -e "${bootstrap_packages}" ]]; then + mapfile -t "bootstrap_pkg_list_from_file_${bootstrap_packages##*.}" < \ + <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${bootstrap_packages}") + eval "bootstrap_pkg_list_${bootstrap_packages##*.}+=(\${bootstrap_pkg_list_from_file_${bootstrap_packages##*.}[@]})" + fi + done + else + # 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 + 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 - if [[ "${arch}" == "armv7h" ]] && [[ ! "$(uname -m)" == armv7? ]]; then - if ! command -v qemu-arm-static &> /dev/null; then + + if [[ "${arch}" == "armv7h" ]] && ! setarch armv7l /bin/true &>/dev/null; then + if ! command -v qemu-arm-static &>/dev/null; then (( validation_error=validation_error+1 )) _msg_error "Validating build mode '${_buildmode}': qemu-arm-static is not available on this host. Install 'qemu-user-static'!" 0 fi - if [[ ! -e "/usr/lib/binfmt.d/qemu-arm.conf" ]]; then - (( validation_error=validation_error+1 )) - _msg_error "Validating build mode '${_buildmode}': qemu-user-static-binfmt is not available on this host. Install 'qemu-user-static-binfmt'!" 0 - fi - if command -v rc-service &> /dev/null; then - if ! rc-service binfmt status &> /dev/null; then + fi +} + +_validate_common_requirements_buildmode_iso_netboot() { + local bootmode + local pkg_list_from_file=() + + # Check if the package list file exists and read packages from it + if [[ "${arch}" == "dual" ]]; then + # Check if the package list files exist and read packages from them for each architecture + for packages in ${packages_dual}; do + if [[ "${packages##*/}" == "packages.both" ]]; then + 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 "Packages file '${packages}' does not exist." 0 + fi + else + (( validation_error=validation_error+1 )) + _msg_error "Packages file '${packages}' does not exist." 0 + fi + elif [[ -e "${packages}" ]]; then + mapfile -t "pkg_list_from_file_${packages##*.}" < <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${packages}") + eval "pkg_list_${packages##*.}+=(\${pkg_list_from_file_${packages##*.}[@]})" + fi + done + else + # 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 "Validating build mode '${_buildmode}': binfmt is not available on this host. Start the binfmt service!" 0 + _msg_error "Packages file '${packages}' does not exist." 0 fi - elif command -v systemctl &> /dev/null; then - if ! systemctl status systemd-binfmt &> /dev/null; then + else + (( validation_error=validation_error+1 )) + _msg_error "Packages file '${packages}' does not exist." 0 + fi + fi + + if [[ -v cert_list ]]; then + # Check if the certificate files exist + for _cert in "${cert_list[@]}"; do + if [[ ! -e "${_cert}" ]]; then (( validation_error=validation_error+1 )) - _msg_error "Validating build mode '${_buildmode}': binfmt is not available on this host. Start the systemd-binfmt service!" 0 + _msg_error "File '${_cert}' does not exist." 0 fi + done + # Check if there are at least three certificate files to sign netboot and rootfs. + if (( ${#cert_list[@]} < 2 )); then + (( validation_error=validation_error+1 )) + _msg_error "Two certificates are required for codesigning netboot artifacts, but '${cert_list[*]}' is provided." 0 + fi + + 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 + fi + + # 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 } _validate_requirements_buildmode_iso() { - _validate_requirements_buildmode_all - if ! command -v awk &> /dev/null; then + _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() { - _validate_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 + _validate_common_requirements_buildmode_iso_netboot + _validate_common_requirements_buildmode_all } # SYSLINUX El Torito _add_xorrisofs_options_bios.syslinux.eltorito() { xorrisofs_options+=( # El Torito boot image for x86 BIOS - '-eltorito-boot' 'syslinux/isolinux.bin' + '-eltorito-boot' 'boot/syslinux/isolinux.bin' # El Torito boot catalog file - '-eltorito-catalog' 'syslinux/boot.cat' + '-eltorito-catalog' 'boot/syslinux/boot.cat' # Required options to boot with ISOLINUX '-no-emul-boot' '-boot-load-size' '4' '-boot-info-table' ) @@ -963,7 +1520,7 @@ _add_xorrisofs_options_bios.syslinux.eltorito() { _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" + '-isohybrid-mbr' "${isofs_dir}/boot/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 @@ -976,6 +1533,25 @@ _add_xorrisofs_options_bios.syslinux.mbr() { ) } +# GRUB in an attached EFI system partition +_add_xorrisofs_options_uefi-ia32.grub.esp() { + # TODO: how does the bootmodes systemd-boot vs x64.grub affect ${bootmodes[*]} tests in _add_xorrisofs_options_uefi-x64.systemd-boot.esp etc? + # shellcheck disable=SC2076 + if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' && ! " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' ]]; then + # _add_xorrisofs_options_uefi-x64.systemd-boot.esp + _add_xorrisofs_options_uefi-x64.grub.esp + fi +} + +# GRUB via El Torito +_add_xorrisofs_options_uefi-ia32.grub.eltorito() { + # shellcheck disable=SC2076 + if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' && ! " ${bootmodes[*]} " =~ ' uefi-x64.grub.eltorito ' ]]; then + # _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito + _add_xorrisofs_options_uefi-x64.grub.eltorito + fi +} + # 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 @@ -983,14 +1559,14 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.esp() { # 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") + xorrisofs_options+=('-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${efibootimg}") # 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 [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' && ! " ${bootmodes[*]} " =~ ' uefi-ia32.grub.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. @@ -1007,7 +1583,7 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.esp() { # systemd-boot via El Torito _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { # shellcheck disable=SC2076 - if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' ]]; then + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' || " ${bootmodes[*]} " =~ ' uefi-ia32.grub.esp ' ]]; then # systemd-boot in an attached EFI system partition via El Torito xorrisofs_options+=( # Start a new El Torito boot entry for UEFI @@ -1030,7 +1606,7 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { # 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/parabolaiso" - cp -a -- "${work_dir}/efiboot.img" "${isofs_dir}/EFI/parabolaiso/efiboot.img" + cp -a -- "${efibootimg}" "${isofs_dir}/EFI/parabolaiso/efiboot.img" # systemd-boot in an embedded efiboot.img via El Torito xorrisofs_options+=( # Start a new El Torito boot entry for UEFI @@ -1046,17 +1622,41 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { [[ " ${bootmodes[*]} " =~ ' bios.' ]] || xorrisofs_options+=('-eltorito-catalog' 'EFI/boot.cat') } -# rEFInd in an attached EFI system partition -_add_xorrisofs_options_uefi-x64.refind.esp() { - # _add_xorrisofs_options_uefi-x64.refind.esp does the exact same thing as _add_xorrisofs_options_uefi-x64.systemd-boot.esp - _add_xorrisofs_options_uefi-x64.systemd-boot.esp +# GRUB in an attached EFI system partition. +# Same as _add_xorrisofs_options_uefi-x64.systemd-boot.esp. +_add_xorrisofs_options_uefi-x64.grub.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' "${efibootimg}") + # 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.grub.eltorito ' && ! " ${bootmodes[*]} " =~ ' uefi-ia32.grub.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 } -# rEFInd via El Torito -_add_xorrisofs_options_uefi-x64.refind.eltorito() { +# GRUB via El Torito +# Same as _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito. +_add_xorrisofs_options_uefi-x64.grub.eltorito() { # shellcheck disable=SC2076 - if [[ " ${bootmodes[*]} " =~ ' uefi-x64.refind.esp ' ]]; then - # rEFInd in an attached EFI system partition via El Torito + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' || " ${bootmodes[*]} " =~ ' uefi-ia32.grub.esp ' ]]; then + # grub in an attached EFI system partition via El Torito xorrisofs_options+=( # Start a new El Torito boot entry for UEFI '-eltorito-alt-boot' @@ -1078,8 +1678,8 @@ _add_xorrisofs_options_uefi-x64.refind.eltorito() { # 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/parabolaiso" - cp -a -- "${work_dir}/efiboot.img" "${isofs_dir}/EFI/parabolaiso/efiboot.img" - # rEFInd in an embedded efiboot.img via El Torito + cp -a -- "${efibootimg}" "${isofs_dir}/EFI/parabolaiso/efiboot.img" + # grub in an embedded efiboot.img via El Torito xorrisofs_options+=( # Start a new El Torito boot entry for UEFI '-eltorito-alt-boot' @@ -1108,7 +1708,7 @@ _build_bootstrap_image() { cd -- "${_bootstrap_parent}" _msg_info "Creating ${arch} bootstrap image..." - bsdtar -cf - "root.${arch}" | gzip -cn9 > "${out_dir}/${image_name}" + bsdtar -cf - "root.${arch}" | gzip -cn9 >"${out_dir}/${image_name}" _msg_info "Done!" du -h -- "${out_dir}/${image_name}" cd -- "${OLDPWD}" @@ -1116,33 +1716,43 @@ _build_bootstrap_image() { # Build ISO _build_iso_image() { - local xorrisofs_options=() + local xorriso_options=() xorrisofs_options=() local bootmode [[ -d "${out_dir}" ]] || install -d -- "${out_dir}" - [[ "${quiet}" == "y" ]] && xorrisofs_options+=('-quiet') + # Do not read xorriso startup files to prevent interference and unintended behavior. + # For it to work, -no_rc must be the first argument passed to xorriso. + xorriso_options=('-no_rc') + + + if [[ "${quiet}" == "y" ]]; then + # 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') + 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}" + 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 -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 ${app_name}" \ - "${xorrisofs_options[@]}" \ - -output "${out_dir}/${image_name}" \ - "${isofs_dir}/" + 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 ${app_name}" \ + "${xorrisofs_options[@]}" \ + -output "${out_dir}/${image_name}" \ + "${isofs_dir}/" _msg_info "Done!" du -h -- "${out_dir}/${image_name}" } @@ -1163,6 +1773,7 @@ _read_profile() { # shellcheck source=configs/releng/profiledef.sh . "${profile}/profiledef.sh" + [[ -n "$arch" ]] || arch="$(uname -m)" if [[ "${arch}" == "dual" ]]; then # Resolve paths of files that are expected to reside in the profile's directory for each architecture [[ -n "$packages_dual" ]] || packages_files_dual=("${profile}/packages."{both,i686,x86_64}) @@ -1195,122 +1806,27 @@ _read_profile() { # Validate set options _validate_options() { - local validation_error=0 bootmode _cert _buildmode - local pkg_list_from_file=() - # shellcheck disable=SC2034 - local pkg_list_from_file_i686=() - # shellcheck disable=SC2034 - local pkg_list_from_file_x86_64=() - local bootstrap_pkg_list_from_file=() - # shellcheck disable=SC2034 - local bootstrap_pkg_list_from_file_i686=() - # shellcheck disable=SC2034 - local bootstrap_pkg_list_from_file_x86_64=() - local _override_cert_list=() + local validation_error=0 _buildmode certfile _msg_info "Validating options..." - if [[ "${arch}" == "dual" ]]; then - # Check if the package list files exist and read packages from them for each architecture - # shellcheck disable=SC2128 - for packages in ${packages_dual}; do - if [[ "${packages##*/}" == "packages.both" ]]; then - 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 "Packages file '${packages}' does not exist." 0 - fi - else - (( validation_error=validation_error+1 )) - _msg_error "Packages file '${packages}' does not exist." 0 - fi - elif [[ -e "${packages}" ]]; then - mapfile -t "pkg_list_from_file_${packages##*.}" < <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${packages}") - eval "pkg_list_${packages##*.}+=(\${pkg_list_from_file_${packages##*.}[@]})" - fi - done - - # Check if packages for the bootstrap image are specified for each architecture - if [[ "${buildmodes[*]}" == *bootstrap* ]]; then - for bootstrap_packages in ${bootstrap_packages_dual}; do - if [[ "${bootstrap_packages##*/}" == "bootstrap_packages.both" ]]; then - 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 - elif [[ -e "${bootstrap_packages}" ]]; then - mapfile -t "bootstrap_pkg_list_from_file_${bootstrap_packages##*.}" < \ - <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${bootstrap_packages}") - eval "bootstrap_pkg_list_${bootstrap_packages##*.}+=(\${bootstrap_pkg_list_from_file_${bootstrap_packages##*.}[@]})" - fi - done - fi - else - # 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 "Packages file '${packages}' does not exist." 0 - fi - else - (( validation_error=validation_error+1 )) - _msg_error "Packages file '${packages}' does not exist." 0 - fi - - # Check if packages for the bootstrap image are specified - if [[ "${buildmodes[*]}" == *bootstrap* ]]; then - 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 - fi - fi - 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 # 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 + # Check if the code signing certificate files exist + for certfile in "${cert_list[@]}"; do + if [[ ! -e "$certfile" ]]; then + (( validation_error=validation_error+1 )) + _msg_error "Code signing certificate '${certfile}' does not exist." 0 + fi + done + # 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 + 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." @@ -1321,31 +1837,6 @@ _validate_options() { fi done - # Check if the specified bootmodes are supported - 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 - # 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 (( validation_error )); then _msg_error "${validation_error} errors were encountered while validating the profile. Aborting." 1 fi @@ -1356,7 +1847,7 @@ _validate_options() { _set_overrides() { # Set variables that have command line overrides [[ ! -v override_buildmodes ]] || buildmodes=("${override_buildmodes[@]}") - if (( "${#buildmodes[@]}" < 1 )); then + if (( ${#buildmodes[@]} < 1 )); then buildmodes+=('iso') fi if [[ -v override_work_dir ]]; then @@ -1401,25 +1892,28 @@ _set_overrides() { 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[@]}") + [[ ! -v override_cert_list ]] || mapfile -t cert_list < <(realpath -- "${override_cert_list[@]}") if [[ -v override_quiet ]]; then quiet="$override_quiet" elif [[ -z "$quiet" ]]; then quiet="y" fi + if [[ -v override_rm_work_dir ]]; then + rm_work_dir="$override_rm_work_dir" + fi # Set variables that do not have overrides - [[ -n "$arch" ]] || arch="$(uname -m)" [[ -n "$airootfs_image_type" ]] || airootfs_image_type="squashfs" [[ -n "$iso_name" ]] || iso_name="${app_name}" + # Precalculate the ISO's modification date in UTC, i.e. its "UUID" + TZ=UTC printf -v iso_uuid '%(%F-%H-%M-%S-00)T' "$SOURCE_DATE_EPOCH" } _export_gpg_publickey() { - rm -f -- "${work_dir}/pubkey.gpg" - gpg --batch --no-armor --output "${work_dir}/pubkey.gpg" --export "${gpg_key}" + gpg_publickey="${work_dir}/pubkey.gpg" + rm -f -- "$gpg_publickey" + gpg --batch --no-armor --output "$gpg_publickey" --export "${gpg_key}" + [[ -s "$gpg_publickey" ]] || return } _make_version() { @@ -1428,16 +1922,23 @@ _make_version() { _msg_info "Creating ${arch} version files..." # Write version file to system installation dir rm -f -- "${pacstrap_dir}/version" - printf '%s\n' "${iso_version}" > "${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" + printf '%s\n' "${iso_version}" >"${isofs_dir}/${install_dir}/version" + + fi + if [[ "${buildmode}" == "iso" ]]; then # Write grubenv with version information to ISO 9660 + # TODO: after sufficient time has passed, do not create this file anymore. + # _make_common_bootmode_grub_cfg and _make_common_grubenv_and_loopbackcfg already create a + # ${isofs_dir}/boot/grub/grubenv file + rm -f -- "${isofs_dir}/${install_dir}/grubenv" 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" + >"${isofs_dir}/${install_dir}/grubenv" fi # Append IMAGE_ID & IMAGE_VERSION to os-release @@ -1449,8 +1950,13 @@ _make_version() { _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}" + printf 'IMAGE_ID=%s\nIMAGE_VERSION=%s\n' "${iso_name}" "${iso_version}" >>"${_os_release}" fi + + # Touch /usr/lib/clock-epoch to give another hint on date and time + # for systems with screwed or broken RTC. + touch -m -d"@${SOURCE_DATE_EPOCH}" -- "${pacstrap_dir}/usr/lib/clock-epoch" + _msg_info "Done!" } @@ -1458,22 +1964,32 @@ _make_pkglist() { _msg_info "Creating a list of installed packages on ${arch} live-enviroment..." case "${buildmode}" in "bootstrap") - pacman -Q --sysroot "${pacstrap_dir}" > "${pacstrap_dir}/pkglist.${arch}.txt" + 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" + pacman -Q --sysroot "${pacstrap_dir}" >"${isofs_dir}/${install_dir}/pkglist.${arch}.txt" ;; esac _msg_info "Done!" } +# Create working directory +_make_work_dir() { + if [[ ! -d "${work_dir}" ]]; then + install -d -- "${work_dir}" + elif (( rm_work_dir )); then + rm_work_dir=0 + _msg_warning "Working directory removal requested, but '${work_dir}' already exists. It will not be removed!" 0 + fi +} + # build the base for an ISO and/or a netboot target _build_iso_base() { local run_once_mode="base" local buildmode_packages="${packages}" if [[ "${arch}" == "dual" ]]; then - local buildmode_packages="${packages_dual}" + buildmode_packages="${packages_dual}" # Set the package list to use for each architecture local buildmode_pkg_list_i686=("${pkg_list_i686[@]}") local buildmode_pkg_list_x86_64=("${pkg_list_x86_64[@]}") @@ -1485,13 +2001,9 @@ _build_iso_base() { 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 + _run_once _make_work_dir + # Write build date to file if it does not exist already + [[ -e "${work_dir}/build_date" ]] || printf '%s\n' "$SOURCE_DATE_EPOCH" >"${work_dir}/build_date" [[ "${quiet}" == "y" ]] || _show_config _run_dual '_run_once _make_pacman_conf' @@ -1501,7 +2013,11 @@ _build_iso_base() { _run_dual '_run_once _make_version' _run_dual '_run_once _make_customize_airootfs' _run_dual '_run_once _make_pkglist' - _make_bootmodes + if [[ "${buildmode}" == 'netboot' ]]; then + _run_dual '_run_once _make_boot_on_iso9660' + else + _make_bootmodes + fi _run_dual '_run_once _cleanup_pacstrap_dir' \ '_run_once _prepare_airootfs_image' } @@ -1554,6 +2070,13 @@ _build_buildmode_netboot() { local run_once_mode="${buildmode}" _build_iso_base + + 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 + if [[ -v cert_list ]]; then _run_once _sign_netboot_artifacts fi @@ -1564,6 +2087,7 @@ _build_buildmode_netboot() { _build_buildmode_iso() { local image_name="${iso_name}-${iso_version}-${arch}.iso" local run_once_mode="${buildmode}" + efibootimg="${work_dir}/efiboot.img" _build_iso_base _run_once _build_iso_image } @@ -1576,23 +2100,29 @@ _build() { for buildmode in "${buildmodes[@]}"; do _run_once "_build_buildmode_${buildmode}" done + if (( rm_work_dir )); then + _msg_info 'Removing the working directory...' + rm -rf -- "${work_dir:?}/" + _msg_info 'Done!' + fi } -while getopts 'c:p:C:L:P:A:D:w:m:o:g:G:vh?' arg; do +while getopts 'c:p:C:L:P:A:D:w:m:o:g:G:vrh?' arg; do case "${arg}" in - p) read -r -a override_pkg_list <<< "${OPTARG}" ;; + 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}" ;; + c) read -r -a override_cert_list <<<"${OPTARG}" ;; w) override_work_dir="${OPTARG}" ;; - m) read -r -a override_buildmodes <<< "${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" ;; + r) declare -i override_rm_work_dir=1 ;; h|?) _usage 0 ;; *) _msg_error "Invalid argument '${arg}'" 0 @@ -1615,6 +2145,13 @@ fi # get the absolute path representation of the first non-option argument profile="$(realpath -- "${1}")" +# Read SOURCE_DATE_EPOCH from file early +build_date_file="$(realpath -q -- "${override_work_dir:-./work}/build_date")" || : +if [[ -f "$build_date_file" ]]; then + SOURCE_DATE_EPOCH="$(<"$build_date_file")" +fi +unset build_date_file + _read_profile _set_overrides _validate_options diff --git a/scripts/run_parabolaiso.sh b/scripts/run_parabolaiso.sh index ca8b4c0..4a64e86 100755 --- a/scripts/run_parabolaiso.sh +++ b/scripts/run_parabolaiso.sh @@ -11,7 +11,6 @@ # - qemu # - edk2-ovmf (when UEFI booting) - set -eu print_help() { |