| #!/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). |
| # Log to stderr since syslog may not be available at this stage. |
| crash_reporter --log_to_stderr --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 |