Vérification disques démarrage Ubuntu

De EjnTricks

Sur une plateforme Ubuntu, les disques peuvent être automatiquement vérifiés lors d'un démarrage de la plateforme. Lors d'une connexion ssh, l'utilisateur est averti lors qu'une vérification sera effectuée lors du prochain redémarrage.

Cependant, il a été constaté que ce message continuait à être affiché même après des redémarrage. Cet article tente de présenter les mécanismes mis en place, sur une version 15.04.

Le message affiché est le suivant.

*** /dev/sda10 will be checked for errors at next reboot ***
*** /dev/sda1 will be checked for errors at next reboot ***


Hand-icon.png Votre avis

Nobody voted on this yet

 You need to enable JavaScript to vote


Study icon.png Etude

Dans un premier, il est nécessaire de comprendre le mode de fonctionnement de ces vérifications. Lors de la connexion d'un utilisateur en ssh, les scripts dans le répertoire /etc/update-motd.d sont exécutés. Il existe le script 98-fsck-at-reboot.

#!/bin/sh

if [ -x /usr/lib/update-notifier/update-motd-fsck-at-reboot ]; then
    exec /usr/lib/update-notifier/update-motd-fsck-at-reboot

Celui-ci exécute donc le script /usr/lib/update-notifier/update-motd-fsck-at-reboot dont le contenu est le suivant.

#!/bin/sh
# Authors:
#   Mads Chr. Olesen <mads@mchro.dk>
#   Kees Cook <kees@ubuntu.com>
set -e

# poor mans force
if [ "$1" = "--force" ]; then
    NEEDS_FSCK_CHECK=yes
fi

# check time when we did the last check
stamp="/var/lib/update-notifier/fsck-at-reboot"
if [ -e "$stamp" ]; then
    stampt=$(stat -c %Y $stamp)
else
    stampt=0
fi

# check time when we last booted
last_boot=$(date -d "now - $(awk '{print $1}' /proc/uptime) seconds" +%s)

now=$(date +%s)
if [ $(($stampt + 3600)) -lt $now ] || [ $stampt -gt $now ] \
   || [ $stampt -lt $last_boot ]
then
    #echo $stampt $now need update
        NEEDS_FSCK_CHECK=yes
fi

# output something for update-motd
if [ -n "$NEEDS_FSCK_CHECK" ]; then
  {
    check_occur_any=

    ext_partitions=$(mount | awk '$5 ~ /^ext(2|3|4)$/ { print $1 }')
    for part in $ext_partitions; do
        dumpe2fs_out=$(dumpe2fs -h $part 2>/dev/null)
        mount_count=$(echo "$dumpe2fs_out" | grep "^Mount count:"|cut -d':' -f 2-)
        if [ -z "$mount_count" ]; then mount_count=0; fi
        max_mount_count=$(echo "$dumpe2fs_out" | grep "^Maximum mount count:"|cut -d':' -f 2-)
        if [ -z "$max_mount_count" ]; then max_mount_count=0; fi
        check_interval=$(echo "$dumpe2fs_out" | grep "^Check interval:" | cut -d':' -f 2- | cut -d'(' -f 1)
        if [ -z "$check_interval" ]; then check_interval=0; fi
        next_check_date=$(echo "$dumpe2fs_out" | grep "^Next check after:" | cut -d':' -f 2-)
        if [ -z "$next_check_interval" ]; then next_check_interval=0; fi
        next_check_tstamp=$(date -d "$next_check_date" +%s)

        #echo "next_check_date=\"$next_check_date\" next_check_tstamp=\"$next_check_tstamp\""
        #echo "part=\"$part\" mount_count=\"$mount_count\" / max=\"$max_mount_count\" "

        check_occur=
        # Check based on mount counts?
        if [ "$max_mount_count" -gt 0 -a \
             "$mount_count" -ge "$max_mount_count" ]; then
            check_occur=yes
        fi
        # Check based on time passed?
        if [ "$check_interval" -gt 0 -a \
             "$next_check_tstamp" -lt "$now" ]; then
            check_occur=yes
        fi
        if [ -n "$check_occur" ]; then
            check_occur_any=yes
            mountpoint=$(mount | grep "^$part" | cut -d ' ' -f 3)
            pass=$(grep -v '^#' /etc/fstab | tr -s ' ' '\t' | cut -s -f 2,6 | grep -w "$mountpoint" | cut -f 2)
            if [ "$pass" = "0" ]; then
                echo "*** $part should be checked for errors ***"
            else
                echo "*** $part will be checked for errors at next reboot ***"
            fi
        fi
    done
    if [ -n "$check_occur_any" ]; then
        echo ""
    fi
  } > $stamp
fi

# output what we have (either cached or newly generated)
cat $stamp

A ce stade, cela n'est pas très compréhensible. Mais il est globalement assez simple.

Dans un premier temps, des calculs sont réalisés pour savoir si la vérification doit être lancée ou si il suffit d'afficher le contenu du fichier /var/lib/update-notifier/fsck-at-reboot.

Globalement, la vérification est réalisée si :

  • La date de modification du fichier date de plus d'une heure;
  • La date de modification du fichier est dans le futur (étonnant, mais pourquoi pas);
  • La date de modification du fichier est antérieure à la dernière connexion.


Si tel est le cas, les vérifications sont réalisées pour chacune des partitions, listées à l'aide de la commande suivante.

ext_partitions=$(mount | awk '$5 ~ /^ext(2|3|4)$/ { print $1 }')

Pour l'analyse, nous prendrons comme exemple la patition /dev/sda10.

Sur chacune des partitions, la commande dumpe2fs est exécutée afin de récupérer un ensemble d'information pour la partition. Dans le cadre de cet exemple, elle peut produire quelque chose comme ceci.

Filesystem volume name:   <none>
Last mounted on:          /
Filesystem UUID:          4b116dd4-8bae-475f-9bf1-8344e5844a08
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              5562368
Block count:              22234368
Reserved block count:     1111718
Free blocks:              21548758
Free inodes:              5530964
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1018
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
Flex block group size:    16
Filesystem created:       Sun Dec 12 09:49:07 2010
Last mount time:          Sat Apr 23 17:08:21 2016
Last write time:          Sat Apr 23 17:08:16 2016
Mount count:              30
Maximum mount count:      30
Last checked:             Fri Jul 17 00:11:26 2015
Check interval:           15552000 (6 months)
Next check after:         Tue Jan 12 23:11:26 2016
Lifetime writes:          98 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      7db1cabc-eba2-4095-bb2c-8a16a78ea693
Journal backup:           inode blocks
Fonctionalités du journal :  journal_incompat_revoke
Taille du journal :         128M
Longueur du journal :      32768
Séquence du journal :      0x00044879
Début du journal :         1

Puis un ensemble d'extraction est réalisé sur ce résultat afin d'obtenir les informations utiles.

  • Mount count;
  • Maximum mount count;
  • Check interval;
  • Next check after;

Les instructions d'extraction sont un peu différente pour la valeur de Check interval, mais cela produit le résultat suivant.

Paramètre Valeur
Mount count 30
Maximum mount count 30
Check interval 15552000
Next check after Tue Jan 12 23:11:26 2016

Enfin deux conditions sont vérifiées pour savoir si une vérification doit être réalisée.

  • Le nombre de montage réalisés est supérieurs ou égale au nombre maximum de montage "autorisés", si ce dernier n'est pas égal à 0;
  • La date de prochaine vérification est inférieur à la date du jour, si la valeur de check_interval n'est pas également à 0.

Si tel est le cas, un message de vérification est construit en fonction d'une valeur récupérée depuis /etc/fstab et en fonction de son point de montage avec les deux commandes suivantes.

mountpoint=$(mount | grep "^$part" | cut -d ' ' -f 3)
pass=$(grep -v '^#' /etc/fstab | tr -s ' ' '\t' | cut -s -f 2,6 | grep -w "$mountpoint" | cut -f 2)

Dans le cadre de cet article, le résultat des commandes est le suivant.

#mount | grep "^/dev/sda10" | cut -d ' ' -f 3
/
#grep -v '^#' /etc/fstab | tr -s ' ' '\t' | cut -s -f 2,6 | grep -w "/" | cut -f 2
1

La dernière nécessite peut être un peu plus de pas à pas pour bien comprendre.

#grep -v '^#' /etc/fstab
proc            /proc           proc    nodev,noexec,nosuid 0       0
UUID=4b116dd4-8bae-475f-9bf1-8344e5844a08 /               ext4    errors=remount-ro 0       1
UUID=4fee39df-8166-4af3-8036-8bf48c59ddc7 /boot           ext4    defaults        0       2
UUID=b11ca971-924e-45a0-9be9-59ce1efdc8ec /opt            ext4    defaults        0       2
UUID=96d9be39-cc11-46f0-bf43-f451ff0eb9fc /srv            ext4    defaults        0       2
UUID=ff94cff0-2e8e-449f-9473-da7caa63a93f /tmp            ext4    defaults        0       2
UUID=8f557a3a-c4c8-4166-8e71-dd7451969a56 /usr            ext4    defaults        0       2
UUID=de58b6c5-2e6f-4efe-8e09-6554d2457cf4 /var            ext4    defaults        0       2
UUID=c86bebd8-c323-4f24-86e2-6a530e185595 none            swap    sw              0       0

#grep -v '^#' /etc/fstab | tr -s ' ' '\t'
proc    /proc   proc    nodev,noexec,nosuid     0       0
UUID=4b116dd4-8bae-475f-9bf1-8344e5844a08       /       ext4    errors=remount-ro       0       1
UUID=4fee39df-8166-4af3-8036-8bf48c59ddc7       /boot   ext4    defaults        0       2
UUID=b11ca971-924e-45a0-9be9-59ce1efdc8ec       /opt    ext4    defaults        0       2
UUID=96d9be39-cc11-46f0-bf43-f451ff0eb9fc       /srv    ext4    defaults        0       2
UUID=ff94cff0-2e8e-449f-9473-da7caa63a93f       /tmp    ext4    defaults        0       2
UUID=8f557a3a-c4c8-4166-8e71-dd7451969a56       /usr    ext4    defaults        0       2
UUID=de58b6c5-2e6f-4efe-8e09-6554d2457cf4       /var    ext4    defaults        0       2
UUID=c86bebd8-c323-4f24-86e2-6a530e185595       none    swap    sw      0       0

#grep -v '^#' /etc/fstab | tr -s ' ' '\t' | cut -s -f 2,6
/proc   0
/       1
/boot   2
/opt    2
/srv    2
/tmp    2
/usr    2
/var    2
none    0

#grep -v '^#' /etc/fstab | tr -s ' ' '\t' | cut -s -f 2,6 | grep -w "/"
/       1

#grep -v '^#' /etc/fstab | tr -s ' ' '\t' | cut -s -f 2,6 | grep -w "/" | cut -f 2
1

La valeur de cette dernière instruction permet de spécialiser le message qui va être affichée.

  • *** XXX should be checked for errors ***
  • *** XXX will be checked for errors at next reboot ***

Une fois terminé, si aucun message n'a été construit, une chaîne vide est envoyée avec la commande echo. Le résultat de ces vérification est redirigé dans le fichier /var/lib/update-notifier/fsck-at-reboot.

Enfin, le contenu de ce dernier est affiché à l'aide de la commande cat.


Bug-icon.png Anomalies

Update icon.png Affichage "infini"

Dans le cadre de cette installation, le message semblait ne jamais disparaître alors que des reboots étaient effectués. Ce cas, c'est produit pour le résultat de la commande dumpe2fs suivant.

Filesystem volume name:   <none>
Last mounted on:          /usr
Filesystem UUID:          8f557a3a-c4c8-4166-8e71-dd7451969a56
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              6111232
Block count:              24413696
Reserved block count:     1220684
Free blocks:              20928817
Free inodes:              5776669
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1018
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
Flex block group size:    16
Filesystem created:       Sun Dec 12 09:48:17 2010
Last mount time:          Sat Apr 23 22:21:49 2016
Last write time:          Sat Apr 23 22:21:45 2016
Mount count:              31
Maximum mount count:      34
Last checked:             Fri Jul 17 00:11:30 2015
Check interval:           15552000 (6 months)
Next check after:         Tue Jan 12 23:11:30 2016
Lifetime writes:          822 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
First orphan inode:       1840531
Default directory hash:   half_md4
Directory Hash Seed:      4ef0802d-d783-4dcb-be96-78865cad4031
Journal backup:           inode blocks
Fonctionalités du journal :  journal_incompat_revoke
Taille du journal :         128M
Longueur du journal :      32768
Séquence du journal :      0x00e945e7
Début du journal :         1

Les extractions de valeur donnaient les informations suivantes.

Paramètre Valeur
Mount count 31
Maximum mount count 34
Check interval 15552000
Next check after Tue Jan 12 23:11:30 2016

Pour une raison inconnue, malgré une date antérieure pour la prochaine vérification, celle-ci ne se déclenchait pas. Elle a été déclenchée qu'une fois que la valeur de Mount count avait atteint celle de Maximum mount count.


Icon-log.png Erreur calcul

L'instruction suivante, permettant de récupérer le point de montage, peut poser un problème dans des cas particuliers.

mountpoint=$(mount | grep "^$part" | cut -d ' ' -f 3)

En effet, dans le cadre de cette installation, il y a les partitions /dev/sda1 et /dev/sda10. L'étude ci dessus donnait le résultat / pour la partition /dev/sda10, mais qu'en est il pour /dev/sda1 ? Et bien, du fait de l'expression régulière, les résultats pour les deux vont être retournés, soit.

#mount | grep "^/dev/sda1" | cut -d ' ' -f 3
/
/usr

Cela n'est potentiellement pas problématique. En effet la valeur, calculée à partir du point de montage, permet uniquement de spécialiser le message d'avertissement. Mais peut être que cette erreur entraîne d'autre problème.


Viewer icon.png Voir Aussi

Un bug a été levé avec cette description: https://bugs.launchpad.net/ubuntu/+source/update-notifier/+bug/1574707