blob: 7ebf35402e5e7e9c789937628705b2a61c6902a7 [file] [log] [blame] [edit]
#!/bin/sh
# Copyright 2017 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Utility functions for chromeos_startup to run in developer mode.
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"
PATHS_TO_PRESERVE="${PATHS_TO_PRESERVE} /usr/local/etc/wifi_creds"
# Returns if we are running on a debug build.
dev_is_debug_build() {
crossystem 'debug_build?1'
}
# Updates stateful partition if pending update is available.
# shellcheck disable=SC2120
dev_update_stateful_partition() {
local stateful_update_args
local stateful_update_file="${STATEFUL_PARTITION}/.update_available"
if [ $# -gt 0 ]; then
stateful_update_args="$*"
elif [ -f "${stateful_update_file}" ]; then
stateful_update_args="$(cat "${stateful_update_file}")"
else
return
fi
# To remain compatible with the prior update_stateful tarballs, expect
# the "var_new" unpack location, but move it into the new "var_overlay"
# target location.
local var_target="${STATEFUL_PARTITION}/var"
local var_new="${var_target}_new"
local var_target="${var_target}_overlay"
local developer_target="${STATEFUL_PARTITION}/dev_image"
local developer_new="${developer_target}_new"
# Only replace the developer and var_overlay directories if new replacements
# are available.
if [ -d "${developer_new}" ] && [ -d "${var_new}" ]; then
clobber-log -- "Updating from ${developer_new} && ${var_new}."
mkdir -p "${developer_target}" "${var_target}"
find "${developer_target}" "${var_target}" -mindepth 1 -maxdepth 1 \
-exec rm -rf {} +
find "${var_new}" -mindepth 1 -maxdepth 1 -exec mv {} "${var_target}" \;
find "${developer_new}" -mindepth 1 -maxdepth 1 -exec mv {} \
"${developer_target}" \;
rmdir "${developer_new}" "${var_new}"
else
clobber-log -- "Stateful update did not find ${developer_new} & ${var_new}."
clobber-log -- "Keeping old development tools."
fi
# Check for clobber.
if [ "${stateful_update_args}" = "clobber" ]; then
# Find everything in stateful and delete it, except for protected paths, and
# non-empty directories. The non-empty directories contain protected content
# or they would already be empty from depth first traversal.
find "${STATEFUL_PARTITION}" -depth -mindepth 1 \
-not -path "${STATEFUL_PARTITION}/.labmachine" \
-not -path "${developer_target}/*" \
-not -path "${var_target}/*" \
-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}/*" \
-type d -print0 | xargs -0 -r rmdir --ignore-fail-on-non-empty
# Let's really be done before coming back.
sync
fi
rm -rf "${stateful_update_file}"
}
# Keep this list in sync with the var_overlay elements in the DIRLIST
# found in chromeos-install from chromeos-base/chromeos-installer.
MOUNTDIRS="
db/pkg
lib/portage
cache/dlc-images
"
# Mount stateful partition for dev packages.
dev_mount_packages() {
# Optionally pass a device to mount the dev-image from.
local device=$1
# Set up the logging dir that ASAN compiled programs will write to. We want
# any privileged account to be able to write here so unittests need not worry
# about settings things up ahead of time. See crbug.com/453579 for details.
mkdir -p /var/log/asan
chmod 1777 /var/log/asan
# Capture a snapshot of "normal" mount state here, for auditability,
# before we start applying devmode-specific changes.
cat /proc/mounts > /var/log/mount_options.log
# Create dev_image directory in base images in developer mode.
if [ ! -d "${STATEFUL_PARTITION}/dev_image" ]; then
mkdir -p -m 0755 "${STATEFUL_PARTITION}/dev_image"
fi
# Mount the dev image if there is a separate device available.
lvchange -ay "${device}"
if [ -n "${device}" ]; then
mount -n "${device}" "${STATEFUL_PARTITION}/dev_image" \
-o "nodev,noexec,nosuid,noatime,discard"
fi
# Checks and updates stateful partition.
dev_update_stateful_partition
# Mount and then remount to enable exec/suid.
mount_or_fail --bind "${STATEFUL_PARTITION}/dev_image" /usr/local
mount -n -o remount,exec,suid /usr/local
if [ ! -e /usr/share/cros/startup/disable_stateful_security_hardening ]; then
# Add exceptions to allow symlink traversal and opening of FIFOs in the
# dev_image subtree.
local d
for d in "/mnt/stateful_partition/dev_image" "/var/tmp/portage"; do
mkdir -p "${d}"
allow_symlink "${d}"
allow_fifo "${d}"
done
fi
# Set up /var elements needed by gmerge.
# TODO(keescook) Use dev/test package installs instead of piling more
# things here (crosbug.com/14091).
local base
base="${STATEFUL_PARTITION}/var_overlay"
if [ -d "${base}" ]; then
local dir dest
echo "${MOUNTDIRS}" | while read -r dir ; do
if [ -n "${dir}" ]; then
if [ ! -d "${base}/${dir}" ]; then
continue
fi
dest="/var/${dir}"
# Previous versions of this script created a symlink instead of setting
# up a bind mount, so get rid of the symlink if it exists.
(rm -f "${dest}" && mkdir -p "${dest}") || :
mount_or_fail --bind "${base}/${dir}" "${dest}"
fi
done
fi
}
# Unmount stateful partition for dev packages.
dev_unmount_packages() {
# Unmount bind mounts for /var elements needed by gmerge.
local base="/var"
if [ -d "${base}" ]; then
echo "${MOUNTDIRS}" | while read -r dir ; do
if [ -n "${dir}" ]; then
if [ ! -d "${base}/${dir}" ]; then
continue
fi
umount -n "${base}/${dir}"
fi
done
fi
# unmount /usr/local to match dev_mount_package.
umount -n /usr/local
# If the dev image is mounted using a logical volume, unmount it.
if mountpoint -q /mnt/stateful_partition/dev_image; then
umount /mnt/stateful_partition/dev_image
fi
}
# 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
}