| Index: src/platform/installer/chromeos_install_functions.sh
|
| diff --git a/src/platform/installer/chromeos_install_functions.sh b/src/platform/installer/chromeos_install_functions.sh
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..c88a5dd12e2099568b2cfa4e8c8061177da227f4
|
| --- /dev/null
|
| +++ b/src/platform/installer/chromeos_install_functions.sh
|
| @@ -0,0 +1,269 @@
|
| +#!/bin/sh
|
| +
|
| +# Copyright (c) 2009 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.
|
| +
|
| +# Shell functions to help create a bootable image or install to a hard disk.
|
| +# NOTE: Please keep this file dash and busybox compliant.
|
| +
|
| +# Variables that affect the install process. Set these as desired before
|
| +# sourcing this file.
|
| +MBR=${MBR:-/tmp/gpt.mbr}
|
| +GPT=${GPT:-gpt}
|
| +STATEFUL_PART_SIZE=${STATEFUL_PART_SIZE:-} # Defaults to automatic computation.
|
| +SWAP_PART_SIZE=${SWAP_PART_SIZE:-$((1024 * 1024 * 1024))}
|
| +DEFAULT_STATEFUL_PART_SIZE=${DEFAULT_STATEFUL_PART_SIZE:-$((512 * 1024 * 1024))}
|
| +
|
| +# Given a path, return the size of the file or device at that path. This
|
| +# fills in the GET_SIZE_RESULT variable.
|
| +GET_SIZE_RESULT=
|
| +get_size() {
|
| + local path="$1"
|
| +
|
| + GET_SIZE_RESULT=0
|
| + if [ -b "$path" ] ; then
|
| + local device="${path#/dev/}"
|
| + if [ -f "/sys/block/${device}/size" ] ; then
|
| + # device must be like 'sdb'
|
| + GET_SIZE_RESULT=$(cat "/sys/block/${device}/size")
|
| + else
|
| + # device must be like 'sdb3'
|
| + local part="$device"
|
| + local len=${#part}
|
| + device=$(printf "%0.$((len - 1))s" $part)
|
| + GET_SIZE_RESULT=$(cat "/sys/block/${device}/${part}/size")
|
| + fi
|
| + GET_SIZE_RESULT=$((GET_SIZE_RESULT * 512))
|
| + else
|
| + GET_SIZE_RESULT=$(stat -c%s "$path") # Bytes
|
| + fi
|
| +}
|
| +
|
| +# A dd equivalent that tries to use a large block size.
|
| +do_copy() {
|
| + local in="$1" # Input file
|
| + local out="$2" # Output file
|
| + local seek_offset="$3" # Offset where to write the data, in bytes.
|
| + local skip_offset="$4" # Offset from where to read the data, in bytes.
|
| +
|
| + # We use a 4M output block size
|
| + local bs=$((4 * 1024 * 1024))
|
| +
|
| + local skip_count=$((skip_offset / 512))
|
| +
|
| + # How much initial non-aligned data do we need to copy?
|
| + local begin_size=$((bs - (seek_offset % bs)))
|
| + local count=$((begin_size / 512))
|
| + local seek=$((seek_offset / 512))
|
| + sudo dd if="$in" of="$out" bs=512 \
|
| + skip=$skip_count seek=$seek count=$count conv=notrunc
|
| +
|
| + # Now copy the rest of the data with output aligned at $bs
|
| + seek=$(( (seek_offset + begin_size) / bs ))
|
| + sudo dd if="$in" of="$out" ibs=512 obs=$bs \
|
| + skip=$((skip_count + count)) seek=$seek conv=notrunc
|
| +}
|
| +
|
| +# Computes the required install size for the system. This does not include
|
| +# the stateful partition. The call fills in the SYSTEM_INSTALL_SIZE variable.
|
| +SYSTEM_INSTALL_SIZE=
|
| +get_system_install_size() {
|
| + local rootfs=$1
|
| + local type=$2 # Either 'minimal' or 'full'
|
| +
|
| + # Approx space for GPT metadata
|
| + local gpt_size=$((34 * 1024))
|
| +
|
| + # Determine the size of one rootfs partition.
|
| + get_size "$rootfs"
|
| + local root_size=$GET_SIZE_RESULT
|
| +
|
| + # A minimal install has just the stateful and system partitions.
|
| + SYSTEM_INSTALL_SIZE=$((gpt_size + root_size))
|
| + if [ "$type" = "full" ] ; then
|
| + # A full install also includes a secondary system partition and swap.
|
| + SYSTEM_INSTALL_SIZE=$((SYSTEM_INSTALL_SIZE + root_size))
|
| + SYSTEM_INSTALL_SIZE=$((SYSTEM_INSTALL_SIZE + SWAP_PART_SIZE))
|
| + fi
|
| +}
|
| +
|
| +# Computes the size of the stateful partition. If the STATEFUL_PART_SIZE is
|
| +# already set then we'll use that, otherwise it will default to the free
|
| +# space on a block device or a default value if output is to a file.
|
| +get_stateful_part_size() {
|
| + local rootfs=$1
|
| + local dest=$2
|
| + local type=$3
|
| +
|
| + if [ -n "$STATEFUL_PART_SIZE" ] ; then
|
| + return; # Already computed or they set an override value.
|
| + fi
|
| + if [ -b "$dest" ] ; then
|
| + # For a block device, we'll default to using up all free space.
|
| + get_system_install_size "$rootfs" "$type"
|
| + get_size "$dest"
|
| + STATEFUL_PART_SIZE=$((GET_SIZE_RESULT - SYSTEM_INSTALL_SIZE))
|
| + else
|
| + # We'll use a default stateful part size.
|
| + STATEFUL_PART_SIZE=$((DEFAULT_STATEFUL_PART_SIZE))
|
| + fi
|
| +}
|
| +
|
| +# Verifies that it is really OK to install to the destination.
|
| +do_verify() {
|
| + local rootfs=$1 # Path to file/device containing the system rootfs
|
| + local dest=$2 # Path to file/device on which the install will happen
|
| + local type=$3 # Either 'minimal' or 'full'
|
| +
|
| + if [ -e "$dest" ] ; then
|
| + echo "This will erase all data at this destination: $dest"
|
| + read -p "Are you sure (y/N)? " SURE
|
| + if [ "$SURE" != "y" ] ; then
|
| + echo "Ok, better safe than sorry; you answered '$SURE'."
|
| + exit 1
|
| + fi
|
| +
|
| + if [ -b "$dest" ] ; then
|
| + # Do we have enough room to install on the block device?
|
| + get_system_install_size "$rootfs" "$type"
|
| + get_stateful_part_size "$rootfs" "$dest" "$type"
|
| + local size_needed=$((SYSTEM_INSTALL_SIZE + STATEFUL_PART_SIZE))
|
| +
|
| + get_size "$dest"
|
| + local dest_size=$GET_SIZE_RESULT
|
| + if [ $dest_size -lt $size_needed ] ; then
|
| + echo "Error: Destination device '$dest' is too small:"
|
| + echo " ($dest_size vs $size_needed)"
|
| + exit 1
|
| + fi
|
| + fi
|
| + fi
|
| +}
|
| +
|
| +do_cleanup() {
|
| + sudo losetup -d "$LOOP_DEV"
|
| +}
|
| +
|
| +# Given a rootfs, sets up the destination to boot it with proper partitions.
|
| +install_chromeos() {
|
| + local rootfs=$1 # Path to file/device containing the system rootfs
|
| + local dest=$2 # Path to file/device on which to create a bootable install
|
| + local label_prefix=$3 # Prefix character to use for file system labels
|
| + local type=$4 # Either 'minimal' or 'full'
|
| +
|
| + # How big are each of our partitions?
|
| + get_size "$rootfs"
|
| + local system_part_size=$GET_SIZE_RESULT # bytes
|
| + get_stateful_part_size "$rootfs" "$dest" "$type"
|
| + local stateful_part_size=$STATEFUL_PART_SIZE
|
| + local swap_part_size=$SWAP_PART_SIZE
|
| +
|
| + # If we output to a file, then create/truncate it to the proper length.
|
| + if [ ! -b "$dest" ] ; then
|
| + get_system_install_size "$rootfs" "$type"
|
| + local dest_size=$((SYSTEM_INSTALL_SIZE + stateful_part_size))
|
| + dd if=/dev/zero of="$dest" bs=1 count=1 seek=$((dest_size - 1))
|
| + fi
|
| +
|
| + # -- Partitions --
|
| +
|
| + # What partition should we make bootable by default?
|
| + local boot_part=
|
| +
|
| + # Set up GPT partition format
|
| + sudo dd if=/dev/zero of="$dest" bs=1M count=1 conv=notrunc
|
| + sudo $GPT create -f "$dest"
|
| +
|
| + # Add and label all partitions. The current partitioning scheme(s) are very
|
| + # likely to change. NOTE: The label is not the same as the file system label.
|
| + if [ "$type" = "minimal" ] ; then
|
| + # Part Label FS Usage
|
| + # 1 User Data (ext3/4) Statefule partition
|
| + # 2 System (ext3/4) Root file system
|
| + sudo $GPT add -i 1 -s $((stateful_part_size / 512)) -t linux "$dest"
|
| + sudo $GPT add -i 2 -s $((system_part_size / 512)) -t linux "$dest"
|
| +
|
| + sudo $GPT label -i 1 -l "User Data" "$dest"
|
| + sudo $GPT label -i 2 -l "System" "$dest"
|
| +
|
| + boot_part=2
|
| + else
|
| + # Part Label FS Usage
|
| + # 1 User Data (ext3/4) Statefule partition
|
| + # 2 Swap swap May be used for swap
|
| + # 3 System (ext3/4) Root file system
|
| + # 4 System2 (ext3/4) Root file system (alternate)
|
| + sudo $GPT add -i 1 -s $((stateful_part_size / 512)) -t linux "$dest"
|
| + sudo $GPT add -i 2 -s $((swap_size / 512)) -t linux-swap "$dest"
|
| + sudo $GPT add -i 3 -s $((system_part_size / 512)) -t linux "$dest"
|
| + sudo $GPT add -i 4 -s $((system_part_size / 512)) -t linux "$dest"
|
| +
|
| + sudo $GPT label -i 1 -l "User Data" "$dest"
|
| + sudo $GPT label -i 2 -l "Swap" "$dest"
|
| + sudo $GPT label -i 3 -l "System" "$dest"
|
| + sudo $GPT label -i 4 -l "System2" "$dest"
|
| +
|
| + boot_part=3
|
| + fi
|
| +
|
| + # Set up a boot MBR for booting on legacy devices.
|
| + sudo $GPT boot -b "$MBR" -i $boot_part "$dest"
|
| +
|
| + # -- System Image --
|
| +
|
| + # We copy the system image a bit strangely here because we have observed
|
| + # cases in install to hard disk where people ctrl-c the operation and then
|
| + # are not longer able to properly boot a USB image. This is because when
|
| + # booting from USB we set the root device by LABEL, so if you partially
|
| + # copy the FS here without updating the label then a subsequent USB boot
|
| + # may try to use the wrong device and fail.
|
| +
|
| + echo "Copying the system image. This might take a while..."
|
| + local offset_sectors=$(sudo $GPT -r show -l "$dest" | grep "\"System\"" \
|
| + | awk '{ print $1 }')
|
| +
|
| + # Copy first 2 kibibytes of the root image to a temp file, set the label,
|
| + # and then copy it to the dest.
|
| + # NOTE: This hack won't work if we stop using an ext based FS
|
| + local superblock_offset=1024
|
| + local label_field_offset=120
|
| + local label_field_length=16
|
| + local tmp=$(mktemp)
|
| + sudo dd if="$rootfs" of="$tmp" bs=1024 count=2
|
| + sudo dd if=/dev/zero of="$tmp" bs=1 \
|
| + seek=$((superblock_offset + label_field_offset)) \
|
| + count=$label_field_length conv=notrunc
|
| + echo -n "${label_prefix}-ROOT" | sudo dd of="$tmp" \
|
| + seek=$((superblock_offset + label_field_offset)) \
|
| + bs=1 count=$((label_field_length - 1)) conv=notrunc
|
| + sudo dd if="$tmp" of="$dest" bs=512 seek=$offset_sectors conv=notrunc
|
| + rm "$tmp"
|
| +
|
| + # Copy all but the first 2 kibibytes to the destination now.
|
| + do_copy "$rootfs" "$dest" $(( (offset_sectors * 512) + 2048)) 2048
|
| +
|
| + # -- Stateful Partition --
|
| +
|
| + echo "Formatting the user data partition..."
|
| + offset=$(sudo $GPT -r show -l "$dest" | grep "\"User Data\"" \
|
| + | awk '{ print $1 }')
|
| + LOOP_DEV=$(sudo losetup -f)
|
| + if [ -z "$LOOP_DEV" ]
|
| + then
|
| + echo "No free loop device. Free up a loop device or reboot. exiting."
|
| + exit 1
|
| + fi
|
| +
|
| + trap do_cleanup EXIT
|
| +
|
| + echo "Creating stateful partition..."
|
| + sudo losetup -o $((offset * 512)) "$LOOP_DEV" "$dest"
|
| + sudo mkfs.ext3 -F -b 4096 -L "${label_prefix}-STATE" \
|
| + "$LOOP_DEV" $((stateful_part_size / 4096))
|
| + sync
|
| + sudo losetup -d "$LOOP_DEV"
|
| + sync
|
| +
|
| + trap - EXIT
|
| +}
|
|
|