AUFS et test sur la racine sans risque

Vous avez besoin de réparer votre système par exemple, ou faire une installation audacieuse. Utilisez aufs

(DECONSEILLÉ AUX NEOPHYTES CAR PEUT FAIRE DU DÉGAT EN CAS D’ERREURS)

Pour cela, vous avez juste besoin d’une autre partition que la racine, mettons home.

Attention, dans ce qui suit on suppose /usr, /var, / sur une même partiton, bien sûr la méthode est générale, il faut adapter à la configuration.

Faites la chose suivante:

mkdir /home/test mount -t aufs aufs /mnt -o dirs=/home/test=rw:/=ro chroot /

Si /var et /usr sont sur d’autres partitions, c’est plus compliqué: faire par exemple si /dev/sda7 est sur /var et /dev/sda6 sur /usr
Faire les commandes plus haut puis

mkdir -p /home/var/var mkdir /home/usr mkdir /home/var mount -t aufs aufs /mnt/usr -o dirs=/home/usr=rw:/usr=ro mount -t aufs aufs /mnt/var -o dirs=/home/var=rw:/var=ro

Attention à penser à démonter ces répertoires avant /mnt. Penser aussi à avoir pas mal de /dev/loop?

Après tout ça, faites vos tests, par exemple ici

[code] apt-get install handbrake-cli
Lecture des listes de paquets… Fait
Construction de l’arbre des dépendances
Lecture des informations d’état… Fait
Les paquets supplémentaires suivants seront installés :
libavcodec-dev libavcodec53 libavformat-dev libavformat53 libavutil-dev
libavutil51 libdvdnav4 libmkv0 libswscale2
Paquets suggérés :

root@portos:/# su francois
francois@portos:/$ HandBrakeCLI --help
Syntax: HandBrakeCLI [options] -i -o

[…] [/code](éventuellement montez /proc, /sys et /dev en bind voire même /home)
Quand c’est fini

francois@portos:/$ exit root@portos:/# exit root@portos:/home/francois# umount /mnt root@portos:/home/francois# dpkg -l handbrake-cli Aucun paquet ne correspond à handbrake-cli. root@portos:/home/francois#
Le système est revenu à son état initial, il ne reste qu’à refaire les manoeuvres, celles ci se retrouve dans /home/test/root/.bash_history. Vous pouvez même finaliser votre test en récupérant toutes les modifications faites. Vous faites un

mkdir /home/rootancienne mkdir /home/rootnouvelle mount -t aufs aufs /home/rootnouvelle -o dirs=/home/test=rw:/=ro mount /dev/root /home/rootancienne rsync -P -av /home/rootnouvelle/* /home/rootancienne/

Voilà un script qui résume tout:
[edit: changement de prompt pour root, rectification d’un petit bug]

[code]#!/bin/sh
#F.Boisson version 1.0 Mars 2013

if [ -z “$2” ] ; then
BASE=/tmp/temporoot
else
BASE=$2
fi
RACINE=${BASE}/M_ROOT
RW_RACINE=${BASE}/RW_ROOT
MONTAGE=${BASE}/mnt
#FAKE="echo “
MOUNT=”$FAKE mount “
UMOUNT=”$FAKE umount "
mkdir -p $RACINE
mkdir -p $RW_RACINE
mkdir -p $BASE
mkdir -p $MONTAGE
if [ ! -z $1 ] && [ $1 = “m” ] ; then
echo -n > $BASE/LST

$MOUNT /dev/root $RACINE

$MOUNT $(mount | grep "on / " | awk '{print $1}') $RACINE
$MOUNT -t aufs aufs $MONTAGE -o dirs=$RW_RACINE=rw:$RACINE=ro
(mount | grep  "/dev/" | grep -v "on / "| grep -v devpts | grep -v $BASE ) | while read LIGNE ; do
DEV=$(echo $LIGNE | awk '{print $1}')
REP=$(echo $LIGNE | awk '{print $3}')
NOM=$(basename $REP)
echo $DEV $REP $NOM
echo $REP >> $BASE/LST
LST=$LST" "$NOM
mkdir -p ${BASE}/RW_${NOM}
mkdir -p ${BASE}/M_${NOM}
$MOUNT $DEV ${BASE}/M_${NOM}
$MOUNT -t aufs aufs $MONTAGE/$REP -o dirs=${BASE}/RW_${NOM}=rw:${BASE}/M_${NOM}=ro 
done 
mv $MONTAGE/root/.bashrc $MONTAGE/root/.bashrc.old
cp $MONTAGE/root/.bashrc.old $MONTAGE/root/.bashrc
echo "export PS1='\u@TEMPORAIRE:\w # '" >> $MONTAGE/root/.bashrc 
echo "Faites chroot "$MONTAGE

fi
if [ ! -z $1 ] && [ $1 = “u” ] ; then
mv $MONTAGE/root/.bashrc.old $MONTAGE/root/.bashrc
for i in $(cat $BASE/LST) ; do
NOM=$(basename $i)
$UMOUNT $MONTAGE/$i
$UMOUNT ${BASE}/M_${NOM}
done
$UMOUNT $MONTAGE
$UMOUNT $RACINE
fi

[/code]
Son usage est simple: Supposons ce fichier sauvé sous le nom de temporoot

  1. Repérer une partition non utilisé par la racine, mettons /home et trouver un nom de répertoire, mettons /home/temporaire. Mettez ce nom dans la variable BASE= du script
  2. Taper sous root
  1. Vous pouvez faire un chroot sur /home/temporaire/mnt
    Cela se voit avec un prompt différent:

root@portos:/home/francois# chroot /home/tmp/temporoot/mnt/ root@TEMPORAIRE:/ #exit root@portos:/home/francois#
4) Quand vous avez fini faites
temporoot u

Cas d’erreurs: Si vous avez le message

mount: wrong fs type, bad option, bad superblock on aufs, missing codepage or helper program, or other error (for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helper program) In some cases useful info is found in syslog - try dmesg | tail or so C’est que vous utilisez une partition que vous montez sur elle même. Dans ce cas, il faut soit trouver un autre point d’attache (une clef USB avec un ext3, un système ramfs fait par

Dans ce deuxième cas, vous perdez les modifications à l’extinction de la machine, etc.)

Exemple:

root@portos:/home/francois# temporoot m /dev/sda7 /home home root@portos:/home/francois# chroot /home/tmp/temporoot/mnt/ root@TEMPORAIRE:/ # cd /boot root@TEMPORAIRE:/boot # ls -l total 33160 -rw-r--r-- 1 root root 134432 sept. 19 17:46 config-3.5.4-fb-aufs -rw-r--r-- 1 root root 139016 févr. 21 17:28 config-3.8.0-fb-aufs drwxr-xr-x 3 root root 12288 févr. 27 11:30 grub -rw-r--r-- 1 root root 11588125 nov. 2 09:17 initrd.img-3.5.4-fb-aufs -rw-r--r-- 1 root root 11809923 févr. 21 19:14 initrd.img-3.8.0-fb-aufs -rw-r--r-- 1 root root 2148979 sept. 19 22:33 System.map-3.5.4-fb-aufs -rw-r--r-- 1 root root 2232103 févr. 21 18:56 System.map-3.8.0-fb-aufs -rw-r--r-- 1 root root 2875184 sept. 19 22:33 vmlinuz-3.5.4-fb-aufs -rw-r--r-- 1 root root 2994528 févr. 21 18:56 vmlinuz-3.8.0-fb-aufs root@TEMPORAIRE:/boot # rm -Rf * root@TEMPORAIRE:/boot # ls -l total 0 root@TEMPORAIRE:/boot # exit root@portos:/home/francois# ls -l /boot total 33160 -rw-r--r-- 1 root root 134432 sept. 19 17:46 config-3.5.4-fb-aufs -rw-r--r-- 1 root root 139016 févr. 21 17:28 config-3.8.0-fb-aufs drwxr-xr-x 3 root root 12288 févr. 27 11:30 grub -rw-r--r-- 1 root root 11588125 nov. 2 09:17 initrd.img-3.5.4-fb-aufs -rw-r--r-- 1 root root 11809923 févr. 21 19:14 initrd.img-3.8.0-fb-aufs -rw-r--r-- 1 root root 2148979 sept. 19 22:33 System.map-3.5.4-fb-aufs -rw-r--r-- 1 root root 2232103 févr. 21 18:56 System.map-3.8.0-fb-aufs -rw-r--r-- 1 root root 2875184 sept. 19 22:33 vmlinuz-3.5.4-fb-aufs -rw-r--r-- 1 root root 2994528 févr. 21 18:56 vmlinuz-3.8.0-fb-aufs root@portos:/home/francois# chroot /home/tmp/temporoot/mnt/ root@TEMPORAIRE:/ # ls /boot root@TEMPORAIRE:/ # exit root@portos:/home/francois# temporoot u root@portos:/home/francois#

Voilà. Attention, manipuler avec précaution mais personnellement ce script me rend bien des services pour faire un environnement temporaire ou tester une mise à jour. Il nécessite un noyau avec aufs comme celui de wheezy. Ne marche pas sous squeeze donc.

Bientôt je ferais un paquet pour bouter sur une racine de test fondée sur ce principe mais là j’ai des copies.

Version légèrement modifié, cf ci dessus.

Attention, ceci est une version alpha. Pour l’utiliser il faut avoir des systèmes de fichiers en ext2|3|4 pour fabriquer la racine (ces systèmes seront protégés, pas les autres).
Il faut également aufs dans le noyau (module aufs.ko en général)

Pour installer le bazar:

  1. Rajouter aufs au fichier /etc/initramfs-tools/modules
  2. Mettre le fichier tempo suivant dans /etc/initramfs-tools/scripts/ avec les droits 755

[code]# F.Boisson Mars 2013

tempo: montage root en aufs

SOL=/terre
BASE=$SOL/tempo
M_ROOT=$BASE/ROOT
RW_ROOT=$BASE/RW_ROOT

pre_mountroot()
{
[ “$quiet” != “y” ] && log_begin_msg "Running /scripts/local-top"
run_scripts /scripts/local-top
[ “$quiet” != “y” ] && log_end_msg

wait_for_udev 10

# Load ubi with the correct MTD partition and return since fstype
# doesn't work with a char device like ubi.
if [ -n "$UBIMTD" ]; then
	modprobe ubi mtd=$UBIMTD
	return
fi

# Don't wait for a root device that doesn't have a corresponding
# device in /dev (ie, mtd0)
if [ "${ROOT#/dev}" = "${ROOT}" ]; then
	return
fi

# If the root device hasn't shown up yet, give it a little while
# to deal with removable devices
if [ ! -e "${ROOT}" ] || ! $(get_fstype "${ROOT}" >/dev/null); then
	log_begin_msg "Waiting for root file system"

	# Default delay is 30s
	slumber=${ROOTDELAY:-30}

	slumber=$(( ${slumber} * 10 ))
	while [ ! -e "${ROOT}" ] \
	|| ! $(get_fstype "${ROOT}" >/dev/null); do
		/bin/sleep 0.1
		slumber=$(( ${slumber} - 1 ))
		[ ${slumber} -gt 0 ] || break
	done

	if [ ${slumber} -gt 0 ]; then
		log_end_msg 0
	else
		log_end_msg 1 || true
	fi
fi

# We've given up, but we'll let the user fix matters if they can
while [ ! -e "${ROOT}" ]; do
	# give hint about renamed root
	case "${ROOT}" in
	/dev/hd*)
		suffix="${ROOT#/dev/hd}"
		major="${suffix%[[:digit:]]}"
		major="${major%[[:digit:]]}"
		if [ -d "/sys/block/sd${major}" ]; then
			echo "WARNING bootdevice may be renamed. Try root=/dev/sd${suffix}"
		fi
		;;
	/dev/sd*)
		suffix="${ROOT#/dev/sd}"
		major="${suffix%[[:digit:]]}"
		major="${major%[[:digit:]]}"
		if [ -d "/sys/block/hd${major}" ]; then
			echo "WARNING bootdevice may be renamed. Try root=/dev/hd${suffix}"
		fi
		;;
	esac
	echo "Gave up waiting for root device.  Common problems:"
	echo " - Boot args (cat /proc/cmdline)"
	echo "   - Check rootdelay= (did the system wait long enough?)"
	echo "   - Check root= (did the system wait for the right device?)"
	echo " - Missing modules (cat /proc/modules; ls /dev)"
	panic "ALERT!  ${ROOT} does not exist.  Dropping to a shell!"
done

}

mountroot()
{
pre_mountroot

# Get the root filesystem type if not set
if [ -z "${ROOTFSTYPE}" ]; then
	FSTYPE=$(get_fstype "${ROOT}")
else
	FSTYPE=${ROOTFSTYPE}
fi

[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-premount"
run_scripts /scripts/local-premount
[ "$quiet" != "y" ] && log_end_msg

if [ "${readonly}" = "y" ]; then
	roflag=-r
else
	roflag=-w
fi

# FIXME This has no error checking
modprobe ${FSTYPE}

# FIXME This has no error checking
# Mount root
# well that's the difference
unset TEMPO
for x in $(cat /proc/cmdline); do
    case $x in
	tempo=*)
            tempop=${x#tempo=}
            TEMPO="/dev/disk/by-uuid/${tempop#UUID=}"
	;;
	esac
done
mkdir -p $SOL
if [ -z "$TEMPO" ] ; then
    mount $ROOT $SOL
    if [ -f $SOL/TEMPO ] ; then
	NOMTEMPO=$(cat $SOL/TEMPO)
            TEMPO="/dev/disk/by-uuid/${NOMTEMPO#UUID=}"
    fi
    umount $SOL
fi
echo "recherche du périphérique temporaire "$TEMPONON
sleep 8
if [ ! -z "$TEMPO" ] && [ -b $TEMPO ] ; then 
# yes men, il y a le perif
    # well on monte $TEMPO

pour cela on fait un système de fichier en RAM qu’on déplacera après dans la racine

    mount -t tmpfs none $SOL
    mkdir -p $BASE
    mount $TEMPO $BASE
# Bon, la racine maintenant
    modprobe aufs
    mkdir -p $M_ROOT
    if [ "${FSTYPE}" != "unknown" ]; then
	mount -r -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} $M_ROOT
    else
	mount -r ${ROOTFLAGS} ${ROOT} $M_ROOT
    fi
    echo "Periphérique "$NOMTEMPO" trouvé, fabrication de la racine..."

ROOT="/dev/disk/by-uuid/${ROOT#UUID=}"

#BASE=/tempo
#M_ROOT=$BASE/root
#RW_ROOT=$BASE/rw_root
mkdir -p $RW_ROOT
[ -f $RW_ROOT/etc/fstab ] && rm $RW_ROOT/etc/fstab
mount -t aufs aufs ${rootmnt} -o dirs=$RW_ROOT=rw:$M_ROOT=ro
# bien, maintenant on parcourt le fstab
mv ${rootmnt}/etc/fstab ${rootmnt}/etc/fstab.old
touch ${rootmnt}/etc/fstab
cat ${rootmnt}/etc/fstab.old | while read LIGNE; do
if (echo $LIGNE | grep -q “^#”) ; then echo $LIGNE >> ${rootmnt}/etc/fstab
elif (echo $LIGNE | grep -q " ext[3|4]" ) ; then
PERIFP=$(echo $LIGNE | awk ‘{print $1}’)
PERIF="/dev/disk/by-uuid/${PERIFP#UUID=}"
REP=$(echo $LIGNE | awk ‘{print $2}’)
NOM=$(basename $REP)
if [ $REP != “/” ] && [ ! $PERIF -ef $TEMPO ] ; then
echo "Installation de "$REP
mkdir -p ${BASE}/RW_${NOM}
mkdir -p ${BASE}/M_${NOM}
mount $PERIF ${BASE}/M_${NOM}
mount -t aufs aufs ${rootmnt}/$REP -o dirs=${BASE}/RW_${NOM}=rw:${BASE}/M_${NOM}=ro
else
echo "$REP ($PERIF) ignoré"
fi
else echo $LIGNE >> ${rootmnt}/etc/fstab
fi
done

on déplace le bazar

    mkdir ${rootmnt}$SOL
    mount --move $SOL ${rootmnt}$SOL
else
    if [ "${FSTYPE}" != "unknown" ]; then
	mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt}
    else
	mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt}
    fi
fi

mount

sleep 10

[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
run_scripts /scripts/local-bottom
[ "$quiet" != "y" ] && log_end_msg

}
[/code]
3) Refaire l’initrd.

  1. Ajouter boot=tempo dans /etc/default/grub à la ligne GRUB_CMDLINE_LINUX_DEFAULT=…

  2. Refaites l’initrd

Si vous boutez comme cela, rien ne changera, mais si vous rajoutez à la racine un fichier TEMPO contenant

L’UUID est celui de la partition sur laquelle seront installés les répertoires en lecture/ecriture. Cette partition ne sera pas montée si elle est listée dans /etc/fstab.
Le système démarrera en montant la racine en aufs suivant un fonctionnement comme précédemment, voir appel-testeurs-audacieux-t42536.html à ce sujet

Je vais faire un crosspostage volontaire, damned:

J’ai fait un paquet aufsroot qui assemble tout.

LISEZ /usr/share/doc/aufsroot/README

Comme l’usage nécessite de comprendre ce que l’on fait, je me suis refusé à modifier de moi même les fichiers /etc/defaut/grub et /etc/initramfs-tools/modules

LISEZ /usr/share/doc/aufsroot/README

Paquet aufsroot sur

deb boisson.homeip.net/depot wheezy divers
(signé)
deb boisson.homeip.net/depot wheezy divers
(non signé)

Voilà

Peaufinage du script temporoot. Celui ci semble au point. Le paquet également.