blob: 2afb6155875937856cd87d4a1065f678c6dc862c [file] [log] [blame]
#!/bin/sh
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Shutdown is best-effort. We don't want to die on errors.
set +e
bootstat shutdown-start
. /sbin/killers
# Remount root in case a developer has remounted it rw for some reason.
mount -n -o remount,ro /
# TODO: swapoff as necessary.
# Kill any that may prevent us from unmounting the stateful partition
# or the crypto-home and then unmount. These should be all that we need
# to unmount for a clean shutdown.
kill_with_open_files_on /mnt/stateful_partition /home/chronos /var
# CROS_DEBUG equals one if we've booted in developer mode or we've booted a
# developer image.
crossystem "cros_debug?1"
CROS_DEBUG=$((! $?))
dev_unmount_packages() { true; }
if [ "${CROS_DEBUG}" -eq 1 ]; then
. /usr/share/cros/dev_utils.sh
fi
STATEFUL_UPDATE="/mnt/stateful_partition/.update_available"
# target_version should only be created for test lab DUTs.
TARGET_VERSION="/run/update_target_version"
UPDATE_TARGET=""
STATE_DEV=""
if [ "${CROS_DEBUG}" = "1" -a -f "${STATEFUL_UPDATE}" ]; then
STATEFUL_UPDATE_ARGS=$(cat "${STATEFUL_UPDATE}")
if [ -r "${TARGET_VERSION}" -a ! -L "${TARGET_VERSION}" ]; then
# Used later to clear Quota parameters from stateful.
UPDATE_TARGET=$(cut -d '.' -f 1 "${TARGET_VERSION}")
STATE_DEV="$(findmnt -n -o SOURCE -M /mnt/stateful_partition)"
rm -f "${TARGET_VERSION}"
fi
if [ "${STATEFUL_UPDATE_ARGS}" = "clobber" ]; then
PRESERVE_DIR="/mnt/stateful_partition/unencrypted/preserve"
# Measure shutdown time up to this point.
bootstat before_preserve
# We preserve a few files. Make sure preservation directory starts empty.
rm -rf "${PRESERVE_DIR}/log"
mkdir -p -m 0755 "${PRESERVE_DIR}"
cp -a "${MNTS}/var/log" "${PRESERVE_DIR}"
# We are about to put this into a directory that will shortly be wiped
# out. Keep a timestamp where it will be preserved as well.
PRESERVE_METRICS="${PRESERVE_DIR}/log/metrics"
bootstat_archive "${PRESERVE_METRICS}/shutdown.$(date '+%Y%m%d%H%M%S')"
fi
fi
# Signal that the clean shutdown point was reached (or at least as
# close to that point as we can be before stateful is unmounted).
crash_reporter --clean_shutdown
# Flush buffers to disk to reflect this part of shutdown in the metrics.
sync
# Measure shutdown time up to this point.
bootstat_archive /var/log/metrics/shutdown.$(date '+%Y%m%d%H%M%S')
# To be safe, flush buffers to disk again before unmounting. (From
# https://crbug.com/760007 it seems that a failed umount can get the filesystem
# into a state that renders a subsequent sync ineffective.)
sync
# Log all the unmount logic to a temp file and move it over to stateful if any
# of the steps failed.
(
set -x
# Unmount stateful partition for dev packages. Will be a NOP unless we're in
# dev mode.
dev_unmount_packages
# Unmount /var/run and /var/lock, which were bind mounted to /run and /run/lock
# respectively to enable backwards compatibility for accessing /run (tmpfs for
# runtime data) through /var.
umount -n /var/run /var/lock
# Unmount /var, /usr/local, /home and encrypted mountpoints, then try to
# unmount /mnt/stateful_partition. Log to /mnt/stateful_partition if any of
# them failed to unmount.
# Note that the other mounts are submounts of /mnt/stateful_partition on
# regular images, but not always true on factory images. To handle both, we
# should unmount /mnt/stateful_partition only if the others successfully
# unmounted, otherwise system may fail to log. See crbug.com/835557.
rc=0
if [ -e /dev/mapper/encstateful ]; then
# Give mount-encrypted umount 10 times to retry, otherwise
# it will fail with 'device is busy' because lazy umount does not finish
# clearing all reference points yet. Check crosbug.com/p/21345.
for i in 1 2 3 4 5 6 7 8 9 10; do
mount-encrypted umount
rc=$?
if [ ${rc} -eq 0 ]; then
break
fi
sleep 0.1
done
umount -n /usr/local /home
# Merge the exit status with the earlier mount-encrypted call.
: $(( rc |= $? ))
else
umount -n /var /usr/local /home
rc=$?
fi
# Unmount /mnt/stateful_partition only if the previous unmounts succeeded.
if [ ${rc} -eq 0 ]; then
umount -n /mnt/stateful_partition
fi
exit $(( rc | $? ))
) >/tmp/umount-encrypted.log 2>&1
if [ $? -ne 0 ]; then
mv /tmp/umount-encrypted.log /mnt/stateful_partition/
(
set -x
cat /proc/$$/mountinfo
dmsetup info
lsof -n
) > /mnt/stateful_partition/shutdown_stateful_umount_failure 2>&1
else
if [ -n "${UPDATE_TARGET}" -a -n "${STATE_DEV}" ]; then
# 10756.0.0 is the first build to turn on ext4 quota.
# See https://crrev.com/c/1016226
# Older builds will fail to mount stateful if quota is enabled.
# This code can be removed when we stop testing pre-R69 FSI updates.
if [ "${UPDATE_TARGET}" -lt 10756 ]; then
if dumpe2fs -h "${STATE_DEV}" 2>/dev/null | \
grep -qe "^Filesystem features:.* quota.*"; then
tune2fs -O^quota -Q^usrquota,^grpquota "${STATE_DEV}"
fi
fi
fi
rm -f /tmp/umount-encrypted.log
fi
# Just in case something didn't unmount properly above.
sync
# Display low battery icon if shutting down due to low battery.
# SHUTDOWN_REASON is passed in with the runlevel event from power manager.
if [ "${SHUTDOWN_REASON}" = "low-battery" ]; then
display_low_battery_alert
fi
# Ensure that we always claim success.
exit 0