diff --git a/archlinux/Containerfile.base b/Containerfile.base similarity index 63% rename from archlinux/Containerfile.base rename to Containerfile.base index 96dc2cf..a21c3aa 100644 --- a/archlinux/Containerfile.base +++ b/Containerfile.base @@ -11,7 +11,7 @@ RUN curl https://gitlab.archlinux.org/archlinux/packaging/packages/pacman/-/raw/ # Perform a clean system installation with latest Arch Linux packages in chroot to correctly execute hooks, this uses host's Pacman RUN pacman --noconfirm --sync --needed arch-install-scripts \ - && pacstrap -K -P /mnt base \ + && pacstrap -K -P /mnt base base-devel linux-firmware fwupd \ && cp -av /etc/pacman.d/ /mnt/etc/ # | @@ -23,14 +23,15 @@ FROM scratch AS base COPY --from=rootfs /mnt / # Clock -ARG SYSTEM_OPT_TIMEZONE -RUN ln --symbolic --force /usr/share/zoneinfo/${SYSTEM_OPT_TIMEZONE} /etc/localtime +# Define o fuso horário para o Brasil (Mato Grosso) +RUN ln --symbolic --force /usr/share/zoneinfo/America/Cuiaba /etc/localtime # Keymap hook -ARG SYSTEM_OPT_KEYMAP -RUN echo "KEYMAP=${SYSTEM_OPT_KEYMAP}" > /etc/vconsole.conf +# Define o layout do teclado para o padrão brasileiro ABNT2 +RUN echo "KEYMAP=br-abnt2" > /etc/vconsole.conf # Language -RUN echo 'LANG=en_US.UTF-8' > /etc/locale.conf \ - && echo 'en_US.UTF-8 UTF-8' > /etc/locale.gen \ +# Define o idioma e local para Português do Brasil +RUN echo 'LANG=pt_BR.UTF-8' > /etc/locale.conf \ + && echo 'pt_BR.UTF-8 UTF-8' > /etc/locale.gen \ && locale-gen diff --git a/README.md b/README.md index a39ab15..3009002 100644 --- a/README.md +++ b/README.md @@ -1,160 +1,156 @@ -## OSTree in Arch Linux using Podman - -Massive shout-out to [M1cha](https://github.com/M1cha/) for making this possible ([M1cha/archlinux-ostree](https://github.com/M1cha/archlinux-ostree)). - -### Overview - -This is a helper script which aids in curating your own setup by demonstrating how to: -1. Build an immutable OSTree image by using rootfs from a Podman Containerfile. -2. Partition and prepare UEFI/GPT disks for a minimal OSTree host system. -3. Generate OSTree repository in a empty filesystem. -4. Integrate OSTree with GRUB2 bootloader. -5. Upgrade an existing OSTree repository with a new rootfs image. - -### Disk structure - -```console -/ -├── boot -│   └── efi -└── ostree - ├── deploy - │   └── archlinux - └── repo - ├── config - ├── extensions - ├── objects - ├── refs - ├── state - └── tmp -``` +----- -### Persistence +# RAGostree-utility -Everything is deleted between deployments **except** for: -- `/dev` partitions which OSTree does not reside on are untouched. -- `/etc` only if `--merge` option is specified. -- `/home` is symlinked to `/var/home` (see below). -- `/var` data here is mounted from `/ostree/deploy/archlinux/var` to avoid duplication. -Notes: -- `/var/cache/podman` is populated _only_ after the first deployment (to avoid including old data from the build machine), this speeds up consecutive builds. -- `/var/lib/containers` same as above but for Podman layers and images. Base images are updated automatically during `upgrade` command. +**RAGLinux** é um sistema operacional baseado em **Arch Linux** com uma abordagem moderna e robusta: um sistema de arquivos raiz **imutável**, gerenciado de forma atômica pelo **OSTree** e construído com a flexibilidade do **Podman**. -### Technology stack +O objetivo deste projeto é fornecer a estabilidade de um sistema imutável, onde as atualizações são seguras e reversíveis, combinada com a vasta gama de pacotes e a filosofia "faça você mesmo" do Arch Linux. -- OSTree -- Podman with CRUN and Native-Overlayfs -- GRUB2 -- XFS _(not required)_ +----- -### Motivation +## 🌟 Principais Características -My vision is to build a secure and minimal base system which is resilient against breakage and provides setup automation to reduce the burden of doing manual tasks. This can be achieved by: + * **Sistema Imutável**: O diretório raiz (`/`) é montado como somente leitura, prevenindo modificações acidentais e garantindo que cada "versão" do sistema seja consistente e testada. + * **Atualizações Atômicas**: As atualizações são aplicadas em uma nova "árvore" do sistema. A mudança para a nova versão ocorre em uma única operação (geralmente na reinicialização), eliminando o risco de um sistema quebrar no meio de uma atualização. + * **Rollbacks Simples**: Se uma atualização causar problemas, reverter para a versão anterior funcional é um comando simples e instantâneo. + * **Construção via Containers**: A imagem base do sistema é construída dentro de um container Podman, garantindo um ambiente de build limpo, reprodutível e isolado. + * **Separação Clara**: O sistema operacional é estritamente separado dos dados e configurações do usuário, que residem em subvolumes Btrfs separados (`/home`, `/var`). -- Git. -- Read-only system files. -- Restore points. -- Automatic deployment, installation & configuration. -- Using only required components like kernel/firmware/driver, microcode and GGC in the base. -- Doing the rest in temporary namespaces such as Podman. +----- -### Goal +## 🛠️ Tecnologias Utilizadas -- Reproducible deployments. -- Versioned rollbacks. -- Immutable filesystem. -- Distribution agnostic toolset. -- Configuration management. -- Rootfs creation via containers. -- Each deployment does a factory reset of system's configuration _(unless overridden)_. + * **Base System**: [Arch Linux](https://archlinux.org/) + * **Gerenciamento Atômico**: [OSTree](https://ostreedev.github.io/ostree/) + * **Sistema de Arquivos**: [Btrfs](https://btrfs.wiki.kernel.org/) + * **Construção (Build)**: [Podman](https://podman.io/) + * **Bootloader**: [GRUB](https://www.gnu.org/software/grub/) -### Similar projects +----- -- **[Elemental Toolkit](https://github.com/rancher/elemental-toolkit)** -- **[KairOS](https://github.com/kairos-io/kairos)** -- **[BootC](https://github.com/containers/bootc)** -- [NixOS](https://nixos.org) -- [ABRoot](https://github.com/Vanilla-OS/ABRoot) -- [Transactional Update + BTRFS snapshots](https://microos.opensuse.org) -- [AshOS](https://github.com/ashos/ashos) -- [LinuxKit](https://github.com/linuxkit/linuxkit) +## 🚀 Estrutura do Projeto -## Usage +``` +raglinux/ +├── raglinux.sh # Script principal de instalação e gerenciamento +├── Containerfile.base # Define a imagem base do sistema (pacotes e configs) +├── post-install.sh # (Opcional) Script para configurações pós-instalação +├── archlinux/ # Configurações específicas do Arch +├── cachyos/ # (Opcional) Configurações para builds alternativas +└── Containerfile.host.example # Exemplo para customizações do host +``` -1. **Boot into any Arch Linux system:** +----- - For instance, using a live CD/USB ISO image from: [Arch Linux Downloads](https://archlinux.org/download). +## ⚙️ Uso e Gerenciamento -2. **Clone this repository:** +O script `raglinux.sh` é a principal ferramenta para interagir com o sistema em nível de build e deploy. - ```console - $ sudo pacman -Sy git - $ git clone https://github.com/GrabbenD/ostree-utility.git && cd ostree-utility - ``` +### Instalação Inicial -3. **Find `ID-LINK` for installation device where OSTree image will be deployed:** +Para criar o primeiro deployment do sistema em um dispositivo de bloco (ex: `/dev/sda`). - ```console - $ lsblk -o NAME,TYPE,FSTYPE,MODEL,ID-LINK,SIZE,MOUNTPOINTS,LABEL - NAME TYPE FSTYPE MODEL ID-LINK SIZE MOUNTPOINTS LABEL - sdb disk Virtual Disk scsi-360022480c22be84f8a61b39bbaed612f 300G - ├─sdb1 part vfat scsi-360022480c22be84f8a61b39bbaed612f-part1 256M SYS_BOOT - ├─sdb2 part xfs scsi-360022480c22be84f8a61b39bbaed612f-part2 24.7G SYS_ROOT - └─sdb3 part xfs scsi-360022480c22be84f8a61b39bbaed612f-part3 275G SYS_HOME - ``` +```bash +# Exemplo de uso +./raglinux.sh install --dev /dev/sda --keymap br-abnt2 --time America/Sao_Paulo +``` -4. **Perform a takeover installation:** +### Atualizando o Sistema (Upgrade) - **⚠️ WARNING ⚠️** +Isso irá construir uma nova imagem, criar um novo commit no OSTree e prepará-lo para ser o próximo boot. - `ostree.sh` is destructive and has no prompts while partitioning the specified disk, **proceed with caution**: +```bash +# Cria um novo commit OSTree com as últimas atualizações +./raglinux.sh upgrade +``` - ```console - $ chmod +x ostree.sh - $ sudo ./ostree.sh install --dev scsi-360022480c22be84f8a61b39bbaed612f - ``` +Após o upgrade, reinicie o sistema para aplicar a nova versão. - ⚙️ Update your BIOS boot order to access the installation. +### Revertendo uma Atualização (Rollback) - 💡 Default login is: `root` / `ostree` +Caso a última atualização apresente algum problema, você pode facilmente reverter. - 💡 Use different Containerfile(s) with `--file FILE1:TAG1,FILE2:TAG2` option +```bash +# Reverte para o deployment anterior (marcado como 0) +./raglinux.sh revert +``` -5. **Upgrade an existing installation:** +### Opções do Script `raglinux.sh` - While booted into a OSTree system, use: +| Opção | Argumento Longo | Descrição | Padrão | +| :--- | :--- | :--- |:--- | +| `-b` | `--base-os` | Nome do sistema operacional para o repositório OSTree. | `raglinux` | +| `-c` | `--cmdline` | Argumentos extras para a linha de comando do Kernel. | | +| `-d` | `--dev` | Dispositivo de bloco (SCSI/NVMe) para a instalação. | | +| `-f` | `--file` | Caminho para o(s) `Containerfile`(s) a serem usados no build. | | +| `-k` | `--keymap` | Layout de teclado para o console (TTY). | | +| `-t` | `--time` | Fuso horário (Timezone) no formato `Região/Cidade`. | | +| `-m` | `--merge` | Mantém o diretório `/etc` durante um upgrade. | | +| `-n` | `--no-cache` | Ignora o cache do Pacman e do Podman durante o build. | | +| `-q` | `--quiet` | Reduz a quantidade de logs exibidos na saída. | | - ```console - $ sudo ./ostree.sh upgrade - ``` +----- - 💡 Use `--merge` option to preserve contents of `/etc` +## 📦 Gerenciamento de Aplicações -6. **Revert to previous commit:** +Em um sistema imutável, o gerenciamento de pacotes tradicional (`pacman -S ...`) não é usado diretamente no sistema host. Em vez disso, a instalação de aplicações de usuário é feita de forma isolada: - To undo the latest deployment _(0)_; boot into the previous configuration _(1)_ and execute: + * **Flatpak**: O método recomendado para aplicações gráficas. Elas rodam em seu próprio sandbox e não alteram o sistema base. + * **Podman / Distrobox**: Ideal para ferramentas de linha de comando e ambientes de desenvolvimento. Crie containers com as distribuições e pacotes que precisar, sem "sujar" o sistema host. + * **Binários em `/home`**: Para aplicações simples que não requerem dependências complexas, você pode executá-las a partir do seu diretório pessoal. - ```console - $ sudo ./ostree.sh revert - ``` +----- -## Tips +## 🗂️ Estrutura do Sistema de Arquivos (Pós-instalação) -### Read-only +O RAGLinux utiliza subvolumes Btrfs para separar os dados do sistema. -This attribute can be temporarily removed with Overlay filesystem which allows you to modify read-only paths without persisting the changes: + * `/` (raiz): **Imutável**. Gerenciado pelo OSTree. + * `/home`: Subvolume `@home`. **Mutável**. Armazena os arquivos e configurações dos usuários. + * `/var`: Subvolume `@var`. **Mutável**. Contém dados variáveis como logs, caches de aplicações, etc. + * `/ostree`: Subvolume `@ostree`. Contém os deployments (versões) do sistema operacional. + * `/boot/efi`: Partição EFI para o bootloader. -```console -$ ostree admin unlock -``` +----- -### Outdated repository cache +## 🧠 Desafios Resolvidos Durante o Desenvolvimento -> `error: failed retrieving file '{name}.pkg.tar.zst' from {source} : The requested URL returned error: 404` +1. **Espaço Insuficiente no LiveCD (`airootfs`)** -Your persistent cache is out of sync with upstream, this can be resolved with: + * **Problema**: O ambiente de instalação do Arch tem um `tmpfs` limitado, que estourava durante o build do container. + * **Solução**: Direcionar o diretório temporário e a raiz do Podman para o disco de destino (`/mnt`), que possui espaço de sobra. + ```bash + export TMPDIR=/mnt/podman/tmp + # Configurar /mnt/podman como storage root do Podman + ``` -```console -$ ./ostree.sh upgrade --no-podman-cache -``` +2. **Volume do Podman Não Encontrado** + + * **Problema**: O Podman não conseguia montar o cache do Pacman pois o diretório de destino não existia no host antes do build. + * **Solução**: Criar manualmente a estrutura de diretórios do cache antes de invocar o comando `podman build`. + ```bash + mkdir -p /mnt/podman/var/cache/pacman + ``` + +3. **GRUB Não se Instalava Corretamente no Chroot** + + * **Problema**: O comando `grub-mkconfig` falhava por não encontrar os dispositivos e informações do sistema quando executado de um chroot simples. + * **Solução**: Fazer o bind mount dos pseudo-sistemas de arquivos (`/dev`, `/proc`, `/sys`) do host para dentro do ambiente chroot antes de executar o comando. + ```bash + for i in /dev /proc /sys; do mount -o bind $i ${DEPLOY_PATH}${i}; done + chroot ${DEPLOY_PATH} grub-mkconfig -o /boot/efi/EFI/grub/grub.cfg + ``` + +----- + +## 🌐 Configurações Padrão + + * **Espelho Brasileiro do Pacman**: Para garantir downloads mais rápidos, o `pacman.conf` é configurado por padrão para utilizar o espelho `br.mirrors.cicku.me`. + * **Pacotes Base**: A imagem (`Containerfile.base`) inclui um sistema funcional com Plasma Desktop (KDE), ferramentas de containerização (Podman, Distrobox), Pipewire para áudio e outros utilitários essenciais. + +----- + +### Autor + +Gabriel Aguiar Rocha – [GitHub](https://github.com/gabrielrocha) diff --git a/ostree.sh b/ostree.sh deleted file mode 100755 index 0506849..0000000 --- a/ostree.sh +++ /dev/null @@ -1,388 +0,0 @@ -#!/usr/bin/env bash -set -o errexit # Exit on non-zero status -set -o nounset # Error on unset variables - -# [ENVIRONMENT]: OVERRIDE DEFAULTS -function ENV_CREATE_OPTS { - if [[ ${CLI_QUIET:-} != 1 ]]; then - set -o xtrace # Print executed commands while performing tasks - fi - - if [[ ! -d '/ostree' ]]; then - # Do not touch disks in a booted system: - declare -g OSTREE_DEV_DISK=${OSTREE_DEV_DISK:="/dev/disk/by-id/${OSTREE_DEV_SCSI}"} - declare -g OSTREE_DEV_BOOT=${OSTREE_DEV_BOOT:="${OSTREE_DEV_DISK}-part1"} - declare -g OSTREE_DEV_ROOT=${OSTREE_DEV_ROOT:="${OSTREE_DEV_DISK}-part2"} - declare -g OSTREE_DEV_HOME=${OSTREE_DEV_HOME:="${OSTREE_DEV_DISK}-part3"} - declare -g OSTREE_SYS_ROOT=${OSTREE_SYS_ROOT:='/tmp/chroot'} - fi - - declare -g OSTREE_SYS_ROOT=${OSTREE_SYS_ROOT:='/'} - declare -g OSTREE_SYS_TREE=${OSTREE_SYS_TREE:='/tmp/rootfs'} - declare -g OSTREE_SYS_KARG=${OSTREE_SYS_KARG:=''} - declare -g OSTREE_SYS_BOOT_LABEL=${OSTREE_SYS_BOOT_LABEL:='SYS_BOOT'} - declare -g OSTREE_SYS_ROOT_LABEL=${OSTREE_SYS_ROOT_LABEL:='SYS_ROOT'} - declare -g OSTREE_SYS_HOME_LABEL=${OSTREE_SYS_HOME_LABEL:='SYS_HOME'} - declare -g OSTREE_OPT_NOMERGE=${OSTREE_OPT_NOMERGE='--no-merge'} - declare -g OSTREE_REP_NAME=${OSTREE_REP_NAME:='archlinux'} - - if [[ -n ${SYSTEM_OPT_TIMEZONE:-} ]]; then - # Do not modify host's time unless explicitly specified - timedatectl set-timezone ${SYSTEM_OPT_TIMEZONE} - timedatectl set-ntp 1 - fi - declare -g SYSTEM_OPT_TIMEZONE=${SYSTEM_OPT_TIMEZONE:='Etc/UTC'} - declare -g SYSTEM_OPT_KEYMAP=${SYSTEM_OPT_KEYMAP:='us'} - - declare -g PODMAN_OPT_BUILDFILE=${PODMAN_OPT_BUILDFILE:="${0%/*}/archlinux/Containerfile.base:ostree/base","${0%/*}/Containerfile.host.example:ostree/host"} - declare -g PODMAN_OPT_NOCACHE=${PODMAN_OPT_NOCACHE:='0'} - declare -g PACMAN_OPT_NOCACHE=${PACMAN_OPT_NOCACHE:='0'} -} - - -# [ENVIRONMENT]: OSTREE CHECK -function ENV_VERIFY_LOCAL { - if [[ ! -d '/ostree' ]]; then - printf >&2 '\e[31m%s\e[0m\n' 'OSTree could not be found in: /ostree' - return 1 - fi -} - -# [ENVIRONMENT]: BUILD DEPENDENCIES -function ENV_CREATE_DEPS { - # Skip in OSTree as filesystem is read-only - if ! ENV_VERIFY_LOCAL 2>/dev/null; then - pacman --noconfirm --sync --needed $@ - fi -} - -# [DISK]: PARTITIONING (GPT+UEFI) -function DISK_CREATE_LAYOUT { - ENV_CREATE_DEPS parted - mkdir -p ${OSTREE_SYS_ROOT} - lsblk --noheadings --output='MOUNTPOINTS' | grep -w ${OSTREE_SYS_ROOT} | xargs -r umount --lazy --verbose - parted -a optimal -s ${OSTREE_DEV_DISK} -- \ - mklabel gpt \ - mkpart ${OSTREE_SYS_BOOT_LABEL} fat32 0% 257MiB \ - set 1 esp on \ - mkpart ${OSTREE_SYS_ROOT_LABEL} xfs 257MiB 25GiB \ - mkpart ${OSTREE_SYS_HOME_LABEL} xfs 25GiB 100% -} - -# [DISK]: FILESYSTEM (ESP+XFS) -function DISK_CREATE_FORMAT { - ENV_CREATE_DEPS dosfstools xfsprogs - mkfs.vfat -n ${OSTREE_SYS_BOOT_LABEL} -F 32 ${OSTREE_DEV_BOOT} - mkfs.xfs -L ${OSTREE_SYS_ROOT_LABEL} -f ${OSTREE_DEV_ROOT} -n ftype=1 - mkfs.xfs -L ${OSTREE_SYS_HOME_LABEL} -f ${OSTREE_DEV_HOME} -n ftype=1 -} - -# [DISK]: BUILD DIRECTORY -function DISK_CREATE_MOUNTS { - mount --mkdir ${OSTREE_DEV_ROOT} ${OSTREE_SYS_ROOT} - mount --mkdir ${OSTREE_DEV_BOOT} ${OSTREE_SYS_ROOT}/boot/efi -} - -# [OSTREE]: FIRST INITIALIZATION -function OSTREE_CREATE_REPO { - ENV_CREATE_DEPS ostree which - ostree admin init-fs --sysroot="${OSTREE_SYS_ROOT}" --modern ${OSTREE_SYS_ROOT} - ostree admin stateroot-init --sysroot="${OSTREE_SYS_ROOT}" ${OSTREE_REP_NAME} - ostree init --repo="${OSTREE_SYS_ROOT}/ostree/repo" --mode='bare' - ostree config --repo="${OSTREE_SYS_ROOT}/ostree/repo" set sysroot.bootprefix 1 -} - -# [OSTREE]: BUILD ROOTFS -function OSTREE_CREATE_ROOTFS { - # Add support for overlay storage driver in LiveCD - if [[ $(df --output=fstype / | tail --lines 1) = 'overlay' ]]; then - ENV_CREATE_DEPS fuse-overlayfs - declare -x TMPDIR='/tmp/podman' - local PODMAN_OPT_GLOBAL=( - --root="${TMPDIR}/storage" - --tmpdir="${TMPDIR}/tmp" - ) - fi - - # Install Podman - ENV_CREATE_DEPS podman - - # Copy Pacman package cache into /var by default (to avoid duplication) - if [[ ${PACMAN_OPT_NOCACHE} == 0 ]]; then - mkdir -p "${TMPDIR:-}/var/cache/pacman" - local PODMAN_OPT_BUILD=( - --volume="${TMPDIR:-}/var/cache/pacman:${TMPDIR:-}/var/cache/pacman" - ) - fi - - # Skip Podman layer cache if requested - if [[ ${PODMAN_OPT_NOCACHE} == 1 ]]; then - local PODMAN_OPT_BUILD=( - ${PODMAN_OPT_BUILD[@]} - --no-cache='1' - ) - fi - - # Podman: create rootfs from multiple Containerfiles - for TARGET in ${PODMAN_OPT_BUILDFILE//,/ }; do - local PODMAN_OPT_IMG=(${TARGET%:*}) - local PODMAN_OPT_TAG=(${TARGET#*:}) - podman ${PODMAN_OPT_GLOBAL[@]} build \ - ${PODMAN_OPT_BUILD[@]} \ - --file="${PODMAN_OPT_IMG}" \ - --tag="${PODMAN_OPT_TAG}" \ - --cap-add='SYS_ADMIN' \ - --build-arg="OSTREE_SYS_BOOT_LABEL=${OSTREE_SYS_BOOT_LABEL}" \ - --build-arg="OSTREE_SYS_HOME_LABEL=${OSTREE_SYS_HOME_LABEL}" \ - --build-arg="OSTREE_SYS_ROOT_LABEL=${OSTREE_SYS_ROOT_LABEL}" \ - --build-arg="SYSTEM_OPT_TIMEZONE=${SYSTEM_OPT_TIMEZONE}" \ - --build-arg="SYSTEM_OPT_KEYMAP=${SYSTEM_OPT_KEYMAP}" \ - --pull='newer' - done - - # Ostreeify: retrieve rootfs (workaround: `podman build --output local` doesn't preserve ownership) - rm -rf ${OSTREE_SYS_TREE} - mkdir -p ${OSTREE_SYS_TREE} - podman ${PODMAN_OPT_GLOBAL[@]} export $(podman ${PODMAN_OPT_GLOBAL[@]} create ${PODMAN_OPT_TAG} bash) | tar -xC ${OSTREE_SYS_TREE} -} - -# [OSTREE]: DIRECTORY STRUCTURE (https://ostree.readthedocs.io/en/stable/manual/adapting-existing) -function OSTREE_CREATE_LAYOUT { - # Doing it here allows the container to be runnable/debuggable and Containerfile reusable - mv ${OSTREE_SYS_TREE}/etc ${OSTREE_SYS_TREE}/usr/ - - rm -r ${OSTREE_SYS_TREE}/home - ln -s var/home ${OSTREE_SYS_TREE}/home - - rm -r ${OSTREE_SYS_TREE}/mnt - ln -s var/mnt ${OSTREE_SYS_TREE}/mnt - - rm -r ${OSTREE_SYS_TREE}/opt - ln -s var/opt ${OSTREE_SYS_TREE}/opt - - rm -r ${OSTREE_SYS_TREE}/root - ln -s var/roothome ${OSTREE_SYS_TREE}/root - - rm -r ${OSTREE_SYS_TREE}/srv - ln -s var/srv ${OSTREE_SYS_TREE}/srv - - mkdir ${OSTREE_SYS_TREE}/sysroot - ln -s sysroot/ostree ${OSTREE_SYS_TREE}/ostree - - rm -r ${OSTREE_SYS_TREE}/usr/local - ln -s ../var/usrlocal ${OSTREE_SYS_TREE}/usr/local - - printf >&1 '%s\n' 'Creating tmpfiles' - echo 'd /var/home 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/lib 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/log/journal 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/mnt 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/opt 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/roothome 0700 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/srv 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/bin 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/etc 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/games 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/include 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/lib 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/man 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/sbin 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/share 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /var/usrlocal/src 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - echo 'd /run/media 0755 root root -' >> ${OSTREE_SYS_TREE}/usr/lib/tmpfiles.d/ostree-0-integration.conf - - # Only retain information about Pacman packages in new rootfs - mv ${OSTREE_SYS_TREE}/var/lib/pacman ${OSTREE_SYS_TREE}/usr/lib/ - sed -i \ - -e 's|^#\(DBPath\s*=\s*\).*|\1/usr/lib/pacman|g' \ - -e 's|^#\(IgnoreGroup\s*=\s*\).*|\1modified|g' \ - ${OSTREE_SYS_TREE}/usr/etc/pacman.conf - - # Allow Pacman to store update notice id during unlock mode - mkdir ${OSTREE_SYS_TREE}/usr/lib/pacmanlocal - - # OSTree mounts /ostree/deploy/${OSTREE_REP_NAME}/var to /var - rm -r ${OSTREE_SYS_TREE}/var/* -} - -# [OSTREE]: CREATE COMMIT -function OSTREE_DEPLOY_IMAGE { - # Update repository and boot entries in GRUB2 - ostree commit --repo="${OSTREE_SYS_ROOT}/ostree/repo" --branch="${OSTREE_REP_NAME}/latest" --tree=dir="${OSTREE_SYS_TREE}" - ostree admin deploy --sysroot="${OSTREE_SYS_ROOT}" --karg="root=LABEL=${OSTREE_SYS_ROOT_LABEL} rw ${OSTREE_SYS_KARG}" --os="${OSTREE_REP_NAME}" ${OSTREE_OPT_NOMERGE} --retain ${OSTREE_REP_NAME}/latest -} - -# [OSTREE]: UNDO COMMIT -function OSTREE_REVERT_IMAGE { - ostree admin undeploy --sysroot="${OSTREE_SYS_ROOT}" 0 -} - -# [BOOTLOADER]: FIRST BOOT -# | Todo: improve grub-mkconfig -function BOOTLOADER_CREATE { - grub-install --target='x86_64-efi' --efi-directory="${OSTREE_SYS_ROOT}/boot/efi" --boot-directory="${OSTREE_SYS_ROOT}/boot/efi/EFI" --bootloader-id="${OSTREE_REP_NAME}" --removable ${OSTREE_DEV_BOOT} - - local OSTREE_SYS_PATH=$(ls -d ${OSTREE_SYS_ROOT}/ostree/deploy/${OSTREE_REP_NAME}/deploy/* | head -n 1) - - rm -rfv ${OSTREE_SYS_PATH}/boot/* - mount --mkdir --rbind ${OSTREE_SYS_ROOT}/boot ${OSTREE_SYS_PATH}/boot - mount --mkdir --rbind ${OSTREE_SYS_ROOT}/ostree ${OSTREE_SYS_PATH}/sysroot/ostree - - for i in /dev /proc /sys; do mount -o bind $i ${OSTREE_SYS_PATH}${i}; done - chroot ${OSTREE_SYS_PATH} /bin/bash -c 'grub-mkconfig -o /boot/efi/EFI/grub/grub.cfg' - - umount --recursive ${OSTREE_SYS_ROOT} -} - -# [CLI]: TASK FINECONTROL -function CLI_SETUP { - CLI_ARGS=$(getopt \ - --alternative \ - --options='b:,c:,d:,f:,k:,t:,m::,n::,q::' \ - --longoptions='base-os:,cmdline:,dev:,file:,keymap:,time:,merge::,no-cache::,no-pacman-cache::,no-podman-cache::,quiet::' \ - --name="${0##*/}" \ - -- "${@}" - ) - - # Rewrite "${@}" - eval set -- "${CLI_ARGS}" - - # Arguments - while [[ ${#} > 0 ]]; do - CLI_ARG=${1:-} - CLI_VAL=${2:-} - - # Options - case ${CLI_ARG} in - '-b' | '--base-os') - declare -g OSTREE_REP_NAME=${CLI_VAL} - ;; - - '-c' | '--cmdline') - declare -g OSTREE_SYS_KARG=${CLI_VAL} - ;; - - '-d' | '--dev') - declare -g OSTREE_DEV_SCSI=${CLI_VAL} - ;; - - '-f' | '--file') - declare -g PODMAN_OPT_BUILDFILE=${CLI_VAL} - ;; - - '-k' | '--keymap') - declare -g SYSTEM_OPT_KEYMAP=${CLI_VAL} - ;; - - '-t' | '--time') - declare -g SYSTEM_OPT_TIMEZONE=${CLI_VAL} - ;; - esac - - # Switches - [[ ${CLI_VAL@L} == 'true' ]] && CLI_VAL='1' - [[ ${CLI_VAL@L} == 'false' ]] && CLI_VAL='0' - case ${CLI_ARG} in - '-m' | '--merge') - declare -g OSTREE_OPT_NOMERGE=${CLI_VAL:-} - ;; - - '-n' | '--no-cache') - declare -g PACMAN_OPT_NOCACHE=${CLI_VAL:-1} - declare -g PODMAN_OPT_NOCACHE=${CLI_VAL:-1} - ;; - - '--no-pacman-cache') - declare -g PACMAN_OPT_NOCACHE=${CLI_VAL:-1} - ;; - - '--no-podman-cache') - declare -g PODMAN_OPT_NOCACHE=${CLI_VAL:-1} - ;; - - '-q' | '--quiet') - declare -g CLI_QUIET=${CLI_VAL:-1} - ;; - esac - - # Commands - if [[ ${CLI_ARG} == '--' ]]; then - case ${CLI_VAL} in - 'install') - ENV_CREATE_OPTS - - DISK_CREATE_LAYOUT - DISK_CREATE_FORMAT - DISK_CREATE_MOUNTS - - OSTREE_CREATE_REPO - OSTREE_CREATE_ROOTFS - OSTREE_CREATE_LAYOUT - OSTREE_DEPLOY_IMAGE - - BOOTLOADER_CREATE - ;; - - 'upgrade') - ENV_VERIFY_LOCAL || exit $? - ENV_CREATE_OPTS - - OSTREE_CREATE_ROOTFS - OSTREE_CREATE_LAYOUT - OSTREE_DEPLOY_IMAGE - ;; - - 'revert') - ENV_VERIFY_LOCAL || exit $? - ENV_CREATE_OPTS - - OSTREE_REVERT_IMAGE - ;; - - *) - if [[ $(type -t ${CLI_VAL}) == 'function' ]]; then - ENV_CREATE_OPTS - ${CLI_VAL} - fi - ;;& - - * | 'help') - local USAGE=( - 'Usage:' - " ${0##*/} [options]" - 'Commands:' - ' install : (Create deployment) : Partitions, formats and initializes a new OSTree repository' - ' upgrade : (Update deployment) : Creates a new OSTree commit' - ' revert : (Update deployment) : Rolls back version 0' - 'Options:' - ' -b, --base-os string : (install/upgrade) : Name of OS to use as a base. Defaults to archlinux' - ' -c, --cmdline string : (install/upgrade) : List of kernel arguments for boot' - ' -d, --dev string : (install ) : Device SCSI (ID-LINK) for new installation' - ' -f, --file stringArray : (install/upgrade) : Containerfile(s) for new deployment' - ' -k, --keymap string : (install/upgrade) : TTY keyboard layout for new deployment' - ' -t, --time string : (install/upgrade) : Update host timezone for new deployment' - 'Switches:' - ' -m, --merge : ( upgrade) : Retain contents of /etc for existing deployment' - ' -n, --no-cache : (install/upgrade) : Skip any cached data (note: implied for first deployment)' - ' --no-pacman-cache : (install/upgrade) : Skip Pacman package cache' - ' --no-podman-cache : (install/upgrade) : Skip Podman layer cache' - ' -q, --quiet : (install/upgrade) : Reduce verbosity' - ) - printf >&1 '%s\n' "${USAGE[@]}" - - if [[ ${CLI_VAL} != 'help' && -n ${CLI_VAL} ]]; then - printf >&2 '\n%s\n' "${0##*/}: unrecognized command '${CLI_VAL}'" - exit 127 - fi - ;; - esac - break - fi - - # Continue to the next argument - shift 2 - done -} - -CLI_SETUP "${@}" diff --git a/post-install.sh b/post-install.sh new file mode 100755 index 0000000..e0a141a --- /dev/null +++ b/post-install.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Habilitar serviços do RAGlinux +systemctl enable sddm +systemctl enable NetworkManager +systemctl enable cockpit.socket +systemctl enable fwupd + +# Configurar usuário padrão +useradd -m -G wheel -s /bin/bash user +echo "user:user" | chpasswd + +# Configurações específicas do Plasma +echo "[General]" > /etc/sddm.conf +echo "DisplayServer=wayland" >> /etc/sddm.conf diff --git a/raglinux.sh b/raglinux.sh new file mode 100755 index 0000000..ac7d2fb --- /dev/null +++ b/raglinux.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +set -o errexit # Exit on non-zero status +set -o nounset # Error on unset variables + +# [ENVIRONMENT]: OVERRIDE DEFAULTS +function ENV_CREATE_OPTS { + if [[ ${CLI_QUIET:-} != 1 ]]; then + set -o xtrace # Print executed commands while performing tasks + fi + + if [[ ! -d '/ostree' ]]; then + # Do not touch disks in a booted system: + declare -g OSTREE_DEV_DISK=${OSTREE_DEV_DISK:="/dev/disk/by-id/${OSTREE_DEV_SCSI}"} + declare -g OSTREE_DEV_BOOT=${OSTREE_DEV_BOOT:="${OSTREE_DEV_DISK}-part1"} + declare -g OSTREE_DEV_ROOT=${OSTREE_DEV_ROOT:="${OSTREE_DEV_DISK}-part2"} + declare -g OSTREE_SYS_ROOT=${OSTREE_SYS_ROOT:='/tmp/chroot'} + fi + + declare -g OSTREE_SYS_ROOT=${OSTREE_SYS_ROOT:='/'} + declare -g OSTREE_SYS_TREE=${OSTREE_SYS_TREE:='/tmp/rootfs'} + declare -g OSTREE_SYS_KARG=${OSTREE_SYS_KARG:=''} + declare -g OSTREE_SYS_BOOT_LABEL=${OSTREE_SYS_BOOT_LABEL:='SYS_BOOT'} + declare -g OSTREE_SYS_ROOT_LABEL=${OSTREE_SYS_ROOT_LABEL:='SYS_ROOT'} + declare -g OSTREE_OPT_NOMERGE=${OSTREE_OPT_NOMERGE='--no-merge'} + declare -g OSTREE_REP_NAME=${OSTREE_REP_NAME:='archlinux'} + + # Timezone and Keymap are now hardcoded in Containerfile.base + # and no longer need to be set here. + + declare -g PODMAN_OPT_BUILDFILE=${PODMAN_OPT_BUILDFILE:="${0%/*}/Containerfile.base:ostree/base","${0%/*}/Containerfile.host.example:ostree/host"} + declare -g PODMAN_OPT_NOCACHE=${PODMAN_OPT_NOCACHE:='0'} + declare -g PACMAN_OPT_NOCACHE=${PACMAN_OPT_NOCACHE:='0'} +} + + +# [ENVIRONMENT]: OSTREE CHECK +function ENV_VERIFY_LOCAL { + if [[ ! -d '/ostree' ]]; then + printf >&2 '\e[31m%s\e[0m\n' 'OSTree could not be found in: /ostree' + return 1 + fi +} + +# [ENVIRONMENT]: BUILD DEPENDENCIES +function ENV_CREATE_DEPS { + # Skip in OSTree as filesystem is read-only + if ! ENV_VERIFY_LOCAL 2>/dev/null; then + pacman --noconfirm --sync --needed $@ + fi +} + +# [DISK]: PARTITIONING (GPT+UEFI) for Btrfs +function DISK_CREATE_LAYOUT { + ENV_CREATE_DEPS parted + mkdir -p ${OSTREE_SYS_ROOT} + lsblk --noheadings --output='MOUNTPOINTS' | grep -w ${OSTREE_SYS_ROOT} | xargs -r umount --lazy --verbose + parted -a optimal -s ${OSTREE_DEV_DISK} -- \ + mklabel gpt \ + mkpart ${OSTREE_SYS_BOOT_LABEL} fat32 0% 257MiB \ + set 1 esp on \ + mkpart ${OSTREE_SYS_ROOT_LABEL} btrfs 257MiB 100% +} + +# [DISK]: FILESYSTEM (ESP+Btrfs) with Subvolumes +function DISK_CREATE_FORMAT { + ENV_CREATE_DEPS dosfstools btrfs-progs + mkfs.vfat -n ${OSTREE_SYS_BOOT_LABEL} -F 32 ${OSTREE_DEV_BOOT} + mkfs.btrfs -L ${OSTREE_SYS_ROOT_LABEL} -f ${OSTREE_DEV_ROOT} + + # Create Btrfs subvolumes for root and home + mount ${OSTREE_DEV_ROOT} ${OSTREE_SYS_ROOT} + btrfs subvolume create ${OSTREE_SYS_ROOT}/@ + btrfs subvolume create ${OSTREE_SYS_ROOT}/@home + umount ${OSTREE_SYS_ROOT} +} + +# [DISK]: BUILD DIRECTORY with Btrfs Subvolumes +function DISK_CREATE_MOUNTS { + # Mount root subvolume + mount -o compress=zstd,subvol=@ ${OSTREE_DEV_ROOT} ${OSTREE_SYS_ROOT} + # Mount boot partition + mount --mkdir ${OSTREE_DEV_BOOT} ${OSTREE_SYS_ROOT}/boot/efi + # Mount home subvolume + mkdir -p ${OSTREE_SYS_ROOT}/home + mount -o compress=zstd,subvol=@home ${OSTREE_DEV_ROOT} ${OSTREE_SYS_ROOT}/home +} + +# [OSTREE]: FIRST INITIALIZATION +function OSTREE_CREATE_REPO { + ENV_CREATE_DEPS ostree which + ostree admin init-fs --sysroot="${OSTREE_SYS_ROOT}" --modern ${OSTREE_SYS_ROOT} + ostree admin stateroot-init --sysroot="${OSTREE_SYS_ROOT}" ${OSTREE_REP_NAME} + ostree init --repo="${OSTREE_SYS_ROOT}/ostree/repo" --mode='bare' + ostree config --repo="${OSTREE_SYS_ROOT}/ostree/repo" set sysroot.bootprefix 1 +} + +# [OSTREE]: BUILD ROOTFS +function OSTREE_CREATE_ROOTFS { + # Add support for overlay storage driver in LiveCD + if [[ $(df --output=fstype / | tail --lines 1) = 'overlay' ]]; then + ENV_CREATE_DEPS fuse-overlayfs + declare -x TMPDIR='/tmp/podman' + local PODMAN_OPT_GLOBAL=( + --root="${TMPDIR}/storage" + --tmpdir="${TMPDIR}/tmp" + ) + fi + + # Install Podman + ENV_CREATE_DEPS podman + + # Copy Pacman package cache into /var by default (