init: Add features to preserve paths on clobbering stateful
Clobbering stateful wipes the stateful partition on reboot, this
provides a way to preserve paths from being wiped.
BUG=b:170883046
TEST=# Verify paths are preserved after clobbering stateful
Change-Id: I3be23efaa6cc340243cc1a6aed37d014dca4b96d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2485908
Tested-by: Jae Hoon Kim <kimjae@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
Commit-Queue: Jae Hoon Kim <kimjae@chromium.org>
diff --git a/init/chromeos_shutdown b/init/chromeos_shutdown
index 2ff4c54..31d7114 100755
--- a/init/chromeos_shutdown
+++ b/init/chromeos_shutdown
@@ -30,6 +30,7 @@
CROS_DEBUG="$((! $?))"
dev_unmount_packages() { true; }
+dev_push_paths_to_preserve() { true; }
collect_shutdown_umount_failure_logs() {
(
@@ -79,7 +80,8 @@
. /usr/share/cros/dev_utils.sh
fi
-STATEFUL_UPDATE="/mnt/stateful_partition/.update_available"
+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"
@@ -92,12 +94,12 @@
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 /mnt/stateful_partition)"
+ STATE_DEV="$(findmnt -n -o SOURCE -M ${STATEFUL_PARTITION})"
rm -f "${TARGET_VERSION}"
fi
if [ "${STATEFUL_UPDATE_ARGS}" = "clobber" ]; then
- PRESERVE_DIR="/mnt/stateful_partition/unencrypted/preserve"
+ PRESERVE_DIR="${STATEFUL_PARTITION}/unencrypted/preserve"
# Measure shutdown time up to this point.
bootstat before_preserve
@@ -106,6 +108,7 @@
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.
@@ -162,7 +165,7 @@
# Unmount /mnt/stateful_partition only if the previous unmounts succeeded.
if [ "${rc}" -eq 0 ]; then
- umount -n /mnt/stateful_partition
+ umount -n "${STATEFUL_PARTITION}"
fi
exit "$(( rc | $? ))"
) >/run/mount_encrypted/umount-encrypted.log 2>&1
@@ -175,8 +178,8 @@
--mount_device="stateful"
crash_reporter --early --log_to_stderr --preserve_across_clobber \
--ephemeral_collect
- mv /run/mount_encrypted/umount-encrypted.log /mnt/stateful_partition/
- mv /run/shutdown_umount_failure.log /mnt/stateful_partition/
+ 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.
diff --git a/init/chromeos_startup b/init/chromeos_startup
index ebca67f..76857a1 100755
--- a/init/chromeos_startup
+++ b/init/chromeos_startup
@@ -165,6 +165,7 @@
dev_gather_logs() { true; }
dev_mount_packages() { true; }
dev_is_debug_build() { false; }
+dev_pop_paths_to_preserve() { true; }
# do_* are wrapper functions that may be redefined in developer mode or test
# images. Find more implementation in {dev,test,factory}_utils.sh.
@@ -692,6 +693,7 @@
# Mount dev packages.
dev_mount_packages
+dev_pop_paths_to_preserve
if [ "${DISABLE_STATEFUL_SECURITY_HARDENING}" = "false" ]; then
# Unmount securityfs so that further modifications to inode security policies
diff --git a/init/dev_utils.sh b/init/dev_utils.sh
index 52a6341..07aac7c 100644
--- a/init/dev_utils.sh
+++ b/init/dev_utils.sh
@@ -7,6 +7,14 @@
STATEFUL_PARTITION="/mnt/stateful_partition"
+PRESERVE_DIR="${STATEFUL_PARTITION}/unencrypted/preserve"
+
+# These paths will be preserved through clobbering.
+PATHS_TO_PRESERVE=""
+PATHS_TO_PRESERVE="${PATHS_TO_PRESERVE} /var/lib/servod"
+PATHS_TO_PRESERVE="${PATHS_TO_PRESERVE} /usr/local/servod"
+PATHS_TO_PRESERVE="${PATHS_TO_PRESERVE} /var/lib/device_health_profile"
+
# Returns if we are running on a debug build.
dev_is_debug_build() {
crossystem 'debug_build?1'
@@ -93,7 +101,6 @@
# Check for clobber.
if [ "${stateful_update_args}" = "clobber" ]; then
- local preserve_dir="${STATEFUL_PARTITION}/unencrypted/preserve"
# Find everything in stateful and delete it, except for protected paths, and
# non-empty directories. The non-empty directories contain protected content
@@ -103,13 +110,13 @@
-not -path "${STATEFUL_PARTITION}/.labmachine" \
-not -path "${developer_target}/*" \
-not -path "${var_target}/*" \
- -not -path "${preserve_dir}/*" \
+ -not -path "${PRESERVE_DIR}/*" \
-not -type d -print0 | xargs -0 -r rm -f
find "${STATEFUL_PARTITION}" -depth -mindepth 1 \
-not -path "${developer_target}/*" \
-not -path "${var_target}/*" \
- -not -path "${preserve_dir}/*" \
+ -not -path "${PRESERVE_DIR}/*" \
-type d -print0 | xargs -0 -r rmdir --ignore-fail-on-non-empty
# Let's really be done before coming back.
@@ -227,6 +234,34 @@
umount -n /usr/local
}
+# Copy contents in src path to dst path if it exists.
+copy_path() {
+ local src_path="$1"
+ local dst_path="$2"
+ if [ -d "${src_path}" ]; then
+ mkdir -p "${dst_path}"
+ cp -a "${src_path}/"* "${dst_path}"
+ fi
+}
+
+# Pushes the array of paths to preserve to protected path.
+dev_push_paths_to_preserve() {
+ local path
+ for path in ${PATHS_TO_PRESERVE}; do
+ copy_path "${path}" "${PRESERVE_DIR}/${path}"
+ done
+}
+
+# Pops the array of paths to preserve from protected path.
+dev_pop_paths_to_preserve() {
+ local path
+ for path in ${PATHS_TO_PRESERVE}; do
+ local src_path="${PRESERVE_DIR}/${path}"
+ copy_path "${src_path}" "${path}"
+ rm -rf "${src_path}"
+ done
+}
+
# Load more utilities on test image.
if [ -f /usr/share/cros/test_utils.sh ]; then
. /usr/share/cros/test_utils.sh