-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdev_utils.sh
280 lines (243 loc) · 9.21 KB
/
dev_utils.sh
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
#!/bin/sh
# Copyright 2017 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.
# 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"
# Returns if we are running on a debug build.
dev_is_debug_build() {
crossystem 'debug_build?1'
}
# Check whether the device is allowed to boot in dev mode.
# 1. If a debug build is already installed on the system, ignore block_devmode.
# It is pointless in this case, as the device is already in a state where the
# local user has full control.
# 2. According to recovery mode only boot with signed images, the block_devmode
# could be ignored here -- otherwise factory shim will be blocked expecially
# that RMA center can't reset this device.
#
# Usage: dev_check_block_dev_mode DEV_MODE_FILE
dev_check_block_dev_mode() {
if ! crossystem "devsw_boot?1" "debug_build?0" "recovery_reason?0"; then
return
fi
# The file indicates the system has booted in developer mode and must initiate
# a wiping process in next (normal mode) boot.
local dev_mode_file="$1"
local vpd_block_devmode_file=/sys/firmware/vpd/rw/block_devmode
local block_devmode=
# Checks ordered by run time: First try reading VPD through sysfs.
if [ -f "${vpd_block_devmode_file}" ] &&
[ "$(cat "${vpd_block_devmode_file}")" = "1" ]; then
block_devmode=1
# Second try crossystem.
elif crossystem "block_devmode?1"; then
block_devmode=1
# Third re-read VPD directly from SPI flash (slow!) but only for systems
# that don't have VPD in sysfs and only when NVRAM indicates that it has
# been cleared.
elif [ ! -d /sys/firmware/vpd/rw ] &&
crossystem "nvram_cleared?1" &&
[ "$(vpd -i RW_VPD -g block_devmode)" = "1" ]; then
block_devmode=1
fi
if [ -n "${block_devmode}" ]; then
# Put a flag file into place that will trigger a stateful partition wipe
# after reboot in verified mode.
touch "${dev_mode_file}"
chromeos-boot-alert block_devmode
fi
}
# Updates stateful partition if pending update is available.
dev_update_stateful_partition() {
local stateful_update_file="${STATEFUL_PARTITION}/.update_available"
if [ ! -f "${stateful_update_file}" ]; then
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_old="${var_target}_old"
local var_target="${var_target}_overlay"
local developer_target="${STATEFUL_PARTITION}/dev_image"
local developer_new="${developer_target}_new"
local developer_old="${developer_target}_old"
local stateful_update_args
stateful_update_args="$(cat "${stateful_update_file}")"
# 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}."
rm -rf "${developer_old}" "${var_old}"
mv "${var_target}" "${var_old}" || true
mv "${developer_target}" "${developer_old}" || true
mv "${var_new}" "${var_target}"
mv "${developer_new}" "${developer_target}"
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
# Backgrounded to take off boot path.
rm -rf "${stateful_update_file}" "${developer_old}" "${var_old}" &
}
# Gather logs.
dev_gather_logs() {
# For dev/test images, if .gatherme presents, copy files listed in .gatherme
# to ${STATEFUL_PARTITION}/unencrypted/prior_logs.
local lab_preserve_logs="${STATEFUL_PARTITION}/.gatherme"
local prior_log_dir="${STATEFUL_PARTITION}/unencrypted/prior_logs"
local log_path
if [ ! -f "${lab_preserve_logs}" ]; then
return
fi
sed -e '/^#/ d' -e '/^$/ d' "${lab_preserve_logs}" | \
while read -r log_path; do
if [ -d "${log_path}" ]; then
cp -a -r --parents "${log_path}" "${prior_log_dir}" || true
elif [ -f "${log_path}" ]; then
cp -a "${log_path}" "${prior_log_dir}" || true
fi
done
# shellcheck disable=SC2115
rm -rf /var/*
rm -rf /home/chronos/*
rm "${lab_preserve_logs}"
}
# 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.
if [ -n "${device}" ]; then
mount -n "${device}" "${STATEFUL_PARTITION}/dev_image"
fi
# 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 "${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
}
# Load more utilities on test image.
if [ -f /usr/share/cros/test_utils.sh ]; then
. /usr/share/cros/test_utils.sh
fi