799f22d4c7
* 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.
350 lines
12 KiB
Bash
Executable File
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
|