| OLD | NEW |
| (Empty) | |
| 1 #!/bin/sh |
| 2 # |
| 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 |
| 5 # found in the LICENSE file. |
| 6 # |
| 7 # Note: This file must be written in dash compatible way as scripts that use |
| 8 # this may run in the Chrome OS client enviornment. |
| 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 |
| 22 # Finds and loads the 'shflags' library, or return as failed. |
| 23 load_shflags() { |
| 24 # Load shflags |
| 25 if [ -f /usr/lib/shflags ]; then |
| 26 . /usr/lib/shflags |
| 27 elif [ -f "${SCRIPT_DIR}/shflags" ]; then |
| 28 . "${SCRIPT_DIR}/shflags" |
| 29 elif [ -f "${SCRIPT_DIR}/lib/shflags/shflags" ]; then |
| 30 . "${SCRIPT_DIR}/lib/shflags/shflags" |
| 31 else |
| 32 echo "ERROR: Cannot find the required shflags library." |
| 33 return 1 |
| 34 fi |
| 35 |
| 36 # Add debug option for debug output below |
| 37 DEFINE_boolean debug $FLAGS_FALSE "Provide debug messages" "d" |
| 38 } |
| 39 |
| 40 # Functions for debug output |
| 41 # ---------------------------------------------------------------------------- |
| 42 |
| 43 # Reports error message and exit(1) |
| 44 # Args: error message |
| 45 err_die() { |
| 46 echo "ERROR: $*" 1>&2 |
| 47 exit 1 |
| 48 } |
| 49 |
| 50 # Returns true if we're running in debug mode. |
| 51 # |
| 52 # Note that if you don't set up shflags by calling load_shflags(), you |
| 53 # must set $FLAGS_debug and $FLAGS_TRUE yourself. The default |
| 54 # behavior is that debug will be off if you define neither $FLAGS_TRUE |
| 55 # nor $FLAGS_debug. |
| 56 is_debug_mode() { |
| 57 [ "${FLAGS_debug:-not$FLAGS_TRUE}" = "$FLAGS_TRUE" ] |
| 58 } |
| 59 |
| 60 # Prints messages (in parameters) in debug mode |
| 61 # Args: debug message |
| 62 debug_msg() { |
| 63 if is_debug_mode; then |
| 64 echo "DEBUG: $*" 1>&2 |
| 65 fi |
| 66 } |
| 67 |
| 68 # Functions for temporary files and directories |
| 69 # ---------------------------------------------------------------------------- |
| 70 |
| 71 # Create a new temporary file and return its name. |
| 72 # File is automatically cleaned when cleanup_temps_and_mounts() is called. |
| 73 make_temp_file() { |
| 74 local tempfile=$(mktemp) |
| 75 echo "$tempfile" >> $TEMP_FILE_LIST |
| 76 echo $tempfile |
| 77 } |
| 78 |
| 79 # Create a new temporary directory and return its name. |
| 80 # Directory is automatically deleted and any filesystem mounted on it unmounted |
| 81 # when cleanup_temps_and_mounts() is called. |
| 82 make_temp_dir() { |
| 83 local tempdir=$(mktemp -d) |
| 84 echo "$tempdir" >> $TEMP_DIR_LIST |
| 85 echo $tempdir |
| 86 } |
| 87 |
| 88 cleanup_temps_and_mounts() { |
| 89 for i in $(cat $TEMP_FILE_LIST); do |
| 90 rm -f $i |
| 91 done |
| 92 set +e # umount may fail for unmounted directories |
| 93 for i in $(cat $TEMP_DIR_LIST); do |
| 94 if [ -n "$i" ]; then |
| 95 if has_needs_to_be_resigned_tag "$i"; then |
| 96 echo "Warning: image may be modified. Please resign image." |
| 97 fi |
| 98 sudo umount -d $i 2>/dev/null |
| 99 rm -rf $i |
| 100 fi |
| 101 done |
| 102 set -e |
| 103 rm -rf $TEMP_DIR_LIST $TEMP_FILE_LIST |
| 104 } |
| 105 |
| 106 trap "cleanup_temps_and_mounts" EXIT |
| 107 |
| 108 # Functions for partition management |
| 109 # ---------------------------------------------------------------------------- |
| 110 |
| 111 # Read GPT table to find the starting location of a specific partition. |
| 112 # Args: DEVICE PARTNUM |
| 113 # Returns: offset (in sectors) of partition PARTNUM |
| 114 partoffset() { |
| 115 sudo $GPT show -b -i $2 $1 |
| 116 } |
| 117 |
| 118 # Read GPT table to find the size of a specific partition. |
| 119 # Args: DEVICE PARTNUM |
| 120 # Returns: size (in sectors) of partition PARTNUM |
| 121 partsize() { |
| 122 sudo $GPT show -s -i $2 $1 |
| 123 } |
| 124 |
| 125 # Tags a file system as "needs to be resigned". |
| 126 # Args: MOUNTDIRECTORY |
| 127 tag_as_needs_to_be_resigned() { |
| 128 local mount_dir="$1" |
| 129 sudo touch "$mount_dir/$TAG_NEEDS_TO_BE_SIGNED" |
| 130 } |
| 131 |
| 132 # Determines if the target file system has the tag for resign |
| 133 # Args: MOUNTDIRECTORY |
| 134 # Returns: true if the tag is there otherwise false |
| 135 has_needs_to_be_resigned_tag() { |
| 136 local mount_dir="$1" |
| 137 [ -f "$mount_dir/$TAG_NEEDS_TO_BE_SIGNED" ] |
| 138 } |
| 139 |
| 140 # Determines if the target file system is a Chrome OS root fs |
| 141 # Args: MOUNTDIRECTORY |
| 142 # Returns: true if MOUNTDIRECTORY looks like root fs, otherwise false |
| 143 is_rootfs_partition() { |
| 144 local mount_dir="$1" |
| 145 [ -f "$mount_dir/$(dirname "$TAG_NEEDS_TO_BE_SIGNED")" ] |
| 146 } |
| 147 |
| 148 # Mount a partition read-only from an image into a local directory |
| 149 # Args: IMAGE PARTNUM MOUNTDIRECTORY |
| 150 mount_image_partition_ro() { |
| 151 local image=$1 |
| 152 local partnum=$2 |
| 153 local mount_dir=$3 |
| 154 local offset=$(partoffset "$image" "$partnum") |
| 155 sudo mount -o loop,ro,offset=$((offset * 512)) "$image" "$mount_dir" |
| 156 } |
| 157 |
| 158 # Mount a partition from an image into a local directory |
| 159 # Args: IMAGE PARTNUM MOUNTDIRECTORY |
| 160 mount_image_partition() { |
| 161 local image=$1 |
| 162 local partnum=$2 |
| 163 local mount_dir=$3 |
| 164 local offset=$(partoffset "$image" "$partnum") |
| 165 # Forcibly call enable_rw_mount. It should fail on unsupported filesystems |
| 166 # and be idempotent on ext*. |
| 167 enable_rw_mount "$image" $((offset * 512)) 2> /dev/null |
| 168 sudo mount -o loop,offset=$((offset * 512)) "$image" "$mount_dir" |
| 169 if is_rootfs_partition "$mount_dir"; then |
| 170 tag_as_needs_to_be_resigned "$mount_dir" |
| 171 fi |
| 172 } |
| 173 |
| 174 # Extract a partition to a file |
| 175 # Args: IMAGE PARTNUM OUTPUTFILE |
| 176 extract_image_partition() { |
| 177 local image=$1 |
| 178 local partnum=$2 |
| 179 local output_file=$3 |
| 180 local offset=$(partoffset "$image" "$partnum") |
| 181 local size=$(partsize "$image" "$partnum") |
| 182 dd if=$image of=$output_file bs=512 skip=$offset count=$size conv=notrunc >/de
v/null 2>&1 |
| 183 } |
| 184 |
| 185 # Replace a partition in an image from file |
| 186 # Args: IMAGE PARTNUM INPUTFILE |
| 187 replace_image_partition() { |
| 188 local image=$1 |
| 189 local partnum=$2 |
| 190 local input_file=$3 |
| 191 local offset=$(partoffset "$image" "$partnum") |
| 192 local size=$(partsize "$image" "$partnum") |
| 193 dd if=$input_file of=$image bs=512 seek=$offset count=$size conv=notrunc |
| 194 } |
| 195 |
| 196 # For details, see crosutils.git/common.sh |
| 197 enable_rw_mount() { |
| 198 local rootfs="$1" |
| 199 local offset="${2-0}" |
| 200 |
| 201 # Make sure we're checking an ext2 image |
| 202 if ! is_ext2 "$rootfs" $offset; then |
| 203 echo "enable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2 |
| 204 return 1 |
| 205 fi |
| 206 |
| 207 local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte |
| 208 # Dash can't do echo -ne, but it can do printf "\NNN" |
| 209 # We could use /dev/zero here, but this matches what would be |
| 210 # needed for disable_rw_mount (printf '\377'). |
| 211 printf '\000' | |
| 212 sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \ |
| 213 conv=notrunc count=1 bs=1 |
| 214 } |
| 215 |
| 216 # For details, see crosutils.git/common.sh |
| 217 is_ext2() { |
| 218 local rootfs="$1" |
| 219 local offset="${2-0}" |
| 220 |
| 221 # Make sure we're checking an ext2 image |
| 222 local sb_magic_offset=$((0x438)) |
| 223 local sb_value=$(sudo dd if="$rootfs" skip=$((offset + sb_magic_offset)) \ |
| 224 count=2 bs=1 2>/dev/null) |
| 225 local expected_sb_value=$(printf '\123\357') |
| 226 if [ "$sb_value" = "$expected_sb_value" ]; then |
| 227 return 0 |
| 228 fi |
| 229 return 1 |
| 230 } |
| 231 |
| 232 disable_rw_mount() { |
| 233 local rootfs="$1" |
| 234 local offset="${2-0}" |
| 235 |
| 236 # Make sure we're checking an ext2 image |
| 237 if ! is_ext2 "$rootfs" $offset; then |
| 238 echo "disable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2 |
| 239 return 1 |
| 240 fi |
| 241 |
| 242 local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte |
| 243 # Dash can't do echo -ne, but it can do printf "\NNN" |
| 244 # We could use /dev/zero here, but this matches what would be |
| 245 # needed for disable_rw_mount (printf '\377'). |
| 246 printf '\377' | |
| 247 sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \ |
| 248 conv=notrunc count=1 bs=1 |
| 249 } |
| 250 |
| 251 rw_mount_disabled() { |
| 252 local rootfs="$1" |
| 253 local offset="${2-0}" |
| 254 |
| 255 # Make sure we're checking an ext2 image |
| 256 if ! is_ext2 "$rootfs" $offset; then |
| 257 return 2 |
| 258 fi |
| 259 |
| 260 local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte |
| 261 local ro_value=$(sudo dd if="$rootfs" skip=$((offset + ro_compat_offset)) \ |
| 262 count=1 bs=1 2>/dev/null) |
| 263 local expected_ro_value=$(printf '\377') |
| 264 if [ "$ro_value" = "$expected_ro_value" ]; then |
| 265 return 0 |
| 266 fi |
| 267 return 1 |
| 268 } |
| 269 |
| 270 # Misc functions |
| 271 # ---------------------------------------------------------------------------- |
| 272 |
| 273 # Returns true if all files in parameters exist. |
| 274 # Args: List of files |
| 275 ensure_files_exist() { |
| 276 local filename return_value=0 |
| 277 for filename in "$@"; do |
| 278 if [ ! -f "$filename" -a ! -b "$filename" ]; then |
| 279 echo "ERROR: Cannot find required file: $filename" |
| 280 return_value=1 |
| 281 fi |
| 282 done |
| 283 |
| 284 return $return_value |
| 285 } |
| 286 |
| 287 # Check if the 'chronos' user already has a password |
| 288 # Args: rootfs |
| 289 no_chronos_password() { |
| 290 local rootfs=$1 |
| 291 sudo grep -q '^chronos:\*:' "$rootfs/etc/shadow" |
| 292 } |
| 293 |
| 294 trap "cleanup_temps_and_mounts" EXIT |
| OLD | NEW |