La seule fonction d'un initramfs est de monter le système de fichier racine. L'initramfs est un ensemble complet de répertoires que vous pouvez trouver dans un système de fichiers racine normal. Il est regroupé dans une seule archive cpio et compressé avec l'un des nombreux algorithmes de compression.
Au moment du démarrage, le chargeur de démarrage charge le noyau et l'image initramfs dans la mémoire et démarre le noyau. Le noyau vérifie la présence d'un initramfs et, s'il le trouve, le monte sur / et lance /init. Le programme init est typiquement un script shell. Notez que le processus de démarrage est plus long, même significativement plus long, si un initramfs est utilisé.
Pour la plupart des distributions, les modules du noyau sont la plus importante raison d'avoir un initramfs. Dans une distribution générale, il y a beaucoup d'inconnues comme les types de systèmes de fichiers et les couches des disques. Dans un sens, c'est l'opposé de LFS où les capacités et les couches du système sont connus et un noyau personnalisé est normalement construit. Dans cette situation, un initramfs est rarement nécessaire.
Il y a seulement quatre raisons d'avoir un initramfs dans un environnement LFS : le chargement du rootfs depuis le réseau, son chargement depuis un volume logique LVM, avoir un rootfs chiffré où un mot de passe est requis, ou pour le confort d'un rootfs spécifié par un LABEL ou un UUID. Les autres cas signifient souvent que le noyau n'est pas configuré correctement.
Si vous décidez de construire un initramfs, les scripts suivants fourniront les bases pour le faire. Les scripts autoriseront la spécification du rootfs via un UUID de partition ou un LABEL de partition ou un rootfs dans un volume logique LVM. Ils ne prennent pas en charge les systèmes de fichier racine chiffrés ou le montage des rootfs par des cartes réseaux. Pour plus d'informations sur les possibilités, voir les astuces LFS (les astuces traduites) ou dracut.
Pour installer ces scripts, lancez les commandes suivantes en tant
qu'utilisateur root
:
cat > /usr/sbin/mkinitramfs << "EOF"
#!/bin/bash
# Ce fichier se base en partie sur le script mkinitramfs du LiveCD LFS
# écrit par Alexander E. Patrakov et 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 "Fichier requis manquant : $1 pour le répertoire $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 "Aucun répertoire de modules nommé $1"
exit 1
fi
printf "Création de $INITRAMFS_FILE... "
binfiles="sh cat cp dd killall ls mkdir mknod mount "
binfiles="$binfiles umount sed sleep ln rm uname"
binfiles="$binfiles readlink basename"
# Systemd installe udevadm dans /bin. Les autres implementations d'udev le placent dans /sbin
if [ -x /usr/bin/udevadm ] ; then binfiles="$binfiles udevadm"; fi
sbinfiles="modprobe blkid switch_root"
# Fichiers en emplacements facultatifs
for f in mdadm mdmon udevd udevadm; do
if [ -x /usr/sbin/$f ] ; then sbinfiles="$sbinfiles $f"; fi
done
# Ajout de lvm s'il est présent (impossible de le faire avec le reste car il
# nécessite également dmsetup)
if [ -x /usr/sbin/lvm ] ; then sbinfiles="$sbinfiles lvm dmsetup"; fi
unsorted=$(mktemp /tmp/unsorted.XXXXXXXXXX)
DATADIR=/usr/share/mkinitramfs
INITIN=init.in
# Création d'un répertoire de travail temporaire
WDIR=$(mktemp -d /tmp/initrd-work.XXXXXXXXXX)
# Création d'une structure de répertoires de base
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
# Création des nœuds de périphérique nécessaires
mknod -m 640 $WDIR/dev/console c 5 1
mknod -m 664 $WDIR/dev/null c 1 3
# Installation des fichiers de configuration d'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
# Installation des micrologiciels présents
cp -a /usr/lib/firmware $WDIR/usr/lib
# Copie du fichier de configuration RAID s'il est présent
if [ -f /etc/mdadm.conf ] ; then
cp /etc/mdadm.conf $WDIR/etc
fi
# Installation du fichier d'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
# Installation des binaires de base
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
# Ajout des bibliothèques udevd s'il n'est pas dans /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
# Ajout des liens symboliques des modules si nécessaire
if [ -n "$KERNEL_VERSION" ] && [ -x /usr/bin/kmod ] ; then
ln -s kmod $WDIR/usr/bin/lsmod
ln -s kmod $WDIR/usr/bin/insmod
fi
# Ajout des liens symboliques de lvm si nécessaire
# Également, copie du fichier 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
# Fichier de configuration
cp -a /etc/lvm $WDIR/etc
fi
# Installation des bibliothèques
sort $unsorted | uniq | while read library ; do
# linux-vdso et linux-gate sont des pseudo-bibliothèque et ne correspondent pas à un fichier
# libsystemd-shared se trouve dans /lib/systemd, donc il n'est pas trouvé par la copie, mais
# il est tout de même copié plus bas
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
# Installation des modules du noyau si nécessaire
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
# Preparation du chargement au plus tôt du microcode s'il est disponible
if ls /usr/lib/firmware/intel-ucode/* >/dev/null 2>&1 ||
ls /usr/lib/firmware/amd-ucode/* >/dev/null 2>&1; then
# on commence par vider WDIR pour le réutiliser
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
# Suppression des répertoires et des fichiers temporaires
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 "Encountered a problem!\n\nDropping you to a shell.\n\n"
sh
}
no_device()
{
printf "The device %s, which is supposed to contain the\n" $1
printf "root file system, does not exist.\n"
printf "Please fix this problem and exit this shell.\n\n"
}
no_mount()
{
printf "Could not mount device %s\n" $1
printf "Sleeping forever. Please reboot and fix the kernel command line.\n\n"
printf "Maybe the device is formatted with an unsupported file system?\n\n"
printf "Or maybe filesystem type autodetection went wrong, in which case\n"
printf "you should add the rootfstype=... parameter to the kernel command line.\n\n"
printf "Available partitions:\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 "No root device specified." ; 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 "Successfully mounted device $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
# udevd location depends on version
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 "Cannot find udevd nor 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 # This function will not return if resuming from disk
do_mount_root
killall -w ${UDEVD##*/}
exec switch_root /.root "$init" "$@"
EOF
LVM2-2.03.23 et mdadm-4.2 doivent être installés avant de générer l'initramfs, si les partitions du système les utilise.
Pour construire un initramfs, lancer ce qui suit en tant
qu'utilisateur root
:
mkinitramfs [KERNEL VERSION]
L'argument facultatif est le répertoire où les modules appropriés
du noyau sont enregistrés. Cela peut être un sous-répertoire de
/lib/modules
. Si aucun module n'est
spécifié, alors l'initramfs est appelé initrd.img-no-kmods. Si une version du
noyau est précisé, le fichier initrd est appelé initrd.img-$KERNEL_VERSION et est
seulement destiné pour le noyau spécifiquement précisé. Les
fichiers de sortie seront enregistrés dans le répertoire courant.
Si vous avez besoin du chargement de microcode au plus tôt (voir
la section intitulée
« Mise à jour de micro-codes pour les CPU »), vous
pouvez installer le blob ou le conteneur approprié dans
/lib/firmware
. Il sera
automatiquement ajouté à l'initrd quand vous lancerez mkinitfs.
Après avoir généré le fichier initrd, copiez-le dans le répertoire
/boot
.
Maintenant éditez /boot/grub/grub.cfg
et ajoutez une nouvelle entrée dans le menu. En dessous, plusieurs
exemples sont présentés.
# Generic initramfs and root fs identified by 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 et système de fichiers racine génériques sur une partition 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 et système de fichiers racine spécifiques identifié par un LABEL 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 }
Finalement, redémarrez le système et sélectionnez le système désiré.