-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathchromeos_shutdown
executable file
·209 lines (174 loc) · 7.6 KB
/
chromeos_shutdown
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#!/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.
# Some startup functions are split into a separate library which may be
# different for different targets (e.g., regular Chrome OS vs. embedded).
. /usr/share/cros/startup_utils.sh
# 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 "shutdown" /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; }
dev_push_paths_to_preserve() { true; }
collect_shutdown_umount_failure_logs() {
(
# Get mount table as seen by this process. This list may not be
# comprehensive: private mounts inside mount namespaces may not
# appear in this list.
echo "Active mounts:"
cat "/proc/self/mountinfo"
# Log information about the dm-crypt device.
echo "Device-mapper target state:"
dmsetup info
# Log upstart jobs that are still running: jobs here can stop the
# stateful partition from getting unmounted.
echo "Active Upstart jobs:"
initctl list | grep running
# Log dbus services still connected to the bus, with a 1 second timeout.
echo "Active D-Bus services:"
dbus-send --system --dest=org.freedesktop.DBus --type=method_call \
--print-reply --reply-timeout=1000 /org/freedesktop/DBus \
org.freedesktop.DBus.ListNames
# Parse pids of processes with active mount namespaces. PID is the fourth
# field and the first line refers to the root mount namespace.
for pid in $(lsns --raw -n -t mnt | cut -f4 -d' ' | tail -n+2); do
echo "====== Comm: $(cat /proc/${pid}/comm) ======"
# The mount namespaces are created by minijail, which shows up as
# 'minijail-init': get child processes for better insight into which
# process is running here.
echo "Child processes:"
ps --ppid ${pid}
# Use findmnt to look inside the mount namespace for any mounts that
# refer to the (enc)stateful partition. These mounts may keep the
# stateful partition from unmounting cleanly.
echo "Open mounts into (enc)stateful:"
findmnt --raw -N ${pid} | grep -e stateful -e mmcblk0p1 -e nvme0n1p1 \
-e sda1
done
# Get a list of processes with files open. lsof is verbose: keep it at the
# end of the log.
echo "Processes with files open:"
lsof -n
) >/run/shutdown_umount_failure.log 2>&1
}
if [ "${CROS_DEBUG}" -eq 1 ]; then
. /usr/share/cros/dev_utils.sh
fi
STATEFUL_PARTITION="/mnt/stateful_partition"
STATEFUL_UPDATE="${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" ] && [ -f "${STATEFUL_UPDATE}" ]; then
STATEFUL_UPDATE_ARGS="$(cat "${STATEFUL_UPDATE}")"
if [ -r "${TARGET_VERSION}" ] && [ ! -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 ${STATEFUL_PARTITION})"
rm -f "${TARGET_VERSION}"
fi
if [ "${STATEFUL_UPDATE_ARGS}" = "clobber" ]; then
PRESERVE_DIR="${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}"
dev_push_paths_to_preserve
# 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, /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.
umount_var_and_home_chronos
rc="$?"
# Check if /home is mounted before attempting to umount().
if mountpoint -q /home; then
umount -n /home
: "$(( rc |= $? ))"
fi
# Unmount /mnt/stateful_partition only if the previous unmounts succeeded.
if [ "${rc}" -eq 0 ]; then
umount -n "${STATEFUL_PARTITION}"
fi
exit "$(( rc | $? ))"
) >/run/mount_encrypted/umount-encrypted.log 2>&1
if [ "$?" -ne 0 ]; then
# Collect information about active mount namespaces and if there are bind
# mounts open inside these namespaces into the (enc)stateful partition.
collect_shutdown_umount_failure_logs
crash_reporter --early --log_to_stderr --umount_failure \
--mount_device="stateful"
crash_reporter --early --log_to_stderr --preserve_across_clobber \
--ephemeral_collect
mv /run/mount_encrypted/umount-encrypted.log "${STATEFUL_PARTITION}/"
mv /run/shutdown_umount_failure.log "${STATEFUL_PARTITION}/"
else
if [ -n "${UPDATE_TARGET}" ] && [ -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,^prjquota "${STATE_DEV}"
fi
fi
fi
rm -f /run/mount_encrypted/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