blob: 9d88e6caa6db4ab855cf369e8a305d2120f6a6a0 [file] [log] [blame]
#!/bin/sh -ex
# Copyright (c) 2010 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.
. "$(dirname "$0")/chromeos-common.sh"
. "/opt/google/memento_updater/memento_updater_logging.sh"
. "/opt/google/memento_updater/find_omaha.sh"
if [ $(id -u) -ne 0 ]; then
echo "You must run this as root."
exit 1
fi
clear_fwwp() {
log "Firmware Write Protect disabled, clearing status registers."
flashrom -p internal:bus=lpc --wp-disable
flashrom -p internal:bus=spi --wp-disable
log "WP registers should be cleared now"
}
clear_tpm() {
log "Clearing TPM"
# Reset TPM
# tcsd needs to have not been run. It locks the TPM.
tpmc ppon
tpmc clear
tpmc enable
tpmc activate
firmware_index="0x1007"
firmware_struct_version="1"
firmware_flags="0"
firmware_fw_versions="1 0 1 0"
firmware_reserved="0 0 0 0"
tpmc write $firmware_index $firmware_struct_version $firmware_flags \
$firmware_fw_versions $firmware_reserved
kernel_index="0x1008"
kernel_struct_version="1"
kernel_uid="4c 57 52 47"
kernel_kernel_versions="1 0 1 0"
kernel_reserved="0 0 0 0"
tpmc write $kernel_index $kernel_struct_version $kernel_uid \
$kernel_kernel_versions $kernel_reserved
log "Done clearing TPM"
}
set_time() {
log "Setting time from:"
# Extract only the server and port.
AUSERVER_URL=$(findLSBValue "CHROMEOS_AUSERVER" |
sed "s|/update||; s|http://||")
log "Server $AUSERVER_URL."
echo "Server $AUSERVER_URL."
RESULT=$(htpdate -s "${AUSERVER_URL}" 2>&1)
if ! echo "${RESULT}" | grep -Eq "(failed|unavailable)"; then
log "Success, time set to $(date)"
return 0
fi
log $(echo "${RESULT}" | grep -E "(failed|unavailable)")
log "Failed to set time"
return 1
}
log "Starting Factory Installer."
log "Checking for Firmware Write Protect"
# Only ChromeOS machines have meaninful output here.
if crossystem hwid >/dev/null; then
# Check for physical firmware write protect. We'll only
# clear this stuff if the case is open.
if [ "$(crossystem wpsw_cur)" = "0" ]; then
# Ensure that flash chips are in a known good state.
clear_fwwp
# Ensure that we can wipe TPM if necessary.
clear_tpm
fi
fi
log "Waiting for ethernet connectivity to install"
log "Or disable developer mode to factory reset."
while ! ifconfig eth0 | grep -q "inet addr"; do
# If developer switch is flipped, go to "reset mode" instead of
# network install mode. Make sure gpio can be read (gpio_setup may
# fail if the device is not ready).
if [ "$(crossystem devsw_cur)" = "0" ]; then
log "Performing factory reset"
if ! /usr/sbin/factory_reset.sh; then
log "Factory reset failed."
exit 1
fi
log "Done"
exit 0
fi
sleep 1
done
log "$(ifconfig eth0 | grep 'inet addr')"
set_time || exit 1
# TODO(adlr): pick an install device in a matter that works on x86 and ARM.
# This works on x86 only, afaik.
DST_DRIVE=/dev/sda
DST_FACTORY_PART=3
DST_RELEASE_PART=5
DST_OEM_PART=8
DST_EFI_PART=12
DST_STATE_PART=1
DST_FIRMWARE=/tmp/firmware.sh
# Light up screen in case you can't see our splash image.
LIGHTUP_SCREEN="/usr/sbin/lightup_screen"
if [ -x /usr/sbin/lightup_screen ]; then
${LIGHTUP_SCREEN}
else
log "${LIGHTUP_SCREEN} does not exist or not executable"
fi
log "Factory Install: Setting partition table"
INST_FLAGS="--dst ${DST_DRIVE} --skip_rootfs --run_as_root --yes"
# in factory mode, we need both GPT_LAYOUT and PMBR_CODE always generated.
FACTORY_GPT_LAYOUT=/root/.gpt_layout
FACTORY_PMBR_CODE=/root/.pmbr_code
if [ -s $FACTORY_GPT_LAYOUT ]; then
INST_FLAGS="${INST_FLAGS} --gpt_layout $FACTORY_GPT_LAYOUT"
else
log "ERROR: MISSING $FACTORY_GPT_LAYOUT ; PLEASE REBUILD FACTORY IMAGE."
log "FACTORY INSTALLER STOPPED."
exit 1
fi
if [ -r $FACTORY_PMBR_CODE ]; then
INST_FLAGS="${INST_FLAGS} --pmbr_code $FACTORY_PMBR_CODE"
else
log "ERROR: MISSING $FACTORY_PMBR_CODE ; PLEASE REBUILD FACTORY IMAGE."
log "FACTORY INSTALLER STOPPED."
exit 1
fi
/usr/sbin/chromeos-install $INST_FLAGS 2>&1 | cat >> "$MEMENTO_AU_LOG"
# Load the new partition table. The autoupdater has trouble with loop devices.
sync
echo 3 > /proc/sys/vm/drop_caches
/sbin/sfdisk -R "$DST_DRIVE"
log "Done preparing disk"
FACTORY_CHANNEL_ARG='--force_track=factory-channel'
RELEASE_CHANNEL_ARG='--force_track=release-channel'
OEM_CHANNEL_ARG='--force_track=oempartitionimg-channel'
EFI_CHANNEL_ARG='--force_track=efipartitionimg-channel'
STATE_CHANNEL_ARG='--force_track=stateimg-channel'
FIRMWARE_CHANNEL_ARG='--force_track=firmware-channel'
# Install the partitions
for i in EFI OEM STATE RELEASE FACTORY FIRMWARE; do
if [ "$i" = "FIRMWARE" ]; then
DST="${DST_FIRMWARE}"
else
PART=$(eval "echo \$DST_${i}_PART")
DST="${DST_DRIVE}${PART}"
fi
log "Factory Install: Installing $i image to $DST"
CHANNEL_ARG=$(eval "echo \$${i}_CHANNEL_ARG")
KPART="none"
if [ "$i" = "FACTORY" -o "$i" = "RELEASE" ]; then
# Set up kernel partition
KPART=""
fi
EXTRA_ARG="--skip_postinst"
if [ "$i" = "FACTORY" ]; then
# Do postinst after update
EXTRA_ARG=""
fi
RESULT="$(IS_FACTORY_INSTALL=1 \
/opt/google/memento_updater/memento_updater.sh \
--dst_partition "${DST}" --kernel_partition "${KPART}" \
--allow_removable_boot $CHANNEL_ARG $EXTRA_ARG)"
RETURNCODE="$?"
# memento update has encountered a fatal error.
if [ "${RETURNCODE}" != "0" ]; then
log "Factory install of target ${DST} has failed."
exit 1
fi
# Only updating the primary root/kernel partition is strictly required.
# If the omahaserver is configured to not update others that's fine.
if [ "${RESULT}" != "UPDATED" -a "$i" = "FACTORY" ]; then
log "Factory Install: AU failed"
exit 1
fi
done
# Release image is not allowed to boot unless the factory test is passed
# otherwise the wipe and final verification can be skipped.
# TODO(hungte) do this in memento_updater or postinst may be better
# TODO(hungte) make a better way to find location of cgpt
if ! cgpt add -i $((${DST_RELEASE_PART} - 1)) -P 0 -T 0 -S 0 ${DST_DRIVE}; then
log "Factory Install: failed to lock release image. Destroy all kernels."
# Destroy kernels otherwise the system is still bootable.
dd if=/dev/zero of=${DST_DRIVE}$((${DST_RELEASE_PART} - 1))
dd if=/dev/zero of=${DST_DRIVE}$((${DST_FACTORY_PART} - 1))
exit 1
fi
log "All done installing."
sleep 3
shutdown -r now
sleep 1d # sleep indefinitely to avoid respawning rather than shutting down