A respeito do initramfs

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.

Construindo um initramfs

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

Usando um initramfs

Dependência Exigida em Tempo de Execução

cpio-2.14

Outras Dependências em Tempo de Execução

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.