| OLD | NEW | 
|    1 #!/bin/sh |    1 #!/bin/sh -eu | 
|    2  |  | 
|    3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |    2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 
|    4 # Use of this source code is governed by a BSD-style license that can be |    3 # Use of this source code is governed by a BSD-style license that can be | 
|    5 # found in the LICENSE file. |    4 # found in the LICENSE file. | 
|    6  |    5 # | 
|    7 # A script to install from removable media to hard disk. |    6 # A script to install from removable media to hard disk. | 
|    8  |    7  | 
|    9 # This is used to force partitions to be larger than they may be |    8 # Load functions and constants for chromeos-install. | 
|   10 # On the source install media |    9 . "$(dirname "$0")/chromeos-common.sh" | 
|   11 INSTALL_ROOT_PART_SIZE=$((1024 * 1024))  # 1024 byte blocks, thus 1 gig |  | 
|   12  |   10  | 
|   13 if [ "$USER_ID" -ne 1000 ] |   11  | 
 |   12 # You can't be root when you start this, because we want to force you to give | 
 |   13 # the root password as confirmation that you're allowed to do it. We don't care | 
 |   14 # what other account you're using; you'll still need to sudo before this works. | 
 |   15 if [ $(id -u) == "0" ] | 
|   14 then |   16 then | 
|   15   echo "" |   17   echo "" | 
|   16   echo "Note: You must be the 'chronos' user to run this script." |   18   echo "Note: You must be the 'chronos' user to run this script." | 
|   17   echo "" |   19   echo "" | 
|   18   echo "Usage: $0 [destination_device] [skip_source_removable_check]" |   20   echo "Usage: $0 [destination_device] [skip_source_removable_check]" | 
|   19   echo "" |   21   echo "" | 
|   20   echo "This will install the usb image to your machine's hard disk." |   22   echo "This will install the usb image to your machine's hard disk." | 
|   21   echo "By default, it will attempt to install to '/dev/sda'." |   23   echo "By default, it will attempt to install to '/dev/sda'." | 
|   22   echo "First 'su chronos' and then run the script. It will ask" |   24   echo "First 'su chronos' and then run the script. It will ask" | 
|   23   echo "for the root password before messing with your hard disk." |   25   echo "for the root password before messing with your hard disk." | 
|   24   echo "Skips checking whether the source device is removable if second" |   26   echo "Skips checking whether the source device is removable if second" | 
|   25   echo "argument is 'true'." |   27   echo "argument is 'true'." | 
|   26   exit 1 |   28   exit 1 | 
|   27 fi |   29 fi | 
|   28  |   30  | 
|   29 DST=/dev/sda |   31 # Default destination is /dev/sda. | 
|   30 if [ -n "$1" ] |   32 DST=${1:-/dev/sda} | 
|   31 then |  | 
|   32   DST="$1" |  | 
|   33 fi |  | 
|   34  |   33  | 
|   35 SKIP_CHECK_SOURCE_REMOVABLE="false" |   34 # Check for a removeable source. | 
|   36 if [ "$2" = "true" ] |   35 SKIP_CHECK_SOURCE_REMOVABLE=${2:-false} | 
|   37 then |  | 
|   38   SKIP_CHECK_SOURCE_REMOVABLE="true" |  | 
|   39 fi |  | 
|   40  |   36  | 
|   41 # First find the root device that we are installing from and verify it. |   37 # First find the root partition that we are installing from and verify it. | 
|   42 CMDLINE=`cat /proc/cmdline` |   38 ROOTDEV=$(rootdev) | 
|   43 SRC_PARTITION=`echo "$CMDLINE" | sed \ |   39 # Remove numbers at end of rootfs device. | 
|   44   's/.*root=\([-/=\.[:alpha:][:digit:]]*\).*/\1/g'` |   40 SRC=${ROOTDEV%%[0-9]*} | 
|   45 if [ ! -b "$SRC_PARTITION" ] |   41 REMOVABLE=$(cat /sys/block/${SRC#/dev/}/removable) | 
|   46 then |  | 
|   47   # Try looking up by label |  | 
|   48   LABEL=`echo "$CMDLINE" | sed \ |  | 
|   49     's/.*root=LABEL=\([-\.[:alpha:][:digit:]]*\).*/\1/g'` |  | 
|   50   if [ "$LABEL" = "$CMDLINE" ] |  | 
|   51   then |  | 
|   52     echo "Error: Unable to find root." |  | 
|   53     exit 1 |  | 
|   54   fi |  | 
|   55   echo "Using source USB device with label: $LABEL" |  | 
|   56   SRC_PARTITION=`readlink -f /dev/disk/by-label/$LABEL` |  | 
|   57 fi |  | 
|   58 if [ ! -b "$SRC_PARTITION" ] |  | 
|   59 then |  | 
|   60   echo "Error: Unable to find USB partition: $SRC_PARTITION" |  | 
|   61   exit 1 |  | 
|   62 fi |  | 
|   63 SRC=`echo "$SRC_PARTITION" | sed 's/\(\/dev\/[[:alpha:]]*\)[[:digit:]]*/\1/g'` |  | 
|   64 if [ ! -b "$SRC" ] |  | 
|   65 then |  | 
|   66   echo "Error: Unable to find USB device: $SRC" |  | 
|   67   exit 1 |  | 
|   68 fi |  | 
|   69 SRC_DEV=${SRC#/dev/} |  | 
|   70 REMOVABLE=`cat /sys/block/$SRC_DEV/removable` |  | 
|   71 if [ "$SKIP_CHECK_SOURCE_REMOVABLE" = "false" -a "$REMOVABLE" != "1" ] |   42 if [ "$SKIP_CHECK_SOURCE_REMOVABLE" = "false" -a "$REMOVABLE" != "1" ] | 
|   72 then |   43 then | 
|   73   echo "Error: Source does not look like a removable device: $SRC_DEV" |   44   echo "Error: Source does not look like a removable device: $SRC" | 
|   74   exit 1 |   45   exit 1 | 
|   75 fi |   46 fi | 
|   76  |   47  | 
|   77 # Check out the dst device. |   48 # Check out the dst device. | 
|   78 if [ ! -b "$DST" ] |   49 if [ ! -b "$DST" ] | 
|   79 then |   50 then | 
|   80   echo "Error: Unable to find destination device: $DST" |   51   echo "Error: Unable to find destination block device: $DST" | 
|   81   exit 1 |   52   exit 1 | 
|   82 fi |   53 fi | 
|   83 DST_DEV=${DST#/dev/} |   54 REMOVABLE=$(cat /sys/block/${DST#/dev/}/removable) | 
|   84 REMOVABLE=`cat /sys/block/$DST_DEV/removable` |  | 
|   85 if [ $? -ne 0 ] |   55 if [ $? -ne 0 ] | 
|   86 then |   56 then | 
|   87   echo "Error: Invalid destiation device (must be whole device): $DST" |   57   echo "Error: Invalid destination device (must be whole device): $DST" | 
|   88   exit 1 |   58   exit 1 | 
|   89 fi |   59 fi | 
|   90 if [ "$REMOVABLE" != "0" ] |   60 if [ "$REMOVABLE" != "0" ] | 
|   91 then |   61 then | 
|   92   echo "Error: Attempt to install to a removeable device: $DST" |   62   echo "Error: Attempt to install to a removeable device: $DST" | 
|   93   exit 1 |   63   exit 1 | 
|   94 fi |   64 fi | 
|   95 if [ "$DST" = "$SRC" ]; then |   65 if [ "$DST" = "$SRC" ]; then | 
|   96   echo "Error: src and dst the same: $SRC = $DST" |   66   echo "Error: src and dst the same: $SRC = $DST" | 
|   97   exit 1 |   67   exit 1 | 
|   98 fi |   68 fi | 
 |   69  | 
|   99 # Ask for root password to be sure. |   70 # Ask for root password to be sure. | 
|  100 echo "This will install from '$SRC' to '$DST'. If you are sure this is " |   71 echo "This will install from '$SRC' to '$DST'. If you are sure this is" | 
|  101 echo "what you want then feel free to enter the root password to proceed." |   72 echo "what you want then feel free to enter the root password to proceed." | 
|  102 sudo -K  # Force them to enter a password |   73 sudo -K | 
|  103  |   74  | 
|  104 # Verify sizes. Since we use sfdisk, this needs to be done after we start |   75 echo "This will erase all data at this destination: $DST" | 
|  105 # asking for the root password. |   76 read -p "Are you sure (y/N)? " SURE | 
|  106 SIZE=`sudo sfdisk -l "$SRC" 2>/dev/null | grep "$SRC_PARTITION" | grep '*' | awk
      '{ print $6 }'` |   77 if [ "$SURE" != "y" ] ; then | 
|  107 if [ $INSTALL_ROOT_PART_SIZE -lt $SIZE ]; then |   78   echo "Ok, better safe than sorry; you answered '$SURE'." | 
|  108   echo "Install partition size too small: $INSTALL_ROOT_PART_SIZE vs $SIZE" |  | 
|  109   echo "(1024 byte blocks)" |  | 
|  110   exit 1 |  | 
|  111 fi |  | 
|  112 SIZE=$INSTALL_ROOT_PART_SIZE |  | 
|  113 SIZE=$((SIZE * 1024)) |  | 
|  114 if [ $SIZE -eq 0 ] |  | 
|  115 then |  | 
|  116   echo "Error: Unable to get system partition size." |  | 
|  117   exit 1 |  | 
|  118 fi |  | 
|  119 SIZE_NEEDED=$((SIZE * 4))  # Assume 2 system images, swap, and user space. |  | 
|  120 DST_SIZE=`cat /sys/block/$DST_DEV/size` |  | 
|  121 DST_SIZE=$((DST_SIZE * 512)) |  | 
|  122 if [ $DST_SIZE -lt $SIZE_NEEDED ] |  | 
|  123 then |  | 
|  124   echo "Error: Destination device is too small ($DST_SIZE vs $SIZE_NEEDED)" |  | 
|  125   exit 1 |   79   exit 1 | 
|  126 fi |   80 fi | 
|  127  |   81  | 
|  128 # Location to temporarily mount the new system image to fix things up. |   82 ############################################################################## | 
|  129 ROOTFS_DIR="/tmp/chromeos_hd_install" |   83 # Helpful constants and functions. | 
|  130  |   84  | 
|  131 # From now on we die on error. We set up a failure handler and continue. |   85 PMBRCODE=/tmp/gptmbr.bin | 
|  132 error_handler() { |   86 TMPFILE=/tmp/install-temp-file | 
|  133   ! sudo umount "$ROOTFS_DIR" |   87 TMPMNT=/tmp/install-mount-point | 
 |   88 mkdir -p ${TMPMNT} | 
|  134  |   89  | 
|  135   echo "Sorry, an error occurred after we messed with the hard disk." |   90 # Create a loop device on the given file at a specified (sector) offset. | 
|  136   echo "The chromeos image was NOT installed successfully and there is " |   91 # Remember the loop device using the global variable LOOP_DEV. | 
|  137   echo "a chance that you will not be able to boot off the netbook hard disk." |   92 # Invoke as: command | 
 |   93 # Args: FILE OFFSET | 
 |   94 loop_offset_setup() { | 
 |   95   local filename=$1 | 
 |   96   local offset=$2 | 
 |   97  | 
 |   98   LOOP_DEV=$(sudo losetup -f) | 
 |   99   if [ -z "$LOOP_DEV" ] | 
 |  100   then | 
 |  101     echo "No free loop device. Free up a loop device or reboot. Exiting." | 
 |  102     exit 1 | 
 |  103   fi | 
 |  104  | 
 |  105   sudo losetup -o $(($offset * 512)) ${LOOP_DEV} ${filename} | 
|  138 } |  106 } | 
|  139 set -e |  | 
|  140 trap error_handler EXIT |  | 
|  141  |  107  | 
|  142 # Set up the partition table. This is different from the USB partition table |  108 # Delete the current loop device. | 
|  143 # because the user paritition expands to fill the space on the disk. |  109 loop_offset_cleanup() { | 
|  144 # NOTE: We currently create an EFI partition rather than swap since the |  110   # losetup -a doesn't always show every active device, so we'll always try to | 
|  145 # eeepc can take advantage of this to speed POST time. |  111   # delete what we think is the active one without checking first. Report | 
|  146 sudo dd if="$SRC" of="$DST" bs=512 count=1 |  112   # success no matter what. | 
 |  113   sudo losetup -d ${LOOP_DEV} || /bin/true | 
 |  114 } | 
|  147  |  115  | 
|  148 PARTITION_NUM_SECTORS=$((SIZE / 512)) |  116 # Mount the existing loop device at the mountpoint in $TMPMNT. | 
|  149 # size of the device in 512 bytes sectors: |  117 # Args: none | 
|  150 DEVICE_NUM_SECTORS=$(cat /sys/block/${DST#/dev/}/size) |  118 mount_on_loop_dev() { | 
 |  119   sudo mount ${LOOP_DEV} ${TMPMNT} | 
 |  120 } | 
|  151  |  121  | 
|  152 sudo sfdisk --force -uS "$DST" <<EOF |  122 # Unmount loop-mounted device. | 
|  153 ,$(($DEVICE_NUM_SECTORS - (3 * $PARTITION_NUM_SECTORS) - 1)),L,-, |  123 umount_from_loop_dev() { | 
|  154 ,$PARTITION_NUM_SECTORS,ef,-, |  124   mount | grep -q " on ${TMPMNT} " && sudo umount ${TMPMNT} | 
|  155 ,$PARTITION_NUM_SECTORS,L,*, |  125 } | 
|  156 ,$PARTITION_NUM_SECTORS,L,-, |  | 
|  157 ; |  | 
|  158 EOF |  | 
|  159 sync |  | 
|  160  |  126  | 
|  161 # Tell kernel to update partition devices based on the new MBR: |  127 # Undo both mount and loop. | 
|  162 sudo sfdisk -R "$DST" |  128 my_cleanup() { | 
 |  129   umount_from_loop_dev | 
 |  130   loop_offset_cleanup | 
 |  131 } | 
|  163  |  132  | 
|  164 # Wait a bit and make sure that the partition device shows up. |  133 # Copy the SRC_PARTITION onto the DST_DEV device at START_OFFSET and label it, | 
|  165 DST_PARTITION="${DST}3" |  134 # assuming it's an ext2-based filesystem. | 
|  166 sleep 5 |  135 # Invoke as: command | 
|  167 if [ ! -b "$DST_PARTITION" ] |  136 # Args: SRC_PARTITION DST_DEV START_OFFSET LABEL | 
|  168 then |  137 install_rootfs() { | 
|  169   echo "Error: Destination system partition was not created: $DST_PARTITION" |  138   local src_partition=$1 | 
|  170   exit 1 |  139   local dst_dev=$2 | 
|  171 fi |  140   local start_offset=$3 | 
 |  141   local label=$4 | 
 |  142    | 
 |  143   # We copy the system image a bit strangely here because we have observed | 
 |  144   # cases in installing to hard disk where people ctrl-c the operation and then | 
 |  145   # are not longer able to properly boot a USB image. This is because when | 
 |  146   # booting from USB we set the root device by label, so if you partially copy | 
 |  147   # the FS here without updating the label then a subsequent USB boot may try | 
 |  148   # to use the wrong device and fail. | 
 |  149   sync | 
|  172  |  150  | 
|  173 # Copy the system image. We sync first to try to make the copy as safe as we |  151   echo "image $label..." | 
|  174 # can. We skip the first block which contains the filesystem label (aka  |  | 
|  175 # volume name). It's 16 bytes in length at 120 bytes in the superblock, |  | 
|  176 # which is itself at offset 1024 of the device. |  | 
|  177 echo "" |  | 
|  178 echo "Copying the system image. This might take a while..." |  | 
|  179 sync |  | 
|  180 sudo dd if="$SRC_PARTITION" of="$DST_PARTITION" bs=1M seek=1 skip=1 |  | 
|  181 # Copy all but the first 2 kibibytes now |  | 
|  182 sudo dd if="$SRC_PARTITION" of="$DST_PARTITION" bs=1024 seek=2 skip=2 count=1022 |  | 
|  183  |  152  | 
|  184 LABEL=$(sudo /sbin/e2label "$SRC_PARTITION") |  153   # Copy first 2 kilobytes of the root image to a temp file, set the label, | 
 |  154   # and then copy it to the dest. | 
 |  155   # NOTE: This hack won't work if we stop using an ext-based rootfs. | 
 |  156   local superblock_offset=1024 | 
 |  157   local label_field_offset=120 | 
 |  158   local label_field_length=16 | 
 |  159   sudo dd if=${src_partition} of=${TMPFILE} bs=512 count=4 | 
 |  160   sudo dd if=/dev/zero of=${TMPFILE} bs=1                \ | 
 |  161     seek=$((superblock_offset + label_field_offset)) \ | 
 |  162     count=$label_field_length conv=notrunc | 
 |  163   echo -n "${label}" | sudo dd of=${TMPFILE} \ | 
 |  164     seek=$((superblock_offset + label_field_offset)) \ | 
 |  165     bs=1 count=$((label_field_length - 1)) conv=notrunc | 
 |  166   # Copy the new label superblock to the dest. | 
 |  167   sudo dd if=${TMPFILE} of=${dst_dev} bs=512 seek=${start_offset} conv=notrunc | 
|  185  |  168  | 
|  186 # Check new file system label. We skip the first char and prefix with 'H' |  169   # Copy the rest of the source to the dest. | 
|  187 NEW_LABEL=`expr substr "$LABEL" 2 ${#LABEL}` |  170   sudo dd if=${src_partition} of=${dst_dev} conv=notrunc \ | 
|  188 NEW_LABEL="H${NEW_LABEL}" |  171     bs=512 skip=4 seek=$((${start_offset} + 4)) | 
|  189 if [ ${#NEW_LABEL} -gt 15 ] |  | 
|  190 then |  | 
|  191   echo "New label " "$NEW_LABEL is too long (greater than 15 bytes)" |  | 
|  192 fi |  | 
|  193  |  172  | 
|  194 # Copy first 2 kibibytes of the partition to a temp file |  173   sync | 
|  195 TEMP_FILE=/tmp/install_part_head |  174 } | 
|  196 sudo dd if="$SRC_PARTITION" of="$TEMP_FILE" bs=1024 count=2 |  | 
|  197  |  175  | 
|  198 # Manually update the label. First zero it, then write the new label. |  176 ############################################################################## | 
|  199 SUPERBLOCK_OFFSET=1024 |  | 
|  200 LABEL_FIELD_OFFSET=120 |  | 
|  201 LABEL_FIELD_LENGTH=16 |  | 
|  202 sudo dd if=/dev/zero of="$TEMP_FILE" bs=1 \ |  | 
|  203     seek=$(( $SUPERBLOCK_OFFSET + $LABEL_FIELD_OFFSET )) \ |  | 
|  204     count=$LABEL_FIELD_LENGTH conv=notrunc |  | 
|  205 echo -n "$NEW_LABEL" | sudo dd of="$TEMP_FILE" \ |  | 
|  206     seek=$(( $SUPERBLOCK_OFFSET + $LABEL_FIELD_OFFSET )) \ |  | 
|  207     bs=1 count=15 conv=notrunc |  | 
|  208  |  177  | 
|  209 # Copy the temp file into the new partition |  178 # What do we expect & require to have on the source device? | 
|  210 sudo dd if="$TEMP_FILE" of="$DST_PARTITION" |  179 STATEFUL_IMG=${SRC}1 | 
|  211 sudo rm -f "$TEMP_FILE" |  180 KERNEL_IMG=${SRC}2 | 
|  212 sync |  181 ROOTFS_IMG=${SRC}3 | 
|  213  |  182  | 
|  214 # Mount root partition |  183 # Steal the PMBR code from the source MBR to put on the dest MBR, for booting | 
|  215 mkdir -p "$ROOTFS_DIR" |  184 # on legacy-BIOS devices. | 
|  216 sudo mount "$DST_PARTITION" "$ROOTFS_DIR" |  185 sudo dd if=$SRC of=$PMBRCODE bs=512 count=1 | 
|  217 # run postinst script |  | 
|  218 sudo "$ROOTFS_DIR"/postinst "$DST_PARTITION" |  | 
|  219 sudo umount "$ROOTFS_DIR" |  | 
|  220  |  186  | 
|  221 # set up stateful partition |  187 # Create the GPT. | 
|  222 STATEFUL_PARTITION="${DST}1" |  188 install_gpt $DST $ROOTFS_IMG $KERNEL_IMG $STATEFUL_IMG $PMBRCODE | 
|  223 sudo mkfs.ext3 "$STATEFUL_PARTITION" |  189  | 
|  224 sudo tune2fs -L "H-STATE" "$STATEFUL_PARTITION" |  190 # Install the content. | 
 |  191 echo "Copying kernel..." | 
 |  192 sudo dd if=${KERNEL_IMG} of=${DST} conv=notrunc bs=512 seek=${START_KERN_A} | 
 |  193 sudo dd if=${KERNEL_IMG} of=${DST} conv=notrunc bs=512 seek=${START_KERN_B} | 
 |  194  | 
 |  195 echo "Copying rootfs..." | 
 |  196 install_rootfs ${ROOTFS_IMG} ${DST} ${START_ROOTFS_A} "H-ROOT-A" | 
 |  197 install_rootfs ${ROOTFS_IMG} ${DST} ${START_ROOTFS_B} "H-ROOT-B" | 
 |  198  | 
 |  199 # We can't guarantee that the kernel will see the new partition table, so we | 
 |  200 # can't use it directly. We could force the kernel to reload it with an ioctl, | 
 |  201 # but then we might have the UI mounting and displaying any old filesystems | 
 |  202 # left over from the last install, and we don't want that either. So any access | 
 |  203 # that we need to do to the destination partitions will have to go through loop | 
 |  204 # devices. | 
 |  205  | 
 |  206 # Now run the postinstall script in each new rootfs. Note that even though | 
 |  207 # we're passing the new destination partition number as an arg, the postinst | 
 |  208 # script had better not try to access it, for the reasons we just gave. | 
 |  209 loop_offset_setup ${DST} ${START_ROOTFS_A} | 
 |  210 trap loop_offset_cleanup EXIT | 
 |  211 mount_on_loop_dev | 
 |  212 trap my_cleanup EXIT | 
 |  213 sudo ${TMPMNT}/postinst ${DST}3 | 
 |  214 umount_from_loop_dev | 
 |  215 trap loop_offset_cleanup EXIT | 
 |  216 loop_offset_cleanup | 
 |  217 trap - EXIT | 
 |  218  | 
 |  219 loop_offset_setup ${DST} ${START_ROOTFS_B} | 
 |  220 trap loop_offset_cleanup EXIT | 
 |  221 mount_on_loop_dev | 
 |  222 trap my_cleanup EXIT | 
 |  223 sudo ${TMPMNT}/postinst ${DST}5 | 
 |  224 umount_from_loop_dev | 
 |  225 trap loop_offset_cleanup EXIT | 
 |  226 loop_offset_cleanup | 
 |  227 trap - EXIT | 
 |  228  | 
 |  229 echo "Installing the stateful partition..." | 
 |  230 loop_offset_setup $DST $START_STATEFUL | 
 |  231 trap loop_offset_cleanup EXIT | 
 |  232 sudo mkfs.ext3 -F -b 4096 -L "H-STATE" ${LOOP_DEV} \ | 
 |  233   $(($NUM_STATEFUL_SECTORS / 8)) | 
|  225  |  234  | 
|  226 # Install dev image into the stateful partition |  235 # Install dev image into the stateful partition | 
|  227 # TODO(sosa@chromium.org) - Remove old autotest support |  236 # TODO(sosa@chromium.org) - Remove old autotest support | 
|  228 if [ -f /root/.dev_mode ] || [ -d /mnt/stateful_partition/dev_image ] ; then |  237 if [ -f /root/.dev_mode ] || [ -d /mnt/stateful_partition/dev_image ] ; then | 
|  229   STATEFUL_DIR=/tmp/stateful_partition_on_hd |  238   mount_on_loop_dev | 
|  230   mkdir -p "$STATEFUL_DIR" |  239   trap my_cleanup EXIT | 
|  231   sudo mount "$STATEFUL_PARTITION" "$STATEFUL_DIR" |  240   sudo cp -fpru /mnt/stateful_partition/dev_image "$TMPMNT/dev_image" | 
|  232   sudo cp -fpru /mnt/stateful_partition/dev_image "$STATEFUL_DIR/dev_image" |  241   umount_from_loop_dev | 
|  233   sudo umount "$STATEFUL_DIR" |  242   trap loop_offset_cleanup EXIT | 
|  234 fi |  243 fi | 
 |  244 loop_offset_cleanup | 
 |  245 trap - EXIT | 
|  235  |  246  | 
|  236 # Force data to disk before we declare done. |  247 # Force data to disk before we declare done. | 
|  237 sync |  248 sync | 
|  238  |  249  | 
|  239 echo "------------------------------------------------------------" |  250 echo "------------------------------------------------------------" | 
|  240 echo "" |  251 echo "" | 
|  241 echo "Installation to '$DST' complete." |  252 echo "Installation to '$DST' complete." | 
|  242 echo "Please shutdown, remove the USB device, cross your fingers, and reboot." |  253 echo "Please shutdown, remove the USB device, cross your fingers, and reboot." | 
|  243  |  | 
|  244 trap - EXIT |  | 
| OLD | NEW |