sonic-buildimage/files/image_config/platform/rc.local
Olivier Singla 799f22d4c7
[baseimage]: Run fsck filesystem check support prior mounting filesystem (#4431)
* Run fsck filesystem check support prior mounting filesystem

If the filesystem become non clean ("dirty"), SONiC does not run fsck to
repair and mark it as clean again.

This patch adds the functionality to run fsck on each boot, prior to the
filesystem being mounted. This allows the filesystem to be repaired if
needed.

Note that if the filesystem is maked as clean, fsck does nothing and simply
return so this is perfectly fine to call fsck every time prior to mount the
filesystem.

How to verify this patch (using bash):

Using an image without this patch:

Make the filesystem "dirty" (not clean)
[we are making the assumption that filesystem is stored in /dev/sda3 - Please adjust depending of the platform]
[do this only on a test platform!]

dd if=/dev/sda3 of=superblock bs=1 count=2048
printf "$(printf '\\x%02X' 2)" | dd of="superblock" bs=1 seek=1082 count=1 conv=notrunc &> /dev/null
dd of=/dev/sda3 if=superblock bs=1 count=2048

Verify that filesystem is not clean
tune2fs -l /dev/sda3 | grep "Filesystem state:"

reboot and verify that the filesystem is still not clean
Redo the same test with an image with this patch, and verify that at next reboot the filesystem is repaired and becomes clean.

fsck log is stored on syslog, using the string FSCK as markup.
2020-04-30 00:33:20 -07:00

350 lines
12 KiB
Bash
Executable File

#!/bin/sh -x
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
SONIC_VERSION=$(sonic-cfggen -y /etc/sonic/sonic_version.yml -v build_version)
FIRST_BOOT_FILE="/host/image-${SONIC_VERSION}/platform/firsttime"
# In case the unit is migrating from another NOS, save the logs
log_migration() {
echo $1 >> /host/migration/migration.log
}
# Import files from another NOS's partition onto SONiC
nos_migration_import() {
[ -f $1 ] && cp $1 $2 || log_migration "ERROR: $1 not found!"
}
# While migrating form another NOS, we need to preserve the MAC addresses
# of eth0 (and eventually switchports).
# Update the eth0 mac and also the EEPROM using ethtool so that subsequent
# reboots use the NOS's mac.
# Input : mgmt_interface.cfg file imported from the previous NOS.
update_mgmt_interface_macaddr() {
mgmt_config=$1
if [ ! -f "$mgmt_config" ]; then
log_migration "ERROR : unable update eth0 MAC : $mgmt_config not found!"
return
fi
# Save the previous NOS's mac
old_mac=`ip link show eth0 | grep ether | awk '{print $2}'`
[ -z "$old_mac" ] && log_migration "Unable to retrieve old mac address !" && return
# Extract, validate and set the eth0's mac address for the current session
new_mac=$(grep "macaddr" $mgmt_config | awk -F'=' '{print $2}')
log_migration "Setting eth0 mac as $new_mac."
if [ `echo $new_mac | egrep "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$"` ]; then
ip link set eth0 down
ip link set eth0 address $new_mac
ip link set eth0 up
else
log_migration "ERROR: mac imported from NOS is invalid : $new_mac !"
return
fi
# Get the ethtool magic and offset for changing the mac address in the EEPROM
ethtool_magic=$(grep "ethtool_magic" $mgmt_config | awk -F'=' '{print $2}')
ethtool_offset=$(grep "ethtool_offset" $mgmt_config | awk -F'=' '{print $2}')
if [ -z "$ethtool_magic" ] || [ -z "$ethtool_offset" ]; then
log_migration "Unable to retrieve ethtool params ($ethtool_magic,$ethtool_offset)"
return
fi
log_migration "eth0 mac in EEPROM before update:"
ethtool -e eth0 offset $ethtool_offset length 6 >> /host/migration/migration.log
# Update the mac address in the EEPROM for subsequent reboots
# Write only changed octets
for i in 1 2 3 4 5 6; do
offset=$(($ethtool_offset+$i-1))
old_mac_octet="$(echo $old_mac | cut -d":" -f$i)"
new_mac_octet="$(echo $new_mac | cut -d":" -f$i)"
if [ "$old_mac_octet" != "$new_mac_octet" ]; then
ethtool -E eth0 magic $ethtool_magic offset $offset value 0x$new_mac_octet
if [ $? != 0 ]; then
log_migration "ERROR: unable to update eth0 EEPROM!"
log_migration "index $i, magic $ethtool_magic offset $offset, value $new_mac_octet"
return
fi
fi
done
log_migration "eth0 mac in EEPROM after update:"
ethtool -e eth0 offset $ethtool_offset length 6 >> /host/migration/migration.log
# Update the 70-persistent-net.rules with the new mac for eth0
log_migration "/etc/udev/rules.d/70-persistent-net.rules : replacing $old_mac with $new_mac for eth0"
sed -i "/eth0/ s/ATTR{address}==\"$old_mac\"/ATTR{address}==\"$new_mac\"/g" /etc/udev/rules.d/70-persistent-net.rules
}
firsttime_exit() {
rm -rf $FIRST_BOOT_FILE
exit 0
}
# Given a string of tuples of the form field=value, extract the value for a field
# In : $string, $field
# Out: $value
value_extract() {
set -- $string
for x in "$@"; do
case "$x" in
$field=*)
value="${x#$field=}"
esac
done
}
program_console_speed()
{
speed=$(cat /proc/cmdline | grep -Eo 'console=ttyS[0-9]+,[0-9]+' | cut -d "," -f2)
if [ -z "$speed" ]; then
CONSOLE_SPEED=9600
else
CONSOLE_SPEED=$speed
fi
sed -i "s|\-\-keep\-baud .* %I| $CONSOLE_SPEED %I|g" /lib/systemd/system/serial-getty@.service
systemctl daemon-reload
}
#### Begin Main Body ####
logger "SONiC version ${SONIC_VERSION} starting up..."
# If the machine.conf is absent, it indicates that the unit booted
# into SONiC from another NOS. Extract the machine.conf from ONIE.
if [ ! -e /host/machine.conf ]; then
mkdir -p /host/migration
onie_dev=$(blkid | grep ONIE-BOOT | head -n 1 | awk '{print $1}' | sed -e 's/:.*$//')
mkdir -p /mnt/onie-boot
mount $onie_dev /mnt/onie-boot
onie_grub_cfg=/mnt/onie-boot/onie/grub/grub-machine.cfg
if [ ! -e $onie_grub_cfg ]; then
log_migration "$onie_grub_cfg not found"
else
. ./$onie_grub_cfg
grep = $onie_grub_cfg | sed -e 's/onie_//' -e 's/=.*$//' | while read var ; do
eval val='$'onie_$var
echo "onie_${var}=${val}" >> /host/machine.conf
done
fi
# Extract the previous NOS's partition that contains the migration artifacts
set -- $(cat /proc/cmdline)
for x in "$@"; do
case "$x" in
nos-config-part=*)
nos_val="${x#nos-config-part=}"
;;
esac
done
if [ -n "$nos_val" ]; then
nos_dev=$(findfs $nos_val)
if [ $? != 0 ]; then
log_migration "ERROR: nos_dev not found. Check grub parameters"
fi
else
log_migration "ERROR: nos_val not found. Check grub parameters"
fi
if [ -n "$nos_dev" ]; then
# Mount the previous NOS's partition
NOS_DIR=/mnt/nos_migration
MG_GZFILE=$NOS_DIR/minigraph.xml.gz.base64.txt
MG_FILE=$NOS_DIR/minigraph.xml
ACL_GZFILE=$NOS_DIR/acl.json.gz.base64.txt
ACL_FILE=$NOS_DIR/acl.json
SNMP_FILE=$NOS_DIR/snmp.yml
mkdir -p $NOS_DIR
mount $nos_dev $NOS_DIR
mkdir -p /host/fast-reboot
# decode & unzip minigraph.xml.gz.base64.txt
[ -f $MG_GZFILE ] && /usr/bin/base64 -d $MG_GZFILE | /bin/gunzip > $MG_FILE
[ -f $ACL_GZFILE ] && /usr/bin/base64 -d $ACL_GZFILE | /bin/gunzip > $ACL_FILE
# Copy relevant files
nos_migration_import $NOS_DIR/mgmt_interface.cfg /host/migration
nos_migration_import $MG_FILE /host/migration
nos_migration_import $ACL_FILE /host/migration
nos_migration_import $SNMP_FILE /host/migration
nos_migration_import $NOS_DIR/arp.json /host/fast-reboot
nos_migration_import $NOS_DIR/fdb.json /host/fast-reboot
nos_migration_import $NOS_DIR/default_routes.json /host/fast-reboot
umount $NOS_DIR
rmdir $NOS_DIR
fi
update_mgmt_interface_macaddr /host/migration/mgmt_interface.cfg
migration="TRUE"
umount /mnt/onie-boot
fi
. /host/machine.conf
program_console_speed
if [ -f $FIRST_BOOT_FILE ]; then
echo "First boot detected. Performing first boot tasks..."
if [ -n "$aboot_platform" ]; then
platform=$aboot_platform
elif [ -n "$onie_platform" ]; then
platform=$onie_platform
else
echo "Unknown SONiC platform"
firsttime_exit
fi
# Try to take old configuration saved during installation
# and create a flag in /tmp/ to let updategraph service know
if [ -d /host/old_config ]; then
mv -f /host/old_config /etc/sonic/
rm -rf /etc/sonic/old_config/old_config
touch /tmp/pending_config_migration
elif [ -f /host/minigraph.xml ]; then
mkdir -p /etc/sonic/old_config
mv /host/minigraph.xml /etc/sonic/old_config/
[ -f /host/acl.json ] && mv /host/acl.json /etc/sonic/old_config/
[ -f /host/snmp.yml ] && mv /host/snmp.yml /etc/sonic/old_config/
touch /tmp/pending_config_migration
elif [ -n "$migration" ] && [ -f /host/migration/minigraph.xml ]; then
mkdir -p /etc/sonic/old_config
mv /host/migration/minigraph.xml /etc/sonic/old_config/
[ -f /host/migration/acl.json ] && mv /host/migration/acl.json /etc/sonic/old_config/
[ -f /host/migration/snmp.yml ] && mv /host/migration/snmp.yml /etc/sonic/old_config/
touch /tmp/pending_config_migration
[ -f /etc/sonic/updategraph.conf ] && sed -i -e "s/enabled=false/enabled=true/g" /etc/sonic/updategraph.conf
else
touch /tmp/pending_config_initialization
fi
# Notify firstboot to Platform, to use it for reboot-cause
touch /tmp/notify_firstboot_to_platform
# Create /host/reboot-cause/platform/ directory
# can be used to track last reboot reason by some platforms
if [ ! -d /host/reboot-cause/platform ]; then
mkdir -p /host/reboot-cause/platform
fi
if [ -d /host/image-$SONIC_VERSION/platform/$platform ]; then
dpkg -i /host/image-$SONIC_VERSION/platform/$platform/*.deb
fi
sync
# If the unit booted into SONiC from another NOS's grub,
# we now install a grub for SONiC.
if [ -n "$onie_platform" ] && [ -n "$migration" ]; then
grub_bin=$(ls /host/image-$SONIC_VERSION/platform/x86_64-grub/grub-pc-bin*.deb 2> /dev/null)
if [ -z "$grub_bin" ]; then
log_migration "Unable to locate grub package !"
firsttime_exit
fi
dpkg -i $grub_bin > /dev/null 2>&1
if [ $? != 0 ]; then
log_migration "Unable to install grub package !"
firsttime_exit
fi
# Determine the block device to install grub
sonic_dev=$(blkid | grep SONiC-OS | head -n 1 | awk '{print $1}' | sed -e 's/[0-9]:.*$//')
if [ -z "$sonic_dev" ]; then
log_migration "Unable to determine sonic partition !"
firsttime_exit
fi
grub-install --boot-directory=/host --recheck $sonic_dev 2>/dev/null
if [ $? != 0 ]; then
log_migration "grub install failed !"
firsttime_exit
fi
# The SONiC "raw" build mode has already generated a proto grub.cfg
# as part of the migration. Platform specific constants need to be
# retrieved from installer.conf (if present) and assigned.
. /usr/share/sonic/device/$platform/installer.conf
if [ ! -z "$CONSOLE_PORT" ]; then
field="\-\-port"
string=$(grep $field /host/grub.cfg)
value_extract $string $field
console_port=$value
if [ ! -z "$console_port" ] && [ "$console_port" != "$CONSOLE_PORT" ]; then
sed -i -e "s/\-\-port=$console_port/\-\-port=$CONSOLE_PORT/g" /host/grub.cfg
fi
log_migration "grub.cfg console port=$console_port & installer.conf CONSOLE_PORT=$CONSOLE_PORT"
fi
if [ ! -z "$CONSOLE_DEV" ]; then
field="console"
string=$(grep $field /host/grub.cfg)
value_extract $string $field
console_dev_name=$(echo $value | sed -e "s/^.*=//" -e "s/,.*//")
console_dev="${console_dev_name#ttyS}"
if [ "$console_dev" != "$CONSOLE_DEV" ]; then
sed -i -e "s/console=ttyS$console_dev/console=ttyS$CONSOLE_DEV/g" /host/grub.cfg
fi
log_migration "grub.cfg console dev=$console_dev & installer.conf CONSOLE_DEV=$CONSOLE_DEV"
fi
if [ ! -z "$VAR_LOG_SIZE" ]; then
field="var_log_size"
string=$(grep $field /host/grub.cfg)
value_extract $string $field
var_log_size=$value
if [ ! -z "$var_log_size" ] && [ "$var_log_size" != "$VAR_LOG_SIZE" ]; then
sed -i -e "s/var_log_size=$var_log_size/var_log_size=$VAR_LOG_SIZE/g" /host/grub.cfg
fi
log_migration "grub.cfg var_log_size=$var_log_size & installer.conf VAR_LOG_SIZE=$VAR_LOG_SIZE"
fi
# Set the root based on the label
sonic_root=$(blkid | grep SONiC-OS | head -n 1 | awk '{print $1}' | sed -e 's/:.*$//')
sonic_root=$(echo "$sonic_root" | sed 's/\//\\\//g')
sed -i -e "s/%%SONIC_ROOT%%/$sonic_root/g" /host/grub.cfg
# Add the Diag and ONIE entries
mount $onie_dev /mnt/onie-boot
. /mnt/onie-boot/onie/grub.d/50_onie_grub >> /host/grub.cfg
umount /mnt/onie-boot
# Initialize the SONiC's grub config
mv /host/grub.cfg /host/grub/grub.cfg
fi
# Create dir where following scripts put their output files
mkdir -p /var/platform
firsttime_exit
fi
# Copy the fsck log into syslog
if [ -f /var/log/fsck.log.gz ]; then
gunzip -d -c /var/log/fsck.log.gz | logger -t "FSCK"
rm -f /var/log/fsck.log.gz
fi
exit 0