O único propósito de um initramfs é o do montar o sistema de arquivos raiz. O initramfs é um conjunto completo de diretórios que você encontraria em um sistema de arquivos raiz normal. Ele é agrupado em um arquivamento cpio e comprimido com um dos vários algoritmos de compressão.
Ao tempo da inicialização, o carregador de inicialização carrega o núcleo e a imagem initramfs na memória e inicia o núcleo. O núcleo verifica a presença do initramfs e, se encontrado, o monta como / e executa /init. O aplicativo init é tipicamente um script de shell. Observe que o processo de inicialização leva mais tempo, possivelmente significativamente mais, se um initramfs for usado.
Para a maioria das distribuições, os módulos do núcleo são a maior razão para ter um initramfs. Em uma distribuição geral, existem muitas incógnitas, como tipos de sistema de arquivos e esquemas de disco. De certa forma, isso é o oposto do LFS, onde os recursos e o esquema do sistema são conhecidos e um núcleo personalizado normalmente é construído. Nessa situação, um initramfs raramente é necessário.
Existem somente quatro razões principais para se ter um initramfs no ambiente LFS: carregar o rootfs a partir de uma rede; carregá-lo a partir de um volume lógico LVM; ter um rootfs encriptado onde uma senha seja exigida; ou para a conveniência de se especificar o rootfs como um RÓTULO ou como um UUID. Qualquer outra coisa geralmente significa que o núcleo não foi configurado adequadamente.
Se você decidir construir um initramfs, [então] os scripts a seguir fornecerão uma base para isso. Os scripts permitirão especificar um rootfs via partição UUID ou partição RÓTULO ou um rootfs em um volume lógico LVM. Eles não suportam um sistema de arquivos raiz encriptado ou montar o rootfs passando por uma placa de rede de comunicação. Para uma capacidade mais completa, vejam-se as Dicas do LFS ou dracut.
Para instalar estes scripts, execute os seguintes comandos como
o(a) usuário(a) root
:
cat > /usr/sbin/mkinitramfs << "EOF"
#!/bin/bash
# Este arquivo é baseado em parte no script mkinitramfs para o LiveCD do LFS
# escrito por Alexander E. Patrakov e Jeremy Huntwork.
copy()
{
local file
if [ "$2" = "lib" ]; then
file=$(PATH=/usr/lib type -p $1)
else
file=$(type -p $1)
fi
if [ -n "$file" ] ; then
cp $file $WDIR/usr/$2
else
echo "Ausente arquivo exigido: $1 para o diretório $2"
rm -rf $WDIR
exit 1
fi
}
if [ -z $1 ] ; then
INITRAMFS_FILE=initrd.img-no-kmods
else
KERNEL_VERSION=$1
INITRAMFS_FILE=initrd.img-$KERNEL_VERSION
fi
if [ -n "$KERNEL_VERSION" ] && [ ! -d "/usr/lib/modules/$1" ] ; then
echo "Sem diretório dos módulos chamado $1"
exit 1
fi
printf "Criando $INITRAMFS_FILE... "
binfiles="sh cat cp dd killall ls mkdir mknod mount "
binfiles="$binfiles umount sed sleep ln rm uname"
binfiles="$binfiles readlink basename"
# O systemd instala udevadm em /bin. Outras implementações do udev o tem em /sbin
if [ -x /usr/bin/udevadm ] ; then binfiles="$binfiles udevadm"; fi
sbinfiles="modprobe blkid switch_root"
# Arquivos e locais opcionais
for f in mdadm mdmon udevd udevadm; do
if [ -x /usr/sbin/$f ] ; then sbinfiles="$sbinfiles $f"; fi
done
# Adiciona lvm se presente (não pode ser feito com os outros, pois
# também precisa do dmsetup
if [ -x /usr/sbin/lvm ] ; then sbinfiles="$sbinfiles lvm dmsetup"; fi
unsorted=$(mktemp /tmp/unsorted.XXXXXXXXXX)
DATADIR=/usr/share/mkinitramfs
INITIN=init.in
# Cria um diretório temporário de trabalho
WDIR=$(mktemp -d /tmp/initrd-work.XXXXXXXXXX)
# Cria a estrutura básica de diretório
mkdir -p $WDIR/{dev,run,sys,proc,usr/{bin,lib/{firmware,modules},sbin}}
mkdir -p $WDIR/etc/{modprobe.d,udev/rules.d}
touch $WDIR/etc/modprobe.d/modprobe.conf
ln -s usr/bin $WDIR/bin
ln -s usr/lib $WDIR/lib
ln -s usr/sbin $WDIR/sbin
ln -s lib $WDIR/lib64
# Cria os nós necessários de dispositivo
mknod -m 640 $WDIR/dev/console c 5 1
mknod -m 664 $WDIR/dev/null c 1 3
# Instala os arquivos de configuração do udev
if [ -f /etc/udev/udev.conf ]; then
cp /etc/udev/udev.conf $WDIR/etc/udev/udev.conf
fi
for file in $(find /etc/udev/rules.d/ -type f) ; do
cp $file $WDIR/etc/udev/rules.d
done
# Instala quaisquer firmware presentes
cp -a /usr/lib/firmware $WDIR/usr/lib
# Copia o arquivo de configuração RAID se presente
if [ -f /etc/mdadm.conf ] ; then
cp /etc/mdadm.conf $WDIR/etc
fi
# Instala o arquivo init
install -m0755 $DATADIR/$INITIN $WDIR/init
if [ -n "$KERNEL_VERSION" ] ; then
if [ -x /usr/bin/kmod ] ; then
binfiles="$binfiles kmod"
else
binfiles="$binfiles lsmod"
sbinfiles="$sbinfiles insmod"
fi
fi
# Instala binários básicos
for f in $binfiles ; do
ldd /usr/bin/$f | sed "s/\t//" | cut -d " " -f1 >> $unsorted
copy /usr/bin/$f bin
done
for f in $sbinfiles ; do
ldd /usr/sbin/$f | sed "s/\t//" | cut -d " " -f1 >> $unsorted
copy $f sbin
done
# Adiciona bibliotecas do udevd se não em /usr/sbin
if [ -x /usr/lib/udev/udevd ] ; then
ldd /usr/lib/udev/udevd | sed "s/\t//" | cut -d " " -f1 >> $unsorted
elif [ -x /usr/lib/systemd/systemd-udevd ] ; then
ldd /usr/lib/systemd/systemd-udevd | sed "s/\t//" | cut -d " " -f1 >> $unsorted
fi
# Adiciona links simbólicos de módulo se apropriado
if [ -n "$KERNEL_VERSION" ] && [ -x /usr/bin/kmod ] ; then
ln -s kmod $WDIR/usr/bin/lsmod
ln -s kmod $WDIR/usr/bin/insmod
fi
# Adiciona links simbólicos do lvm se apropriado
# Também copia o arquivo lvm.conf
if [ -x /usr/sbin/lvm ] ; then
ln -s lvm $WDIR/usr/sbin/lvchange
ln -s lvm $WDIR/usr/sbin/lvrename
ln -s lvm $WDIR/usr/sbin/lvextend
ln -s lvm $WDIR/usr/sbin/lvcreate
ln -s lvm $WDIR/usr/sbin/lvdisplay
ln -s lvm $WDIR/usr/sbin/lvscan
ln -s lvm $WDIR/usr/sbin/pvchange
ln -s lvm $WDIR/usr/sbin/pvck
ln -s lvm $WDIR/usr/sbin/pvcreate
ln -s lvm $WDIR/usr/sbin/pvdisplay
ln -s lvm $WDIR/usr/sbin/pvscan
ln -s lvm $WDIR/usr/sbin/vgchange
ln -s lvm $WDIR/usr/sbin/vgcreate
ln -s lvm $WDIR/usr/sbin/vgscan
ln -s lvm $WDIR/usr/sbin/vgrename
ln -s lvm $WDIR/usr/sbin/vgck
# Arquivo(s) de configuração
cp -a /etc/lvm $WDIR/etc
fi
# Instala bibliotecas
sort $unsorted | uniq | while read library ; do
# linux-vdso e linux-gate são pseudo bibliotecas e não correspondem a um arquivo
# libsystemd-shared está em /lib/systemd, de forma que não é encontrada pela cópia, e
# é copiada abaixo de qualquer forma
if [[ "$library" == linux-vdso.so.1 ]] ||
[[ "$library" == linux-gate.so.1 ]] ||
[[ "$library" == libsystemd-shared* ]]; then
continue
fi
copy $library lib
done
if [ -d /usr/lib/udev ]; then
cp -a /usr/lib/udev $WDIR/usr/lib
fi
if [ -d /usr/lib/systemd ]; then
cp -a /usr/lib/systemd $WDIR/usr/lib
fi
if [ -d /usr/lib/elogind ]; then
cp -a /usr/lib/elogind $WDIR/usr/lib
fi
# Instala os módulos do núcleo se solicitado
if [ -n "$KERNEL_VERSION" ]; then
find \
/usr/lib/modules/$KERNEL_VERSION/kernel/{crypto,fs,lib} \
/usr/lib/modules/$KERNEL_VERSION/kernel/drivers/{block,ata,nvme,md,firewire} \
/usr/lib/modules/$KERNEL_VERSION/kernel/drivers/{scsi,message,pcmcia,virtio} \
/usr/lib/modules/$KERNEL_VERSION/kernel/drivers/usb/{host,storage} \
-type f 2> /dev/null | cpio --make-directories -p --quiet $WDIR
cp /usr/lib/modules/$KERNEL_VERSION/modules.{builtin,order} \
$WDIR/usr/lib/modules/$KERNEL_VERSION
if [ -f /usr/lib/modules/$KERNEL_VERSION/modules.builtin.modinfo ]; then
cp /usr/lib/modules/$KERNEL_VERSION/modules.builtin.modinfo \
$WDIR/usr/lib/modules/$KERNEL_VERSION
fi
depmod -b $WDIR $KERNEL_VERSION
fi
( cd $WDIR ; find . | cpio -o -H newc --quiet | gzip -9 ) > $INITRAMFS_FILE
# Prepare o carregamento antecipado do micro código se disponível
if ls /usr/lib/firmware/intel-ucode/* >/dev/null 2>&1 ||
ls /usr/lib/firmware/amd-ucode/* >/dev/null 2>&1; then
# Primeiro, esvazia WDIR para reusá-lo
rm -r $WDIR/*
DSTDIR=$WDIR/kernel/x86/microcode
mkdir -p $DSTDIR
if [ -d /usr/lib/firmware/amd-ucode ]; then
cat /usr/lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
fi
if [ -d /usr/lib/firmware/intel-ucode ]; then
cat /usr/lib/firmware/intel-ucode/* > $DSTDIR/GenuineIntel.bin
fi
( cd $WDIR; find . | cpio -o -H newc --quiet ) > microcode.img
cat microcode.img $INITRAMFS_FILE > tmpfile
mv tmpfile $INITRAMFS_FILE
rm microcode.img
fi
# Remove os arquivos e diretórios temporários
rm -rf $WDIR $unsorted
printf "done.\n"
EOF
chmod 0755 /usr/sbin/mkinitramfs
mkdir -p /usr/share/mkinitramfs &&
cat > /usr/share/mkinitramfs/init.in << "EOF"
#!/bin/sh
PATH=/usr/bin:/usr/sbin
export PATH
problem()
{
printf "Encontrado um problema!\n\nDeixando você em um shell.\n\n"
sh
}
no_device()
{
printf "O dispositivo %s, que se presume conter o\n" $1
printf "sistema de arquivos raiz, não existe.\n"
printf "Por favor, corrija esse problema e saia deste shell.\n\n"
}
no_mount()
{
printf "Não poderia montar o dispositivo %s\n" $1
printf "Dormindo para sempre. Por favor, reinicialize e corrija a linha de comando do núcleo.\n\n"
printf "Talvez o dispositivo esteja formatado com um sistema de arquivos não suportado?\n\n"
printf "Ou talvez a auto detecção do tipo do sistema de arquivos foi errada, caso no qual\n"
printf "você deveria adicionar o parâmetro rootfstype=... à linha de comando do núcleo.\n\n"
printf "Partições disponíveis:\n"
}
do_mount_root()
{
mkdir /.root
[ -n "$rootflags" ] && rootflags="$rootflags,"
rootflags="$rootflags$ro"
case "$root" in
/dev/* ) device=$root ;;
UUID=* ) eval $root; device="/dev/disk/by-uuid/$UUID" ;;
PARTUUID=*) eval $root; device="/dev/disk/by-partuuid/$PARTUUID" ;;
LABEL=* ) eval $root; device="/dev/disk/by-label/$LABEL" ;;
"" ) echo "Nenhum dispositivo raiz especificado." ; problem ;;
esac
while [ ! -b "$device" ] ; do
no_device $device
problem
done
if ! mount -n -t "$rootfstype" -o "$rootflags" "$device" /.root ; then
no_mount $device
cat /proc/partitions
while true ; do sleep 10000 ; done
else
echo "Dispositivo montado com sucesso $root"
fi
}
do_try_resume()
{
case "$resume" in
UUID=* ) eval $resume; resume="/dev/disk/by-uuid/$UUID" ;;
LABEL=*) eval $resume; resume="/dev/disk/by-label/$LABEL" ;;
esac
if $noresume || ! [ -b "$resume" ]; then return; fi
ls -lH "$resume" | ( read x x x x maj min x
echo -n ${maj%,}:$min > /sys/power/resume )
}
init=/sbin/init
root=
rootdelay=
rootfstype=auto
ro="ro"
rootflags=
device=
resume=
noresume=false
mount -n -t devtmpfs devtmpfs /dev
mount -n -t proc proc /proc
mount -n -t sysfs sysfs /sys
mount -n -t tmpfs tmpfs /run
read -r cmdline < /proc/cmdline
for param in $cmdline ; do
case $param in
init=* ) init=${param#init=} ;;
root=* ) root=${param#root=} ;;
rootdelay=* ) rootdelay=${param#rootdelay=} ;;
rootfstype=*) rootfstype=${param#rootfstype=} ;;
rootflags=* ) rootflags=${param#rootflags=} ;;
resume=* ) resume=${param#resume=} ;;
noresume ) noresume=true ;;
ro ) ro="ro" ;;
rw ) ro="rw" ;;
esac
done
# Local do udevd depende da versão
if [ -x /sbin/udevd ]; then
UDEVD=/sbin/udevd
elif [ -x /lib/udev/udevd ]; then
UDEVD=/lib/udev/udevd
elif [ -x /lib/systemd/systemd-udevd ]; then
UDEVD=/lib/systemd/systemd-udevd
else
echo "Não consigo encontrar o udevd nem o systemd-udevd"
problem
fi
${UDEVD} --daemon --resolve-names=never
udevadm trigger
udevadm settle
if [ -f /etc/mdadm.conf ] ; then mdadm -As ; fi
if [ -x /sbin/vgchange ] ; then /sbin/vgchange -a y > /dev/null ; fi
if [ -n "$rootdelay" ] ; then sleep "$rootdelay" ; fi
do_try_resume # Esta função não retornará se retomar a partir do disco
do_mount_root
killall -w ${UDEVD##*/}
exec switch_root /.root "$init" "$@"
EOF
LVM2-2.03.22 e(ou) mdadm-4.2 precisam ser instalados antes de gerar o initramfs, se a partição do sistema os usar.
Para construir um initramfs, execute o seguinte como o(a)
usuário(a) root
:
mkinitramfs [VERSÃO DO NÚCLEO]
O argumento opcional é o diretório onde os módulos apropriados do
núcleo estão localizados. Esse precisa ser um subdiretório de
/lib/modules
. Se nenhum módulo for
especificado, então o initramfs é nomeado initrd.img-no-kmods. Se uma versão do
núcleo for especificada, [então] o initrd é nomeado de initrd.img-$VERSÃO_DO_NÚCLEO e é
apropriado somente para o núcleo específico especificado. O arquivo
de saída gerada será colocado no diretório atual.
Se for necessário o carregamento antecipado do microcódigo (veja-se
“Atualizações de
microcódigo para CPUs”), [então] você pode instalar o blob ou
contêiner apropriado em /lib/firmware
. Ele será adicionado
automaticamente ao initrd ao executar mkinitramfs.
Depois de gerar o initrd, copie-o para o diretório /boot
.
Agora edite /boot/grub/grub.cfg
e
adicione uma nova entrada de menu. Abaixo estão vários exemplos.
# initramfs genérico e sistema de arquivos raiz identificado por UUID menuentry "LFS Dev (LFS-7.0-Feb14) initrd, Linux 3.0.4" { linux /vmlinuz-3.0.4-lfs-20120214 root=UUID=54b934a9-302d-415e-ac11-4988408eb0a8 ro initrd /initrd.img-no-kmods }
# initramfs genérico e sistema de arquivos raiz na partição LVM menuentry "LFS Dev (LFS-7.0-Feb18) initrd lvm, Linux 3.0.4" { linux /vmlinuz-3.0.4-lfs-20120218 root=/dev/mapper/myroot ro initrd /initrd.img-no-kmods }
# initramfs específico e sistema de arquivos raiz identificado por RÓTULO menuentry "LFS Dev (LFS-7.1-Feb20) initrd label, Linux 3.2.6" { linux /vmlinuz-3.2.6-lfs71-120220 root=LABEL=lfs71 ro initrd /initrd.img-3.2.6-lfs71-120220 }
Finalmente, reinicialize o sistema e selecione o sistema desejado.