├── files ├── hooks │ ├── issue.txt │ ├── issue │ ├── issue.net │ ├── command-not-found.json.license │ ├── command-not-found-common.json.license │ ├── htoprc.license │ ├── issue.license │ ├── issue.net.license │ ├── issue.txt.license │ ├── os-release.license │ ├── zram-generator.conf │ ├── gpm.service │ ├── udisks2.service │ ├── htoprc │ ├── initramfs-conf │ ├── getting-started │ ├── ssh.service │ ├── getty.service │ ├── serial-getty.service │ ├── container-getty.service │ ├── systemd-binfmt.service │ ├── strings.wrapper │ ├── cmdline-sshd.service │ ├── cmdline-passwd.service │ ├── shared-ssh-agent@.service │ ├── network-config-setup.service │ ├── shared-ssh-agent │ ├── cmdline-locale-config.service │ ├── ssh-agent │ ├── sshd-keygen │ ├── locale-config │ ├── bash_profile │ ├── initramfs-strace-init │ ├── command-not-found.json │ ├── strace-init │ ├── initramfs-live-uuid │ ├── os-release │ ├── initramfs-machine-id │ ├── cmdline-passwd │ ├── command-not-found │ ├── wifi-connect │ ├── strings │ └── interfaces-convert ├── keyrings │ ├── debian-ports-archive.gpg │ └── debian-ports-archive.gpg.license ├── grub │ ├── splash.svg.license │ ├── config.cfg │ └── theme.txt ├── syslinux │ ├── splash.svg.license │ └── isolinux.cfg ├── manpages │ ├── wifi-connect.metadata.yaml │ ├── locale-config.metadata.yaml │ ├── getting-started.metadata.yaml │ ├── locale-config.md │ ├── wifi-connect.md │ └── getting-started.md └── docker │ ├── container-entrypoint │ ├── Dockerfile │ └── container-build ├── .gitmodules ├── Makefile ├── pyproject.toml ├── .gitignore ├── hooks ├── 0005-finnix-1000-fstab.hook.chroot ├── 0005-finnix-1000-zram.hook.chroot ├── 8500-finnix-1000-mandb.hook.chroot ├── 0005-finnix-1000-gpm.hook.chroot ├── 8500-finnix-1000-live-uuid.hook.binary ├── 0005-finnix-1000-defaults.hook.chroot ├── 0005-finnix-1000-machine-id.hook.chroot ├── 0005-finnix-1000-cmdline-passwd.hook.chroot ├── 8500-finnix-1000-syslog.hook.chroot ├── 9900-finnix-2000-clean.hook.chroot ├── 0005-finnix-1000-remove-packages.hook.chroot ├── 0005-finnix-1000-wifi-connect.hook.chroot ├── 0005-finnix-1000-initramfs.hook.chroot ├── 0005-finnix-1000-strace.hook.chroot ├── 0005-finnix-1000-strings.hook.chroot ├── 0005-finnix-1000-getting-started.hook.chroot ├── 0005-finnix-1000-firmware-license.hook.chroot ├── 0005-finnix-1000-user.hook.chroot ├── 0005-finnix-1000-python.hook.chroot ├── 0005-finnix-1000-bash-profile.hook.chroot ├── 0005-finnix-1000-htop.hook.chroot ├── 8500-finnix-1000-systemd.hook.chroot ├── 0005-finnix-1000-command-not-found.hook.chroot ├── 8500-finnix-1000-locale.hook.chroot ├── 8500-finnix-1000-diskinfo.hook.binary ├── 0005-finnix-1000-distro.hook.chroot ├── 0005-finnix-1000-getty.hook.chroot ├── 0005-finnix-1000-network.hook.chroot ├── 0005-finnix-1000-ssh.hook.chroot ├── 0005-finnix-0100-systemd.hook.chroot └── 9900-finnix-1000-recompress.hook.chroot ├── tools ├── jinja2-render ├── get-dependencies ├── cnf-build-common └── strace-reorder ├── .github └── workflows │ ├── pre-commit.yml │ ├── schedule.yml │ ├── release.yml │ └── ci.yml ├── lists ├── finnix-firmware.list.chroot ├── live.list.chroot └── finnix.list.chroot ├── .rrpcid ├── README.md └── jobs │ └── ci │ └── build ├── Dockerfile ├── .yamllint.yml ├── .pre-commit-config.yaml ├── README.md ├── LICENSES ├── CC0-1.0.txt ├── MPL-2.0.txt └── CC-BY-SA-4.0.txt ├── LICENSE.md └── finnix-live-build /files/hooks/issue.txt: -------------------------------------------------------------------------------- 1 | Run "{{ PRODUCT_ID }}" to get started. 2 | -------------------------------------------------------------------------------- /files/keyrings/debian-ports-archive.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finnix/finnix-live-build/HEAD/files/keyrings/debian-ports-archive.gpg -------------------------------------------------------------------------------- /files/hooks/issue: -------------------------------------------------------------------------------- 1 | {{ PRODUCT }} {{ VERSION }}{% if VERSION == 'dev' %} ({{ DATETIME }}{% if GIT_DESC %} {{ GIT_DESC }}{% endif %}){% endif %} (\l) 2 | -------------------------------------------------------------------------------- /files/hooks/issue.net: -------------------------------------------------------------------------------- 1 | {{ PRODUCT }} {{ VERSION }}{% if VERSION == 'dev' %} ({{ DATETIME }}{% if GIT_DESC %} {{ GIT_DESC }}{% endif %}){% endif %} 2 | -------------------------------------------------------------------------------- /files/hooks/command-not-found.json.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: None 3 | SPDX-License-Identifier: CC0-1.0 4 | -------------------------------------------------------------------------------- /files/hooks/command-not-found-common.json.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: None 3 | SPDX-License-Identifier: CC0-1.0 4 | -------------------------------------------------------------------------------- /files/hooks/htoprc.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | SPDX-License-Identifier: MPL-2.0 4 | -------------------------------------------------------------------------------- /files/hooks/issue.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | SPDX-License-Identifier: CC-BY-SA-4.0 4 | -------------------------------------------------------------------------------- /files/grub/splash.svg.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | SPDX-License-Identifier: CC-BY-SA-4.0 4 | -------------------------------------------------------------------------------- /files/hooks/issue.net.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | SPDX-License-Identifier: CC-BY-SA-4.0 4 | -------------------------------------------------------------------------------- /files/hooks/issue.txt.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | SPDX-License-Identifier: CC-BY-SA-4.0 4 | -------------------------------------------------------------------------------- /files/hooks/os-release.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | SPDX-License-Identifier: CC-BY-SA-4.0 4 | -------------------------------------------------------------------------------- /files/syslinux/splash.svg.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | SPDX-License-Identifier: CC-BY-SA-4.0 4 | -------------------------------------------------------------------------------- /files/hooks/zram-generator.conf: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [zram0] 6 | zram-size=ram / 2 7 | -------------------------------------------------------------------------------- /files/hooks/gpm.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Unit] 6 | ConditionPathExists=/dev/input/mice 7 | -------------------------------------------------------------------------------- /files/hooks/udisks2.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Install] 6 | WantedBy= 7 | WantedBy=multi-user.target 8 | -------------------------------------------------------------------------------- /files/syslinux/isolinux.cfg: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | include menu.cfg 6 | default vesamenu.c32 7 | prompt 0 8 | timeout 300 9 | -------------------------------------------------------------------------------- /files/hooks/htoprc: -------------------------------------------------------------------------------- 1 | config_reader_min_version=3 2 | column_meters_0=LeftCPUs2 MemorySwap Zram DiskIO NetworkIO Battery 3 | column_meter_modes_0=1 1 1 1 1 1 4 | column_meters_1=RightCPUs2 DateTime Uptime Systemd Tasks LoadAverage 5 | column_meter_modes_1=1 2 2 2 2 2 6 | -------------------------------------------------------------------------------- /files/hooks/initramfs-conf: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2022 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | # /etc/initramfs-tools/conf.d/{{ PRODUCT_ID }} 6 | 7 | BOOT=live 8 | export BOOT 9 | -------------------------------------------------------------------------------- /files/hooks/getting-started: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: Finnix getting-started 5 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | exec man getting-started 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [submodule "live-build"] 6 | path = live-build 7 | url = https://github.com/finnix/live-build.git 8 | branch = main 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | .PHONY: all test lint 6 | 7 | all: 8 | 9 | test: lint 10 | 11 | lint: 12 | env LINT=true ./finnix-live-build 13 | -------------------------------------------------------------------------------- /files/manpages/wifi-connect.metadata.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-PackageSummary: finnix-live-build 3 | # SPDX-FileCopyrightText: © 2022 Ryan Finnie 4 | # SPDX-License-Identifier: CC-BY-SA-4.0 5 | 6 | title: "WIFI-CONNECT(1) | wifi-connect" 7 | author: "Ryan Finnie " 8 | -------------------------------------------------------------------------------- /files/hooks/ssh.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Service] 6 | ExecStartPre= 7 | ExecStartPre=/usr/lib/{{ PRODUCT_ID }}/sshd-keygen 8 | ExecStartPre=/usr/sbin/sshd -t 9 | -------------------------------------------------------------------------------- /files/manpages/locale-config.metadata.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-PackageSummary: finnix-live-build 3 | # SPDX-FileCopyrightText: © 2022 Ryan Finnie 4 | # SPDX-License-Identifier: CC-BY-SA-4.0 5 | 6 | title: "LOCALE-CONFIG(1) | locale-config" 7 | author: "Ryan Finnie " 8 | -------------------------------------------------------------------------------- /files/manpages/getting-started.metadata.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-PackageSummary: finnix-live-build 3 | # SPDX-FileCopyrightText: © 2022 Ryan Finnie 4 | # SPDX-License-Identifier: CC-BY-SA-4.0 5 | 6 | title: "GETTING-STARTED(1) | {{ PRODUCT }}" 7 | author: "Ryan Finnie " 8 | -------------------------------------------------------------------------------- /files/hooks/getty.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Service] 6 | ExecStart= 7 | ExecStart=-/sbin/agetty --autologin root --noclear --skip-login %I $TERM 8 | TTYVTDisallocate=no 9 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2025 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [tool.black] 6 | line-length = 132 7 | 8 | # https://pypi.org/project/Flake8-pyproject/ 9 | [tool.flake8] 10 | max-line-length = 132 11 | -------------------------------------------------------------------------------- /files/hooks/serial-getty.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Service] 6 | ExecStart= 7 | ExecStart=-/sbin/agetty --autologin root --noclear --skip-login --keep-baud 115200,38400,9600 %I $TERM 8 | -------------------------------------------------------------------------------- /files/hooks/container-getty.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Service] 6 | ExecStart= 7 | ExecStart=-/sbin/agetty --autologin root --noclear --skip-login --keep-baud 115200,38400,9600 pts/%I $TERM 8 | -------------------------------------------------------------------------------- /files/keyrings/debian-ports-archive.gpg.license: -------------------------------------------------------------------------------- 1 | SPDX-PackageSummary: finnix-live-build 2 | SPDX-FileCopyrightText: None 3 | SPDX-License-Identifier: CC0-1.0 4 | 5 | # From debian-ports-archive-keyring-2025.02.02/debian/copyright: 6 | # 7 | # Copyright: 8 | # 9 | # The keys in the keyrings don't fall under any copyright. 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | build/ 6 | .rrpcid/artifacts 7 | live-build_*.dsc 8 | live-build_*.tar.xz 9 | live-build_*.deb 10 | live-build_*.build* 11 | live-build_*.changes 12 | squashfs.sort 13 | -------------------------------------------------------------------------------- /files/hooks/systemd-binfmt.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Unit] 6 | # systemd-binfmt will freeze if running with strace attached to pid 1, 7 | # so disable when running "init.strace=1" 8 | ConditionKernelCommandLine=!init.strace=1 9 | -------------------------------------------------------------------------------- /files/hooks/strings.wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-FileComment: Wrapper for preferring GNU strings 4 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 5 | # SPDX-License-Identifier: MPL-2.0 6 | 7 | set -e 8 | 9 | PRODUCT_ID="{{ PRODUCT_ID }}" 10 | 11 | if command -v strings.distrib >/dev/null; then 12 | exec strings.distrib "$@" 13 | else 14 | exec "strings.${PRODUCT_ID}" "$@" 15 | fi 16 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-fstab.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: fstab chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | grep -q 'UNCONFIGURED FSTAB FOR BASE SYSTEM' /etc/fstab >/dev/null 11 | sed -i -e 's/UNCONFIGURED FSTAB FOR BASE SYSTEM/Live environment/' /etc/fstab 12 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-zram.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: zram chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0644 /hook-files/zram-generator.conf "/etc/systemd/zram-generator.conf.d/${PRODUCT_ID}.conf" 13 | -------------------------------------------------------------------------------- /files/hooks/cmdline-sshd.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Unit] 6 | Description=Kernel command line SSH daemon 7 | After=network.target 8 | ConditionKernelCommandLine=sshd 9 | 10 | [Service] 11 | Type=oneshot 12 | ExecStart=systemctl --no-block start ssh.service 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /hooks/8500-finnix-1000-mandb.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: mandb chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Upstream depends: 8070-remove-temporary-files.hook.chroot 9 | 10 | set -e 11 | 12 | # Regenerate man cache after live-build hook 13 | # https://github.com/finnix/finnix/issues/9 14 | mandb -qpc 15 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-gpm.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: gpm chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0644 /hook-files/gpm.service "/etc/systemd/system/gpm.service.d/${PRODUCT_ID}.conf" 13 | systemctl add-wants multi-user.target gpm.service 14 | -------------------------------------------------------------------------------- /tools/jinja2-render: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: jinja2-render 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | import os 9 | import sys 10 | 11 | from jinja2 import Template 12 | 13 | 14 | if __name__ == "__main__": 15 | tmpl = Template(sys.stdin.read()) 16 | vars = dict(os.environ) 17 | print(tmpl.render(vars)) 18 | -------------------------------------------------------------------------------- /files/hooks/cmdline-passwd.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Unit] 6 | Description=Change passwords from command line 7 | ConditionKernelCommandLine=|passwd 8 | ConditionKernelCommandLine=|sshd_password 9 | 10 | [Service] 11 | Type=oneshot 12 | ExecStart=/usr/lib/{{ PRODUCT_ID }}/cmdline-passwd 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /files/hooks/shared-ssh-agent@.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Unit] 6 | Description=Shared SSH agent init (%i) 7 | Before=getty.target 8 | After=nss-user-lookup.target 9 | 10 | [Service] 11 | ExecStart=/usr/lib/{{ PRODUCT_ID }}/shared-ssh-agent 12 | Type=notify 13 | NotifyAccess=all 14 | User=%i 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /files/grub/config.cfg: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | set default=0 6 | set timeout=30 7 | 8 | loadfont $prefix/dejavu-bold-16.pf2 9 | loadfont $prefix/dejavu-bold-14.pf2 10 | loadfont $prefix/unicode.pf2 11 | set gfxmode=auto 12 | insmod all_video 13 | insmod gfxterm 14 | insmod png 15 | insmod progress 16 | 17 | source /boot/grub/theme.cfg 18 | 19 | terminal_output gfxterm 20 | -------------------------------------------------------------------------------- /hooks/8500-finnix-1000-live-uuid.hook.binary: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: live-uuid binary hook 5 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | BUILD_UUID="{{ BUILD_UUID }}" 11 | 12 | # 9990-misc-helpers.sh from live-boot on the initramfs will verify /conf/uuid.conf 13 | # on the initramfs against /.disk/live-uuid on the live image 14 | echo "${BUILD_UUID}" >.disk/live-uuid 15 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2025 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | --- 5 | name: "pre-commit" 6 | "on": 7 | pull_request: 8 | push: 9 | jobs: 10 | pre-commit: 11 | runs-on: "ubuntu-latest" 12 | steps: 13 | - uses: "actions/checkout@v4" 14 | - uses: "actions/setup-python@v5" 15 | with: 16 | python-version: "3.12" 17 | - uses: "pre-commit/action@v3.0.1" 18 | -------------------------------------------------------------------------------- /files/hooks/network-config-setup.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Unit] 6 | Description=Set up network configurations 7 | Before=systemd-networkd.service networking.service 8 | After=systemd-udev-settle.service 9 | Wants=systemd-udev-settle.service 10 | 11 | [Service] 12 | Type=oneshot 13 | ExecStart=/usr/lib/{{ PRODUCT_ID }}/interfaces-convert 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-defaults.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: defaults chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | update-alternatives --set editor /bin/nano 11 | update-alternatives --set nc /bin/nc.openbsd 12 | update-alternatives --set pager /usr/bin/less 13 | update-alternatives --set vi /usr/bin/vim.tiny 14 | update-alternatives --set www-browser /usr/bin/elinks 15 | -------------------------------------------------------------------------------- /files/hooks/shared-ssh-agent: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: shared-ssh-agent 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # systemd service 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | [ -n "${USER}" ] || exit 1 13 | HOME="$(getent passwd "${USER}" | cut -d: -f6)" 14 | export HOME 15 | 16 | # shellcheck source=/dev/null 17 | . "/usr/lib/${PRODUCT_ID}/ssh-agent" 18 | systemd-notify --ready --pid="${SSH_AGENT_PID?}" 19 | -------------------------------------------------------------------------------- /lists/finnix-firmware.list.chroot: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | # 5 | {%- if DOCKER_BUILD == "false" %} 6 | {%- if ARCH == "amd64" %} 7 | amd64-microcode 8 | {%- endif %} 9 | atmel-firmware 10 | firmware-linux 11 | firmware-atheros 12 | firmware-bnx2 13 | firmware-bnx2x 14 | firmware-brcm80211 15 | firmware-ipw2x00 16 | firmware-iwlwifi 17 | firmware-realtek 18 | {%- if ARCH == "amd64" %} 19 | intel-microcode 20 | {%- endif %} 21 | {%- endif %} 22 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-machine-id.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: machine-id chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # live-build hook positioning doesn't really matter on this; 9 | # update-initramfs has almost certainly run before this, but is 10 | # guaranteed to run after the hooks. 11 | 12 | set -e 13 | 14 | install -D -m 0755 /hook-files/initramfs-machine-id /etc/initramfs-tools/scripts/live-bottom/machine-id 15 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-cmdline-passwd.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: cmdline-passwd chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0755 /hook-files/cmdline-passwd "/usr/lib/${PRODUCT_ID}/cmdline-passwd" 13 | install -D -m 0644 /hook-files/cmdline-passwd.service /etc/systemd/system/cmdline-passwd.service 14 | systemctl add-wants multi-user.target cmdline-passwd.service 15 | -------------------------------------------------------------------------------- /files/docker/container-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 5 | # SPDX-License-Identifier: MPL-2.0 6 | 7 | set -e 8 | 9 | cmd="$1"; shift 10 | if [ -z "${cmd}" ]; then 11 | cmd=bash 12 | fi 13 | # /tmp/_defaultcwd is the Dockerfile default; unless overridden, use the user's home directory 14 | if [ "$(pwd)" = "/tmp/_defaultcwd" ]; then 15 | cd 16 | fi 17 | mapfile -t env < <(grep -h '^[A-Z]' /etc/environment /etc/locale.conf; env) 18 | exec env -- "${env[@]}" "${cmd}" "$@" 19 | -------------------------------------------------------------------------------- /hooks/8500-finnix-1000-syslog.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: syslog chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Upstream depends: 8030-remove-log-files.hook.chroot 9 | 10 | set -e 11 | 12 | # Since we have no syslog, create /var/log/syslog 13 | # pointing users to journalctl 14 | cat <<"EOM" >/var/log/syslog 15 | This environment does not log directly to disk using syslog. 16 | To see boot / service logs, please run `journalctl`. 17 | EOM 18 | -------------------------------------------------------------------------------- /hooks/9900-finnix-2000-clean.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: clean chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | rm -rf /hook-files 11 | 12 | rm -f \ 13 | /etc/nvme/hostnqn \ 14 | /etc/nvme/hostid \ 15 | /etc/group- \ 16 | /etc/gshadow- \ 17 | /etc/passwd- \ 18 | /etc/shadow- \ 19 | /etc/subgid- \ 20 | /etc/subuid- 21 | 22 | # Remove remaining pycache 23 | rm -rf /usr/lib/python3.*/__pycache__ 24 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-remove-packages.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: remove-packages chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | # Remove unwanted bootstrap packages 11 | apt -y --purge remove rsyslog 12 | apt -y --purge remove tasksel tasksel-data 13 | 14 | # Not used (and conflicts with interfaces-convert) 15 | apt -y --purge remove ifupdown 16 | 17 | # Remove any auto-installed dependencies 18 | apt -y --purge autoremove 19 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-wifi-connect.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: wifi-connect chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | install -D -m 0755 /hook-files/wifi-connect /usr/sbin/wifi-connect 11 | install -D -m 0755 /hook-files/wifi-connect.1 /usr/share/man/man1/wifi-connect.1 12 | 13 | # Utilized by wifi-connect but not enabled at install time; 14 | # make sure it exists. 15 | [ -e /usr/lib/systemd/system/wpa_supplicant@.service ] 16 | -------------------------------------------------------------------------------- /.rrpcid/README.md: -------------------------------------------------------------------------------- 1 | # Repository Run-Parts CI Directory (RRPCID) 2 | 3 | This directory contains workflow(s) following the [Repository Run-Parts CI 4 | Directory 5 | (RRPCID)](https://www.finnie.org/2021/05/17/the-repository-runparts-ci-directory-rrpcid-specification/) 6 | specification, a CI-agnostic in-repository specification for basic CI workflows. 7 | 8 | ## License 9 | 10 | This document is provided under the following license: 11 | 12 | SPDX-PackageSummary: finnix-live-build 13 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 14 | SPDX-License-Identifier: CC-BY-SA-4.0 15 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-initramfs.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: initramfs chroot hook 5 | # SPDX-FileCopyrightText: © 2022 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Set default BOOT=live so "boot=live" does not need to be on the 9 | # kernel command line. 10 | 11 | set -e 12 | 13 | PRODUCT_ID="{{ PRODUCT_ID }}" 14 | 15 | install -D -m 0755 /hook-files/initramfs-conf "/etc/initramfs-tools/conf.d/${PRODUCT_ID}" 16 | install -D -m 0755 /hook-files/initramfs-live-uuid "/etc/initramfs-tools/hooks/live-uuid" 17 | -------------------------------------------------------------------------------- /files/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | FROM docker.io/library/debian:testing 6 | COPY . /build 7 | RUN /build/container-build && rm -rf /build 8 | 9 | FROM scratch 10 | COPY --from=0 / / 11 | ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games 12 | # Unless overridden at runtime, this should be automatically changed to the user's home directory 13 | WORKDIR /tmp/_defaultcwd 14 | ENTRYPOINT ["container-entrypoint"] 15 | CMD ["bash"] 16 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-strace.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: strace chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0755 /hook-files/strace-init "/usr/lib/${PRODUCT_ID}/strace-init" 13 | install -D -m 0755 /hook-files/initramfs-strace-init /etc/initramfs-tools/scripts/init-top/strace-init 14 | install -D -m 0644 /hook-files/systemd-binfmt.service "/etc/systemd/system/systemd-binfmt.service.d/${PRODUCT_ID}.conf" 15 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-strings.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: strings chroot hook 5 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0755 /hook-files/strings "/usr/bin/strings.${PRODUCT_ID}" 13 | 14 | # Diverts /usr/bin/strings to /usr/bin/strings.distrib 15 | # in package "binutils" if it is installed after boot. 16 | dpkg-divert --rename --add /usr/bin/strings 17 | 18 | install -D -m 0755 /hook-files/strings.wrapper /usr/bin/strings 19 | -------------------------------------------------------------------------------- /lists/live.list.chroot: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | # 5 | {%- if DOCKER_BUILD == "false" %} 6 | # Note that we don't want to install live-config itself, as we 7 | # replicate all of its functionality we want. To avoid automatic 8 | # installation of live-config, this file (which is installed to 9 | # config/package-lists/live.list.chroot) must exist. 10 | live-boot 11 | live-tools 12 | # Required by interfaces-convert, used to convert live-boot 13 | # e-n-i to systemd-networkd configs. 14 | python3-pyudev 15 | {%- endif %} 16 | -------------------------------------------------------------------------------- /files/hooks/cmdline-locale-config.service: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | [Unit] 6 | Description=Kernel command line locale configuration 7 | DefaultDependencies=no 8 | Conflicts=shutdown.target 9 | After=systemd-remount-fs.service 10 | Before=systemd-sysusers.service systemd-vconsole-setup.service sysinit.target shutdown.target 11 | ConditionKernelCommandLine=|locale-config 12 | ConditionKernelCommandLine=|0 13 | 14 | [Service] 15 | Type=oneshot 16 | RemainAfterExit=yes 17 | ExecStart=locale-config 18 | StandardOutput=tty 19 | StandardInput=tty 20 | StandardError=tty 21 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-getting-started.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: getting-started chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0644 /hook-files/issue.txt "/etc/issue.d/${PRODUCT_ID}.issue" 13 | install -D -m 0755 /hook-files/getting-started.1 /usr/share/man/man1/getting-started.1 14 | ln -sf getting-started.1 "/usr/share/man/man1/${PRODUCT_ID}.1" 15 | install -D -m 0755 /hook-files/getting-started /usr/bin/getting-started 16 | ln -sf getting-started "/usr/bin/${PRODUCT_ID}" 17 | -------------------------------------------------------------------------------- /files/hooks/ssh-agent: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: ssh-agent 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Meant to be run from .profile or equivalent, to provide a per-user 9 | # shared SSH agent environment 10 | 11 | [ -n "${USER}" ] || return 12 | [ -n "${HOME}" ] || return 13 | 14 | if [ -n "${SSH_AUTH_SOCK}" ]; then 15 | return 16 | fi 17 | 18 | if [ ! -e "${HOME}/.ssh/ssh-agent.sh" ]; then 19 | mkdir -p "${HOME}/.ssh" 20 | ssh-agent -s | grep ^SSH >"${HOME}/.ssh/ssh-agent.sh" 21 | fi 22 | # shellcheck source=/dev/null 23 | . "${HOME}/.ssh/ssh-agent.sh" 24 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-firmware-license.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: firmware-license chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | # License acceptance is bypassed to allow for automatic image building. 11 | # Here we revert that so the next user package interaction triggers it. 12 | 13 | if [ -e /var/lib/dpkg/info/firmware-ipw2x00.list ]; then 14 | debconf-set-selections <<"EOM" 15 | firmware-ipw2x00 firmware-ipw2x00/license/accepted select false 16 | firmware-ipw2x00 firmware-ipw2x00/license/accepted seen false 17 | EOM 18 | fi 19 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-user.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: user chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | useradd \ 13 | --create-home \ 14 | --comment "{{ PRODUCT }} user" \ 15 | --password '*' \ 16 | --shell /bin/bash \ 17 | --groups audio,cdrom,dialout,dip,floppy,video,plugdev,adm,sudo \ 18 | "${PRODUCT_ID}" 19 | 20 | mkdir -p /etc/sudoers.d 21 | cat <"/etc/sudoers.d/${PRODUCT_ID}" 22 | {{ PRODUCT_ID }} ALL=(ALL) NOPASSWD: ALL 23 | EOM 24 | chmod 0440 "/etc/sudoers.d/${PRODUCT_ID}" 25 | -------------------------------------------------------------------------------- /files/hooks/sshd-keygen: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: sshd-keygen 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Populates SSH host keys; called before starting sshd. 9 | 10 | set -e 11 | 12 | for fn in /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf; do 13 | [ -e "${fn}" ] || continue 14 | keytypes="$(sed -E 's,^#?HostKey .*/ssh_host_(.*?)_key,\1,;t;d' "${fn}")" 15 | for keytype in ${keytypes}; do 16 | if [ ! -e "/etc/ssh/ssh_host_${keytype}_key" ]; then 17 | ssh-keygen -q -f "/etc/ssh/ssh_host_${keytype}_key" -N "" -t "${keytype}" 18 | fi 19 | done 20 | done 21 | -------------------------------------------------------------------------------- /files/hooks/locale-config: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: locale-config / 0 - Keyboard/locale reconfiguration 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Reconfigure keyboard/locale access in a fairly universal way, 9 | # requiring the following keys on a potentially misconfigured keyboard: 10 | # - 0 11 | # - Enter 12 | # - Arrow keys 13 | 14 | set -e 15 | 16 | dpkg-reconfigure keyboard-configuration 17 | setupcon -k 18 | # udevadm will not work in a container 19 | udevadm trigger --subsystem-match=input --action=change || true 20 | dpkg-reconfigure locales 21 | echo 22 | echo "Be sure to exit active shells to use new locale settings." 23 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-python.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: python chroot hook 5 | # SPDX-FileCopyrightText: © 2022 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | echo "PYTHONDONTWRITEBYTECODE=1" >>/etc/environment 11 | 12 | for fn in /etc/python3.*/sitecustomize.py; do 13 | [ -e "${fn}" ] || continue 14 | tmpfn="$(mktemp)" 15 | cat <<"EOM" >"${tmpfn}" 16 | # Do not compile bytecode (pyc) 17 | import sys 18 | sys.dont_write_bytecode = True 19 | 20 | EOM 21 | cat "${fn}" >>"${tmpfn}" 22 | cat "${tmpfn}" >"${fn}" 23 | rm -f "${tmpfn}" 24 | done 25 | 26 | # Verification 27 | python3 -c "import sys; assert(sys.dont_write_bytecode == True)" 28 | -------------------------------------------------------------------------------- /files/hooks/bash_profile: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | __sh_exitcode() { ret=$?; if [[ $ret != 0 ]]; then echo "$ret "; fi } 6 | 7 | if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then 8 | PS1='${debian_chroot:+($debian_chroot)}\[\033[1;31m\]$(__sh_exitcode)\[\033[1;37m\]\u\[\033[0;39m\]@\[\033[1;37m\]\h(\l)\[\033[0;39m\]:\[\033[1;37m\]\w\[\033[1;34m\]\$\[\033[0;39m\] ' 9 | else 10 | PS1='${debian_chroot:+($debian_chroot)}$(__sh_exitcode)\u@\h:\w\$ ' 11 | fi 12 | 13 | export GPG_TTY="$(tty)" 14 | 15 | if [ -x "/usr/lib/{{ PRODUCT_ID }}/ssh-agent" ]; then 16 | . "/usr/lib/{{ PRODUCT_ID }}/ssh-agent" 17 | fi 18 | 19 | alias l='ls -CF' 20 | alias la='ls -A' 21 | alias ll='ls -alF' 22 | 23 | alias httpd='python3 -m http.server' 24 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-bash-profile.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: bash-profile chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | cat <<"EOM" >"/etc/profile.d/${PRODUCT_ID}.sh" 13 | export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games 14 | EOM 15 | 16 | if ! grep -q "^# {{ PRODUCT }} additions" /etc/skel/.bashrc >/dev/null 2>/dev/null; then 17 | cat <<"EOM" >>/etc/skel/.bashrc 18 | 19 | # {{ PRODUCT }} additions 20 | if [ -f ~/.bash_{{ PRODUCT_ID }} ]; then 21 | . ~/.bash_{{ PRODUCT_ID }} 22 | fi 23 | EOM 24 | fi 25 | 26 | install -D -m 0644 /hook-files/bash_profile "/etc/skel/.bash_${PRODUCT_ID}" 27 | rsync -a /etc/skel/ /root/ 28 | chmod 0700 /root 29 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-htop.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: htop chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Adds a few extra default fields: 9 | # - Zram (left, bar) 10 | # - DiskIO (left, bar) 11 | # - NetworkIO (right, text) 12 | # - Battery (right, text) 13 | # 14 | # Note that htoprc is not externally-modified friendly, and 15 | # pretty much any manual modification will cause the config to 16 | # reset back to default. The current hook-files file is based 17 | # on an htop 3.2.2 config; as of this version it does appear 18 | # to support a subset against implicit defaults, so the file 19 | # only contains changed fields. But this is not guaranteed, 20 | # and should be periodically checked. 21 | 22 | set -e 23 | 24 | install -D -m 0644 /hook-files/htoprc /etc/htoprc 25 | -------------------------------------------------------------------------------- /files/hooks/initramfs-strace-init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 5 | # SPDX-License-Identifier: MPL-2.0 6 | 7 | set -e 8 | 9 | PREREQS="" 10 | 11 | prereqs() { echo "$PREREQS"; } 12 | 13 | case "$1" in 14 | prereqs) 15 | prereqs 16 | exit 0 17 | ;; 18 | esac 19 | 20 | PRODUCT_ID="{{ PRODUCT_ID }}" 21 | INIT="/usr/lib/${PRODUCT_ID}/strace-init" 22 | STRACE_INIT="0" 23 | 24 | # shellcheck disable=SC2013 25 | for arg in $(cat /proc/cmdline); do 26 | case "$arg" in 27 | init=*) 28 | # Allow overriding init=, even when running init.strace=1 29 | INIT="${arg#init=}" 30 | ;; 31 | init.strace=*) 32 | STRACE_INIT="${arg#init.strace=}" 33 | ;; 34 | esac 35 | done 36 | 37 | if [ "${STRACE_INIT}" = "1" ]; then 38 | echo "init=\"${INIT}\"" >>/conf/param.conf 39 | fi 40 | -------------------------------------------------------------------------------- /files/hooks/command-not-found.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "commands": ["ar"], 4 | "packages": ["binutils"] 5 | }, 6 | { 7 | "commands": ["ftp"], 8 | "packages": ["ftp"], 9 | "similar_commands": ["lftp"] 10 | }, 11 | { 12 | "commands": ["ftp-ssl"], 13 | "packages": ["ftp-ssl"], 14 | "similar_commands": ["lftp"] 15 | }, 16 | { 17 | "commands": ["lynx"], 18 | "packages": ["lynx"], 19 | "similar_commands": ["elinks", "w3m"] 20 | }, 21 | { 22 | "commands": ["links2"], 23 | "packages": ["links2"], 24 | "similar_commands": ["elinks", "w3m"] 25 | }, 26 | { 27 | "commands": ["strings"], 28 | "packages": ["binutils"] 29 | }, 30 | { 31 | "commands": ["vim"], 32 | "packages": ["vim", "neovim"], 33 | "similar_commands": ["vim.tiny"] 34 | } 35 | ] 36 | -------------------------------------------------------------------------------- /files/hooks/strace-init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: strace-init 5 | # SPDX-FileCopyrightText: © 2012 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Called as: init.strace=1 9 | # Once booted, wait about 10 seconds before running `killall strace`. 10 | # Use the `tools/strace-reorder` program in finnix-live-build to 11 | # convert to a sort format usable by mksquashfs: 12 | # tools/strace-reorder squashfs.sort 13 | 14 | set -e 15 | 16 | PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" 17 | 18 | exec strace \ 19 | --daemonize=session \ 20 | --no-abbrev \ 21 | --quiet=all \ 22 | --decode-fds=all \ 23 | --string-limit=65535 \ 24 | --follow-forks \ 25 | --successful-only \ 26 | --interruptible=anywhere \ 27 | --output=/var/log/strace-init.trace \ 28 | --trace=open,openat,execve \ 29 | /sbin/init "$@" 30 | -------------------------------------------------------------------------------- /files/manpages/locale-config.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | locale-config - Simple locale configuration utility 4 | 5 | # SYNOPSIS 6 | 7 | locale-config 8 | 9 | # DESCRIPTION 10 | 11 | `locale-config` -- also available by its intended alias `0` -- is a simple 12 | command line menu utility designed to configure the console keyboard and 13 | language settings. As a (potentially misconfigured) keyboard is required to run 14 | this utility, `0` was chosen to minimize the number of keys needed to configure 15 | the keyboard: 16 | 17 | - 0 18 | - Enter 19 | - Arrow keys 20 | 21 | Once run, keyboard changes should take effect immediately, but you must restart 22 | current shells for language changes to take effect. 23 | 24 | # OPTIONS 25 | 26 | None. 27 | 28 | # BUGS 29 | 30 | None known, many assumed. 31 | 32 | # LICENSE 33 | 34 | This document is provided under the following license: 35 | 36 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 37 | SPDX-License-Identifier: CC-BY-SA-4.0 38 | -------------------------------------------------------------------------------- /hooks/8500-finnix-1000-systemd.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: systemd chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | # Create any remaining systemd users/groups which would be created 11 | # at runtime. (Just "systemd-coredump" as of this writing.) 12 | systemd-sysusers 13 | 14 | mkdir -p /usr/lib/systemd/diverted-generators 15 | 16 | # systemd-gpt-auto-generator is unneeded on a live system, and produces 17 | # a warning on EFI systems. 18 | dpkg-divert --add --rename --divert /usr/lib/systemd/diverted-generators/systemd-gpt-auto-generator /usr/lib/systemd/system-generators/systemd-gpt-auto-generator 19 | 20 | # sshd does not start on boot by default, and systemd-ssh-generator has 21 | # started spamming login issue. 22 | dpkg-divert --add --rename --divert /usr/lib/systemd/diverted-generators/systemd-ssh-generator /usr/lib/systemd/system-generators/systemd-ssh-generator 23 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-command-not-found.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: command-not-found chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0755 /hook-files/command-not-found "/usr/lib/${PRODUCT_ID}/command-not-found" 13 | install -D -m 0644 /hook-files/command-not-found.json "/etc/simple-cnf/handlers.d/20-${PRODUCT_ID}.json" 14 | # Commands from the top 1000 packages (by Debian popcon) which are not 15 | # installed in Finnix. 16 | install -D -m 0644 /hook-files/command-not-found-common.json "/etc/simple-cnf/handlers.d/50-common.json" 17 | 18 | # Diverts /usr/lib/command-not-found to /usr/lib/command-not-found.distrib 19 | # in package "command-not-found" if it is installed after boot. 20 | dpkg-divert --rename --add /usr/lib/command-not-found 21 | 22 | ln -s "/usr/lib/${PRODUCT_ID}/command-not-found" /usr/lib/command-not-found 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2025 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | FROM docker.io/library/debian:testing AS prebuild 6 | ARG BUILD_TAGS 7 | ARG BUILD_URL 8 | ARG GITHUB_SERVER_URL 9 | ARG GITHUB_REPOSITORY 10 | ARG GITHUB_RUN_ID 11 | COPY . /prebuild 12 | ENV DOCKER_BUILD=true 13 | WORKDIR /prebuild 14 | RUN apt update && apt -y install git python3 && ( ./tools/get-dependencies | xargs apt -y install ) 15 | RUN git submodule update --init --recursive 16 | RUN ./finnix-live-build 17 | 18 | FROM docker.io/library/debian:testing AS build 19 | COPY --from=prebuild /prebuild/build/docker /build 20 | RUN /build/container-build && rm -rf /build 21 | 22 | FROM scratch AS assemble 23 | COPY --from=build / / 24 | ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games 25 | # Unless overridden at runtime, this should be automatically changed to the user's home directory 26 | WORKDIR /tmp/_defaultcwd 27 | ENTRYPOINT ["container-entrypoint"] 28 | CMD ["bash"] 29 | -------------------------------------------------------------------------------- /hooks/8500-finnix-1000-locale.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: locale chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Upstream depends: 1020-create-locales-files.hook.chroot 9 | 10 | set -e 11 | 12 | echo 'LANG=en_US.UTF-8' >/etc/default/locale 13 | sed -i -e 's/^# en_US.UTF-8 /en_US.UTF-8 /g' /etc/locale.gen 14 | grep -q '^en_US.UTF-8 ' /etc/locale.gen # Verification 15 | locale-gen 16 | 17 | install -D -m 0755 /hook-files/locale-config /usr/sbin/locale-config 18 | ln -sf locale-config /usr/sbin/0 19 | install -D -m 0755 /hook-files/locale-config.1 /usr/share/man/man1/locale-config.1 20 | ln -sf locale-config.1 /usr/share/man/man1/0.1 21 | 22 | echo 'Etc/UTC' >/etc/timezone 23 | rm -f /etc/localtime 24 | dpkg-reconfigure -f noninteractive -p critical tzdata 25 | 26 | install -D -m 0644 /hook-files/cmdline-locale-config.service /etc/systemd/system/cmdline-locale-config.service 27 | systemctl add-wants multi-user.target cmdline-locale-config.service 28 | -------------------------------------------------------------------------------- /files/hooks/initramfs-live-uuid: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: initramfs-live-uuid 5 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | # (SC1091) Do not attempt to read file when linting 11 | # shellcheck disable=SC1091 12 | . /usr/share/initramfs-tools/hook-functions 13 | 14 | if [ -e /etc/os-release ]; then 15 | # (SC2043) Remove if multiple vars are pulled in 16 | # shellcheck disable=SC2043 17 | for i in BUILD_UUID; do 18 | read -r "${i?}" || true 19 | done <"${DESTDIR}/conf/uuid.conf" 31 | fi 32 | fi 33 | -------------------------------------------------------------------------------- /hooks/8500-finnix-1000-diskinfo.hook.binary: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: diskinfo binary hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | # This replaces live-build's file (which always says Debian but 11 | # conflates our VERSION) 12 | cat <<"EOM" >.disk/info 13 | {{ PRODUCT }} {{ VERSION }}{% if VERSION == 'dev' %} ({{ DATETIME }}{% if GIT_DESC %} {{ GIT_DESC }}{% endif %}){% endif %} 14 | EOM 15 | 16 | # This is specific to finnix-live-build 17 | cat <<"EOM" >.disk/build_info 18 | PRODUCT="{{ PRODUCT }}" 19 | PRODUCT_ID="{{ PRODUCT_ID }}" 20 | VERSION="{{ VERSION }}" 21 | CODENAME="{{ CODENAME }}" 22 | ARCH="{{ ARCH }}" 23 | DATETIME="{{ DATETIME }}" 24 | GIT_COMMIT="{{ GIT_COMMIT }}" 25 | GIT_DESC="{{ GIT_DESC }}" 26 | LIVE_BUILD_GIT_COMMIT="{{ LIVE_BUILD_GIT_COMMIT }}" 27 | LIVE_BUILD_GIT_DESC="{{ LIVE_BUILD_GIT_DESC }}" 28 | BUILD_UUID="{{ BUILD_UUID }}" 29 | BUILD_TAGS="{{ BUILD_TAGS }}" 30 | {%- if BUILD_URL %} 31 | BUILD_URL="{{ BUILD_URL }}" 32 | {%- endif %} 33 | EOM 34 | -------------------------------------------------------------------------------- /files/hooks/os-release: -------------------------------------------------------------------------------- 1 | PRETTY_NAME="{{ PRODUCT }} {{ VERSION }}{% if VERSION == 'dev' %} ({{ DATETIME }}{% if GIT_DESC %} {{ GIT_DESC }}{% endif %}){% endif %}" 2 | NAME="{{ PRODUCT }}" 3 | VERSION="{{ VERSION }}{% if VERSION == 'dev' %} ({{ DATETIME }}{% if GIT_DESC %} {{ GIT_DESC }}{% endif %}){% endif %}" 4 | VERSION_ID="{{ VERSION }}" 5 | VERSION_CODENAME="{{ CODENAME }}" 6 | ARCH="{{ ARCH }}" 7 | BUILD_ID="{{ DATETIME }}{% if GIT_DESC %} {{ GIT_DESC }}{% endif %}{% if BUILD_TAGS %} {{ BUILD_TAGS }}{% endif %}" 8 | BUILD_UUID="{{ BUILD_UUID }}" 9 | BUILD_TAGS="{{ BUILD_TAGS }}" 10 | BUILD_DATETIME="{{ DATETIME }}" 11 | BUILD_GIT_COMMIT="{{ GIT_COMMIT }}" 12 | BUILD_GIT_DESC="{{ GIT_DESC }}" 13 | BUILD_LIVE_BUILD_GIT_COMMIT="{{ LIVE_BUILD_GIT_COMMIT }}" 14 | BUILD_LIVE_BUILD_GIT_DESC="{{ LIVE_BUILD_GIT_DESC }}" 15 | {%- if BUILD_URL %} 16 | BUILD_URL="{{ BUILD_URL }}" 17 | {%- endif %} 18 | ID="{{ PRODUCT_ID }}" 19 | ID_LIKE="debian" 20 | ANSI_COLOR="1;34" 21 | {%- if PRODUCT_ID == 'finnix' %} 22 | HOME_URL="https://www.finnix.org/" 23 | SUPPORT_URL="https://www.finnix.org/" 24 | BUG_REPORT_URL="https://www.finnix.org/" 25 | {%- endif %} 26 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-distro.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: distro chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | dpkg-divert --add --rename --divert /usr/lib/os-release.debian /usr/lib/os-release 11 | install -D -m 0644 /hook-files/os-release /usr/lib/os-release 12 | 13 | if ! [ -L /etc/os-release ]; then 14 | # Revert debian-live's os-release modification 15 | dpkg-divert --local --remove --no-rename --divert /etc/os-release.debootstrap /etc/os-release 16 | rm -f /etc/os-release 17 | ln -s ../usr/lib/os-release /etc/os-release 18 | fi 19 | 20 | dpkg-divert --add --rename --divert /etc/issue.debian /etc/issue 21 | install -D -m 0644 /hook-files/issue /etc/issue 22 | # We need a trailing newline in /etc/issue (but not /etc/issue.net), but linters tend to hate 23 | # that in source files, so we just tack it on here. 24 | echo "" >>/etc/issue 25 | 26 | dpkg-divert --add --rename --divert /etc/issue.net.debian /etc/issue.net 27 | install -D -m 0644 /hook-files/issue.net /etc/issue.net 28 | 29 | : >/etc/motd 30 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-getty.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: getty chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | # live-config-getty-generator is part of live-config which we don't 13 | # install, but technically isn't incompatible with our setup... except 14 | # for live-config-getty-generator, we we don't want in any case. 15 | # Diverting here is therefore pre-emptive, in case the end user does 16 | # install it during the live session. 17 | mkdir -p /usr/lib/systemd/diverted-generators 18 | dpkg-divert --add --rename --divert /usr/lib/systemd/diverted-generators/live-config-getty-generator /usr/lib/systemd/system-generators/live-config-getty-generator 19 | 20 | install -D -m 0644 /hook-files/getty.service "/etc/systemd/system/getty@.service.d/${PRODUCT_ID}.conf" 21 | install -D -m 0644 /hook-files/serial-getty.service "/etc/systemd/system/serial-getty@.service.d/${PRODUCT_ID}.conf" 22 | install -D -m 0644 /hook-files/container-getty.service "/etc/systemd/system/container-getty@.service.d/${PRODUCT_ID}.conf" 23 | -------------------------------------------------------------------------------- /files/manpages/wifi-connect.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | wifi-connect - Simple Wi-Fi connection utility 4 | 5 | # SYNOPSIS 6 | 7 | wifi-connect \[-i *interface*\] "Access Point Name" "Access Point Passphrase" 8 | 9 | # DESCRIPTION 10 | 11 | `wifi-connect` is a simple command line utility to connect to a Wi-Fi access 12 | point. It will automatically configure and activate `wpa_supplicant` using 13 | default (WPA2) settings, and `systemd-networkd` for a basic DHCP configuration. 14 | 15 | Note that this utility is meant to be for the most common Wi-Fi setups 16 | encountered, and is not meant to be exhaustive. 17 | 18 | # OPTIONS 19 | 20 | -i *interface* 21 | 22 | > Interface name to configure. If not specified, the interface name will be 23 | > selected automatically, if the system has one wireless interface. If more than 24 | > one wireless interface is present, `wifi-connect` will list all discovered 25 | > wireless interfaces, and *-i* will need to be explicitly set. 26 | 27 | # BUGS 28 | 29 | None known, many assumed. 30 | 31 | # LICENSE 32 | 33 | This document is provided under the following license: 34 | 35 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 36 | SPDX-License-Identifier: CC-BY-SA-4.0 37 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-network.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: network chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0755 /hook-files/interfaces-convert "/usr/lib/${PRODUCT_ID}/interfaces-convert" 13 | install -D -m 0644 /hook-files/network-config-setup.service /etc/systemd/system/network-config-setup.service 14 | systemctl add-wants sysinit.target network-config-setup.service 15 | systemctl add-wants network.target systemd-networkd.service 16 | systemctl add-wants network.target systemd-resolved.service 17 | 18 | # Do our best to work around ifupdown, even if it gets installed. 19 | dpkg-divert --rename --add /lib/udev/rules.d/80-ifupdown.rules 20 | dpkg-divert --rename --add /lib/udev/ifupdown-hotplug 21 | # ifupdown uses /lib, but if it ever gets updated to /usr/lib to match 22 | # the /usr migration, guard against that too. 23 | dpkg-divert --rename --add /usr/lib/udev/rules.d/80-ifupdown.rules 24 | dpkg-divert --rename --add /usr/lib/udev/ifupdown-hotplug 25 | 26 | systemctl add-wants multi-user.target network.target 27 | -------------------------------------------------------------------------------- /hooks/0005-finnix-1000-ssh.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: ssh chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | install -D -m 0755 /hook-files/sshd-keygen "/usr/lib/${PRODUCT_ID}/sshd-keygen" 13 | install -D -m 0644 /hook-files/ssh.service "/etc/systemd/system/ssh.service.d/${PRODUCT_ID}.conf" 14 | 15 | cat <<"EOM" >"/etc/ssh/sshd_config.d/${PRODUCT_ID}.conf" 16 | # "Safe" for maintenance use since by default, the user needs to set a 17 | # root password and start ssh.service. 18 | PasswordAuthentication yes 19 | PermitRootLogin yes 20 | EOM 21 | 22 | # Shared per-user SSH agent 23 | install -D -m 0755 /hook-files/shared-ssh-agent "/usr/lib/${PRODUCT_ID}/shared-ssh-agent" 24 | install -D -m 0755 /hook-files/ssh-agent "/usr/lib/${PRODUCT_ID}/ssh-agent" 25 | install -D -m 0644 /hook-files/shared-ssh-agent@.service /etc/systemd/system/shared-ssh-agent@.service 26 | systemctl add-wants multi-user.target shared-ssh-agent@root.service 27 | 28 | install -D -m 0644 /hook-files/cmdline-sshd.service /etc/systemd/system/cmdline-sshd.service 29 | systemctl add-wants multi-user.target cmdline-sshd.service 30 | -------------------------------------------------------------------------------- /.rrpcid/jobs/ci/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 5 | # SPDX-License-Identifier: MPL-2.0 6 | 7 | set -e 8 | set -x 9 | 10 | if [ -e /etc/dnf/dnf.conf ]; then 11 | # (SC2046) Word splitting is desired here 12 | # shellcheck disable=SC2046 13 | sudo dnf -y install $(tools/get-dependencies --only required) 14 | for pkg in $(tools/get-dependencies --only optional); do 15 | sudo dnf -y install "${pkg}" || true 16 | done 17 | else 18 | sudo apt update 19 | # (SC2046) Word splitting is desired here 20 | # shellcheck disable=SC2046 21 | sudo apt -y install $(tools/get-dependencies --only required) 22 | for pkg in $(tools/get-dependencies --only optional); do 23 | sudo apt -y install "${pkg}" || true 24 | done 25 | fi 26 | 27 | # Build image 28 | sudo chown -R root:root . 29 | sudo env ARCH="${ARCH}" BUILD_TAGS="rrpcid ci ${BUILD_TAGS}" ./finnix-live-build 30 | sudo rm -rf build/cache/lb/bootstrap build/cache/lb/contents.chroot build/cache/lb/indices.bootstrap 31 | sudo chown -R "$(id -un):$(id -gn)" . 32 | 33 | # Save artifacts 34 | mkdir -p .rrpcid/artifacts 35 | mv \ 36 | build/lb/finnix-* \ 37 | build/lb/chroot.files \ 38 | build/lb/chroot.packages.* \ 39 | .rrpcid/artifacts/ 40 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2023 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | --- 5 | extends: "default" 6 | 7 | rules: 8 | braces: 9 | max-spaces-inside: 1 10 | max-spaces-inside-empty: 0 11 | min-spaces-inside: 1 12 | min-spaces-inside-empty: 0 13 | level: "error" 14 | brackets: 15 | max-spaces-inside: 0 16 | max-spaces-inside-empty: 0 17 | min-spaces-inside: 0 18 | min-spaces-inside-empty: 0 19 | level: "error" 20 | colons: 21 | max-spaces-after: 1 22 | level: "error" 23 | commas: 24 | max-spaces-after: -1 25 | level: "error" 26 | comments: 27 | ignore-shebangs: true 28 | level: "error" 29 | min-spaces-from-content: 1 30 | require-starting-space: true 31 | comments-indentation: 32 | level: "error" 33 | document-start: 34 | present: true 35 | level: "error" 36 | empty-lines: 37 | max: 2 38 | level: "error" 39 | hyphens: 40 | max-spaces-after: 1 41 | level: "error" 42 | indentation: 43 | spaces: 2 44 | key-duplicates: "enable" 45 | line-length: 46 | max: 160 47 | level: "warning" 48 | new-lines: 49 | type: "unix" 50 | quoted-strings: 51 | quote-type: "any" 52 | required: true 53 | truthy: 54 | allowed-values: 55 | - "true" 56 | - "false" 57 | level: "error" 58 | -------------------------------------------------------------------------------- /files/grub/theme.txt: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | desktop-image: "../splash.png" 6 | title-text: "" 7 | message-font: "Unifont Regular 16" 8 | terminal-font: "Unifont Regular 16" 9 | 10 | #help bar at the bottom 11 | + label { 12 | top = 100%-50 13 | left = 0 14 | width = 100% 15 | height = 20 16 | text = "@KEYMAP_SHORT@" 17 | align = "center" 18 | color = "#ffffff" 19 | font = "DejaVu Sans Bold 14" 20 | } 21 | 22 | #boot menu 23 | + boot_menu { 24 | left = 10% 25 | width = 80% 26 | top = 52% 27 | height = 48%-80 28 | item_color = "#a8a8a8" 29 | item_font = "DejaVu Sans Bold 14" 30 | selected_item_color= "#d4d4ff" 31 | selected_item_font = "DejaVu Sans Bold 14" 32 | item_height = 16 33 | item_padding = 0 34 | item_spacing = 4 35 | icon_width = 0 36 | icon_heigh = 0 37 | item_icon_space = 0 38 | } 39 | 40 | #progress bar 41 | + progress_bar { 42 | id = "__timeout__" 43 | left = 15% 44 | top = 100%-80 45 | height = 16 46 | width = 70% 47 | font = "DejaVu Sans Bold 14" 48 | text_color = "#d4d4ff" 49 | fg_color = "#252534" 50 | bg_color = "#14141c" 51 | border_color = "#252534" 52 | text = "@TIMEOUT_NOTIFICATION_LONG@" 53 | } 54 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2023 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | # https://pre-commit.com/hooks.html 6 | # pre-commit install --install-hooks 7 | # pre-commit autoupdate 8 | # pre-commit run -a 9 | 10 | --- 11 | fail_fast: false 12 | 13 | repos: 14 | - repo: "https://github.com/pre-commit/pre-commit-hooks" 15 | rev: "v5.0.0" 16 | hooks: 17 | - id: "check-added-large-files" 18 | - id: "check-case-conflict" 19 | - id: "check-executables-have-shebangs" 20 | - id: "check-json" 21 | - id: "check-merge-conflict" 22 | - id: "check-yaml" 23 | - id: "check-shebang-scripts-are-executable" 24 | exclude: | 25 | (?x)^( 26 | hooks/.*\.hook\.(chroot|binary) 27 | )$ 28 | - id: "detect-private-key" 29 | - id: "end-of-file-fixer" 30 | - id: "fix-byte-order-marker" 31 | - id: "mixed-line-ending" 32 | - id: "trailing-whitespace" 33 | 34 | - repo: "https://github.com/adrienverge/yamllint" 35 | rev: "v1.35.1" 36 | hooks: 37 | - id: "yamllint" 38 | 39 | - repo: "https://github.com/fsfe/reuse-tool" 40 | rev: "v5.0.2" 41 | hooks: 42 | - id: "reuse" 43 | 44 | - repo: "https://github.com/rhysd/actionlint" 45 | rev: "v1.7.7" 46 | hooks: 47 | - id: "actionlint" 48 | 49 | - repo: "https://github.com/psf/black" 50 | rev: "25.1.0" 51 | hooks: 52 | - id: "black" 53 | 54 | - repo: "https://github.com/pycqa/flake8" 55 | rev: "7.2.0" 56 | hooks: 57 | - id: "flake8" 58 | additional_dependencies: ["Flake8-pyproject"] 59 | -------------------------------------------------------------------------------- /files/manpages/getting-started.md: -------------------------------------------------------------------------------- 1 | # WELCOME 2 | 3 | Welcome to {{ PRODUCT }}! 4 | 5 | # CUSTOM COMMANDS 6 | 7 | This is mostly a fully-featured Debian-based text utility distribution, but 8 | there are a few custom utilities to know about: 9 | 10 | - 0 11 | 12 | > Easy (and mostly keyboard-agnostic) way to change your locale and keyboard 13 | > information. 14 | 15 | - wifi-connect "Access Point" "Passphrase" 16 | 17 | > Set up a standard WPA wireless connection. 18 | 19 | # OTHER INFORMATION 20 | 21 | DHCP is attemped on any found wired Ethernet interface. 22 | 23 | For a text-mode web browser, "elinks" and "w3m" are available. 24 | 25 | By default, no attempt is made to modify the system clock. If you would like to 26 | sync against an NTP server (local NTP server if given by the DHCP server, 27 | otherwise Debian's pool), run: 28 | 29 | timedatectl set-ntp true 30 | 31 | If you would like to update any dpkg alternatives, such as for the "editor" 32 | command perhaps, "rover" is a friendly curses-based alternatives selection 33 | program. 34 | 35 | If you need to work with ZFS disks, run the following beforehand: 36 | 37 | service zfs-fuse start 38 | 39 | The running ramdisk is limited to 50% of the system's RAM by default. If you 40 | need more working disk space, run: 41 | 42 | mount -o remount,size=80% /run/live/overlay 43 | 44 | {% if PRODUCT_ID == 'finnix' %}# DOCUMENTATION 45 | 46 | More Finnix documentation is available at [the finnix-docs repository on 47 | GitHub](https://github.com/finnix/finnix-docs).{% endif %} 48 | 49 | # LICENSE 50 | 51 | This document is provided under the following license: 52 | 53 | SPDX-FileCopyrightText: © 2021 Ryan Finnie 54 | SPDX-License-Identifier: CC-BY-SA-4.0 55 | -------------------------------------------------------------------------------- /tools/get-dependencies: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: get-dependencies 5 | # SPDX-FileCopyrightText: © 2022 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | import argparse 9 | import json 10 | import os 11 | import pathlib 12 | import sys 13 | 14 | 15 | def parse_args(argv=None): 16 | if argv is None: 17 | argv = sys.argv 18 | 19 | parser = argparse.ArgumentParser( 20 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 21 | prog=os.path.basename(argv[0]), 22 | ) 23 | 24 | parser.add_argument( 25 | "--manager", 26 | choices=["apt", "dnf"], 27 | default=("dnf" if os.path.exists("/etc/dnf/dnf.conf") else "apt"), 28 | ) 29 | parser.add_argument("--only", choices=["required", "optional"]) 30 | parser.add_argument("--file", type=pathlib.Path, default="build-dependencies.json") 31 | parser.add_argument("--null", "-0", action="store_true") 32 | 33 | return parser.parse_args(args=argv[1:]) 34 | 35 | 36 | if __name__ == "__main__": 37 | args = parse_args() 38 | out = [] 39 | with args.file.open() as f: 40 | for d in json.load(f): 41 | d["rh"] = d.get("rh", d["debian"]) 42 | d["optional"] = d.get("optional", False) 43 | if args.only: 44 | if (args.only == "required" and d["optional"]) or (args.only == "optional" and (not d["optional"])): 45 | continue 46 | k = "rh" if args.manager == "dnf" else "debian" 47 | if d[k]: 48 | out.append(d[k]) 49 | if args.null: 50 | print("\x00".join(out), end="") 51 | else: 52 | for v in out: 53 | print(v) 54 | -------------------------------------------------------------------------------- /files/docker/container-build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileCopyrightText: © 2024 Ryan Finnie 5 | # SPDX-License-Identifier: MPL-2.0 6 | 7 | set -e 8 | 9 | PRODUCT_ID="{{ PRODUCT_ID }}" 10 | 11 | export DEBIAN_FRONTEND=noninteractive 12 | 13 | ln -s /build/hook-files /hook-files 14 | mkdir -p /live-build/config 15 | touch /live-build/config/binary 16 | 17 | for fn in /build/archives/*.list.chroot; do 18 | [ -e "${fn}" ] || continue 19 | base="$(basename "${fn}" .chroot)" 20 | cp "${fn}" "/etc/apt/sources.list.d/${base}" 21 | done 22 | for fn in /build/archives/*.pref.chroot; do 23 | [ -e "${fn}" ] || continue 24 | base="$(basename "${fn}" .chroot)" 25 | cp "${fn}" "/etc/apt/preferences.d/${base}" 26 | done 27 | for fn in /build/archives/*.conf.chroot; do 28 | [ -e "${fn}" ] || continue 29 | base="$(basename "${fn}" .chroot)" 30 | cp "${fn}" "/etc/apt/apt.conf.d/${base}" 31 | done 32 | 33 | cat >"/etc/apt/apt.conf.d/99${PRODUCT_ID}" <<"EOM" 34 | APT::Install-Recommends "false"; 35 | EOM 36 | 37 | 38 | apt update 39 | apt -y install $(grep -h '^[a-z0-9]' /build/package-lists/*.list.chroot) 40 | 41 | install -D -m 0755 /build/container-entrypoint /usr/bin/container-entrypoint 42 | 43 | export GZIP_RECOMPRESS=no 44 | for fn in /build/hooks/*.hook.chroot; do 45 | [ -x "${fn}" ] || continue 46 | echo "Running: ${fn}" 47 | "${fn}" 48 | done 49 | 50 | rm -rf /var/lib/apt/lists 51 | mkdir -p /var/lib/apt/lists/partial 52 | rm -rf /hook-files /live-build 53 | 54 | # /tmp/_defaultcwd is the Dockerfile default; unless overridden, use the user's home directory 55 | # (but it should still be usable if it somehow doesn't get changed, so a+t) 56 | mkdir -p /tmp/_defaultcwd 57 | chmod 1777 /tmp/_defaultcwd 58 | -------------------------------------------------------------------------------- /hooks/0005-finnix-0100-systemd.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: systemd chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PRODUCT_ID="{{ PRODUCT_ID }}" 11 | 12 | # Set up our running target 13 | systemctl set-default multi-user.target 14 | 15 | # Clear unwanted targets below our running target 16 | for target in basic.target sysinit.target timers.target default.target network.target network-online.target multi-user.target graphical.target; do 17 | rm -rf "/etc/systemd/system/${target}.wants" 18 | mkdir -p "/usr/lib/systemd/diverted-system/${target}.wants" 19 | for i in "/usr/lib/systemd/system/${target}.wants"/*.timer; do 20 | [ -e "${i}" ] || continue 21 | dpkg-divert --add --rename --divert "/usr/lib/systemd/diverted-system/${target}.wants/$(basename "${i}")" "${i}" 22 | done 23 | done 24 | rm -f /etc/rc?.d/* 25 | 26 | # Show service startup/shutdown statuses 27 | mkdir -p "/etc/systemd/system.conf.d" 28 | cat <<"EOM" >"/etc/systemd/system.conf.d/${PRODUCT_ID}.conf" 29 | [Manager] 30 | DefaultEnvironment=PYTHONDONTWRITEBYTECODE=1 31 | ShowStatus=yes 32 | StatusUnitFormat=description 33 | EOM 34 | 35 | # udisks2.service is (currently) the only service in an installed package 36 | # which wants to install to graphical.target. Override it to instead 37 | # use multi-user.target. 38 | install -D -m 0644 /hook-files/udisks2.service "/etc/systemd/system/udisks2.service.d/${PRODUCT_ID}.conf" 39 | 40 | # systemd-resolved apt postinst will break resolv.conf in a chroot, 41 | # but luckily it makes a backup of the original resolv.conf. 42 | # (#1032937, WONTFIX, by design) 43 | apt -y install systemd-resolved 44 | if [ -e /etc/.resolv.conf.systemd-resolved.bak ]; then 45 | echo "https://bugs.debian.org/1032937 is still present" 46 | rm -f /etc/resolv.conf 47 | mv /etc/.resolv.conf.systemd-resolved.bak /etc/resolv.conf 48 | fi 49 | -------------------------------------------------------------------------------- /files/hooks/initramfs-machine-id: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: initramfs-machine-id 5 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | PREREQS="" 11 | rootmnt="${rootmnt:-}" # Set by initrd environment 12 | 13 | prereqs() { echo "$PREREQS"; } 14 | 15 | case "$1" in 16 | prereqs) 17 | prereqs 18 | exit 0 19 | ;; 20 | esac 21 | 22 | is_usable_product_uuid() { 23 | [ -e /sys/class/dmi/id/sys_vendor ] || return 1 24 | [ -e /sys/class/dmi/id/product_uuid ] || return 1 25 | [ "$(cat /sys/class/dmi/id/sys_vendor)" = "QEMU" ] && return 0 26 | return 1 27 | } 28 | 29 | MACHINE_ID="" 30 | if is_usable_product_uuid; then 31 | # We can trust these vendors' product_uuid to be decent. 32 | MACHINE_ID="$(sed -e 's/-//g' /sys/class/dmi/id/product_uuid)" 33 | elif [ -e /proc/device-tree/vm,uuid ]; then 34 | # DT vm,uuid will be unique, but can have a trailing null byte 35 | MACHINE_ID="$(sed -e 's/[-\x0]//g' /proc/device-tree/vm,uuid)" 36 | elif [ -e /sys/firmware/dmi/tables/DMI ]; then 37 | # product_uuid is available, but isn't guaranteed to be decent on 38 | # all systems, so let's just hash the entire DMI. 39 | # Note that this isn't wise on a permanent machine, as it's 40 | # possible two exact machines (with broken vendor UUIDs/serials) 41 | # could have the exact same DMI, but it's fine in a live 42 | # environment. 43 | MACHINE_ID="$(md5sum /sys/firmware/dmi/tables/DMI | cut -d' ' -f1)" 44 | elif [ -e /proc/sys/kernel/random/boot_id ]; then 45 | # Kernel boot ID (random per-boot) 46 | MACHINE_ID="$(sed -e 's/-//g' /proc/sys/kernel/random/boot_id)" 47 | elif [ -e /proc/sys/kernel/random/uuid ]; then 48 | # Random ID 49 | MACHINE_ID="$(sed -e 's/-//g' /proc/sys/kernel/random/uuid)" 50 | fi 51 | 52 | rm -f "${rootmnt}/etc/machine-id" "${rootmnt}/var/lib/dbus/machine-id" 53 | echo "${MACHINE_ID}" >"${rootmnt}/etc/machine-id" 54 | mkdir -p "${rootmnt}/var/lib/dbus" 55 | ln -s /etc/machine-id "${rootmnt}/var/lib/dbus/machine-id" 56 | -------------------------------------------------------------------------------- /files/hooks/cmdline-passwd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: cmdline-passwd - Set user passwords from kernel command line 5 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Kernel command-line usage examples: 9 | # passwd=foo (root assumed) 10 | # passwd=root:foo passwd=finnix:bar 11 | # passwd=root:$1$QnvsFWnz$MppFa1JL0xsMjB/VQwvwv. 12 | # 13 | # "sshd_password" is accepted as a legacy equivalent to "passwd" 14 | 15 | import os 16 | import re 17 | import shlex 18 | import subprocess 19 | import sys 20 | 21 | 22 | RE_ENCRYPTED = re.compile(r"\$.{1,2}\$") 23 | 24 | 25 | def parse_cmdline(cmdline_text): 26 | cmdline = [] 27 | for i in shlex.split(cmdline_text): 28 | if "=" in i: 29 | cmdline.append(tuple(i.split("=", 1))) 30 | else: 31 | cmdline.append((i, None)) 32 | 33 | return cmdline 34 | 35 | 36 | def main(): 37 | if not os.path.exists("/proc/cmdline"): 38 | return 39 | 40 | with open("/proc/cmdline") as f: 41 | cmdline = parse_cmdline(f.read()) 42 | 43 | userpasses = [] 44 | userpasses_encrypted = [] 45 | for userpass in [v for k, v in cmdline if k in ("passwd", "sshd_password") and v is not None]: 46 | if ":" not in userpass: 47 | userpass = "root:" + userpass 48 | username, password = userpass.split(":", 1) 49 | if RE_ENCRYPTED.match(password): 50 | userpasses_encrypted.append(userpass) 51 | else: 52 | userpasses.append(userpass) 53 | 54 | if userpasses: 55 | subprocess.run( 56 | ["chpasswd"], 57 | input=("\n".join(sorted(userpasses)) + "\n").encode("UTF-8"), 58 | check=True, 59 | ) 60 | 61 | if userpasses_encrypted: 62 | subprocess.run( 63 | ["chpasswd", "--encrypted"], 64 | input=("\n".join(sorted(userpasses_encrypted)) + "\n").encode("UTF-8"), 65 | check=True, 66 | ) 67 | 68 | 69 | if __name__ == "__main__": 70 | sys.exit(main()) 71 | -------------------------------------------------------------------------------- /files/hooks/command-not-found: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: Finnix command-not-found 5 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | import argparse 9 | import json 10 | import os 11 | import pathlib 12 | import sys 13 | 14 | 15 | def eprint(*args, **kwargs): 16 | kwargs["file"] = sys.stderr 17 | return print(*args, **kwargs) 18 | 19 | 20 | def do_handler(handler): 21 | if handler.get("packages"): 22 | if os.getuid() == 0: 23 | apt_command = "apt" 24 | else: 25 | apt_command = "sudo apt" 26 | eprint() 27 | eprint("It can be installed with:") 28 | eprint(" {} update".format(apt_command)) 29 | for i, package in enumerate(handler["packages"], 1): 30 | eprint( 31 | " {} install {}{}".format( 32 | apt_command, 33 | package, 34 | (" # or" if i < len(handler["packages"]) else ""), 35 | ) 36 | ) 37 | if handler.get("similar_commands"): 38 | eprint() 39 | eprint("Other installed programs provide similar functionality:") 40 | for similar_command in handler["similar_commands"]: 41 | eprint(" {}".format(similar_command)) 42 | eprint() 43 | if handler.get("note"): 44 | eprint() 45 | eprint(handler["note"]) 46 | 47 | 48 | def main(): 49 | parser = argparse.ArgumentParser() 50 | parser.add_argument("command") 51 | args = parser.parse_args(args=sys.argv[1:]) 52 | 53 | eprint("{}: command not found".format(args.command)) 54 | 55 | for fn in pathlib.Path("/etc/simple-cnf/handlers.d").glob("*.json"): 56 | with fn.open() as f: 57 | for handler in json.load(f): 58 | if args.command not in handler["commands"]: 59 | continue 60 | do_handler(handler) 61 | return 127 62 | return 127 63 | 64 | 65 | if __name__ == "__main__": 66 | if os.path.exists("/usr/lib/command-not-found.distrib"): 67 | os.execv("/usr/lib/command-not-found.distrib", sys.argv) 68 | sys.exit(main()) 69 | -------------------------------------------------------------------------------- /files/hooks/wifi-connect: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: wifi-connect - Handy wrapper around wpa_supplicant/networkd 5 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | set -e 9 | 10 | interface="" 11 | while getopts ":i:" opt; do 12 | case "${opt}" in 13 | i) 14 | interface="$OPTARG" 15 | ;; 16 | *) 17 | echo "Usage: $0 [-i interface] \"access point\" \"passphrase\"" 18 | exit 1 19 | ;; 20 | esac 21 | done 22 | shift $((OPTIND - 1)) 23 | ap="$1" 24 | passphrase="$2" 25 | 26 | if [ -z "${interface}" ]; then 27 | interfaces="" 28 | multiple_interfaces="no" 29 | for p in /sys/class/net/*; do 30 | [ -e "${p}" ] || continue 31 | [ -e "${p}/phy80211" ] || [ -e "${p}/wireless" ] || continue 32 | iname="$(basename "${p}")" 33 | if [ -n "${interfaces}" ]; then 34 | multiple_interfaces="yes" 35 | interfaces="${interfaces} ${iname}" 36 | else 37 | interfaces="${iname}" 38 | fi 39 | done 40 | 41 | if [ -z "${interfaces}" ]; then 42 | echo "Sorry, no wireless interfaces found" 43 | exit 1 44 | elif [ "${multiple_interfaces}" = "yes" ]; then 45 | echo "Multiple interfaces found: ${multiple_interfaces}" 46 | echo "Usage: $0 -i interface \"access point\" \"passphrase\"" 47 | exit 1 48 | fi 49 | interface="${interfaces}" 50 | fi 51 | 52 | if [ ! -e "/sys/class/net/${interface}" ]; then 53 | echo "Interface ${interface} not found" 54 | exit 1 55 | fi 56 | if [ -z "${ap}" ] || [ -z "${passphrase}" ]; then 57 | echo "Usage: $0 [-i interface] \"access point\" \"passphrase\"" 58 | echo 59 | echo "Nearby access points:" 60 | echo 61 | ip link set dev "${interface}" up 62 | iw dev "${interface}" scan | 63 | grep -E 'signal:|SSID:' | 64 | sed -E -e 's/\t(SSID|signal): //' | 65 | awk '{ORS = (NR % 2 == 0)? "\n" : " "; print}' | 66 | sort -n -r | 67 | sed -E -e 's/ dBm / /; s/^[-0-9\/\.]+ //' | 68 | awk '$1 && $1 !~ /\\x00/' | 69 | awk '!seen[$0]++' | 70 | head -n 15 71 | echo 72 | exit 1 73 | fi 74 | 75 | mkdir -p /etc/wpa_supplicant 76 | wpa_passphrase_block="$(wpa_passphrase "${ap}" "${passphrase}")" 77 | rm -f "/etc/wpa_supplicant/wpa_supplicant-${interface}.conf" 78 | touch "/etc/wpa_supplicant/wpa_supplicant-${interface}.conf" 79 | chmod 0600 "/etc/wpa_supplicant/wpa_supplicant-${interface}.conf" 80 | cat <"/etc/wpa_supplicant/wpa_supplicant-${interface}.conf" 81 | ctrl_interface=/run/wpa_supplicant 82 | update_config=1 83 | 84 | ${wpa_passphrase_block} 85 | EOM 86 | 87 | mkdir -p /etc/systemd/network 88 | rm -f "/etc/systemd/network/10-${interface}.network" 89 | cat <"/etc/systemd/network/10-${interface}.network" 90 | [Match] 91 | Name=${interface} 92 | 93 | [Network] 94 | DHCP=yes 95 | EOM 96 | 97 | systemctl restart "wpa_supplicant@${interface}.service" systemd-networkd.service systemd-resolved.service 98 | 99 | echo "" 100 | echo "Interface ${interface} is now being managed by wpa_supplicant and networkd." 101 | echo "To see the status of these services:" 102 | echo " networkctl" 103 | echo " journalctl -a -u wpa_supplicant@${interface}.service -u systemd-networkd.service" 104 | echo "" 105 | -------------------------------------------------------------------------------- /lists/finnix.list.chroot: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | 2048 5 | 2ping 6 | 7zip 7 | {%- if ARCH == "amd64" %} 8 | acpi 9 | {%- endif %} 10 | aespipe 11 | apg 12 | apt-utils 13 | arj 14 | arping 15 | arpwatch 16 | at 17 | attr 18 | bash-completion 19 | bc 20 | bcache-tools 21 | bind9-dnsutils 22 | bind9-host 23 | bonnie++ 24 | bridge-utils 25 | btrfs-progs 26 | buffer 27 | bzip2 28 | cabextract 29 | ca-certificates 30 | cdpr 31 | chntpw 32 | cifs-utils 33 | {%- if ARCH == "amd64" %} 34 | cmospwd 35 | {%- endif %} 36 | console-data 37 | console-setup 38 | cpio 39 | cpu-checker 40 | {%- if ARCH == "amd64" %} 41 | cpuid 42 | {%- endif %} 43 | cron 44 | cryptsetup-bin 45 | curl 46 | dbus 47 | dc3dd 48 | debootstrap 49 | {%- if ARCH != "ppc64el" and ARCH != "s390x" %} 50 | dmidecode 51 | {%- endif %} 52 | dosfstools 53 | dselect 54 | dump 55 | ed 56 | edid-decode 57 | {%- if ARCH != "ppc64el" and ARCH != "s390x" %} 58 | efibootmgr 59 | efivar 60 | efitools 61 | {%- endif %} 62 | eject 63 | elinks 64 | etherwake 65 | ethtool 66 | exfat-fuse 67 | exfatprogs 68 | f2fs-tools 69 | fdutils 70 | fetchmail 71 | file 72 | finger 73 | fsarchiver 74 | {%- if ARCH == "amd64" %} 75 | fuseext2 76 | {%- endif %} 77 | fxload 78 | gawk 79 | gddrescue 80 | gdisk 81 | gdu 82 | genromfs 83 | git 84 | gpart 85 | gpg-agent 86 | gpm 87 | grepcidr 88 | hdparm 89 | hexedit 90 | hfsutils 91 | htop 92 | iftop 93 | inetutils-telnet 94 | inxi 95 | iotop 96 | iozone3 97 | ipcalc 98 | iperf3 99 | ipmitool 100 | iptables 101 | iptraf-ng 102 | iputils-ping 103 | irssi 104 | isomd5sum 105 | iw 106 | jfsutils 107 | joe 108 | jove 109 | kbd 110 | keyboard-configuration 111 | keyutils 112 | kpartx 113 | less 114 | lftp 115 | {%- if ARCH == "amd64" %} 116 | libc6-i386 117 | {%- endif %} 118 | lldpd 119 | lm-sensors 120 | locales 121 | lpr 122 | lrzip 123 | lrzsz 124 | lsb-release 125 | lshw 126 | lsof 127 | {%- if ARCH == "amd64" or ARCH == "s390x" %} 128 | ltrace 129 | {%- endif %} 130 | lvm2 131 | lz4 132 | lzip 133 | lzop 134 | man-db 135 | mbr 136 | mc 137 | mdadm 138 | memtester 139 | minicom 140 | mscompress 141 | mtools 142 | mtr-tiny 143 | mt-st 144 | nano 145 | ncal 146 | ncat 147 | ncdu 148 | netcat-openbsd 149 | netcat-traditional 150 | net-tools 151 | nicstat 152 | ninvaders 153 | nmap 154 | ntfs-3g 155 | ntpsec-ntpdate 156 | ntpsec-ntpdig 157 | nvme-cli 158 | nwipe 159 | nyancat 160 | oathtool 161 | openssh-client 162 | openssh-server 163 | openvpn 164 | partclone 165 | parted 166 | patch 167 | pciutils 168 | pcmciautils 169 | picocom 170 | powermgmt-base 171 | pppconfig 172 | pppoe 173 | pptp-linux 174 | procinfo 175 | psmisc 176 | pv 177 | pwgen 178 | quota 179 | quotatool 180 | ranger 181 | rdate 182 | rdiff-backup 183 | rename 184 | rlwrap 185 | rmlint 186 | robotfindskitten 187 | rover 188 | rsync 189 | screen 190 | sdparm 191 | setserial 192 | sharutils 193 | sipcalc 194 | smartmontools 195 | smbclient 196 | snmp 197 | socat 198 | squashfs-tools 199 | sshfs 200 | strace 201 | stress 202 | stunnel4 203 | sunxi-tools 204 | sudo 205 | systemd-timesyncd 206 | systemd-zram-generator 207 | tcpdump 208 | testdisk 209 | tftp-hpa 210 | time 211 | tmux 212 | tofrodos 213 | traceroute 214 | udftools 215 | udisks2 216 | udisks2-btrfs 217 | udisks2-lvm2 218 | units 219 | unp 220 | unzip 221 | usbutils 222 | user-setup 223 | util-linux-extra 224 | uuid-runtime 225 | vim-tiny 226 | vitetris 227 | vlan 228 | w3m 229 | wakeonlan 230 | wget 231 | whois 232 | wipe 233 | wireless-regdb 234 | wireless-tools 235 | wpasupplicant 236 | xfsprogs 237 | xorriso 238 | xxd 239 | xxhash 240 | xz-utils 241 | zerofree 242 | {%- if ARCH == "amd64" or ARCH == "ppc64el" %} 243 | {#- Weird combination; correct as of 2024-02-09 #} 244 | zfs-fuse 245 | {%- endif %} 246 | zip 247 | zstd 248 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Finnix live-build tools 2 | 3 | `finnix-live-build` is Finnix's image build system, and is a wrapper around 4 | Debian Live's `live-build` system. 5 | 6 | ## Building 7 | 8 | Requirements: 9 | 10 | - Debian testing/sid, or Ubuntu 20.04 focal or later. 11 | - live-build, built from [live-build git 12 | HEAD](https://github.com/finnix/live-build). 13 | - This is available as a git submodule in this repository. 14 | - While upstream HEAD is usually fine, the link above (and this repository's 15 | submodule) points to a Finnix-specific branch which is usually in sync with 16 | [live-build upstream](https://salsa.debian.org/live-team/live-build), but 17 | sometimes includes fixes/changes which have not (yet) been accepted 18 | upstream. 19 | - See `build-dependencies.json` for required host packages. 20 | 21 | This can be built on dedicated hardware, in a virtual machine, or in a 22 | systemd-nspawn container. Building in a chroot within one of these environments 23 | is supported. Docker and LXD containers are not supported, as they do not allow 24 | mounting proc/devpts (even the container-specific restricted versions), required 25 | by live-build/debootstrap. 26 | 27 | The default build directory will be `build/lb/` from the script directory. 28 | 29 | ## Scheduled builds 30 | 31 | - Weekly AMD64 builds are made on the [GitHub finnix-live-build "schedule" 32 | workflow](https://github.com/finnix/finnix-live-build/actions?query=workflow%3Aschedule), 33 | with ISO build artifacts uploaded. The "ci" workflow is built on each push as 34 | an indication, but artifacts are not available. 35 | - Daily AMD64 builds are made on a [container in a colocated 36 | environment](https://ci.colobox.com/colobox/finnix-live-build-amd64/), with 37 | ISO build artifacts uploaded to 38 | [snapshots.finnix.org](https://snapshots.finnix.org/ci/finnix-live-build-amd64/). 39 | - Indicator builds are built on [my home CI 40 | system](https://ci.colobox.com/home/) for many architectures (see below). 41 | Artifacts are not publicly available. Most architectures are built daily, 42 | except for slow pure emulation architectures like s390x and ppc64el. 43 | 44 | ## Architectures 45 | 46 | finnix-live-build supports multiple architectures, but are considered in 47 | multiple tiers: 48 | 49 | ### Tier 1 50 | 51 | - amd64 52 | 53 | The only supported architecture in the sense that ISOs are officially released. 54 | Built images are tested often. Build failures are a blocker and fixed ASAP. 55 | 56 | ### Tier 2 57 | 58 | - arm64 59 | 60 | While ISOs are not officially released, these are still considered important 61 | architectures. Built images are tested often. Build failures are a blocker and 62 | fixed soon. 63 | 64 | ### Tier 3 65 | 66 | - ppc64el 67 | - riscv64 68 | - s390x 69 | 70 | Not supported, and produced images are not directly bootable. However, they can 71 | be booted by direct kernel/initrd boot in QEMU, and are tested occasionally. 72 | Build failures are not a blocker. 73 | 74 | ## Issues and pull requests 75 | 76 | To open a Finnix issue, please use the main [Finnix issue 77 | tracker](https://github.com/finnix/finnix/issues), not this repository's. Pull 78 | requests will be considered here, but you probably also want to open an issue to 79 | track it. 80 | 81 | ## Remastering / forking 82 | 83 | If you are looking to build a live environment which is outside of the scope of 84 | Finnix's goals, feel free to use this build repository as a base. In essence, 85 | this repository is a thin wrapper around live-build, and builds upon the massive 86 | work done by the Debian Live project. I encourage you to study this repository 87 | and live-build, and to experiment with your own builds. 88 | 89 | If you do produce builds based directly off the finnix-live-build repository, 90 | please change the branding to indicate it is not an official Finnix release. 91 | Please see the top of `finnix-live-build` for branding-related variables. 92 | 93 | ## License 94 | 95 | The finnix-live-build package is mostly licensed under the terms of the Mozilla 96 | Public License v2.0, but please check individual files for license terms. 97 | 98 | This document is provided under the following license: 99 | 100 | SPDX-PackageSummary: finnix-live-build 101 | SPDX-FileCopyrightText: © 2020 Ryan Finnie 102 | SPDX-License-Identifier: CC-BY-SA-4.0 103 | -------------------------------------------------------------------------------- /.github/workflows/schedule.yml: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | --- 5 | name: "schedule" 6 | "on": 7 | schedule: 8 | - cron: "34 5 * * 1" 9 | workflow_dispatch: 10 | jobs: 11 | build: 12 | name: "Build image (${{ matrix.arch }})" 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | include: 17 | - arch: "amd64" 18 | runs-on: "ubuntu-latest" 19 | - arch: "arm64" 20 | runs-on: "ubuntu-24.04-arm" 21 | runs-on: "${{ matrix.runs-on }}" 22 | permissions: 23 | id-token: "write" 24 | attestations: "write" 25 | env: 26 | BUILD_WORKFLOW_TAG: "schedule" 27 | steps: 28 | - uses: "actions/checkout@v4" 29 | with: 30 | submodules: true 31 | - name: "Dependency packages" 32 | run: | 33 | sudo apt update 34 | tools/get-dependencies --only required -0 | xargs -0 sudo apt -y install 35 | tools/get-dependencies --only optional | while IFS='' read -r pkg; do 36 | sudo apt -y install "${pkg}" || true 37 | done 38 | - name: "Build image" 39 | run: | 40 | env | grep ^GITHUB_ | sudo tee -a /etc/environment >/dev/null 41 | sudo chown -R root:root . 42 | sudo env BUILD_TAGS="${BUILD_WORKFLOW_TAG}" ./finnix-live-build 43 | sudo rm -rf build/cache/lb/bootstrap build/cache/lb/contents.chroot build/cache/lb/indices.bootstrap 44 | sudo chown -R "$(id -un):$(id -gn)" . 45 | - name: "Attest" 46 | uses: "actions/attest-build-provenance@v3" 47 | with: 48 | subject-path: "${{ github.workspace }}/build/lb/finnix-*.iso" 49 | - name: "Upload artifacts" 50 | uses: "actions/upload-artifact@v4" 51 | with: 52 | name: "finnix-live-build.${{ github.workflow }}.${{ github.job }}.${{ matrix.arch }}.${{ github.run_number }}.${{ github.run_id }}" 53 | path: | 54 | build/lb/finnix-* 55 | build/lb/chroot.files 56 | build/lb/chroot.packages.* 57 | # Faster uploads as ISOs are already heavily compressed 58 | compression-level: 0 59 | build-docker: 60 | name: "Build Docker image (${{ matrix.arch }})" 61 | strategy: 62 | fail-fast: false 63 | matrix: 64 | include: 65 | - arch: "amd64" 66 | runs-on: "ubuntu-latest" 67 | - arch: "arm64" 68 | runs-on: "ubuntu-24.04-arm" 69 | runs-on: "${{ matrix.runs-on }}" 70 | permissions: 71 | id-token: "write" 72 | contents: "read" 73 | packages: "write" 74 | attestations: "write" 75 | env: 76 | BUILD_WORKFLOW_TAG: "schedule" 77 | steps: 78 | - uses: "actions/checkout@v4" 79 | with: 80 | submodules: true 81 | - name: "Authentication" 82 | run: | 83 | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin 84 | - name: "Set environment variables" 85 | run: | 86 | IMAGE_NAME="$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')" 87 | IMAGE_TAG="${BUILD_WORKFLOW_TAG}-${{ matrix.arch }}" 88 | echo "IMAGE_NAME=${IMAGE_NAME}" >>"${GITHUB_ENV}" 89 | echo "IMAGE_TAG=${IMAGE_TAG}" >>"${GITHUB_ENV}" 90 | - name: "Build image" 91 | run: | 92 | IMAGE_ID="ghcr.io/${IMAGE_NAME}:${IMAGE_TAG}" 93 | docker image build -t "${IMAGE_ID}" \ 94 | --build-arg BUILD_TAGS="docker ${BUILD_WORKFLOW_TAG}" \ 95 | --build-arg GITHUB_SERVER_URL \ 96 | --build-arg GITHUB_REPOSITORY \ 97 | --build-arg GITHUB_RUN_ID \ 98 | . 99 | docker image history "${IMAGE_ID}" 100 | docker image inspect "${IMAGE_ID}" 101 | docker image push "${IMAGE_ID}" 102 | IMAGE_DIGEST="sha256:$(docker buildx imagetools inspect "${IMAGE_ID}" --raw | sha256sum | awk '{print $1}')" 103 | echo "IMAGE_DIGEST=${IMAGE_DIGEST}" >>"${GITHUB_ENV}" 104 | - name: "Attest" 105 | uses: "actions/attest-build-provenance@v3" 106 | with: 107 | subject-name: "ghcr.io/${{ env.IMAGE_NAME }}" 108 | subject-digest: "${{ env.IMAGE_DIGEST }}" 109 | push-to-registry: true 110 | -------------------------------------------------------------------------------- /files/hooks/strings: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-FileComment: Pure Python semi-reimplimentation of GNU strings 4 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 5 | # SPDX-License-Identifier: MPL-2.0 6 | 7 | import argparse 8 | import itertools 9 | import pathlib 10 | import sys 11 | 12 | 13 | def readiter(fh, size=1024): 14 | return itertools.takewhile(lambda t: t, map(lambda chunk: fh.read(size), itertools.count(0))) 15 | 16 | 17 | class Strings: 18 | def parse_args(self, argv=None): 19 | if argv is None: 20 | argv = sys.argv 21 | 22 | parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) 23 | 24 | parser.add_argument( 25 | "files", 26 | nargs="*", 27 | type=pathlib.Path, 28 | help="File to examine", 29 | metavar="file", 30 | ) 31 | parser.add_argument( 32 | "--print-file-name", 33 | "-f", 34 | action="store_true", 35 | help="Print filename before each string line", 36 | ) 37 | parser.add_argument( 38 | "--include-all-whitespace", 39 | "-w", 40 | action="store_true", 41 | help="Include all whitespace when considering strings", 42 | ) 43 | parser.add_argument( 44 | "--bytes", 45 | "-n", 46 | type=int, 47 | default=4, 48 | metavar="number", 49 | help="Length of printable bytes to be considered a string", 50 | ) 51 | parser.add_argument( 52 | "--output-separator", 53 | "-s", 54 | default="\n", 55 | metavar="string", 56 | help="Line separator between output strings", 57 | ) 58 | parser.add_argument( 59 | "--radix", 60 | "-t", 61 | choices=["d", "x", "o"], 62 | help="Print byte position of string in decimal/hex/octal", 63 | ) 64 | 65 | return parser.parse_args(args=argv[1:]) 66 | 67 | def process_file(self, fn): 68 | self.output_buffer = bytearray() 69 | self.position = 0 70 | self.filename = fn 71 | 72 | i = -1 73 | if fn is None: 74 | fh = sys.stdin.buffer 75 | else: 76 | fh = fn.open("rb") 77 | for buf in readiter(fh): 78 | for b in buf: 79 | i += 1 80 | if (b >= 32 and b <= 126) or b in self.whitespace: 81 | if len(self.output_buffer) == 0: 82 | self.position = i 83 | self.output_buffer.append(b) 84 | elif len(self.output_buffer) > 0: 85 | self.print_output() 86 | self.print_output() 87 | fh.close() 88 | 89 | def print_output(self): 90 | if len(self.output_buffer) < self.args.bytes: 91 | self.output_buffer.clear() 92 | return 93 | 94 | output_format = "{string}" 95 | if self.args.radix: 96 | output_format = "{position:>7" + self.args.radix + "} " + output_format 97 | if self.args.print_file_name: 98 | output_format = "{filename}: " + output_format 99 | 100 | if self.filename is None: 101 | filename = "{standard input}" 102 | else: 103 | filename = self.filename 104 | print( 105 | output_format.format( 106 | string=self.output_buffer.decode("ascii"), 107 | filename=filename, 108 | position=self.position, 109 | ), 110 | end=self.args.output_separator, 111 | ) 112 | self.output_buffer.clear() 113 | 114 | def main(self): 115 | self.args = self.parse_args() 116 | if self.args.include_all_whitespace: 117 | self.whitespace = bytearray(b" \t\v\r\n\f") 118 | else: 119 | self.whitespace = bytearray(b" \t") 120 | 121 | if not self.args.files: 122 | self.args.files.append(None) 123 | 124 | for fn in self.args.files: 125 | try: 126 | self.process_file(fn) 127 | except BrokenPipeError: 128 | return 0 129 | except KeyboardInterrupt: 130 | return 130 131 | 132 | 133 | if __name__ == "__main__": 134 | sys.exit(Strings().main()) 135 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | --- 5 | name: "release" 6 | "on": 7 | workflow_dispatch: 8 | jobs: 9 | build: 10 | name: "Build image (${{ matrix.arch }})" 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | include: 15 | - arch: "amd64" 16 | runs-on: "ubuntu-latest" 17 | - arch: "arm64" 18 | runs-on: "ubuntu-24.04-arm" 19 | runs-on: "${{ matrix.runs-on }}" 20 | permissions: 21 | id-token: "write" 22 | attestations: "write" 23 | env: 24 | BUILD_WORKFLOW_TAG: "release" 25 | steps: 26 | - uses: "actions/checkout@v4" 27 | with: 28 | submodules: true 29 | - name: "Dependency packages" 30 | run: | 31 | sudo apt update 32 | tools/get-dependencies --only required -0 | xargs -0 sudo apt -y install 33 | tools/get-dependencies --only optional | while IFS='' read -r pkg; do 34 | sudo apt -y install "${pkg}" || true 35 | done 36 | - name: "Build image" 37 | run: | 38 | # Prepare 39 | env | grep ^GITHUB_ | sudo tee -a /etc/environment >/dev/null 40 | sudo chown -R root:root . 41 | 42 | # Main ISO image 43 | sudo env BUILD_TAGS="${BUILD_WORKFLOW_TAG}" ./finnix-live-build 44 | 45 | # Source ISO 46 | TEMP_BUILD_DIR="$(sudo mktemp -d -p "$(pwd)/build")" 47 | sudo env SOURCE_ISO=true BUILD_DIR="${TEMP_BUILD_DIR?}" ./finnix-live-build 48 | sudo mv "${TEMP_BUILD_DIR}/lb/finnix-source.iso" build/lb/ 49 | sudo rm -rf "${TEMP_BUILD_DIR?}" 50 | echo "Note: The build information listed above is not used; only the source ISO is saved." 51 | echo "See the 'Build image' step for actual build information." 52 | 53 | # Cleanup 54 | sudo chown -R "$(id -un):$(id -gn)" . 55 | - name: "Attest" 56 | uses: "actions/attest-build-provenance@v3" 57 | with: 58 | subject-path: "${{ github.workspace }}/build/lb/finnix-*.iso" 59 | - name: "Upload artifacts" 60 | uses: "actions/upload-artifact@v4" 61 | with: 62 | name: "finnix-live-build.${{ github.workflow }}.${{ github.job }}.${{ matrix.arch }}.${{ github.run_number }}.${{ github.run_id }}" 63 | path: | 64 | build/lb/finnix-* 65 | build/lb/chroot.files 66 | build/lb/chroot.packages.* 67 | # Faster uploads as ISOs are already heavily compressed 68 | compression-level: 0 69 | build-docker: 70 | name: "Build Docker image (${{ matrix.arch }})" 71 | strategy: 72 | fail-fast: false 73 | matrix: 74 | include: 75 | - arch: "amd64" 76 | runs-on: "ubuntu-latest" 77 | - arch: "arm64" 78 | runs-on: "ubuntu-24.04-arm" 79 | runs-on: "${{ matrix.runs-on }}" 80 | permissions: 81 | id-token: "write" 82 | contents: "read" 83 | packages: "write" 84 | attestations: "write" 85 | env: 86 | BUILD_WORKFLOW_TAG: "release" 87 | steps: 88 | - uses: "actions/checkout@v4" 89 | with: 90 | submodules: true 91 | - name: "Authentication" 92 | run: | 93 | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin 94 | - name: "Set environment variables" 95 | run: | 96 | IMAGE_NAME="$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')" 97 | IMAGE_TAG="${BUILD_WORKFLOW_TAG}-${{ matrix.arch }}" 98 | echo "IMAGE_NAME=${IMAGE_NAME}" >>"${GITHUB_ENV}" 99 | echo "IMAGE_TAG=${IMAGE_TAG}" >>"${GITHUB_ENV}" 100 | - name: "Build image" 101 | run: | 102 | IMAGE_ID="ghcr.io/${IMAGE_NAME}:${IMAGE_TAG}" 103 | docker image build -t "${IMAGE_ID}" \ 104 | --build-arg BUILD_TAGS="docker ${BUILD_WORKFLOW_TAG}" \ 105 | --build-arg GITHUB_SERVER_URL \ 106 | --build-arg GITHUB_REPOSITORY \ 107 | --build-arg GITHUB_RUN_ID \ 108 | . 109 | docker image history "${IMAGE_ID}" 110 | docker image inspect "${IMAGE_ID}" 111 | docker image push "${IMAGE_ID}" 112 | IMAGE_DIGEST="sha256:$(docker buildx imagetools inspect "${IMAGE_ID}" --raw | sha256sum | awk '{print $1}')" 113 | echo "IMAGE_DIGEST=${IMAGE_DIGEST}" >>"${GITHUB_ENV}" 114 | - name: "Attest" 115 | uses: "actions/attest-build-provenance@v3" 116 | with: 117 | subject-name: "ghcr.io/${{ env.IMAGE_NAME }}" 118 | subject-digest: "${{ env.IMAGE_DIGEST }}" 119 | push-to-registry: true 120 | -------------------------------------------------------------------------------- /tools/cnf-build-common: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: cnf-build-common 5 | # SPDX-FileCopyrightText: © 2023 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Builds a simple-cnf json config of all commands in the top 1000 (by 9 | # Debian popcon) packages which are not already installed. 10 | # 11 | # Usage: zcat Contents-all.gz Contents-amd64.gz | ./cnf-build-common >common.json 12 | # 13 | # Contents files: http://deb.debian.org/debian/dists/testing/main/ 14 | # Popcon: https://popcon.debian.org/main/by_inst 15 | 16 | import argparse 17 | import logging 18 | import json 19 | import os 20 | import pathlib 21 | import re 22 | import sys 23 | 24 | 25 | class CNFBuildCommon: 26 | re_contents_line = re.compile(r"^(.*) +(.*?)$") 27 | re_bin_path = re.compile(r"^(?:usr/)?s?bin/(.*?)$") 28 | re_popcorn_line = re.compile(r"^([0-9]+) +(.*?) +") 29 | args = None 30 | pkgassoc = {} 31 | 32 | def main(self): 33 | self.args = self.parse_args() 34 | logging.basicConfig( 35 | level=(logging.DEBUG if self.args.debug else logging.INFO), 36 | format="%(levelname)s: %(message)s", 37 | ) 38 | self.get_top_pkgs() 39 | self.parse_contents() 40 | self.print_json() 41 | 42 | def parse_args(self, argv=None): 43 | if argv is None: 44 | argv = sys.argv 45 | 46 | parser = argparse.ArgumentParser( 47 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 48 | prog=os.path.basename(argv[0]), 49 | ) 50 | parser.add_argument("--debug", action="store_true", help="Print debugging information") 51 | parser.add_argument( 52 | "--contents-file", 53 | action="append", 54 | type=pathlib.Path, 55 | help="Debian Contents file", 56 | ) 57 | parser.add_argument( 58 | "--top-packages", 59 | type=int, 60 | default=1000, 61 | help="Top number of Popcon packages to consider", 62 | ) 63 | parser.add_argument( 64 | "--popcon-file", 65 | type=pathlib.Path, 66 | default="by_inst", 67 | help="Popcon data file", 68 | ) 69 | parser.add_argument( 70 | "--skip-package-check", 71 | action="store_true", 72 | help="Skip checking if package is installed", 73 | ) 74 | parser.add_argument( 75 | "--path-base", 76 | type=pathlib.Path, 77 | default="/", 78 | help="Path base for package checks", 79 | ) 80 | 81 | return parser.parse_args(args=argv[1:]) 82 | 83 | def get_top_pkgs(self): 84 | self.top_pkgs = [] 85 | with self.args.popcon_file.open() as f: 86 | for line in f: 87 | r = self.re_popcorn_line.search(line.rstrip()) 88 | if not r: 89 | continue 90 | pos = int(r.group(1)) 91 | pkg = r.group(2) 92 | self.top_pkgs.append(pkg) 93 | if pos == self.args.top_packages: 94 | return 95 | 96 | def parse_contents(self): 97 | if self.args.contents_file: 98 | for file in self.args.contents_file: 99 | self.parse_contents_file(file.open()) 100 | else: 101 | self.parse_contents_file(sys.stdin) 102 | 103 | def parse_contents_file(self, fh): 104 | for line in fh: 105 | r = self.re_contents_line.search(line.rstrip()) 106 | if not r: 107 | continue 108 | fn = r.group(1).strip() 109 | p = r.group(2) 110 | for pkg in p.split(","): 111 | pkg = pkg.split("/")[1] 112 | if pkg not in self.top_pkgs: 113 | continue 114 | if not self.args.skip_package_check: 115 | if pathlib.Path(self.args.path_base).joinpath("var/lib/dpkg/info/{}.list".format(pkg)).exists(): 116 | continue 117 | barefn = self.re_bin_path.findall(fn) 118 | if not barefn: 119 | continue 120 | barefn = barefn[0] 121 | logging.info("{}: {}".format(pkg, barefn)) 122 | if pkg not in self.pkgassoc: 123 | self.pkgassoc[pkg] = [] 124 | self.pkgassoc[pkg].append(barefn) 125 | 126 | def print_json(self): 127 | out = [] 128 | for pkg in sorted(self.pkgassoc): 129 | out.append( 130 | { 131 | "commands": sorted(self.pkgassoc[pkg]), 132 | "packages": [pkg], 133 | } 134 | ) 135 | 136 | print(json.dumps(out, sort_keys=True, indent=4)) 137 | 138 | 139 | if __name__ == "__main__": 140 | sys.exit(CNFBuildCommon().main()) 141 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-PackageSummary: finnix-live-build 2 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 3 | # SPDX-License-Identifier: MPL-2.0 4 | --- 5 | name: "ci" 6 | "on": 7 | push: 8 | pull_request: 9 | workflow_dispatch: 10 | jobs: 11 | lint: 12 | runs-on: "ubuntu-latest" 13 | steps: 14 | - uses: "actions/checkout@v4" 15 | with: 16 | submodules: true 17 | - name: "Dependency packages" 18 | run: | 19 | sudo apt update 20 | tools/get-dependencies --only required -0 | xargs -0 sudo apt -y install 21 | tools/get-dependencies --only optional | while IFS='' read -r pkg; do 22 | sudo apt -y install "${pkg}" || true 23 | done 24 | - name: "Lint codebase" 25 | env: 26 | LINT: "true" 27 | run: "./finnix-live-build" 28 | build: 29 | name: "Build image (${{ matrix.arch }})" 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | include: 34 | - arch: "amd64" 35 | runs-on: "ubuntu-latest" 36 | - arch: "arm64" 37 | runs-on: "ubuntu-24.04-arm" 38 | runs-on: "${{ matrix.runs-on }}" 39 | permissions: 40 | id-token: "write" 41 | attestations: "write" 42 | env: 43 | BUILD_WORKFLOW_TAG: "ci" 44 | steps: 45 | - uses: "actions/checkout@v4" 46 | with: 47 | submodules: true 48 | - name: "Cache live-build" 49 | uses: "actions/cache@v4" 50 | with: 51 | path: "build/cache" 52 | key: "finnix-live-build-1" 53 | - name: "Dependency packages" 54 | run: | 55 | sudo apt update 56 | tools/get-dependencies --only required -0 | xargs -0 sudo apt -y install 57 | tools/get-dependencies --only optional | while IFS='' read -r pkg; do 58 | sudo apt -y install "${pkg}" || true 59 | done 60 | - name: "Build image" 61 | run: | 62 | env | grep ^GITHUB_ | sudo tee -a /etc/environment >/dev/null 63 | sudo chown -R root:root . 64 | sudo env BUILD_TAGS="${BUILD_WORKFLOW_TAG}" ./finnix-live-build 65 | sudo rm -rf build/cache/lb/bootstrap build/cache/lb/contents.chroot build/cache/lb/indices.bootstrap 66 | sudo chown -R "$(id -un):$(id -gn)" . 67 | - name: "Attest" 68 | uses: "actions/attest-build-provenance@v3" 69 | with: 70 | subject-path: "${{ github.workspace }}/build/lb/finnix-*.iso" 71 | - name: "Upload artifacts" 72 | uses: "actions/upload-artifact@v4" 73 | with: 74 | name: "finnix-live-build.${{ github.workflow }}.${{ github.job }}.${{ matrix.arch }}.${{ github.run_number }}.${{ github.run_id }}" 75 | path: | 76 | build/lb/finnix-* 77 | build/lb/chroot.files 78 | build/lb/chroot.packages.* 79 | # Faster uploads as ISOs are already heavily compressed 80 | compression-level: 0 81 | # Reduced retention for CI builds 82 | retention-days: 5 83 | build-docker: 84 | name: "Build Docker image (${{ matrix.arch }})" 85 | strategy: 86 | fail-fast: false 87 | matrix: 88 | include: 89 | - arch: "amd64" 90 | runs-on: "ubuntu-latest" 91 | - arch: "arm64" 92 | runs-on: "ubuntu-24.04-arm" 93 | runs-on: "${{ matrix.runs-on }}" 94 | permissions: 95 | id-token: "write" 96 | contents: "read" 97 | packages: "write" 98 | attestations: "write" 99 | env: 100 | BUILD_WORKFLOW_TAG: "ci" 101 | steps: 102 | - uses: "actions/checkout@v4" 103 | with: 104 | submodules: true 105 | - name: "Authentication" 106 | run: | 107 | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin 108 | - name: "Set environment variables" 109 | run: | 110 | IMAGE_NAME="$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')" 111 | IMAGE_TAG="${BUILD_WORKFLOW_TAG}-${{ matrix.arch }}" 112 | echo "IMAGE_NAME=${IMAGE_NAME}" >>"${GITHUB_ENV}" 113 | echo "IMAGE_TAG=${IMAGE_TAG}" >>"${GITHUB_ENV}" 114 | - name: "Build image" 115 | run: | 116 | IMAGE_ID="ghcr.io/${IMAGE_NAME}:${IMAGE_TAG}" 117 | docker image build -t "${IMAGE_ID}" \ 118 | --build-arg BUILD_TAGS="docker ${BUILD_WORKFLOW_TAG}" \ 119 | --build-arg GITHUB_SERVER_URL \ 120 | --build-arg GITHUB_REPOSITORY \ 121 | --build-arg GITHUB_RUN_ID \ 122 | . 123 | docker image history "${IMAGE_ID}" 124 | docker image inspect "${IMAGE_ID}" 125 | docker image push "${IMAGE_ID}" 126 | IMAGE_DIGEST="sha256:$(docker buildx imagetools inspect "${IMAGE_ID}" --raw | sha256sum | awk '{print $1}')" 127 | echo "IMAGE_DIGEST=${IMAGE_DIGEST}" >>"${GITHUB_ENV}" 128 | - name: "Attest" 129 | uses: "actions/attest-build-provenance@v3" 130 | with: 131 | subject-name: "ghcr.io/${{ env.IMAGE_NAME }}" 132 | subject-digest: "${{ env.IMAGE_DIGEST }}" 133 | push-to-registry: true 134 | -------------------------------------------------------------------------------- /tools/strace-reorder: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: strace-reorder 5 | # SPDX-FileCopyrightText: © 2011 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | import argparse 9 | import logging 10 | import pathlib 11 | import random 12 | import re 13 | import sys 14 | 15 | 16 | def numfmt( 17 | num, 18 | fmt="{num.real:0.02f} {num.prefix}", 19 | binary=False, 20 | rollover=1.0, 21 | limit=0, 22 | prefixes=None, 23 | ): 24 | """Formats a number with decimal or binary prefixes 25 | 26 | num: Input number 27 | fmt: Format string of default repr/str output 28 | binary: If True, use divide by 1024 and use IEC binary prefixes 29 | rollover: Threshold to roll over to the next prefix 30 | limit: Stop after a specified number of rollovers 31 | prefixes: List of (decimal, binary) prefix strings, ascending 32 | """ 33 | # SPDX-SnippetComment: Originally from https://github.com/rfinnie/rf-pymods 34 | # SPDX-SnippetCopyrightText: Copyright (C) 2020-2025 Ryan Finnie 35 | # SPDX-LicenseInfoInSnippet: MIT 36 | 37 | class NumberFormat(float): 38 | prefix = "" 39 | fmt = "{num.real:0.02f} {num.prefix}" 40 | 41 | def __str__(self): 42 | return self.fmt.format(num=self) 43 | 44 | def __repr__(self): 45 | return str(self) 46 | 47 | if prefixes is None: 48 | prefixes = [ 49 | ("k", "Ki"), 50 | ("M", "Mi"), 51 | ("G", "Gi"), 52 | ("T", "Ti"), 53 | ("P", "Pi"), 54 | ("E", "Ei"), 55 | ("Z", "Zi"), 56 | ("Y", "Yi"), 57 | ] 58 | divisor = 1024 if binary else 1000 59 | if limit <= 0 or limit > len(prefixes): 60 | limit = len(prefixes) 61 | 62 | count = 0 63 | p = "" 64 | for prefix in prefixes: 65 | if num < (divisor * rollover): 66 | break 67 | if count >= limit: 68 | break 69 | count += 1 70 | num = num / float(divisor) 71 | p = prefix[1] if binary else prefix[0] 72 | ret = NumberFormat(num) 73 | ret.fmt = fmt 74 | ret.prefix = p 75 | return ret 76 | 77 | 78 | class StraceReorder: 79 | regexps = ( 80 | re.compile(r"^[0-9]+ +(?P(open|openat))\(.*?\) = [0-9]+<(?P.*?)()?>$"), 81 | re.compile(r"^[0-9]+ +(?P(execve))\(\"(?P.*?)\".*?\) = [0-9]+$"), 82 | ) 83 | 84 | def parse_args(self, argv=None): 85 | if argv is None: 86 | argv = sys.argv 87 | 88 | parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) 89 | 90 | parser.add_argument("trace_file", nargs="?", type=argparse.FileType("r"), default=sys.stdin) 91 | 92 | parser.add_argument("--debug", action="store_true", help="Print debugging information") 93 | parser.add_argument( 94 | "--layout", 95 | default="end", 96 | const="end", 97 | nargs="?", 98 | choices=["end", "beginning", "pain", "random"], 99 | help="SquashFS order file layout strategy", 100 | ) 101 | 102 | parser.add_argument( 103 | "--root", 104 | type=pathlib.Path, 105 | default="/run/live/rootfs/filesystem.squashfs", 106 | help="Actual root of SquashFS tree", 107 | metavar="DIR", 108 | ) 109 | 110 | return parser.parse_args(args=argv[1:]) 111 | 112 | def get_filename(self, line): 113 | for r in self.regexps: 114 | m = r.search(line) 115 | if m: 116 | return m.group("filename") 117 | 118 | def main(self): 119 | self.args = self.parse_args() 120 | logging.basicConfig( 121 | level=(logging.DEBUG if self.args.debug else logging.INFO), 122 | format="%(asctime)s %(levelname)-8s %(message)s", 123 | ) 124 | 125 | seen = [] 126 | seen_size = 0 127 | for line in self.args.trace_file.readlines(): 128 | filename = self.get_filename(line.rstrip()) 129 | if not filename: 130 | continue 131 | 132 | file = pathlib.Path(filename).resolve() 133 | if file in seen: 134 | continue 135 | root_file = self.args.root.joinpath(*file.parts[1:]) 136 | if not root_file.is_file(): 137 | continue 138 | seen.append(file) 139 | seen_size += root_file.stat().st_size 140 | 141 | # The position numbers work with SquashFS order files as follows: 142 | # 32767 32766 [...] 3 2 1 0 -1 -2 -3 [...] -32767 -32768 143 | # All files not in the order file default to 0. 144 | # Beginning or end doesn't matter for flash devices, but end is 145 | # preferred for CDs since the highest speeds are at the end of 146 | # the CD. 147 | for idx, file in enumerate(seen): 148 | if self.args.layout == "pain": 149 | # Beginning/end alternating seeks on a CD 150 | # Please don't use this for anything serious... 151 | if idx % 2: 152 | pos = (-1 - len(seen) + idx) / 2 153 | else: 154 | pos = ((len(seen) - idx) / 2) + 1 155 | elif self.args.layout == "random": 156 | # Again, please don't use this. 157 | pos = random.randint(-32768, 32767) 158 | elif self.args.layout == "beginning": 159 | # Files move forward from the beginning of the CD 160 | pos = len(seen) - idx 161 | else: 162 | # Files move forward to the end of the CD 163 | pos = -1 - idx 164 | if pos < -32768 or pos > 32767: 165 | continue 166 | print("{}\t{}".format(str(file)[1:], int(pos))) 167 | logging.info( 168 | "{files} files arranged at {layout}, {size.real:0.02f} {size.prefix}B".format( 169 | files=len(seen), 170 | layout=self.args.layout, 171 | size=numfmt(seen_size, binary=True), 172 | ) 173 | ) 174 | 175 | 176 | if __name__ == "__main__": 177 | sys.exit(StraceReorder().main()) 178 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /files/hooks/interfaces-convert: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: interfaces-convert 5 | # SPDX-FileCopyrightText: © 2021 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # This program converts sections in /etc/network/interfaces to files in 9 | # /etc/systemd/network/, and (if needed) from /etc/resolv.conf to 10 | # /etc/systemd/resolved.conf, putting the systemd-resolved stub in its 11 | # place. 12 | # 13 | # Note that this was built to translate entries built by live-boot, and 14 | # is not meant to be a general-purpose e-n-i converter. 15 | 16 | import configparser 17 | import io 18 | import ipaddress 19 | import os 20 | import shlex 21 | import sys 22 | 23 | try: 24 | import pyudev 25 | except ImportError as e: 26 | pyudev = e 27 | 28 | 29 | class InterfacesConvert: 30 | def __init__(self): 31 | self.files = {} 32 | self.replace_resolvconf = False 33 | if isinstance(pyudev, ImportError): 34 | self.udev_context = None 35 | else: 36 | self.udev_context = pyudev.Context() 37 | 38 | def get_udev_properties(self, interface_name): 39 | if self.udev_context is None: 40 | return 41 | try: 42 | device = pyudev.Devices.from_path(self.udev_context, "/sys/class/net/{}".format(interface_name)) 43 | except pyudev.DeviceNotFoundAtPathError: 44 | return 45 | if "ID_PATH" not in device.properties or "ID_PATH_TAG" not in device.properties: 46 | return 47 | return dict(device.properties) 48 | 49 | def systemd_config(self): 50 | config = configparser.ConfigParser() 51 | config.optionxform = str 52 | return config 53 | 54 | def generate_systemd_conf(self, config, filename, device_properties=None): 55 | with io.StringIO() as f: 56 | if device_properties is not None: 57 | for k, v in device_properties.items(): 58 | print("# {}={}".format(k, shlex.quote(v)), file=f) 59 | print(file=f) 60 | config.write(f, space_around_delimiters=False) 61 | self.files[filename] = f.getvalue() 62 | 63 | def process_section(self, section): 64 | if "iface" not in section: 65 | return 66 | interface_name = section["iface"][0] 67 | if section["iface"][2] == "loopback": 68 | return 69 | elif not os.path.exists("/sys/class/net/{}".format(interface_name)): 70 | return 71 | 72 | device_properties = self.get_udev_properties(interface_name) 73 | if device_properties is None: 74 | id_path = None 75 | interface_fn_id = interface_name 76 | else: 77 | id_path = device_properties["ID_PATH"] 78 | interface_fn_id = device_properties["ID_PATH_TAG"] 79 | 80 | filename = "/etc/systemd/network/10-{}.network".format(interface_fn_id) 81 | if (section["iface"][1] != "inet") or (section["iface"][2] not in ("dhcp", "static")): 82 | output = self.systemd_config() 83 | if id_path is None: 84 | output["Match"] = {"Name": interface_name} 85 | else: 86 | output["Match"] = {"Path": id_path} 87 | output["Link"] = {"Unmanaged": "yes"} 88 | self.generate_systemd_conf(output, filename) 89 | return 90 | 91 | output = self.systemd_config() 92 | if id_path is None: 93 | output["Match"] = {"Name": interface_name} 94 | else: 95 | output["Match"] = {"Path": id_path} 96 | output["Link"] = {} 97 | output["Network"] = {} 98 | if ("address" in section) and ("netmask" in section): 99 | output["Network"]["Address"] = ipaddress.ip_interface( 100 | "{}/{}".format(section["address"][0], section["netmask"][0]) 101 | ).with_prefixlen 102 | if "gateway" in section: 103 | output["Network"]["Gateway"] = section["gateway"][0] 104 | else: 105 | output["Network"]["DHCP"] = "yes" 106 | if "allow-hotplug" in section: 107 | output["Link"]["RequiredForOnline"] = "no" 108 | self.generate_systemd_conf(output, filename, device_properties) 109 | return (interface_name, filename) 110 | 111 | def convert_interfaces(self): 112 | if not os.path.exists("/etc/network/interfaces"): 113 | return 114 | 115 | rewritten_interfaces = "" 116 | section = {} 117 | section_text = "" 118 | section_text_commented = "" 119 | with open("/etc/network/interfaces") as f: 120 | for raw_line in f: 121 | line = raw_line.strip() 122 | if line == "" and section: 123 | ret = self.process_section(section) 124 | if ret: 125 | rewritten_interfaces += "# Interface {} migrated to {}\n".format(ret[0], ret[1]) 126 | rewritten_interfaces += section_text_commented + "\n" 127 | else: 128 | rewritten_interfaces += section_text + "\n" 129 | section = {} 130 | section_text = "" 131 | section_text_commented = "" 132 | continue 133 | ls = line.split(" ") 134 | if not ls[0].startswith("#"): 135 | section[ls[0]] = ls[1:] 136 | section_text += raw_line 137 | section_text_commented += "#" + raw_line 138 | 139 | if section: 140 | ret = self.process_section(section) 141 | if ret: 142 | rewritten_interfaces += "# Interface {} migrated to {}\n".format(ret[0], ret[1]) 143 | rewritten_interfaces += section_text_commented + "\n" 144 | else: 145 | rewritten_interfaces += section_text + "\n" 146 | 147 | self.files["/etc/network/interfaces"] = rewritten_interfaces 148 | 149 | def convert_resolv(self): 150 | if not os.path.exists("/etc/systemd/resolved.conf"): 151 | return 152 | if not os.path.exists("/etc/resolv.conf"): 153 | self.replace_resolvconf = True 154 | return 155 | 156 | nameservers = [] 157 | domains = [] 158 | with open("/etc/resolv.conf") as f: 159 | for line in f: 160 | line = line.strip() 161 | ls = line.split(" ") 162 | if ls[0] == "nameserver": 163 | if ls[1] == "127.0.0.53": 164 | continue 165 | nameservers.append(ls[1]) 166 | elif ls[0] in ("search", "domain"): 167 | for s in ls[1:]: 168 | if s == ".": 169 | continue 170 | domains.append(s) 171 | 172 | if nameservers or domains: 173 | resolved = self.systemd_config() 174 | resolved.read("/etc/systemd/resolved.conf") 175 | if "Resolve" not in resolved: 176 | resolved["Resolve"] = {} 177 | if nameservers: 178 | resolved["Resolve"]["DNS"] = " ".join(nameservers) 179 | if domains: 180 | resolved["Resolve"]["Domains"] = " ".join(domains) 181 | self.generate_systemd_conf(resolved, "/etc/systemd/resolved.conf") 182 | 183 | self.replace_resolvconf = True 184 | 185 | def write_files(self): 186 | for fn in self.files: 187 | with open(fn, "w") as f: 188 | f.write(self.files[fn]) 189 | 190 | if self.replace_resolvconf: 191 | try: 192 | os.remove("/etc/resolv.conf") 193 | except FileNotFoundError: 194 | pass 195 | os.symlink("/run/systemd/resolve/stub-resolv.conf", "/etc/resolv.conf") 196 | 197 | def main(self): 198 | self.convert_interfaces() 199 | self.convert_resolv() 200 | self.write_files() 201 | 202 | 203 | if __name__ == "__main__": 204 | sys.exit(InterfacesConvert().main()) 205 | -------------------------------------------------------------------------------- /hooks/9900-finnix-1000-recompress.hook.chroot: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileComment: recompress chroot hook 5 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 6 | # SPDX-License-Identifier: MPL-2.0 7 | 8 | # Re-"compress" all .gz files at gzip level 0 so mksquashfs can compress 9 | # it more efficiently 10 | 11 | import argparse 12 | import gzip 13 | import hashlib 14 | import os 15 | import logging 16 | import pathlib 17 | import shutil 18 | import sys 19 | 20 | 21 | def numfmt( 22 | num, 23 | fmt="{num.real:0.02f} {num.prefix}", 24 | binary=False, 25 | rollover=1.0, 26 | limit=0, 27 | prefixes=None, 28 | ): 29 | """Formats a number with decimal or binary prefixes 30 | 31 | num: Input number 32 | fmt: Format string of default repr/str output 33 | binary: If True, use divide by 1024 and use IEC binary prefixes 34 | rollover: Threshold to roll over to the next prefix 35 | limit: Stop after a specified number of rollovers 36 | prefixes: List of (decimal, binary) prefix strings, ascending 37 | """ 38 | # SPDX-SnippetComment: Originally from https://github.com/rfinnie/rf-pymods 39 | # SPDX-SnippetCopyrightText: Copyright (C) 2020-2025 Ryan Finnie 40 | # SPDX-LicenseInfoInSnippet: MIT 41 | 42 | class NumberFormat(float): 43 | prefix = "" 44 | fmt = "{num.real:0.02f} {num.prefix}" 45 | 46 | def __str__(self): 47 | return self.fmt.format(num=self) 48 | 49 | def __repr__(self): 50 | return str(self) 51 | 52 | if prefixes is None: 53 | prefixes = [ 54 | ("k", "Ki"), 55 | ("M", "Mi"), 56 | ("G", "Gi"), 57 | ("T", "Ti"), 58 | ("P", "Pi"), 59 | ("E", "Ei"), 60 | ("Z", "Zi"), 61 | ("Y", "Yi"), 62 | ] 63 | divisor = 1024 if binary else 1000 64 | if limit <= 0 or limit > len(prefixes): 65 | limit = len(prefixes) 66 | 67 | count = 0 68 | p = "" 69 | for prefix in prefixes: 70 | if num < (divisor * rollover): 71 | break 72 | if count >= limit: 73 | break 74 | count += 1 75 | num = num / float(divisor) 76 | p = prefix[1] if binary else prefix[0] 77 | ret = NumberFormat(num) 78 | ret.fmt = fmt 79 | ret.prefix = p 80 | return ret 81 | 82 | 83 | class RecompressGz: 84 | args = None 85 | diversions = None 86 | file_count = 0 87 | pre_size = 0 88 | post_size = 0 89 | 90 | def __init__(self): 91 | self.diversions = {} 92 | 93 | def parse_args(self, argv=None): 94 | if argv is None: 95 | argv = sys.argv 96 | 97 | parser = argparse.ArgumentParser( 98 | formatter_class=argparse.ArgumentDefaultsHelpFormatter 99 | ) 100 | 101 | parser.add_argument( 102 | "--debug", action="store_true", help="Print debugging information" 103 | ) 104 | parser.add_argument( 105 | "--base-dir", 106 | type=pathlib.Path, 107 | default="/", 108 | help="Base directory of Debian filesystem tree", 109 | ) 110 | 111 | return parser.parse_args(args=argv[1:]) 112 | 113 | def load_diversions(self): 114 | with self.args.base_dir.joinpath("var/lib/dpkg/diversions").open() as f: 115 | while True: 116 | orig = f.readline() 117 | if orig == "": 118 | break 119 | orig = pathlib.Path(orig.rstrip()) 120 | diverted_to = pathlib.Path(f.readline().rstrip()) 121 | f.readline() # Package name; we don't need 122 | self.diversions[orig] = diverted_to 123 | logging.debug("Loaded {} diversions".format(len(self.diversions))) 124 | 125 | def recompress(self, file): 126 | file_mod = pathlib.Path(str(file) + "~mod") 127 | file_size_pre = file.stat().st_size 128 | with gzip.open(file, "rb") as fsrc, file_mod.open("wb") as fdst: 129 | # Explicitly do not set filename and mtime in resulting .gz 130 | with gzip.GzipFile( 131 | filename="", mode="wb", compresslevel=0, mtime=0, fileobj=fdst 132 | ) as fdstgz: 133 | shutil.copyfileobj(fsrc, fdstgz) 134 | shutil.copystat(file, file_mod) 135 | file = file_mod.replace(file) 136 | file_size_post = file.stat().st_size 137 | 138 | self.file_count += 1 139 | self.pre_size += file_size_pre 140 | self.post_size += file_size_post 141 | 142 | logging.debug( 143 | "Recompressed {file} - {pre.real:0.02f} {pre.prefix}B to {post.real:0.02f} {post.prefix}B".format( 144 | file=file, pre=numfmt(file_size_pre), post=numfmt(file_size_post) 145 | ) 146 | ) 147 | return hashlib.md5(file.read_bytes()).hexdigest() 148 | 149 | def process_dpkg_file(self, dpkg_filename, orig_md5): 150 | if not dpkg_filename.endswith(".gz"): 151 | return orig_md5 152 | 153 | file = pathlib.Path("/").joinpath(dpkg_filename) 154 | if file in self.diversions: 155 | logging.debug( 156 | "{} was diverted to {} - using that instead".format( 157 | file, self.diversions[file] 158 | ) 159 | ) 160 | file = self.diversions[file] 161 | 162 | file = self.args.base_dir.joinpath(*file.parts[1:]) 163 | if file.is_symlink(): 164 | logging.warning("File is a symlink, skipping: {}".format(file)) 165 | return orig_md5 166 | fstat = file.stat() 167 | if fstat.st_nlink > 1: 168 | logging.warning( 169 | "File has {} hard links, skipping: {}".format(fstat.st_nlink, file) 170 | ) 171 | return orig_md5 172 | found_md5 = hashlib.md5(file.read_bytes()).hexdigest() 173 | if orig_md5 != found_md5: 174 | logging.error( 175 | "MD5 mismatch (expected {}, got {}), skipping: {}".format( 176 | orig_md5, found_md5, file 177 | ) 178 | ) 179 | return orig_md5 180 | 181 | return self.recompress(file) 182 | 183 | def main(self): 184 | self.args = self.parse_args() 185 | logging.basicConfig( 186 | level=(logging.DEBUG if self.args.debug else logging.INFO), 187 | format="%(asctime)s %(levelname)-8s %(message)s", 188 | ) 189 | self.load_diversions() 190 | for file in self.args.base_dir.joinpath("var/lib/dpkg/info").glob("*.md5sums"): 191 | file_mod = pathlib.Path(str(file) + "~mod") 192 | file_output = "" 193 | with file.open() as f: 194 | for line in f: 195 | orig_md5, dpkg_filename = line.rstrip().split(" ", 1) 196 | new_md5 = self.process_dpkg_file(dpkg_filename, orig_md5) 197 | file_output += "{} {}\n".format(new_md5, dpkg_filename) 198 | file_mod.write_text(file_output) 199 | shutil.copystat(file, file_mod) 200 | file = file_mod.replace(file) 201 | 202 | logging.info( 203 | '{} files re-"compressed" at gzip level 0.'.format(self.file_count) 204 | ) 205 | logging.info( 206 | "{pre.real:0.02f} {pre.prefix}B (previous gzip total) expanded to " 207 | "{post.real:0.02f} {post.prefix}B (gzip level 0).".format( 208 | pre=numfmt(self.pre_size), post=numfmt(self.post_size) 209 | ) 210 | ) 211 | ballpark_xz = int(self.post_size * 0.15) 212 | logging.info( 213 | "If subsequently compressed with xz, approximately {ballpark.real:0.02f} " 214 | "{ballpark.prefix}B might be saved ({ballpark_pct:0.02%} of previous gzip).".format( 215 | ballpark=numfmt(self.pre_size - ballpark_xz), 216 | ballpark_pct=((self.pre_size - ballpark_xz) / self.pre_size), 217 | ) 218 | ) 219 | 220 | 221 | if __name__ == "__main__": 222 | if os.environ.get("GZIP_RECOMPRESS", "yes") != "yes": 223 | sys.exit(0) 224 | sys.exit(RecompressGz().main()) 225 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Mozilla Public License Version 2.0 2 | 3 | ### 1. Definitions 4 | 5 | **1.1. "Contributor"** means each individual or legal entity that creates, 6 | contributes to the creation of, or owns Covered Software. 7 | 8 | **1.2. "Contributor Version"** means the combination of the Contributions of 9 | others (if any) used by a Contributor and that particular Contributor's 10 | Contribution. 11 | 12 | **1.3. "Contribution"** means Covered Software of a particular Contributor. 13 | 14 | **1.4. "Covered Software"** means Source Code Form to which the initial 15 | Contributor has attached the notice in Exhibit A, the Executable Form of such 16 | Source Code Form, and Modifications of such Source Code Form, in each case 17 | including portions thereof. 18 | 19 | **1.5. "Incompatible With Secondary Licenses"** means 20 | 21 | - **(a)** that the initial Contributor has attached the notice described in 22 | Exhibit B to the Covered Software; or 23 | - **(b)** that the Covered Software was made available under the terms of 24 | version 1.1 or earlier of the License, but not also under the terms of a 25 | Secondary License. 26 | 27 | **1.6. "Executable Form"** means any form of the work other than Source Code 28 | Form. 29 | 30 | **1.7. "Larger Work"** means a work that combines Covered Software with other 31 | material, in a separate file or files, that is not Covered Software. 32 | 33 | **1.8. "License"** means this document. 34 | 35 | **1.9. "Licensable"** means having the right to grant, to the maximum extent 36 | possible, whether at the time of the initial grant or subsequently, any and all 37 | of the rights conveyed by this License. 38 | 39 | **1.10. "Modifications"** means any of the following: 40 | 41 | - **(a)** any file in Source Code Form that results from an addition to, 42 | deletion from, or modification of the contents of Covered Software; or 43 | - **(b)** any new file in Source Code Form that contains any Covered Software. 44 | 45 | **1.11. "Patent Claims" of a Contributor** means any patent claim(s), including 46 | without limitation, method, process, and apparatus claims, in any patent 47 | Licensable by such Contributor that would be infringed, but for the grant of the 48 | License, by the making, using, selling, offering for sale, having made, import, 49 | or transfer of either its Contributions or its Contributor Version. 50 | 51 | **1.12. "Secondary License"** means either the GNU General Public License, 52 | Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero 53 | General Public License, Version 3.0, or any later versions of those licenses. 54 | 55 | **1.13. "Source Code Form"** means the form of the work preferred for making 56 | modifications. 57 | 58 | **1.14. "You" (or "Your")** means an individual or a legal entity exercising 59 | rights under this License. For legal entities, "You" includes any entity that 60 | controls, is controlled by, or is under common control with You. For purposes of 61 | this definition, "control" means **(a)** the power, direct or indirect, to cause 62 | the direction or management of such entity, whether by contract or otherwise, or 63 | **(b)** ownership of more than fifty percent (50%) of the outstanding shares or 64 | beneficial ownership of such entity. 65 | 66 | ### 2. License Grants and Conditions 67 | 68 | #### 2.1. Grants 69 | 70 | Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive 71 | license: 72 | 73 | - **(a)** under intellectual property rights (other than patent or trademark) 74 | Licensable by such Contributor to use, reproduce, make available, modify, 75 | display, perform, distribute, and otherwise exploit its Contributions, either 76 | on an unmodified basis, with Modifications, or as part of a Larger Work; and 77 | - **(b)** under Patent Claims of such Contributor to make, use, sell, offer for 78 | sale, have made, import, and otherwise transfer either its Contributions or 79 | its Contributor Version. 80 | 81 | #### 2.2. Effective Date 82 | 83 | The licenses granted in Section 2.1 with respect to any Contribution become 84 | effective for each Contribution on the date the Contributor first distributes 85 | such Contribution. 86 | 87 | #### 2.3. Limitations on Grant Scope 88 | 89 | The licenses granted in this Section 2 are the only rights granted under this 90 | License. No additional rights or licenses will be implied from the distribution 91 | or licensing of Covered Software under this License. Notwithstanding Section 92 | 2.1(b) above, no patent license is granted by a Contributor: 93 | 94 | - **(a)** for any code that a Contributor has removed from Covered Software; or 95 | - **(b)** for infringements caused by: **(i)** Your and any other third party's 96 | modifications of Covered Software, or **(ii)** the combination of its 97 | Contributions with other software (except as part of its Contributor Version); 98 | or 99 | - **(c)** under Patent Claims infringed by Covered Software in the absence of 100 | its Contributions. 101 | 102 | This License does not grant any rights in the trademarks, service marks, or 103 | logos of any Contributor (except as may be necessary to comply with the notice 104 | requirements in Section 3.4). 105 | 106 | #### 2.4. Subsequent Licenses 107 | 108 | No Contributor makes additional grants as a result of Your choice to distribute 109 | the Covered Software under a subsequent version of this License (see Section 110 | 10.2) or under the terms of a Secondary License (if permitted under the terms of 111 | Section 3.3). 112 | 113 | #### 2.5. Representation 114 | 115 | Each Contributor represents that the Contributor believes its Contributions are 116 | its original creation(s) or it has sufficient rights to grant the rights to its 117 | Contributions conveyed by this License. 118 | 119 | #### 2.6. Fair Use 120 | 121 | This License is not intended to limit any rights You have under applicable 122 | copyright doctrines of fair use, fair dealing, or other equivalents. 123 | 124 | #### 2.7. Conditions 125 | 126 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 127 | Section 2.1. 128 | 129 | ### 3. Responsibilities 130 | 131 | #### 3.1. Distribution of Source Form 132 | 133 | All distribution of Covered Software in Source Code Form, including any 134 | Modifications that You create or to which You contribute, must be under the 135 | terms of this License. You must inform recipients that the Source Code Form of 136 | the Covered Software is governed by the terms of this License, and how they can 137 | obtain a copy of this License. You may not attempt to alter or restrict the 138 | recipients' rights in the Source Code Form. 139 | 140 | #### 3.2. Distribution of Executable Form 141 | 142 | If You distribute Covered Software in Executable Form then: 143 | 144 | - **(a)** such Covered Software must also be made available in Source Code Form, 145 | as described in Section 3.1, and You must inform recipients of the Executable 146 | Form how they can obtain a copy of such Source Code Form by reasonable means 147 | in a timely manner, at a charge no more than the cost of distribution to the 148 | recipient; and 149 | 150 | - **(b)** You may distribute such Executable Form under the terms of this 151 | License, or sublicense it under different terms, provided that the license for 152 | the Executable Form does not attempt to limit or alter the recipients' rights 153 | in the Source Code Form under this License. 154 | 155 | #### 3.3. Distribution of a Larger Work 156 | 157 | You may create and distribute a Larger Work under terms of Your choice, provided 158 | that You also comply with the requirements of this License for the Covered 159 | Software. If the Larger Work is a combination of Covered Software with a work 160 | governed by one or more Secondary Licenses, and the Covered Software is not 161 | Incompatible With Secondary Licenses, this License permits You to additionally 162 | distribute such Covered Software under the terms of such Secondary License(s), 163 | so that the recipient of the Larger Work may, at their option, further 164 | distribute the Covered Software under the terms of either this License or such 165 | Secondary License(s). 166 | 167 | #### 3.4. Notices 168 | 169 | You may not remove or alter the substance of any license notices (including 170 | copyright notices, patent notices, disclaimers of warranty, or limitations of 171 | liability) contained within the Source Code Form of the Covered Software, except 172 | that You may alter any license notices to the extent required to remedy known 173 | factual inaccuracies. 174 | 175 | #### 3.5. Application of Additional Terms 176 | 177 | You may choose to offer, and to charge a fee for, warranty, support, indemnity 178 | or liability obligations to one or more recipients of Covered Software. However, 179 | You may do so only on Your own behalf, and not on behalf of any Contributor. You 180 | must make it absolutely clear that any such warranty, support, indemnity, or 181 | liability obligation is offered by You alone, and You hereby agree to indemnify 182 | every Contributor for any liability incurred by such Contributor as a result of 183 | warranty, support, indemnity or liability terms You offer. You may include 184 | additional disclaimers of warranty and limitations of liability specific to any 185 | jurisdiction. 186 | 187 | ### 4. Inability to Comply Due to Statute or Regulation 188 | 189 | If it is impossible for You to comply with any of the terms of this License with 190 | respect to some or all of the Covered Software due to statute, judicial order, 191 | or regulation then You must: **(a)** comply with the terms of this License to 192 | the maximum extent possible; and **(b)** describe the limitations and the code 193 | they affect. Such description must be placed in a text file included with all 194 | distributions of the Covered Software under this License. Except to the extent 195 | prohibited by statute or regulation, such description must be sufficiently 196 | detailed for a recipient of ordinary skill to be able to understand it. 197 | 198 | ### 5. Termination 199 | 200 | **5.1.** The rights granted under this License will terminate automatically if 201 | You fail to comply with any of its terms. However, if You become compliant, then 202 | the rights granted under this License from a particular Contributor are 203 | reinstated **(a)** provisionally, unless and until such Contributor explicitly 204 | and finally terminates Your grants, and **(b)** on an ongoing basis, if such 205 | Contributor fails to notify You of the non-compliance by some reasonable means 206 | prior to 60 days after You have come back into compliance. Moreover, Your grants 207 | from a particular Contributor are reinstated on an ongoing basis if such 208 | Contributor notifies You of the non-compliance by some reasonable means, this is 209 | the first time You have received notice of non-compliance with this License from 210 | such Contributor, and You become compliant prior to 30 days after Your receipt 211 | of the notice. 212 | 213 | **5.2.** If You initiate litigation against any entity by asserting a patent 214 | infringement claim (excluding declaratory judgment actions, counter-claims, and 215 | cross-claims) alleging that a Contributor Version directly or indirectly 216 | infringes any patent, then the rights granted to You by any and all Contributors 217 | for the Covered Software under Section 2.1 of this License shall terminate. 218 | 219 | **5.3.** In the event of termination under Sections 5.1 or 5.2 above, all end 220 | user license agreements (excluding distributors and resellers) which have been 221 | validly granted by You or Your distributors under this License prior to 222 | termination shall survive termination. 223 | 224 | ### 6. Disclaimer of Warranty 225 | 226 | > Covered Software is provided under this License on an "as is" basis, without 227 | > warranty of any kind, either expressed, implied, or statutory, including, 228 | > without limitation, warranties that the Covered Software is free of defects, 229 | > merchantable, fit for a particular purpose or non-infringing. The entire risk 230 | > as to the quality and performance of the Covered Software is with You. Should 231 | > any Covered Software prove defective in any respect, You (not any Contributor) 232 | > assume the cost of any necessary servicing, repair, or correction. This 233 | > disclaimer of warranty constitutes an essential part of this License. No use 234 | > of any Covered Software is authorized under this License except under this 235 | > disclaimer. 236 | 237 | ### 7. Limitation of Liability 238 | 239 | > Under no circumstances and under no legal theory, whether tort (including 240 | > negligence), contract, or otherwise, shall any Contributor, or anyone who 241 | > distributes Covered Software as permitted above, be liable to You for any 242 | > direct, indirect, special, incidental, or consequential damages of any 243 | > character including, without limitation, damages for lost profits, loss of 244 | > goodwill, work stoppage, computer failure or malfunction, or any and all other 245 | > commercial damages or losses, even if such party shall have been informed of 246 | > the possibility of such damages. This limitation of liability shall not apply 247 | > to liability for death or personal injury resulting from such party's 248 | > negligence to the extent applicable law prohibits such limitation. Some 249 | > jurisdictions do not allow the exclusion or limitation of incidental or 250 | > consequential damages, so this exclusion and limitation may not apply to You. 251 | 252 | ### 8. Litigation 253 | 254 | Any litigation relating to this License may be brought only in the courts of a 255 | jurisdiction where the defendant maintains its principal place of business and 256 | such litigation shall be governed by laws of that jurisdiction, without 257 | reference to its conflict-of-law provisions. Nothing in this Section shall 258 | prevent a party's ability to bring cross-claims or counter-claims. 259 | 260 | ### 9. Miscellaneous 261 | 262 | This License represents the complete agreement concerning the subject matter 263 | hereof. If any provision of this License is held to be unenforceable, such 264 | provision shall be reformed only to the extent necessary to make it enforceable. 265 | Any law or regulation which provides that the language of a contract shall be 266 | construed against the drafter shall not be used to construe this License against 267 | a Contributor. 268 | 269 | ### 10. Versions of the License 270 | 271 | #### 10.1. New Versions 272 | 273 | Mozilla Foundation is the license steward. Except as provided in Section 10.3, 274 | no one other than the license steward has the right to modify or publish new 275 | versions of this License. Each version will be given a distinguishing version 276 | number. 277 | 278 | #### 10.2. Effect of New Versions 279 | 280 | You may distribute the Covered Software under the terms of the version of the 281 | License under which You originally received the Covered Software, or under the 282 | terms of any subsequent version published by the license steward. 283 | 284 | #### 10.3. Modified Versions 285 | 286 | If you create software not governed by this License, and you want to create a 287 | new license for such software, you may create and use a modified version of this 288 | License if you rename the license and remove any references to the name of the 289 | license steward (except to note that such modified license differs from this 290 | License). 291 | 292 | #### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses 293 | 294 | If You choose to distribute Source Code Form that is Incompatible With Secondary 295 | Licenses under the terms of this version of the License, the notice described in 296 | Exhibit B of this License must be attached. 297 | 298 | ## Exhibit A - Source Code Form License Notice 299 | 300 | This Source Code Form is subject to the terms of the Mozilla Public 301 | License, v. 2.0. If a copy of the MPL was not distributed with this 302 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 303 | 304 | If it is not possible or desirable to put the notice in a particular file, then 305 | You may include the notice in a location (such as a LICENSE file in a relevant 306 | directory) where a recipient would be likely to look for such a notice. 307 | 308 | You may add additional accurate notices of copyright ownership. 309 | 310 | ## Exhibit B - "Incompatible With Secondary Licenses" Notice 311 | 312 | This Source Code Form is "Incompatible With Secondary Licenses", as 313 | defined by the Mozilla Public License, v. 2.0. 314 | -------------------------------------------------------------------------------- /LICENSES/MPL-2.0.txt: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at https://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /LICENSES/CC-BY-SA-4.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Attribution-ShareAlike 4.0 International 2 | 3 | Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. 4 | 5 | Using Creative Commons Public Licenses 6 | 7 | Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. 8 | 9 | Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors. 10 | 11 | Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. 12 | 13 | Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public. 14 | 15 | Creative Commons Attribution-ShareAlike 4.0 International Public License 16 | 17 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. 18 | 19 | Section 1 – Definitions. 20 | 21 | a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. 22 | 23 | b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. 24 | 25 | c. BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. 26 | 27 | d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 28 | 29 | e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. 30 | 31 | f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. 32 | 33 | g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike. 34 | 35 | h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. 36 | 37 | i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. 38 | 39 | j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. 40 | 41 | k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. 42 | 43 | l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. 44 | 45 | m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. 46 | 47 | Section 2 – Scope. 48 | 49 | a. License grant. 50 | 51 | 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: 52 | 53 | A. reproduce and Share the Licensed Material, in whole or in part; and 54 | 55 | B. produce, reproduce, and Share Adapted Material. 56 | 57 | 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 58 | 59 | 3. Term. The term of this Public License is specified in Section 6(a). 60 | 61 | 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 62 | 63 | 5. Downstream recipients. 64 | 65 | A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. 66 | 67 | B. Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. 68 | 69 | C. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 70 | 71 | 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). 72 | 73 | b. Other rights. 74 | 75 | 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 76 | 77 | 2. Patent and trademark rights are not licensed under this Public License. 78 | 79 | 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. 80 | 81 | Section 3 – License Conditions. 82 | 83 | Your exercise of the Licensed Rights is expressly made subject to the following conditions. 84 | 85 | a. Attribution. 86 | 87 | 1. If You Share the Licensed Material (including in modified form), You must: 88 | 89 | A. retain the following if it is supplied by the Licensor with the Licensed Material: 90 | 91 | i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); 92 | 93 | ii. a copyright notice; 94 | 95 | iii. a notice that refers to this Public License; 96 | 97 | iv. a notice that refers to the disclaimer of warranties; 98 | 99 | v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; 100 | 101 | B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and 102 | 103 | C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 104 | 105 | 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 106 | 107 | 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 108 | 109 | b. ShareAlike.In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 110 | 111 | 1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License. 112 | 113 | 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 114 | 115 | 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. 116 | 117 | Section 4 – Sui Generis Database Rights. 118 | 119 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: 120 | 121 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; 122 | 123 | b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and 124 | 125 | c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. 126 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. 127 | 128 | Section 5 – Disclaimer of Warranties and Limitation of Liability. 129 | 130 | a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. 131 | 132 | b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. 133 | 134 | c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. 135 | 136 | Section 6 – Term and Termination. 137 | 138 | a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. 139 | 140 | b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 141 | 142 | 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 143 | 144 | 2. upon express reinstatement by the Licensor. 145 | 146 | c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. 147 | 148 | d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. 149 | 150 | e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 151 | 152 | Section 7 – Other Terms and Conditions. 153 | 154 | a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. 155 | 156 | b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. 157 | 158 | Section 8 – Interpretation. 159 | 160 | a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. 161 | 162 | b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. 163 | 164 | c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. 165 | 166 | d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 167 | 168 | Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. 169 | 170 | Creative Commons may be contacted at creativecommons.org. 171 | -------------------------------------------------------------------------------- /finnix-live-build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-PackageSummary: finnix-live-build 4 | # SPDX-FileCopyrightText: © 2020 Ryan Finnie 5 | # SPDX-License-Identifier: MPL-2.0 6 | 7 | set -e 8 | 9 | PRODUCT="${PRODUCT:-Finnix}" 10 | PRODUCT_ID="${PRODUCT_ID:-finnix}" 11 | VERSION="${VERSION:-dev}" 12 | CODENAME="${CODENAME:-Fond du Lac}" 13 | ARCH="${ARCH:-$(dpkg --print-architecture)}" 14 | SOURCE_ISO="${SOURCE_ISO:-false}" 15 | CACHE_FROZEN="${CACHE_FROZEN:-false}" 16 | SAVE_ISO="${SAVE_ISO:-false}" 17 | LINT="${LINT:-false}" 18 | BUILD_TAGS="${BUILD_TAGS:-}" 19 | BUILD_URL="${BUILD_URL:-}" 20 | PYTHON="${PYTHON:-python3}" 21 | UNSTABLE_PIN="${UNSTABLE_PIN:-true}" 22 | BUILD_UUID="${BUILD_UUID:-$(uuidgen -r)}" 23 | DOCKER_BUILD="${DOCKER_BUILD:-false}" 24 | 25 | lock() { 26 | _file=$1 27 | exec 9>"${_file}" 28 | if ! flock -x -w 1 9; then 29 | echo "${_file} lock failed" >&2 30 | exit 1 31 | fi 32 | } 33 | 34 | cleanup() { 35 | for file in "${LINT_DIR}" "${compare_tmp_fn}" "${current_tmp_fn}" "${diff_tmp_fn}"; do 36 | [ -n "${file}" ] || continue 37 | [ -e "${file}" ] || continue 38 | rm -rf "${file}" 39 | done 40 | } 41 | trap cleanup EXIT 42 | 43 | render() { 44 | env \ 45 | "PRODUCT=${PRODUCT}" \ 46 | "PRODUCT_ID=${PRODUCT_ID}" \ 47 | "VERSION=${VERSION}" \ 48 | "CODENAME=${CODENAME}" \ 49 | "ARCH=${ARCH}" \ 50 | "DATETIME=${DATETIME}" \ 51 | "DATE=${DATE}" \ 52 | "YEAR=${YEAR}" \ 53 | "GIT_COMMIT=${GIT_COMMIT}" \ 54 | "GIT_DESC=${GIT_DESC}" \ 55 | "LIVE_BUILD_GIT_COMMIT=${LIVE_BUILD_GIT_COMMIT}" \ 56 | "LIVE_BUILD_GIT_DESC=${LIVE_BUILD_GIT_DESC}" \ 57 | "BUILD_TAGS=${BUILD_TAGS}" \ 58 | "BUILD_URL=${BUILD_URL}" \ 59 | "BUILD_UUID=${BUILD_UUID}" \ 60 | "DOCKER_BUILD=${DOCKER_BUILD}" \ 61 | "${BASE_DIR}/tools/jinja2-render" 62 | } 63 | 64 | render_files() { 65 | destdir="$1" 66 | shift 67 | mkdir -p "${destdir}" 68 | for i in "$@"; do 69 | basefn="$(basename "$i")" 70 | rm -f "${destdir}/${basefn}" 71 | render <"${i}" >"${destdir}/${basefn}" 72 | done 73 | } 74 | 75 | lint_shfmt() { 76 | fn="$1" 77 | shift 78 | bfn="$(basename "$fn")" 79 | shfmt -ln=posix -i 4 "${fn}" >"$LINT_DIR/${bfn}" 80 | diff -u "${fn}" "$LINT_DIR/${bfn}" 81 | } 82 | 83 | # PACKAGES USED: 84 | # Required: cpio: live-build 85 | # Required: debootstrap (debootstrap): live-build initial bootstrap 86 | # Required: debian-archive-keyring: live-build initial bootstrap 87 | # Required: python3 (${PYTHON}): Templating 88 | # Required: python3-jinja2: Templating 89 | # Required: librsvg2-bin (rsvg-convert): splash.png 90 | # Required: fonts-liberation2: splash.png 91 | # Required: pandoc: Manpage builds 92 | # Required: uuid-runtime (uuidgen): UUID generation 93 | # Optional: shellcheck (shellcheck): Lint, required for LINT=true 94 | # Optional: flake8 (${PYTHON} -mflake8): Lint, required for LINT=true 95 | # Optional: shfmt (shfmt): Lint, optional for LINT=true 96 | # Optional: git (git): Build IDs 97 | # Optional: file (file): Post-build file info 98 | 99 | host_commands="debootstrap ${PYTHON} rsvg-convert pandoc cpio" 100 | missing_commands="" 101 | if [ "${LINT}" = "true" ]; then 102 | host_commands="${host_commands} shellcheck" 103 | fi 104 | for c in ${host_commands}; do 105 | command -v "${c}" >/dev/null || missing_commands="${missing_commands} ${c}" 106 | done 107 | if [ -n "${missing_commands}" ]; then 108 | echo "ERROR: Missing required commands:${missing_commands}" >&2 109 | exit 1 110 | fi 111 | has_shfmt=true 112 | command -v shfmt >/dev/null 2>/dev/null || has_shfmt=false 113 | if command -v dpkg >/dev/null 2>/dev/null; then 114 | if ! dpkg --compare-versions "$(debootstrap --version | cut -d' ' -f2)" ge 1.0.107; then 115 | echo "ERROR: debootstrap 1.0.107 or later is required" 116 | exit 1 117 | fi 118 | fi 119 | if [ "${LINT}" = "true" ]; then 120 | if ! "${PYTHON}" -mflake8 /dev/null; then 121 | echo "ERROR: flake8 is required for LINT=true" 122 | exit 1 123 | fi 124 | fi 125 | 126 | DATETIME="$(date -u +"%F %T")" 127 | DATE="$(date -u +"%F")" 128 | YEAR="$(date -u +"%Y")" 129 | SQUASHFS_COMP="xz" 130 | if [ "${ARCH}" = "amd64" ]; then 131 | BINARY_IMAGES="iso-hybrid" 132 | BOOTLOADERS="grub-efi,syslinux" 133 | ISO_FILENAME="${PRODUCT_ID}-${ARCH}.hybrid.iso" 134 | MEMTEST="memtest86+" 135 | SQUASHFS_COMP="xz -Xbcj x86" 136 | elif [ "${ARCH}" = "arm64" ]; then 137 | BINARY_IMAGES="iso-hybrid" 138 | BOOTLOADERS="grub-efi" 139 | ISO_FILENAME="${PRODUCT_ID}-${ARCH}.hybrid.iso" 140 | MEMTEST="" 141 | else 142 | BINARY_IMAGES="iso" 143 | BOOTLOADERS="" 144 | ISO_FILENAME="${PRODUCT_ID}-${ARCH}.iso" 145 | MEMTEST="" 146 | fi 147 | 148 | if [ -z "${APT_HTTP_PROXY}" ]; then 149 | eval "$(apt-config shell APT_HTTP_PROXY Acquire::http::Proxy 2>/dev/null || true)" 150 | fi 151 | 152 | if [ "${LINT}" = "true" ]; then 153 | LINT_DIR="$(mktemp -d)" 154 | BUILD_DIR="${BUILD_DIR:-${LINT_DIR}}" 155 | fi 156 | 157 | BASE_DIR="${BASE_DIR:-$(dirname "$(readlink -f "$0")")}" 158 | FILES_DIR="${FILES_DIR:-${BASE_DIR}/files}" 159 | BUILD_DIR="${BUILD_DIR:-${BASE_DIR}/build}" 160 | CACHE_DIR="${CACHE_DIR:-${BUILD_DIR}/cache}" 161 | RENDER_DIR="${RENDER_DIR:-${BUILD_DIR}/render}" 162 | LOCK_DIR="${LOCK_DIR:-${BUILD_DIR}/lock}" 163 | LOCK_NAME="${LOCK_NAME:-$(basename "$(readlink -f "$0")")}" 164 | BUILD_INFO_DIR="${BUILD_INFO_DIR:-${BUILD_DIR}/info}" 165 | LB_DIR="${LB_DIR:-${BUILD_DIR}/lb}" 166 | LB_CACHE_DIR="${LB_CACHE_DIR:-${CACHE_DIR}/lb}" 167 | LIVE_BUILD="${LIVE_BUILD:-${BASE_DIR}/live-build}" 168 | 169 | is_dirty=false 170 | GIT_COMMIT="$(git -C "${BASE_DIR}" log --format="%H" -n 1 2>/dev/null || true)" 171 | GIT_DESC="$(git -C "${BASE_DIR}" describe --always --dirty 2>/dev/null || true)" 172 | if [ -n "${GIT_DESC}" ]; then 173 | if ! git -C "${BASE_DIR}" diff --quiet 2>/dev/null; then 174 | is_dirty=true 175 | BUILD_TAGS="${BUILD_TAGS} dirty" 176 | fi 177 | fi 178 | LIVE_BUILD_GIT_COMMIT="" 179 | LIVE_BUILD_GIT_DESC="" 180 | 181 | if [ "${LIVE_BUILD}" = "-" ]; then 182 | LIVE_BUILD="" 183 | fi 184 | export LIVE_BUILD 185 | if [ -n "${LIVE_BUILD}" ]; then 186 | if [ ! -e "${LIVE_BUILD}/frontend/lb" ]; then 187 | echo "ERROR: ${LIVE_BUILD}/frontend/lb not found" >&2 188 | if [ "${LIVE_BUILD}" = "${BASE_DIR}/live-build" ]; then 189 | echo "You probably want: git -C \"${BASE_DIR}\" submodule update --init --recursive" >&2 190 | fi 191 | exit 1 192 | fi 193 | export PATH="${LIVE_BUILD}/frontend:${PATH}" 194 | LIVE_BUILD_GIT_COMMIT="$(git -C "${LIVE_BUILD}" log --format="%H" -n 1 2>/dev/null || true)" 195 | LIVE_BUILD_GIT_DESC="$(git -C "${LIVE_BUILD}" describe --always --dirty 2>/dev/null || true)" 196 | fi 197 | 198 | BUILD_TAGS="${BUILD_TAGS} ${ARCH}" 199 | if [ -t 0 ]; then 200 | BUILD_TAGS="${BUILD_TAGS} terminal" 201 | fi 202 | if [ -n "${SCHROOT_SESSION_ID}" ]; then 203 | BUILD_TAGS="${BUILD_TAGS} schroot" 204 | fi 205 | if [ -e "/.dockerenv" ]; then 206 | BUILD_TAGS="${BUILD_TAGS} docker" 207 | fi 208 | # (SC2154) Lowercase variable is conditionally set by systemd-nspawn, 209 | # nothing we can do 210 | # shellcheck disable=SC2154 211 | if [ "${container}" = "systemd-nspawn" ]; then 212 | BUILD_TAGS="${BUILD_TAGS} systemd-nspawn" 213 | fi 214 | # shellcheck disable=SC2154 215 | if [ "${container}" = "podman" ]; then 216 | BUILD_TAGS="${BUILD_TAGS} podman" 217 | fi 218 | 219 | if [ -e /etc/os-release ]; then 220 | for i in BUILD_OS_ID BUILD_OS_VERSION_CODENAME BUILD_OS_VERSION_ID; do 221 | read -r "${i?}" || true 222 | done </dev/null; then 251 | # This relies on cloud-init, but there doesn't appear to be any 252 | # hardware/etc way to determine if running on Azure. 253 | BUILD_TAGS="${BUILD_TAGS} azure" 254 | fi 255 | if [ -n "${GITHUB_RUN_ID}" ]; then 256 | BUILD_TAGS="${BUILD_TAGS} gha" 257 | fi 258 | 259 | BUILD_TAGS="$(for i in ${BUILD_TAGS}; do echo "${i}"; done | sort | uniq | xargs)" 260 | 261 | if [ -z "${BUILD_URL}" ] && [ -n "${GITHUB_RUN_ID}" ]; then 262 | BUILD_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" 263 | fi 264 | 265 | if [ "${LINT}" = "true" ]; then 266 | failed_lint=false 267 | shellcheck "${BASE_DIR}/finnix-live-build" || failed_lint=true 268 | if [ "${has_shfmt}" = "true" ]; then lint_shfmt "${BASE_DIR}/finnix-live-build" || failed_lint=true; fi 269 | for script_dir in "${BASE_DIR}/tools" "${BASE_DIR}/.rrpcid/jobs"/* "${BASE_DIR}/hooks"; do 270 | # Interpet output as words 271 | # shellcheck disable=SC2013 272 | for fn in $(grep -l -E '^#!/(usr/)?bin/(env )?(ba)?sh' "${script_dir}"/*); do 273 | [ -e "${fn}" ] || continue 274 | shellcheck "${fn}" || failed_lint=true 275 | if [ "${has_shfmt}" = "true" ]; then lint_shfmt "${fn}" || failed_lint=true; fi 276 | done 277 | grep -l -E '^#!/(usr/)?bin/(env )?python3' "${script_dir}"/* | xargs -r "${PYTHON}" -mflake8 --config=/dev/null --max-line-length=120 || failed_lint=true 278 | done 279 | 280 | mkdir -p "${LINT_DIR}/md/in" "${LINT_DIR}/md/out" 281 | for fn in "${BASE_DIR}"/*.md "${BASE_DIR}/.rrpcid"/*.md "${BASE_DIR}/files/manpages"/*.md; do 282 | md_full_path="${fn#"${BASE_DIR}/"}" 283 | md_dir="$(dirname "${md_full_path}")" 284 | mkdir -p "${LINT_DIR}/md/in/${md_dir}" "${LINT_DIR}/md/out/${md_dir}" 285 | render <"${fn}" >"${LINT_DIR}/md/in/${md_full_path}" 286 | pandoc -s -t gfm+smart --columns=80 -i "${LINT_DIR}/md/in/${md_full_path}" -o "${LINT_DIR}/md/out/${md_full_path}" 287 | done 288 | diff -ru "${LINT_DIR}/md/in" "${LINT_DIR}/md/out" || failed_lint=true 289 | 290 | if [ "${failed_lint}" = "true" ]; then 291 | echo 292 | echo "Failed lint checks" 293 | exit 1 294 | fi 295 | fi 296 | 297 | mkdir -p "${LOCK_DIR}" 298 | lock "${LOCK_DIR}/${LOCK_NAME}.lock" 299 | 300 | rm -rf "${RENDER_DIR}" 301 | render_files "${RENDER_DIR}/hooks" "${BASE_DIR}/hooks"/*.hook.* 302 | render_files "${RENDER_DIR}/hook-files" "${FILES_DIR}/hooks"/* 303 | render_files "${RENDER_DIR}/docker-files" "${FILES_DIR}/docker"/* 304 | render_files "${RENDER_DIR}/package-lists" "${BASE_DIR}/lists"/*.list.chroot 305 | for i in "${FILES_DIR}/manpages"/*.md; do 306 | basefn="$(basename "$i" .md)" 307 | ( 308 | render <"${FILES_DIR}/manpages/${basefn}.metadata.yaml" 309 | echo "---" 310 | render <"${i}" 311 | ) | pandoc -s -f markdown_github-smart+yaml_metadata_block -t man -o "${RENDER_DIR}/hook-files/${basefn}.1" 312 | done 313 | # pandoc 2.13 supports gfm+yaml_metadata_block input, but generates identical output to markdown_github-smart+yaml_metadata_block. 314 | # It should be safe to migrate this eventually when markdown_github-smart is hard deprecated, 315 | # but until then we can keep it for maximum build compatibility. 316 | 317 | mkdir -p "${RENDER_DIR}/archives" 318 | if [ "${UNSTABLE_PIN}" = "true" ]; then 319 | cat >"${RENDER_DIR}/archives/unstable.list.chroot" <<"EOM" 320 | deb http://deb.debian.org/debian/ unstable main contrib non-free non-free-firmware 321 | deb-src http://deb.debian.org/debian/ unstable main contrib non-free non-free-firmware 322 | EOM 323 | cp "${RENDER_DIR}/archives/unstable.list.chroot" "${RENDER_DIR}/archives/unstable.list.binary" 324 | cat >"${RENDER_DIR}/archives/unstable.pref.chroot" <<"EOM" 325 | Package: * 326 | Pin: release a=unstable 327 | Pin-Priority: 400 328 | EOM 329 | cp "${RENDER_DIR}/archives/unstable.pref.chroot" "${RENDER_DIR}/archives/unstable.pref.binary" 330 | fi 331 | cat >"${RENDER_DIR}/archives/80${PRODUCT_ID}.conf.chroot" <<"EOM" 332 | Acquire::PDiffs "false"; 333 | Acquire::Languages { "none"; }; 334 | EOM 335 | cp "${RENDER_DIR}/archives/80${PRODUCT_ID}.conf.chroot" "${RENDER_DIR}/archives/80${PRODUCT_ID}.conf.binary" 336 | if [ "${SOURCE_ISO}" = "false" ]; then 337 | for fn in "${RENDER_DIR}/archives"/*.list.*; do 338 | [ -e "${fn}" ] || continue 339 | sed -i "s/^deb-src/#deb-src/g" "${fn}" 340 | done 341 | fi 342 | 343 | if [ "${DOCKER_BUILD}" = "true" ]; then 344 | DOCKER_DIR="${BUILD_DIR}/docker" 345 | rm -rf "${DOCKER_DIR}" 346 | mkdir -p "${DOCKER_DIR}" 347 | cp -a "${RENDER_DIR}/docker-files/." "${DOCKER_DIR}/" 348 | render_files "${DOCKER_DIR}/hooks" "${LIVE_BUILD}/share/hooks/normal"/*.hook.chroot 349 | cp -a "${RENDER_DIR}/hooks"/*.hook.chroot "${DOCKER_DIR}/hooks/" 350 | mkdir -p "${DOCKER_DIR}/hook-files" 351 | cp -a "${RENDER_DIR}/hook-files/." "${DOCKER_DIR}/hook-files/" 352 | chmod 0755 "${DOCKER_DIR}/container-build" "${DOCKER_DIR}/hooks"/*.hook.chroot 353 | mkdir -p "${DOCKER_DIR}/package-lists" 354 | cp -a "${RENDER_DIR}/package-lists"/*.chroot "${DOCKER_DIR}/package-lists/" 355 | mkdir -p "${DOCKER_DIR}/archives" 356 | cp -a "${RENDER_DIR}/archives"/*.chroot "${DOCKER_DIR}/archives/" 357 | 358 | exit 0 359 | fi 360 | 361 | cd / 362 | rm -rf "${LB_DIR}" 363 | mkdir -p "${LB_DIR}" 364 | cd "${LB_DIR}" 365 | 366 | # do_lb_config references arguments, but none are ever passed. 367 | # shellcheck disable=SC2120 368 | do_lb_config() { 369 | # Note that --source true also requires --apt-source-archives true 370 | 371 | lb config noauto \ 372 | --apt-http-proxy "${APT_HTTP_PROXY}" \ 373 | --apt-indices false \ 374 | --apt-recommends false \ 375 | --apt-source-archives "${SOURCE_ISO}" \ 376 | --architectures "${ARCH}" \ 377 | --archive-areas "main contrib non-free non-free-firmware" \ 378 | --binary-images "${BINARY_IMAGES}" \ 379 | --bootappend-live "quiet" \ 380 | --bootloaders "${BOOTLOADERS}" \ 381 | --cache-indices true \ 382 | --chroot-squashfs-compression-type "${SQUASHFS_COMP}" \ 383 | --debootstrap-options "--no-merged-usr" \ 384 | --distribution testing \ 385 | --firmware-chroot false \ 386 | --hdd-label "$(echo "${PRODUCT_ID}" | tr '[:lower:]' '[:upper:]')" \ 387 | --image-name "${PRODUCT_ID}" \ 388 | --iso-application "${PRODUCT}" \ 389 | --iso-preparer "${PRODUCT}" \ 390 | --iso-publisher "${PRODUCT}" \ 391 | --iso-volume "${PRODUCT} ${VERSION}" \ 392 | --memtest "${MEMTEST}" \ 393 | --source "${SOURCE_ISO}" \ 394 | --source-images iso \ 395 | --zsync false \ 396 | --mode debian \ 397 | "$@" 398 | } 399 | 400 | do_lb_config 401 | 402 | mkdir -p "${LB_CACHE_DIR}" 403 | if [ "${CACHE_FROZEN}" = "false" ]; then 404 | if [ -e "${LB_CACHE_DIR}/bootstrap/etc/hostname" ]; then 405 | if [ -n "$(find "${LB_CACHE_DIR}/bootstrap/etc/hostname" -mmin +1080)" ]; then 406 | rm -rf "${LB_CACHE_DIR}/bootstrap" 407 | fi 408 | else 409 | rm -rf "${LB_CACHE_DIR}/bootstrap" 410 | fi 411 | if [ -e "${LB_CACHE_DIR}/indices.bootstrap/pkgcache.bin" ]; then 412 | if [ -n "$(find "${LB_CACHE_DIR}/indices.bootstrap/pkgcache.bin" -mmin +1080)" ]; then 413 | rm -rf "${LB_CACHE_DIR}/indices.bootstrap" "${LB_CACHE_DIR}/contents.chroot" 414 | fi 415 | else 416 | rm -rf "${LB_CACHE_DIR}/indices.bootstrap" "${LB_CACHE_DIR}/contents.chroot" 417 | fi 418 | find "${LB_CACHE_DIR}"/packages.* -name '*.deb' -mtime +30 -delete 2>/dev/null || true 419 | fi 420 | if [ "${container}" = "systemd-nspawn" ] && [ -e "${LB_CACHE_DIR}/bootstrap/dev/console" ]; then 421 | # Restoring parts of bootstrap/dev/ created outside systemd-nspawn 422 | # will fail inside systemd-nspawn 423 | rm -rf "${LB_CACHE_DIR}/bootstrap" 424 | fi 425 | rm -rf "${LB_DIR}/cache" 426 | ln -sf "${LB_CACHE_DIR}" "${LB_DIR}/cache" 427 | 428 | mkdir -p "${LB_DIR}/config/hooks/normal" 429 | cp -a "${RENDER_DIR}/hooks/." "${LB_DIR}/config/hooks/normal/" 430 | mkdir -p "${LB_DIR}/config/includes.chroot_after_packages/hook-files" 431 | cp -a "${RENDER_DIR}/hook-files/." "${LB_DIR}/config/includes.chroot_after_packages/hook-files/" 432 | mkdir -p "${LB_DIR}/config/package-lists" 433 | cp -a "${RENDER_DIR}/package-lists/." "${LB_DIR}/config/package-lists/" 434 | 435 | if [ "${is_dirty}" = "true" ]; then 436 | mkdir -p "${LB_DIR}/config/includes.binary/.disk" 437 | git -C "${BASE_DIR}" status >"${LB_DIR}/config/includes.binary/.disk/build-dirty.patch" 438 | git -C "${BASE_DIR}" diff >>"${LB_DIR}/config/includes.binary/.disk/build-dirty.patch" 439 | fi 440 | 441 | render_files "${LB_DIR}/config/bootloaders/syslinux_common" "${FILES_DIR}/syslinux"/*.cfg 442 | render <"${FILES_DIR}/syslinux/splash.svg" | rsvg-convert --format png --width 640 --height 480 >"${LB_DIR}/config/bootloaders/syslinux_common/splash.png" 443 | render_files "${LB_DIR}/config/bootloaders/grub-pc" "${FILES_DIR}/grub"/*.cfg 444 | render <"${FILES_DIR}/grub/splash.svg" | rsvg-convert --format png --width 1920 --height 1080 >"${LB_DIR}/config/bootloaders/grub-pc/splash.png" 445 | render_files "${LB_DIR}/config/bootloaders/grub-pc/live-theme" "${FILES_DIR}/grub/theme.txt" 446 | 447 | if [ -z "${SQUASHFS_SORT_FILE}" ]; then 448 | for f in \ 449 | "${FILES_DIR}/squashfs.${VERSION}.${ARCH}.sort" \ 450 | "${FILES_DIR}/squashfs.${ARCH}.sort" \ 451 | "${FILES_DIR}/squashfs.sort"; do 452 | if [ -e "${f}" ]; then 453 | SQUASHFS_SORT_FILE="${f}" 454 | break 455 | fi 456 | done 457 | fi 458 | if [ -n "${SQUASHFS_SORT_FILE}" ]; then 459 | mkdir -p "${LB_DIR}/config/rootfs" 460 | cp "${SQUASHFS_SORT_FILE}" "${LB_DIR}/config/rootfs/squashfs.sort" 461 | fi 462 | 463 | # The in-squashfs initrds are unused; exclude them 464 | mkdir -p "${LB_DIR}/config/rootfs" 465 | cat <<"EOM" >"${LB_DIR}/config/rootfs/excludes" 466 | boot/initrd.img* 467 | initrd.img* 468 | EOM 469 | 470 | mkdir -p "${LB_DIR}/config/includes.chroot_after_packages/etc" 471 | echo "${PRODUCT_ID}" >"${LB_DIR}/config/includes.chroot_after_packages/etc/hostname" 472 | cat <"${LB_DIR}/config/includes.chroot_after_packages/etc/hosts" 473 | 127.0.0.1 localhost 474 | 127.0.1.1 ${PRODUCT_ID} 475 | 476 | ::1 ip6-localhost ip6-loopback 477 | fe00::0 ip6-localnet 478 | ff00::0 ip6-mcastprefix 479 | ff00::1 ip6-allnodes 480 | ff00::2 ip6-allrouters 481 | EOM 482 | 483 | cat <<"EOM" >config/preseed/firmware-nonfree.cfg.chroot 484 | firmware-ipw2x00 firmware-ipw2x00/license/accepted boolean true 485 | EOM 486 | 487 | mkdir -p "${LB_DIR}/config/archives" 488 | cp -a "${RENDER_DIR}/archives/." "${LB_DIR}/config/archives/" 489 | 490 | if [ "${LINT}" = "true" ]; then 491 | # Interpet output as words 492 | # shellcheck disable=SC2013 493 | for fn in $( 494 | grep -l -E '^#!/(usr/)?bin/(env )?(ba)?sh' \ 495 | "${LB_DIR}/config/hooks/normal"/*-finnix-*.hook.chroot \ 496 | "${LB_DIR}/config/includes.chroot_after_packages/hook-files"/* 497 | ); do 498 | [ -e "${fn}" ] || continue 499 | shellcheck "${fn}" 500 | [ "${has_shfmt}" = "true" ] && lint_shfmt "${fn}" 501 | done 502 | grep -l -E '^#!/(usr/)?bin/(env )?python3' "${LB_DIR}/config/hooks/normal"/*-finnix-*.hook.chroot | xargs -r "${PYTHON}" -mflake8 --config=/dev/null --max-line-length=120 503 | grep -l -E '^#!/(usr/)?bin/(env )?python3' "${LB_DIR}/config/includes.chroot_after_packages/hook-files"/* | xargs -r "${PYTHON}" -mflake8 --config=/dev/null --max-line-length=120 504 | fi 505 | 506 | if [ "${LINT}" = "true" ]; then 507 | rm -rf "${LINT_DIR}" 508 | echo "Lint completed without error" 509 | exit 0 510 | fi 511 | 512 | lb build 513 | 514 | build_id="$(echo "${DATETIME}" | sed -e 's/ /_/g')" 515 | if [ -n "${GIT_DESC}" ]; then 516 | build_id="${build_id}_${GIT_DESC}" 517 | fi 518 | build_size="$(stat -c "%s" "${LB_DIR}/${ISO_FILENAME}")" 519 | mkdir -p "${BUILD_INFO_DIR}/${build_id}" 520 | cp -a "${LB_DIR}"/*.contents "${BUILD_INFO_DIR}/${build_id}/" 521 | cp -a "${LB_DIR}"/*.files "${BUILD_INFO_DIR}/${build_id}/" 522 | cp -a "${LB_DIR}"/*.packages "${BUILD_INFO_DIR}/${build_id}/" 523 | cp -a "${LB_DIR}"/*.packages.* "${BUILD_INFO_DIR}/${build_id}/" 524 | if [ "${is_dirty}" = "true" ]; then 525 | cp "${LB_DIR}/config/includes.binary/.disk/build-dirty.patch" "${BUILD_INFO_DIR}/${build_id}/dirty.patch" 526 | fi 527 | echo "${build_size}" >"${BUILD_INFO_DIR}/${build_id}/${ISO_FILENAME}.size" 528 | if [ "${SAVE_ISO}" = "true" ]; then 529 | cp -a "${LB_DIR}/${ISO_FILENAME}" "${BUILD_INFO_DIR}/${build_id}/${ISO_FILENAME}" 530 | if [ "${SOURCE_ISO}" = "true" ]; then 531 | cp -a "${LB_DIR}/${PRODUCT_ID}-source.iso" "${BUILD_INFO_DIR}/${build_id}/${PRODUCT_ID}-source.iso" 532 | fi 533 | fi 534 | 535 | ls -lsa "${LB_DIR}/${ISO_FILENAME}" 536 | sha256="$(sha256sum "${LB_DIR}/${ISO_FILENAME}" | cut -f1 -d" ")" 537 | echo "SHA256: ${sha256}" 538 | fileoutput="" 539 | if command -v file >/dev/null; then 540 | fileoutput="$(file -b "${LB_DIR}/${ISO_FILENAME}")" 541 | echo "${fileoutput}" 542 | fi 543 | if [ "${SOURCE_ISO}" = "true" ]; then 544 | source_iso_filename="${PRODUCT_ID}-source.iso" 545 | ls -lsa "${LB_DIR}/${source_iso_filename}" 546 | source_sha256="$(sha256sum "${LB_DIR}/${source_iso_filename}" | cut -f1 -d" ")" 547 | echo "Source SHA256: ${sha256}" 548 | source_fileoutput="" 549 | if command -v file >/dev/null; then 550 | source_fileoutput="$(file -b "${LB_DIR}/${source_iso_filename}")" 551 | echo "${source_fileoutput}" 552 | fi 553 | source_build_size="$(stat -c "%s" "${LB_DIR}/${source_iso_filename}")" 554 | fi 555 | echo "Build: ${DATETIME} ${GIT_DESC} ${BUILD_TAGS}" 556 | echo 557 | 558 | if [ -n "${GITHUB_STEP_SUMMARY}" ]; then 559 | if [ "${SOURCE_ISO}" = "true" ]; then 560 | { 561 | echo "### Source build information" 562 | echo "" 563 | echo "- Build: ${DATETIME} ${GIT_DESC} ${BUILD_TAGS}" 564 | echo "- Size: $((source_build_size / 1048576)) MiB (${source_build_size})" 565 | echo "- SHA256: \`${source_sha256}\`" 566 | if [ -n "${source_fileoutput}" ]; then 567 | echo "- File: ${source_fileoutput}" 568 | fi 569 | } >>"${GITHUB_STEP_SUMMARY}" 570 | else 571 | { 572 | echo "### Build information" 573 | echo "" 574 | echo "- Build: ${DATETIME} ${GIT_DESC} ${BUILD_TAGS}" 575 | echo "- Size: $((build_size / 1048576)) MiB (${build_size})" 576 | echo "- SHA256: \`${sha256}\`" 577 | if [ -n "${fileoutput}" ]; then 578 | echo "- File: ${fileoutput}" 579 | fi 580 | echo "- Packages: $(wc -l "${LB_DIR}/chroot.packages.live" | cut -f1 -d" ")" 581 | } >>"${GITHUB_STEP_SUMMARY}" 582 | fi 583 | fi 584 | 585 | current_tmp_fn="$(mktemp)" 586 | compare_tmp_fn="$(mktemp)" 587 | diff_tmp_fn="$(mktemp)" 588 | cut -f1 <"${BUILD_INFO_DIR}/${build_id}/chroot.packages.live" | sort >"${current_tmp_fn}" 589 | 590 | for compare_link in "${BUILD_INFO_DIR}"/*; do 591 | [ -h "$compare_link" ] || continue 592 | compare_name="$(basename "${compare_link}")" 593 | compare_build_id="$(basename "$(readlink -f "${compare_link}")")" 594 | 595 | compare_build_size="$(cat "${compare_link}/${ISO_FILENAME}.size")" 596 | build_size_delta=$((build_size - compare_build_size)) 597 | if [ "${build_size_delta}" -ge 1048576 ] || [ "${build_size_delta}" -le -1048576 ]; then 598 | echo "NOTE: Build size changed from build \"${compare_name}\" (${compare_build_id}):" 599 | echo " - $((compare_build_size / 1048576)) MiB - ${compare_build_id}" 600 | echo " + $((build_size / 1048576)) MiB - ${build_id}" 601 | echo 602 | fi 603 | 604 | cut -f1 <"${compare_link}/chroot.packages.live" | sort >"${compare_tmp_fn}" 605 | (diff "${compare_tmp_fn}" "${current_tmp_fn}" | grep -e '^[<>]') >"${diff_tmp_fn}" || true 606 | if [ -s "${diff_tmp_fn}" ]; then 607 | echo "NOTE: Packages names changed from build \"${compare_name}\" (${compare_build_id}):" 608 | cat "${diff_tmp_fn}" 609 | echo 610 | fi 611 | done 612 | 613 | rm -f "${compare_tmp_fn}" "${current_tmp_fn}" "${diff_tmp_fn}" 614 | rm -f "${BUILD_INFO_DIR}/previous" 615 | ln -s "${build_id}" "${BUILD_INFO_DIR}/previous" 616 | --------------------------------------------------------------------------------