| OLD | NEW |
| (Empty) | |
| 1 #!/bin/sh |
| 2 |
| 3 # Copyright (c) 2009 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 # Shell functions to help create a bootable image or install to a hard disk. |
| 8 # NOTE: Please keep this file dash and busybox compliant. |
| 9 |
| 10 # Variables that affect the install process. Set these as desired before |
| 11 # sourcing this file. |
| 12 MBR=${MBR:-/tmp/gpt.mbr} |
| 13 GPT=${GPT:-gpt} |
| 14 STATEFUL_PART_SIZE=${STATEFUL_PART_SIZE:-} # Defaults to automatic computation. |
| 15 SWAP_PART_SIZE=${SWAP_PART_SIZE:-$((1024 * 1024 * 1024))} |
| 16 DEFAULT_STATEFUL_PART_SIZE=${DEFAULT_STATEFUL_PART_SIZE:-$((512 * 1024 * 1024))} |
| 17 |
| 18 # Given a path, return the size of the file or device at that path. This |
| 19 # fills in the GET_SIZE_RESULT variable. |
| 20 GET_SIZE_RESULT= |
| 21 get_size() { |
| 22 local path="$1" |
| 23 |
| 24 GET_SIZE_RESULT=0 |
| 25 if [ -b "$path" ] ; then |
| 26 local device="${path#/dev/}" |
| 27 if [ -f "/sys/block/${device}/size" ] ; then |
| 28 # device must be like 'sdb' |
| 29 GET_SIZE_RESULT=$(cat "/sys/block/${device}/size") |
| 30 else |
| 31 # device must be like 'sdb3' |
| 32 local part="$device" |
| 33 local len=${#part} |
| 34 device=$(printf "%0.$((len - 1))s" $part) |
| 35 GET_SIZE_RESULT=$(cat "/sys/block/${device}/${part}/size") |
| 36 fi |
| 37 GET_SIZE_RESULT=$((GET_SIZE_RESULT * 512)) |
| 38 else |
| 39 GET_SIZE_RESULT=$(stat -c%s "$path") # Bytes |
| 40 fi |
| 41 } |
| 42 |
| 43 # A dd equivalent that tries to use a large block size. |
| 44 do_copy() { |
| 45 local in="$1" # Input file |
| 46 local out="$2" # Output file |
| 47 local seek_offset="$3" # Offset where to write the data, in bytes. |
| 48 local skip_offset="$4" # Offset from where to read the data, in bytes. |
| 49 |
| 50 # We use a 4M output block size |
| 51 local bs=$((4 * 1024 * 1024)) |
| 52 |
| 53 local skip_count=$((skip_offset / 512)) |
| 54 |
| 55 # How much initial non-aligned data do we need to copy? |
| 56 local begin_size=$((bs - (seek_offset % bs))) |
| 57 local count=$((begin_size / 512)) |
| 58 local seek=$((seek_offset / 512)) |
| 59 sudo dd if="$in" of="$out" bs=512 \ |
| 60 skip=$skip_count seek=$seek count=$count conv=notrunc |
| 61 |
| 62 # Now copy the rest of the data with output aligned at $bs |
| 63 seek=$(( (seek_offset + begin_size) / bs )) |
| 64 sudo dd if="$in" of="$out" ibs=512 obs=$bs \ |
| 65 skip=$((skip_count + count)) seek=$seek conv=notrunc |
| 66 } |
| 67 |
| 68 # Computes the required install size for the system. This does not include |
| 69 # the stateful partition. The call fills in the SYSTEM_INSTALL_SIZE variable. |
| 70 SYSTEM_INSTALL_SIZE= |
| 71 get_system_install_size() { |
| 72 local rootfs=$1 |
| 73 local type=$2 # Either 'minimal' or 'full' |
| 74 |
| 75 # Approx space for GPT metadata |
| 76 local gpt_size=$((34 * 1024)) |
| 77 |
| 78 # Determine the size of one rootfs partition. |
| 79 get_size "$rootfs" |
| 80 local root_size=$GET_SIZE_RESULT |
| 81 |
| 82 # A minimal install has just the stateful and system partitions. |
| 83 SYSTEM_INSTALL_SIZE=$((gpt_size + root_size)) |
| 84 if [ "$type" = "full" ] ; then |
| 85 # A full install also includes a secondary system partition and swap. |
| 86 SYSTEM_INSTALL_SIZE=$((SYSTEM_INSTALL_SIZE + root_size)) |
| 87 SYSTEM_INSTALL_SIZE=$((SYSTEM_INSTALL_SIZE + SWAP_PART_SIZE)) |
| 88 fi |
| 89 } |
| 90 |
| 91 # Computes the size of the stateful partition. If the STATEFUL_PART_SIZE is |
| 92 # already set then we'll use that, otherwise it will default to the free |
| 93 # space on a block device or a default value if output is to a file. |
| 94 get_stateful_part_size() { |
| 95 local rootfs=$1 |
| 96 local dest=$2 |
| 97 local type=$3 |
| 98 |
| 99 if [ -n "$STATEFUL_PART_SIZE" ] ; then |
| 100 return; # Already computed or they set an override value. |
| 101 fi |
| 102 if [ -b "$dest" ] ; then |
| 103 # For a block device, we'll default to using up all free space. |
| 104 get_system_install_size "$rootfs" "$type" |
| 105 get_size "$dest" |
| 106 STATEFUL_PART_SIZE=$((GET_SIZE_RESULT - SYSTEM_INSTALL_SIZE)) |
| 107 else |
| 108 # We'll use a default stateful part size. |
| 109 STATEFUL_PART_SIZE=$((DEFAULT_STATEFUL_PART_SIZE)) |
| 110 fi |
| 111 } |
| 112 |
| 113 # Verifies that it is really OK to install to the destination. |
| 114 do_verify() { |
| 115 local rootfs=$1 # Path to file/device containing the system rootfs |
| 116 local dest=$2 # Path to file/device on which the install will happen |
| 117 local type=$3 # Either 'minimal' or 'full' |
| 118 |
| 119 if [ -e "$dest" ] ; then |
| 120 echo "This will erase all data at this destination: $dest" |
| 121 read -p "Are you sure (y/N)? " SURE |
| 122 if [ "$SURE" != "y" ] ; then |
| 123 echo "Ok, better safe than sorry; you answered '$SURE'." |
| 124 exit 1 |
| 125 fi |
| 126 |
| 127 if [ -b "$dest" ] ; then |
| 128 # Do we have enough room to install on the block device? |
| 129 get_system_install_size "$rootfs" "$type" |
| 130 get_stateful_part_size "$rootfs" "$dest" "$type" |
| 131 local size_needed=$((SYSTEM_INSTALL_SIZE + STATEFUL_PART_SIZE)) |
| 132 |
| 133 get_size "$dest" |
| 134 local dest_size=$GET_SIZE_RESULT |
| 135 if [ $dest_size -lt $size_needed ] ; then |
| 136 echo "Error: Destination device '$dest' is too small:" |
| 137 echo " ($dest_size vs $size_needed)" |
| 138 exit 1 |
| 139 fi |
| 140 fi |
| 141 fi |
| 142 } |
| 143 |
| 144 do_cleanup() { |
| 145 sudo losetup -d "$LOOP_DEV" |
| 146 } |
| 147 |
| 148 # Given a rootfs, sets up the destination to boot it with proper partitions. |
| 149 install_chromeos() { |
| 150 local rootfs=$1 # Path to file/device containing the system rootfs |
| 151 local dest=$2 # Path to file/device on which to create a bootable install |
| 152 local label_prefix=$3 # Prefix character to use for file system labels |
| 153 local type=$4 # Either 'minimal' or 'full' |
| 154 |
| 155 # How big are each of our partitions? |
| 156 get_size "$rootfs" |
| 157 local system_part_size=$GET_SIZE_RESULT # bytes |
| 158 get_stateful_part_size "$rootfs" "$dest" "$type" |
| 159 local stateful_part_size=$STATEFUL_PART_SIZE |
| 160 local swap_part_size=$SWAP_PART_SIZE |
| 161 |
| 162 # If we output to a file, then create/truncate it to the proper length. |
| 163 if [ ! -b "$dest" ] ; then |
| 164 get_system_install_size "$rootfs" "$type" |
| 165 local dest_size=$((SYSTEM_INSTALL_SIZE + stateful_part_size)) |
| 166 dd if=/dev/zero of="$dest" bs=1 count=1 seek=$((dest_size - 1)) |
| 167 fi |
| 168 |
| 169 # -- Partitions -- |
| 170 |
| 171 # What partition should we make bootable by default? |
| 172 local boot_part= |
| 173 |
| 174 # Set up GPT partition format |
| 175 sudo dd if=/dev/zero of="$dest" bs=1M count=1 conv=notrunc |
| 176 sudo $GPT create -f "$dest" |
| 177 |
| 178 # Add and label all partitions. The current partitioning scheme(s) are very |
| 179 # likely to change. NOTE: The label is not the same as the file system label. |
| 180 if [ "$type" = "minimal" ] ; then |
| 181 # Part Label FS Usage |
| 182 # 1 User Data (ext3/4) Statefule partition |
| 183 # 2 System (ext3/4) Root file system |
| 184 sudo $GPT add -i 1 -s $((stateful_part_size / 512)) -t linux "$dest" |
| 185 sudo $GPT add -i 2 -s $((system_part_size / 512)) -t linux "$dest" |
| 186 |
| 187 sudo $GPT label -i 1 -l "User Data" "$dest" |
| 188 sudo $GPT label -i 2 -l "System" "$dest" |
| 189 |
| 190 boot_part=2 |
| 191 else |
| 192 # Part Label FS Usage |
| 193 # 1 User Data (ext3/4) Statefule partition |
| 194 # 2 Swap swap May be used for swap |
| 195 # 3 System (ext3/4) Root file system |
| 196 # 4 System2 (ext3/4) Root file system (alternate) |
| 197 sudo $GPT add -i 1 -s $((stateful_part_size / 512)) -t linux "$dest" |
| 198 sudo $GPT add -i 2 -s $((swap_size / 512)) -t linux-swap "$dest" |
| 199 sudo $GPT add -i 3 -s $((system_part_size / 512)) -t linux "$dest" |
| 200 sudo $GPT add -i 4 -s $((system_part_size / 512)) -t linux "$dest" |
| 201 |
| 202 sudo $GPT label -i 1 -l "User Data" "$dest" |
| 203 sudo $GPT label -i 2 -l "Swap" "$dest" |
| 204 sudo $GPT label -i 3 -l "System" "$dest" |
| 205 sudo $GPT label -i 4 -l "System2" "$dest" |
| 206 |
| 207 boot_part=3 |
| 208 fi |
| 209 |
| 210 # Set up a boot MBR for booting on legacy devices. |
| 211 sudo $GPT boot -b "$MBR" -i $boot_part "$dest" |
| 212 |
| 213 # -- System Image -- |
| 214 |
| 215 # We copy the system image a bit strangely here because we have observed |
| 216 # cases in install to hard disk where people ctrl-c the operation and then |
| 217 # are not longer able to properly boot a USB image. This is because when |
| 218 # booting from USB we set the root device by LABEL, so if you partially |
| 219 # copy the FS here without updating the label then a subsequent USB boot |
| 220 # may try to use the wrong device and fail. |
| 221 |
| 222 echo "Copying the system image. This might take a while..." |
| 223 local offset_sectors=$(sudo $GPT -r show -l "$dest" | grep "\"System\"" \ |
| 224 | awk '{ print $1 }') |
| 225 |
| 226 # Copy first 2 kibibytes of the root image to a temp file, set the label, |
| 227 # and then copy it to the dest. |
| 228 # NOTE: This hack won't work if we stop using an ext based FS |
| 229 local superblock_offset=1024 |
| 230 local label_field_offset=120 |
| 231 local label_field_length=16 |
| 232 local tmp=$(mktemp) |
| 233 sudo dd if="$rootfs" of="$tmp" bs=1024 count=2 |
| 234 sudo dd if=/dev/zero of="$tmp" bs=1 \ |
| 235 seek=$((superblock_offset + label_field_offset)) \ |
| 236 count=$label_field_length conv=notrunc |
| 237 echo -n "${label_prefix}-ROOT" | sudo dd of="$tmp" \ |
| 238 seek=$((superblock_offset + label_field_offset)) \ |
| 239 bs=1 count=$((label_field_length - 1)) conv=notrunc |
| 240 sudo dd if="$tmp" of="$dest" bs=512 seek=$offset_sectors conv=notrunc |
| 241 rm "$tmp" |
| 242 |
| 243 # Copy all but the first 2 kibibytes to the destination now. |
| 244 do_copy "$rootfs" "$dest" $(( (offset_sectors * 512) + 2048)) 2048 |
| 245 |
| 246 # -- Stateful Partition -- |
| 247 |
| 248 echo "Formatting the user data partition..." |
| 249 offset=$(sudo $GPT -r show -l "$dest" | grep "\"User Data\"" \ |
| 250 | awk '{ print $1 }') |
| 251 LOOP_DEV=$(sudo losetup -f) |
| 252 if [ -z "$LOOP_DEV" ] |
| 253 then |
| 254 echo "No free loop device. Free up a loop device or reboot. exiting." |
| 255 exit 1 |
| 256 fi |
| 257 |
| 258 trap do_cleanup EXIT |
| 259 |
| 260 echo "Creating stateful partition..." |
| 261 sudo losetup -o $((offset * 512)) "$LOOP_DEV" "$dest" |
| 262 sudo mkfs.ext3 -F -b 4096 -L "${label_prefix}-STATE" \ |
| 263 "$LOOP_DEV" $((stateful_part_size / 4096)) |
| 264 sync |
| 265 sudo losetup -d "$LOOP_DEV" |
| 266 sync |
| 267 |
| 268 trap - EXIT |
| 269 } |
| OLD | NEW |