| OLD | NEW |
| 1 #!/bin/bash | 1 #!/bin/bash |
| 2 | 2 # |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 # Globals | 7 . "$(dirname "$0")/common_minimal.sh" |
| 8 # ---------------------------------------------------------------------------- | |
| 9 | |
| 10 # Determine script directory | |
| 11 SCRIPT_DIR=$(dirname $0) | |
| 12 PROG=$(basename $0) | |
| 13 GPT=cgpt | |
| 14 | |
| 15 # The tag when the rootfs is changed. | |
| 16 TAG_NEEDS_TO_BE_SIGNED="/root/.need_to_be_signed" | |
| 17 | |
| 18 # List of Temporary files and mount points. | |
| 19 TEMP_FILE_LIST=$(mktemp) | |
| 20 TEMP_DIR_LIST=$(mktemp) | |
| 21 | 8 |
| 22 # Array of actions that are executed during the clean up process. | 9 # Array of actions that are executed during the clean up process. |
| 23 declare -a cleanup_actions | 10 declare -a cleanup_actions |
| 24 | 11 |
| 25 # Adds an action to be executed during the clean up process. | 12 # Adds an action to be executed during the clean up process. |
| 26 # Actions are executed in the reverse order of when they were added. | 13 # Actions are executed in the reverse order of when they were added. |
| 27 # ARGS: ACTION | 14 # ARGS: ACTION |
| 28 add_cleanup_action() { | 15 add_cleanup_action() { |
| 29 cleanup_actions[${#cleanup_actions[*]}]=$1 | 16 cleanup_actions[${#cleanup_actions[*]}]=$1 |
| 30 } | 17 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 } | 68 } |
| 82 | 69 |
| 83 # Prints an error message and exit with an error code. | 70 # Prints an error message and exit with an error code. |
| 84 # Taken from src/scripts/common.sh. | 71 # Taken from src/scripts/common.sh. |
| 85 # Args: MESSAGE | 72 # Args: MESSAGE |
| 86 die() { | 73 die() { |
| 87 error "$1" | 74 error "$1" |
| 88 exit 1 | 75 exit 1 |
| 89 } | 76 } |
| 90 | 77 |
| 91 # Finds and loads the 'shflags' library, or return as failed. | 78 # This will override the trap set in common_minmal.sh |
| 92 load_shflags() { | |
| 93 # Load shflags | |
| 94 if [ -f /usr/lib/shflags ]; then | |
| 95 . /usr/lib/shflags | |
| 96 elif [ -f "${SCRIPT_DIR}/shflags" ]; then | |
| 97 . "${SCRIPT_DIR}/shflags" | |
| 98 elif [ -f "${SCRIPT_DIR}/lib/shflags/shflags" ]; then | |
| 99 . "${SCRIPT_DIR}/lib/shflags/shflags" | |
| 100 else | |
| 101 echo "ERROR: Cannot find the required shflags library." | |
| 102 return 1 | |
| 103 fi | |
| 104 | |
| 105 # Add debug option for debug output below | |
| 106 DEFINE_boolean debug $FLAGS_FALSE "Provide debug messages" "d" | |
| 107 } | |
| 108 | |
| 109 # Functions for debug output | |
| 110 # ---------------------------------------------------------------------------- | |
| 111 | |
| 112 # Reports error message and exit(1) | |
| 113 # Args: error message | |
| 114 err_die() { | |
| 115 echo "ERROR: $*" 1>&2 | |
| 116 exit 1 | |
| 117 } | |
| 118 | |
| 119 # Returns true if we're running in debug mode. | |
| 120 # | |
| 121 # Note that if you don't set up shflags by calling load_shflags(), you | |
| 122 # must set $FLAGS_debug and $FLAGS_TRUE yourself. The default | |
| 123 # behavior is that debug will be off if you define neither $FLAGS_TRUE | |
| 124 # nor $FLAGS_debug. | |
| 125 is_debug_mode() { | |
| 126 [ "${FLAGS_debug:-not$FLAGS_TRUE}" = "$FLAGS_TRUE" ] | |
| 127 } | |
| 128 | |
| 129 # Prints messages (in parameters) in debug mode | |
| 130 # Args: debug message | |
| 131 debug_msg() { | |
| 132 if is_debug_mode; then | |
| 133 echo "DEBUG: $*" 1>&2 | |
| 134 fi | |
| 135 } | |
| 136 | |
| 137 # Functions for temporary files and directories | |
| 138 # ---------------------------------------------------------------------------- | |
| 139 | |
| 140 # Create a new temporary file and return its name. | |
| 141 # File is automatically cleaned when cleanup_temps_and_mounts() is called. | |
| 142 make_temp_file() { | |
| 143 local tempfile=$(mktemp) | |
| 144 echo "$tempfile" >> $TEMP_FILE_LIST | |
| 145 echo $tempfile | |
| 146 } | |
| 147 | |
| 148 # Create a new temporary directory and return its name. | |
| 149 # Directory is automatically deleted and any filesystem mounted on it unmounted | |
| 150 # when cleanup_temps_and_mounts() is called. | |
| 151 make_temp_dir() { | |
| 152 local tempdir=$(mktemp -d) | |
| 153 echo "$tempdir" >> $TEMP_DIR_LIST | |
| 154 echo $tempdir | |
| 155 } | |
| 156 | |
| 157 cleanup_temps_and_mounts() { | |
| 158 for i in $(cat $TEMP_FILE_LIST); do | |
| 159 rm -f $i | |
| 160 done | |
| 161 set +e # umount may fail for unmounted directories | |
| 162 for i in $(cat $TEMP_DIR_LIST); do | |
| 163 if [ -n "$i" ]; then | |
| 164 if has_needs_to_be_resigned_tag "$i"; then | |
| 165 echo "Warning: image may be modified. Please resign image." | |
| 166 fi | |
| 167 sudo umount -d $i 2>/dev/null | |
| 168 rm -rf $i | |
| 169 fi | |
| 170 done | |
| 171 set -e | |
| 172 rm -rf $TEMP_DIR_LIST $TEMP_FILE_LIST | |
| 173 } | |
| 174 | |
| 175 trap "cleanup_temps_and_mounts" EXIT | |
| 176 | |
| 177 # Functions for partition management | |
| 178 # ---------------------------------------------------------------------------- | |
| 179 | |
| 180 # Read GPT table to find the starting location of a specific partition. | |
| 181 # Args: DEVICE PARTNUM | |
| 182 # Returns: offset (in sectors) of partition PARTNUM | |
| 183 partoffset() { | |
| 184 sudo $GPT show -b -i $2 $1 | |
| 185 } | |
| 186 | |
| 187 # Read GPT table to find the size of a specific partition. | |
| 188 # Args: DEVICE PARTNUM | |
| 189 # Returns: size (in sectors) of partition PARTNUM | |
| 190 partsize() { | |
| 191 sudo $GPT show -s -i $2 $1 | |
| 192 } | |
| 193 | |
| 194 # Tags a file system as "needs to be resigned". | |
| 195 # Args: MOUNTDIRECTORY | |
| 196 tag_as_needs_to_be_resigned() { | |
| 197 local mount_dir="$1" | |
| 198 sudo touch "$mount_dir/$TAG_NEEDS_TO_BE_SIGNED" | |
| 199 } | |
| 200 | |
| 201 # Determines if the target file system has the tag for resign | |
| 202 # Args: MOUNTDIRECTORY | |
| 203 # Returns: true if the tag is there otherwise false | |
| 204 has_needs_to_be_resigned_tag() { | |
| 205 local mount_dir="$1" | |
| 206 [ -f "$mount_dir/$TAG_NEEDS_TO_BE_SIGNED" ] | |
| 207 } | |
| 208 | |
| 209 # Determines if the target file system is a Chrome OS root fs | |
| 210 # Args: MOUNTDIRECTORY | |
| 211 # Returns: true if MOUNTDIRECTORY looks like root fs, otherwise false | |
| 212 is_rootfs_partition() { | |
| 213 local mount_dir="$1" | |
| 214 [ -f "$mount_dir/$(dirname "$TAG_NEEDS_TO_BE_SIGNED")" ] | |
| 215 } | |
| 216 | |
| 217 # Mount a partition read-only from an image into a local directory | |
| 218 # Args: IMAGE PARTNUM MOUNTDIRECTORY | |
| 219 mount_image_partition_ro() { | |
| 220 local image=$1 | |
| 221 local partnum=$2 | |
| 222 local mount_dir=$3 | |
| 223 local offset=$(partoffset "$image" "$partnum") | |
| 224 sudo mount -o loop,ro,offset=$((offset * 512)) "$image" "$mount_dir" | |
| 225 } | |
| 226 | |
| 227 # Mount a partition from an image into a local directory | |
| 228 # Args: IMAGE PARTNUM MOUNTDIRECTORY | |
| 229 mount_image_partition() { | |
| 230 local image=$1 | |
| 231 local partnum=$2 | |
| 232 local mount_dir=$3 | |
| 233 local offset=$(partoffset "$image" "$partnum") | |
| 234 # Forcibly call enable_rw_mount. It should fail on unsupported filesystems | |
| 235 # and be idempotent on ext*. | |
| 236 enable_rw_mount "$image" $((offset * 512)) 2> /dev/null | |
| 237 sudo mount -o loop,offset=$((offset * 512)) "$image" "$mount_dir" | |
| 238 if is_rootfs_partition "$mount_dir"; then | |
| 239 tag_as_needs_to_be_resigned "$mount_dir" | |
| 240 fi | |
| 241 } | |
| 242 | |
| 243 # Extract a partition to a file | |
| 244 # Args: IMAGE PARTNUM OUTPUTFILE | |
| 245 extract_image_partition() { | |
| 246 local image=$1 | |
| 247 local partnum=$2 | |
| 248 local output_file=$3 | |
| 249 local offset=$(partoffset "$image" "$partnum") | |
| 250 local size=$(partsize "$image" "$partnum") | |
| 251 dd if=$image of=$output_file bs=512 skip=$offset count=$size conv=notrunc >/de
v/null 2>&1 | |
| 252 } | |
| 253 | |
| 254 # Replace a partition in an image from file | |
| 255 # Args: IMAGE PARTNUM INPUTFILE | |
| 256 replace_image_partition() { | |
| 257 local image=$1 | |
| 258 local partnum=$2 | |
| 259 local input_file=$3 | |
| 260 local offset=$(partoffset "$image" "$partnum") | |
| 261 local size=$(partsize "$image" "$partnum") | |
| 262 dd if=$input_file of=$image bs=512 seek=$offset count=$size conv=notrunc | |
| 263 } | |
| 264 | |
| 265 # For details, see crosutils.git/common.sh | |
| 266 enable_rw_mount() { | |
| 267 local rootfs="$1" | |
| 268 local offset="${2-0}" | |
| 269 | |
| 270 # Make sure we're checking an ext2 image | |
| 271 if ! is_ext2 "$rootfs" $offset; then | |
| 272 echo "enable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2 | |
| 273 return 1 | |
| 274 fi | |
| 275 | |
| 276 local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte | |
| 277 # Dash can't do echo -ne, but it can do printf "\NNN" | |
| 278 # We could use /dev/zero here, but this matches what would be | |
| 279 # needed for disable_rw_mount (printf '\377'). | |
| 280 printf '\000' | | |
| 281 sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \ | |
| 282 conv=notrunc count=1 bs=1 | |
| 283 } | |
| 284 | |
| 285 # For details, see crosutils.git/common.sh | |
| 286 is_ext2() { | |
| 287 local rootfs="$1" | |
| 288 local offset="${2-0}" | |
| 289 | |
| 290 # Make sure we're checking an ext2 image | |
| 291 local sb_magic_offset=$((0x438)) | |
| 292 local sb_value=$(sudo dd if="$rootfs" skip=$((offset + sb_magic_offset)) \ | |
| 293 count=2 bs=1 2>/dev/null) | |
| 294 local expected_sb_value=$(printf '\123\357') | |
| 295 if [ "$sb_value" = "$expected_sb_value" ]; then | |
| 296 return 0 | |
| 297 fi | |
| 298 return 1 | |
| 299 } | |
| 300 | |
| 301 disable_rw_mount() { | |
| 302 local rootfs="$1" | |
| 303 local offset="${2-0}" | |
| 304 | |
| 305 # Make sure we're checking an ext2 image | |
| 306 if ! is_ext2 "$rootfs" $offset; then | |
| 307 echo "disable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2 | |
| 308 return 1 | |
| 309 fi | |
| 310 | |
| 311 local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte | |
| 312 # Dash can't do echo -ne, but it can do printf "\NNN" | |
| 313 # We could use /dev/zero here, but this matches what would be | |
| 314 # needed for disable_rw_mount (printf '\377'). | |
| 315 printf '\377' | | |
| 316 sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \ | |
| 317 conv=notrunc count=1 bs=1 | |
| 318 } | |
| 319 | |
| 320 rw_mount_disabled() { | |
| 321 local rootfs="$1" | |
| 322 local offset="${2-0}" | |
| 323 | |
| 324 # Make sure we're checking an ext2 image | |
| 325 if ! is_ext2 "$rootfs" $offset; then | |
| 326 return 2 | |
| 327 fi | |
| 328 | |
| 329 local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte | |
| 330 local ro_value=$(sudo dd if="$rootfs" skip=$((offset + ro_compat_offset)) \ | |
| 331 count=1 bs=1 2>/dev/null) | |
| 332 local expected_ro_value=$(printf '\377') | |
| 333 if [ "$ro_value" = "$expected_ro_value" ]; then | |
| 334 return 0 | |
| 335 fi | |
| 336 return 1 | |
| 337 } | |
| 338 | |
| 339 # Misc functions | |
| 340 # ---------------------------------------------------------------------------- | |
| 341 | |
| 342 # Returns true if all files in parameters exist. | |
| 343 # Args: List of files | |
| 344 ensure_files_exist() { | |
| 345 local filename return_value=0 | |
| 346 for filename in "$@"; do | |
| 347 if [ ! -f "$filename" -a ! -b "$filename" ]; then | |
| 348 echo "ERROR: Cannot find required file: $filename" | |
| 349 return_value=1 | |
| 350 fi | |
| 351 done | |
| 352 | |
| 353 return $return_value | |
| 354 } | |
| 355 | |
| 356 # Check if the 'chronos' user already has a password | |
| 357 # Args: rootfs | |
| 358 no_chronos_password() { | |
| 359 local rootfs=$1 | |
| 360 sudo grep -q '^chronos:\*:' "$rootfs/etc/shadow" | |
| 361 } | |
| 362 | |
| 363 trap "cleanup" INT TERM EXIT | 79 trap "cleanup" INT TERM EXIT |
| 364 | 80 |
| 365 add_cleanup_action "cleanup_temps_and_mounts" | 81 add_cleanup_action "cleanup_temps_and_mounts" |
| OLD | NEW |