Continuação — chroot
No imenso post anterior, Breakdown — meu script de instalação do Arch pt. 1 (archinstall.sh), expliquei toda a primeira etapa do meu script de instalação do Arch: desde a coleta de informações e preparação do disco até a instalação do sistema base e a entrada no ambiente chroot. Este artigo continua exatamente desse ponto, detalhando a configuração final do sistema antes da primeira inicialização.
Vale ressaltar um ponto importante do post anterior: este script não é executado manualmente; o archinstall.sh é responsável por chamá-lo automaticamente. Nesse momento, ele já está rodando dentro do chroot, ou seja, todo comando executado aqui modifica diretamente o sistema que será inicializado depois. É nesta etapa que é definido como o sistema irá se comportar de verdade: bootloader, locale, usuários, serviços e assim por diante.
Uma curiosidade interessante é que, nesse ambiente, não existe nenhum sistema init em execução — ou seja, não há um processo PID 1 gerenciando serviços. Isso significa que comandos como systemctl start não funcionariam.
Novamente, o link para o repositório contendo o código discutido neste post:
Shebang, set -euo, source e logs
Nada de novo por aqui: são as mesmas linhas presentes no archinstall.sh, já explicadas no post anterior.
#!/usr/bin/env bash
# Stage 2 — executed inside arch-chroot by archinstall.sh. Not meant to be run standalone.
set -euo pipefail
cd /root
source ./config.sh
source ./.archinstall_secrets
log() { echo -e "\n==> $*"; }
err() { echo "ERROR: $*" >&2; }
Primeiro, declaramos a shebang para que o script seja executado com o Bash. Em seguida, ativamos opções que o tornam mais seguro — por exemplo, encerrando sua execução caso algum comando falhe. Depois, entramos no diretório /root, onde estão os arquivos necessários, importamos as configurações de config.sh e .archinstall_secrets e, por fim, definimos duas funções simples para registrar mensagens de log e de erro.
Na prática, é exatamente a mesma estrutura do archinstall.sh, então não há muito de novo para explorar aqui.
enable_locale
Fora log() e err(), enable_locale() é a única outra função presente neste script.
enable_locale() {
local locale="$1"
if grep -qE "^${locale} UTF-8" /etc/locale.gen; then
return
elif grep -qE "^#${locale} UTF-8" /etc/locale.gen; then
sed -i "s/^#${locale} UTF-8/${locale} UTF-8/" /etc/locale.gen
else
echo "${locale} UTF-8" >> /etc/locale.gen
fi
}
Locale é a configuração que informa ao sistema em qual idioma e formato regional exibir informações como datas, números, moedas, entre outras. O arquivo /etc/locale.gen lista todos os locales que o sistema pode gerar. Por padrão, praticamente todos vêm comentados, ou seja, desativados.
Esta função lida com os três estados possíveis desse arquivo:
- O locale já está habilitado.
if grep -qE "^${locale} UTF-8" /etc/locale.gen; then return→grepprocura uma linha que corresponde exatamente ao conteúdo de$locale. Se encontrar, significa que o locale já está habilitado, então a função simplesmente retorna.
- O locale existe, mas está comentado.
elif ... sed -i "s/^#${locale} UTF-8/${locale} UTF-8/" /etc/locale.gen→grepprocura o mesmo padrão do caso anterior, mas com#no início da linha, indicando que o locale está desabilitado. Em seguida,sed -iremove o#, habilitando o locale.
- O locale nem sequer aparece no arquivo.
else echo "${locale} UTF-8" >> /etc/locale.gen→ Se nenhuma das verificações anteriores encontrar o locale, significa que ele não existe em/etc/locale.gen. Nesse caso,>>adiciona uma nova linha ao final do arquivo contendo o locale.
Como complemento, grep é um comando utilizado para procurar linhas em um arquivo que correspondam a um padrão especificado. Já sed é um editor de texto não interativo; a flag -i modifica o próprio arquivo (in-place), em vez de apenas imprimir o resultado no terminal.
O padrão de substituição do sed é semelhante ao do vim: s/padrão/substituição/, em que s significa substitute (substituir).
timezone, hwclock e locale-gen
log "Setting timezone"
ln -sf "/usr/share/zoneinfo/${TIMEZONE}" /etc/localtime
hwclock --systohc
log "Generating locale"
enable_locale "$LOCALE_LANG"
[[ "$LOCALE_REGIONAL" != "$LOCALE_LANG" ]] && enable_locale "$LOCALE_REGIONAL"
locale-gen
cat > /etc/locale.conf <<EOF
LANG=${LOCALE_LANG}
LC_TIME=${LOCALE_REGIONAL}
LC_MONETARY=${LOCALE_REGIONAL}
LC_PAPER=${LOCALE_REGIONAL}
LC_MEASUREMENT=${LOCALE_REGIONAL}
LC_NAME=${LOCALE_REGIONAL}
LC_ADDRESS=${LOCALE_REGIONAL}
LC_TELEPHONE=${LOCALE_REGIONAL}
EOF
ln -sf "/usr/share/zoneinfo/${TIMEZONE}" /etc/localtime → Cria um link simbólico em /etc/localtime apontando para o timezone definido em config.sh. O timezone informa ao sistema como interpretar e exibir o horário local, definindo regras como o deslocamento em relação ao UTC (por exemplo, UTC-3), horário de verão e mudanças históricas do fuso.
hwclock --systohc → Computadores possuem dois relógios: o RTC (Real-Time Clock) e o System Clock. O RTC é um pequeno chip na placa-mãe, alimentado pela bateria, que continua contando o tempo mesmo com o computador desligado. Já o System Clock é mantido pelo kernel enquanto o sistema está em execução. Durante o boot, o Linux inicializa o System Clock a partir do RTC e, a partir desse momento, passa a utilizar apenas o relógio do sistema. O comando hwclock --systohc faz o caminho inverso: grava a hora atual do System Clock no RTC. Isso garante que, após ajustar a hora do sistema (por exemplo, via NTP) ou configurar o timezone, o relógio de hardware também permaneça sincronizado para o próximo boot.
enable_locale "$LOCALE_LANG" e [[ "$LOCALE_REGIONAL" != "$LOCALE_LANG" ]] && enable_locale "$LOCALE_REGIONAL" → Na primeira linha, enable_locale garante que o locale definido em LOCALE_LANG esteja habilitado em /etc/locale.gen. A segunda linha faz uma comparação entre LOCALE_REGIONAL e LOCALE_LANG; caso sejam diferentes, o script executa enable_locale novamente, dessa vez passando o locale regional. Isso é necessário porque é comum utilizar uma combinação em que o idioma principal do sistema é diferente das configurações regionais. Por exemplo, alguém pode preferir a interface do sistema em inglês, mas utilizar formato brasileiro para moeda, datas, medidas e outros padrões regionais.
locale-gen → Como explicado anteriormente, locale indica ao sistema como interpretar informações como moeda, datas, números, entre outras. O arquivo /etc/locale.gen apenas informa quais locales devem ser gerados; já o comando locale-gen é o responsável por efetivamente gerá-los.
cat > /etc/locale.conf <<EOF ... → Surge então uma dúvida natural: se acabamos de gerar os locales, por que ainda precisamos de um locale.conf? A resposta é que locale-gen apenas torna esses locales disponíveis para o sistema. Ainda é necessário escolher qual deles será utilizado por padrão. É justamente essa a função do /etc/locale.conf: definir o locale padrão do sistema (LANG) e, se desejado, sobrescrever configurações específicas por meio das variáveis LC_*, como formato de datas, moeda e unidades de medida.
- E como não comentei anteriormente,
<<EOFtorna possível escrever o conteúdo de forma multilinha diretamente no arquivo. Esse recurso é chamado de heredoc (here document). Tudo que estiver entre o<<EOFe oEOFfinal será interpretado como entrada para o comando anterior. Nesse caso, o operador>redireciona esse conteúdo para/etc/locale.conf, criando ou sobrescrevendo o arquivo.
vconsole.conf, hostname, localhost, NetworkManager e root password
No trecho a seguir, o teclado é configurado para os TTYs (por exemplo, quando usamos CTRL+ALT+F1, F2 etc. para abrir um terminal virtual). Em seguida, são configuradas informações de rede e identificação do sistema, como o hostname e a resolução local via /etc/hosts. Depois, o serviço do NetworkManager é habilitado no systemd, permitindo que ele gerencie as conexões de rede durante a inicialização. Por fim, a senha do usuário root é alterada.
log "Setting console keymap"
echo "KEYMAP=${KEYMAP_CONSOLE}" > /etc/vconsole.conf
log "Setting hostname"
echo "$HOSTNAME" > /etc/hostname
cat > /etc/hosts <<EOF
127.0.0.1 localhost
::1 localhost
127.0.1.1 ${HOSTNAME}.localdomain ${HOSTNAME}
EOF
log "Enabling NetworkManager"
systemctl enable NetworkManager
log "Setting root password"
echo "root:${ROOT_PASSWORD}" | chpasswd
echo "KEYMAP=${KEYMAP_CONSOLE}" > /etc/vconsole.conf → Escreve em /etc/vconsole.conf a configuração responsável por mapear o teclado correto no TTY, utilizando o valor de KEYMAP_CONSOLE declarado em config.sh.
echo "$HOSTNAME" > /etc/hostname → Define o hostname da máquina, utilizando o valor declarado em config.sh.
cat > /etc/hosts <<EOF ... → Configura o arquivo /etc/hosts, responsável por mapear nomes de máquinas para endereços IP localmente. Nesse caso, ele associa o hostname da máquina ao endereço local, permitindo que o próprio sistema resolva seu nome sem depender de um servidor DNS.
systemctl enable NetworkManager → Habilita o serviço NetworkManager para iniciar automaticamente junto com o sistema. O NetworkManager é responsável por gerenciar as conexões de rede.
echo "root:${ROOT_PASSWORD}" | chpasswd → Altera a senha do usuário root utilizando o comando chpasswd, que recebe a nova senha pela entrada padrão e aplica a alteração sem precisar de uma confirmação interativa.
useradd, sudoers, wheel
Aqui se refere a criação de um usuário, inclusão do diretório sudoers.d (se não estiver incluso no arquivo sudoers) e habilitar o wheel do Arch para permitir a utilização do comando sudo para os usuários deste grupo (rodar comandos com privilégios de root).
O wheel no Arch é um grupo de usuários. Grupos em Linux servem para aplicar permissoes em conjunto. No caso do wheel, tradicionalmente significa que usuários desse grupo possuem privilégios administrativos.
log "Creating user $USERNAME"
useradd -m -G "$USER_GROUPS" -s /bin/bash "$USERNAME"
echo "${USERNAME}:${USER_PASSWORD}" | chpasswd
log "Configuring sudo for wheel group"
if ! grep -qE '^[#@]includedir /etc/sudoers.d' /etc/sudoers; then
echo "@includedir /etc/sudoers.d" >> /etc/sudoers
fi
echo "%wheel ALL=(ALL:ALL) ALL" > /etc/sudoers.d/99-wheel
chmod 440 /etc/sudoers.d/99-wheel
if ! visudo -cf /etc/sudoers.d/99-wheel; then
err "Generated sudoers drop-in failed validation; removing it."
rm -f /etc/sudoers.d/99-wheel
exit 1
fi
useradd -m -G "$USER_GROUPS" -s /bin/bash "$USERNAME" → Cria um novo usuário no sistema.
-m→ Cria o diretóriohome-G→ Define os grupos dos quais o usuário fará parte (configurado emconfig.sh).-s→ Define oshellpadrão do usuário como/bin/bash.
if ! grep -qE '^[#@]includedir /etc/sudoers.d' /etc/sudoers; then e echo "@includedir /etc/sudoers.d" >> /etc/sudoers → Verifica se o arquivo principal de configuração do sudo, /etc/sudoers, já possui a referência ao diretório /etc/sudoers.d/. Caso essa configuração não exista, ela é adicionada ao final do arquivo. Essa diretiva permite que o sudo carregue arquivos adicionais de configuração presentes dentro do diretório /etc/sudoers.d/, como o arquivo 99-wheel criado posteriormente pelo script.
!→ Inverte o resultado dogrep, fazendo o bloco executar caso o padrão não seja encontrado.^[#@]includedir /etc/sudoers.d→ Padrão procurado:^indica início da linha,[#@]indica que pode começar com#ou@, e o restante é o texto buscado.
echo "%wheel ALL=(ALL:ALL) ALL" > /etc/sudoers.d/99-wheel → Cria o arquivo 99-wheel dentro do diretório /etc/sudoers.d/ contendo uma regra para o grupo wheel. O símbolo % indica que wheel é um grupo, e a regra permite que qualquer usuário pertencente a esse grupo execute qualquer comando utilizando sudo, com privilégios de qualquer usuário e grupo (incluindo root).
%wheel→ Todos os usuários pertencentes ao grupowheel.ALL=...→ Em qualquer máquina (relevante em ambientes com configurações compartilhadas).(ALL:ALL)→ Podem executar comandos como qualquer usuário e grupo.ALL→ Podem executar qualquer comando.
chmod 440 /etc/sudoers.d/99-wheel → Garante permissão de leitura somente para o dono do arquivo e para integrantes do grupo. Demais usuários não possuem acesso ao arquivo. Essa é uma diretiva importante de segurança, pois impede que usuários sem privilégios alterem a configuração do sudo e concedam permissões administrativas a si mesmos.
if ! visudo -cf /etc/sudoers.d/99-wheel; then e rm -f /etc/sudoers.d/99-wheel → Valida se o arquivo 99-wheel possui uma sintaxe correta. Caso a validação falhe, o arquivo é removido e o script é encerrado, evitando deixar uma configuração inválida do sudo.
visudo -cf→ Ferramenta utilizada para editar e validar arquivos de configuração dosudo.-cverifica a sintaxe, sem editar o arquivo.-fespecifica o arquivo que será validado.rm -f→ Remove o arquivo sem pedir confirmação (se estiver invalida a configuração).
GRUB
GRUB (GRand Unified Bootloader) é um bootloader, ou seja, sua única função é carregar o sistema operacional.
O GRUB é extremamente importante, pois ele faz a ponte entre o firmware da máquina (BIOS ou UEFI) e o kernel do Linux.
O fluxo típico quando um computador liga é o seguinte: Liga o computador → BIOS/UEFI → GRUB → Kernel do Linux → systemd (PID 1) → Sistema operacional.
log "Installing GRUB ($BOOT_MODE)"
if [[ "$BOOT_MODE" == "uefi" ]]; then
if ! grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB; then
log "Standard GRUB install failed, retrying with --removable (NVRAM likely unavailable, e.g. some VM firmwares)"
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB --removable
fi
else
grub-install --target=i386-pc "$DISK"
fi
grub-mkconfig -o /boot/grub/grub.cfg
O script verifica o valor de BOOT_MODE. Se for uefi, instala o GRUB para sistemas UEFI, informando onde a partição EFI está montada (/boot). Caso essa instalação falhe (algo comum em algumas máquinas virtuais, onde não é possível registrar uma entrada de boot na NVRAM), o script tenta novamente utilizando a flag --removable, que instala o bootloader em um caminho padrão reconhecido pelo firmware UEFI.
Se BOOT_MODE não for uefi, o script assume que o sistema foi iniciado em modo BIOS legado (Legacy BIOS) e instala a versão correspondente do GRUB diretamente no disco especificado por DISK.
Por fim, grub-mkconfig -o /boot/grub/grub.cfg gera o arquivo de configuração do GRUB (grub.cfg), responsável por definir as entradas do menu de boot e informar ao GRUB qual kernel e initramfs devem ser carregados durante a inicialização.
Cinnamon LightDM, xorg keyboard
Neste trecho, o script verifica se o ambiente gráfico escolhido foi o Cinnamon. Caso tenha sido, habilita o LightDM (gerenciador de login gráfico) para iniciar automaticamente junto com o sistema. Em seguida, cria o diretório de configuração do Xorg (caso ainda não exista) e escreve um arquivo contendo o layout e o modelo do teclado, utilizando os valores definidos em config.sh.
if [[ "$DESKTOP_ENV" == "cinnamon" ]]; then
log "Enabling LightDM"
systemctl enable lightdm
mkdir -p /etc/X11/xorg.conf.d
cat > /etc/X11/xorg.conf.d/00-keyboard.conf <<EOF
Section "InputClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
Option "XkbLayout" "${KEYMAP_X11_LAYOUT}"
Option "XkbModel" "${KEYMAP_X11_MODEL}"
EndSection
EOF
fi
DETECTED_VIRT
Por fim, o script verifica se está sendo executado dentro de uma máquina virtual. Dependendo do ambiente detectado, habilita automaticamente o serviço correspondente: VirtualBox Guest Services para VirtualBox ou QEMU Guest Agent para máquinas virtuais QEMU/KVM. Esses serviços são responsáveis por habilitar funcionalidades específicas das plataformas de virtualização detectadas, garantindo que o sistema funcione corretamente nesse ambiente.
case "$DETECTED_VIRT" in
oracle)
log "Enabling VirtualBox guest services"
systemctl enable vboxservice
;;
kvm|qemu)
log "Enabling QEMU guest agent"
systemctl enable qemu-guest-agent
;;
esac
log "Chroot setup finished"
Ao final, o script imprime a mensagem Chroot setup finished, indicando que toda a configuração realizada dentro do chroot foi concluída e o sistema está pronto para ser inicializado.
Considerações finais
Com certeza foram dois posts enormes e cheios de conteúdo. Embora eu já tivesse instalado o Arch Linux manualmente dezenas de vezes, o processo de automatizar essa instalação por meio de um script me mostrou diversas camadas novas e edge cases que precisam ser tratados corretamente.
Além disso, entender todo esse processo me proporcionou uma compreensão muito mais profunda sobre os fundamentos de sistemas operacionais e scripting. Mais do que aprender a instalar uma distribuição Linux, esse conhecimento desenvolveu uma habilidade transferível para diversas outras áreas da computação.
Agora, uma mudança que talvez eu vá fazer em breve neste script é a possibilidade de criar o home separado em outra partição — dessa forma eu poderia trocar de distribuição ou reinstalar o sistema base caso necessário sem a necessidade de mexer nos meus dados.
Enfim, o script me proporciona uma forma muito portátil e eficiente de replicar meu ambiente Arch em qualquer computador, tendo que lidar menos com máquinas com configurações diferentes, ou tendo que frequentemente pesquisar comandos como instalação do GRUB para UEFI ou BIOS ou até mesmo a necessidade de configurar locale, wheel, etc.