| #!/bin/sh |
| |
| # Copyright (c) 2012 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. |
| |
| # Provides alert messages in boot stage, called by chromeos_startup. |
| |
| # Two instances of this script should never be run in parallel: the alert |
| # animations will fight with each other, and there is a potential race in the |
| # emission of the boot-alert-request signal (see http://crosbug.com/33838). |
| |
| # Since this script only provides messages, never abort. |
| set +e |
| |
| # Prints usage help for commands supports |
| usage_help() { |
| echo "Usage: $0 mode terminal [arg ...] |
| |
| warn_dev: Message for warning about developer mode on normal firmware. |
| Arg #1: (optional, default=30) Countdown in seconds before continue |
| |
| enter_dev: Message for entering developer mode from non-dev. |
| Arg #1: (optional, default=30) Countdown in seconds before continue |
| |
| leave_dev: Message when leaving developer mode. |
| Arg: none |
| |
| update_firmware: Message before starting firmware update. |
| Arg: none |
| |
| wipe: Message when starting to erase stateful partition. |
| Arg #1: (optional) Image file to show. |
| |
| power_wash: Message when users wants to wipe the stateful partition. |
| Arg: none |
| |
| self_repair: Message when starting to rebuild stateful partition. |
| |
| dev_fwcheck: Message when staring with developer firmware, to check if there |
| is available updates. |
| |
| block_devmode: Message shown to indicate that dev mode is blocked by request |
| of the device owner. |
| Arg: none |
| " |
| } |
| |
| # Prints out system locale by searching cached settings or VPD. |
| find_current_locale() { |
| # TODO(hungte) Find some better way other than hard coding file path here. |
| local state_file='/mnt/stateful_partition/home/chronos/Local State' |
| # VPD cache file is generated by src/platform/util/dump_vpd_log. |
| local vpd_file='/mnt/stateful_partition/unencrypted/cache/vpd/filtered.txt' |
| local locale="" |
| if [ -f "$state_file" ]; then |
| locale="$(grep -w '"app_locale":' "$state_file" | |
| sed 's/.*"\([^"]*\)",$/\1/')" || locale="" |
| fi |
| if [ -n "$locale" ]; then |
| echo "$locale" |
| elif [ -f "$vpd_file" ]; then |
| sed -nr '/^"initial_locale"=".*"/s/.*="(.*)"/\1/p' "$vpd_file" |
| else |
| vpd -i RO_VPD -g initial_locale 2>/dev/null || true |
| fi |
| } |
| |
| # Shows boot messages in assets folder on screen center if available. |
| # Arguments: message in /usr/share/chromeos-assets/text/boot_messages/$locale |
| show_assets_message_image() { |
| local message="$1" |
| local locale locale_list |
| |
| # Build locale list |
| locale="$(find_current_locale)" || locale="" |
| # Starting from R34, the initial_locale from VPD may have multiple values, |
| # separated by ',' -- and we only want to try the primary one. |
| locale="${locale%%,*}" |
| locale_list="$locale" |
| while [ "${locale%[-_]*}" != "$locale" ]; do |
| locale="${locale%[-_]*}" |
| locale_list="$locale_list $locale" |
| done |
| locale_list="$locale_list en-US en" |
| |
| display_boot_message "$message" "$locale_list" || return "$?" |
| } |
| |
| # Prints the two byte hex code of the matched char or |
| # exists non-zero on timeout. It reads from the current tty. |
| # To override, call it as follows, |
| # match_char_timeout args < "$STDOUT" |
| # |
| # Arguments: time_in_seconds two_byte_hex_match_1 two_byte_hex_match_2 ... |
| match_char_timeout() { |
| local delay_secs="$1" |
| shift |
| |
| local input='' |
| local match='' |
| local start_time=$(date +%s) |
| local stop_time=$((start_time + delay_secs)) |
| local tty_config=$(stty -g) |
| stty raw -echo |
| while [ $delay_secs -gt 0 ]; do |
| input=$(timeout -s KILL ${delay_secs}s head -c 1) |
| [ $? -eq 137 ] && break # Timed out. |
| input=$(printf "%02x" "'$input") |
| for char in "$@"; do |
| if [ "$input" = "$char" ]; then |
| match="$input" |
| break |
| fi |
| done |
| [ -n "$match" ] && break |
| delay_secs=$((stop_time - $(date +%s) )) |
| done |
| # Restores the tty's settings. |
| stty $tty_config |
| |
| [ -z "$match" ] && return 1 |
| printf "$match" |
| return 0 |
| } |
| |
| # Returns if current device is using virtual developer switch. |
| has_virtual_dev_switch() { |
| local VBSD_HONOR_VIRT_DEV_SWITCH="0x400" |
| local vdat_flags="$(crossystem vdat_flags || echo 0)" |
| [ "$((vdat_flags & VBSD_HONOR_VIRT_DEV_SWITCH))" != "0" ] |
| } |
| |
| # Prints message when in developer mode |
| # Argument: time to countdown (in seconds) |
| mode_warn_dev() { |
| local delay_secs="${1:-30}" |
| # Don't show a broken/partial background image. |
| tput clear > "$STDOUT" |
| echo ' |
| |
| |
| |
| |
| |
| |
| __________________________ |
| |.------------------------.| |
| || || |
| || (_) (_) || |
| || || |
| || __________ || |
| || / \ || |
| ||________________________|| |
| / __/___/_____________\__\__ \ |
| / _ \ |
| / /_______\ \_____\ \ |
| /__________________\ \_____________\ |
| \___________________\ \____________/ |
| \ \_-_-_-. |
| /| | |
| | | | |
| \ | |
| \_______/ |
| |
| Chrome OS verification is turned off. |
| Press space to begin recovery. |
| ' >"$STDOUT" |
| # TODO(wad) Use the developer mode firmware image |
| |
| # Read a space bar or Ctrl+D or timeout. |
| local input=$(match_char_timeout "$delay_secs" 04 20 < "$STDOUT") |
| local exit_code=$? |
| tput clear > "$STDOUT" |
| # If we timed out, we're done. |
| [ $exit_code -ne 0 ] && return 0 |
| case "$input" in |
| "04") # Ctrl+D |
| # Done. |
| ;; |
| "20") # Spacebar |
| crossystem recovery_request=1 |
| reboot |
| # To prevent the system from continuing to boot. |
| sleep infinity |
| ;; |
| esac |
| return 0 |
| } |
| |
| |
| # Prints message when entering developer mode |
| # Argument: time to countdown (in seconds) |
| mode_enter_dev() { |
| local delay_secs="${1:-30}" |
| |
| # The text below is only fallback of localized assets message. |
| # Please sync with text there if you want to change the message. |
| local enter_dev1_text=" |
| Local data will be cleared. |
| |
| Modifications you make to the system are not supported by Google, may cause |
| hardware issues and may void warranty. |
| |
| To cancel, turn your computer off now and toggle the Developer Switch back |
| to Verified Mode. |
| " |
| local enter_dev1_virtual_text=" |
| Your system is transitioning to Developer Mode. |
| Local data has been cleared. |
| |
| Modifications you make to the system are not supported by Google, may cause |
| hardware issues and may void warranty. |
| |
| To cancel, turn your computer off now. |
| " |
| if has_virtual_dev_switch; then |
| show_assets_message_image "enter_dev1_virtual" || |
| echo "$enter_dev1_virtual_text" >"$STDOUT" |
| else |
| show_assets_message_image "enter_dev1" || |
| echo "$enter_dev1_text" >"$STDOUT" |
| fi |
| |
| local format='\r %-30s' |
| for dev_count_down in $(seq $delay_secs -1 1); do |
| # Trailing spaces must exist to clear previous message when the printed |
| # counter width changed (ex, 100->99). |
| # TODO(hungte) merge this with assets messages so it can be localized. |
| printf "$format" "Starting in $dev_count_down second(s)..." >"$STDOUT" |
| sleep 1 |
| done |
| |
| # Count-down |
| tput clear >"$STDOUT" && |
| show_assets_message_image "enter_dev2" || |
| # The text by echo below is only fallback of localized assets message. |
| # Please sync with text there if you want to change the message. |
| echo " |
| Preparing system for Developer Mode (may take 5 - 10 minutes). |
| Do not turn your computer off until it has restarted. |
| |
| On reboot, press Ctrl+Alt+[->] (F2) for information about Developer Mode. |
| " >"$STDOUT" |
| # TODO(wad,wfrichar) Request a root password here. |
| # TODO(wad,reinauer) Inform the user of chromeos-firmwareupdate --mode=todev |
| } |
| |
| # Prints message when leaving developer mode |
| mode_leave_dev() { |
| show_assets_message_image "leave_dev" || |
| # The text by echo below is only fallback of localized assets message. |
| # Please sync with text there if you want to change the message. |
| echo " |
| Your system last booted in Developer Mode. |
| Returning to Normal (Verified) Mode... |
| Upon completion, the system will reboot. |
| " >"$STDOUT" |
| } |
| |
| # Prints messages before starting firmware update |
| mode_update_firmware() { |
| show_assets_message_image "update_firmware" || |
| # The text by echo below is only fallback of localized assets message. |
| # Please sync with text there if you want to change the message. |
| echo " |
| Your system is applying a critical update. |
| Please do not turn it off. |
| " >"$STDOUT" |
| } |
| |
| # Prints message before starting to erase stateful partition (wipe). |
| # Argument: (optional) file for splash image to show |
| mode_wipe() { |
| local splash_file="$1" |
| |
| if [ -s "$splash_file" ] && type ply-image >/dev/null 2>&1; then |
| # Do not use background execution because this file is going to be wiped. |
| ply-image "$splash_file" |
| else |
| echo " Erasing stateful partition..." >"$STDOUT" |
| fi |
| } |
| |
| # Prints messages before starting user-initiated wipe. |
| mode_power_wash() { |
| show_assets_message_image "power_wash" || |
| # The text by echo below is only fallback of localized assets message. |
| # Please sync with text there if you want to change the message. |
| echo " |
| Powerwash in progress. Do not switch off your device. |
| |
| Powerwashes happen when critical errors are detected, or when you choose |
| to reset your device. This will reset Chrome OS to be just like new, and |
| you'll be back in operation in just a minute. |
| " >"$STDOUT" |
| } |
| |
| |
| # Prints message before starting to rebuild a corrupted stateful partition. |
| mode_self_repair() { |
| show_assets_message_image "self_repair" || |
| # The text by echo below is only fallback of localized assets message. |
| # Please sync with text there if you want to change the message. |
| echo " |
| Your system is repairing itself. Please wait. |
| " >"$STDOUT" |
| } |
| |
| # Prints message when starting with developer firmware, to check if there's |
| # available updates for firmware. |
| mode_dev_fwcheck() { |
| # TODO(hungte) Find some better way to store firmware value, like using |
| # /etc/lsb-release. Currently the firmware updater may contain fields like |
| # TARGET_* in the beginning of updater script. |
| local TARGET_FWID="" |
| local TARGET_ECID="" |
| # The magic value 40 is verified on current updaters (using line 23-24) |
| eval "$(head -40 /usr/sbin/chromeos-firmwareupdate | |
| grep '^ *TARGET_..ID=')" |
| if [ -z "$TARGET_FWID" -a -z "$TARGET_ECID" ]; then |
| return |
| fi |
| |
| local fwid="$(crossystem fwid)" |
| local ec_info |
| ec_info="$(mosys -k ec info 2>/dev/null)" || ec_info="" |
| local ecid="$(fw_version="Unknown"; eval "$ec_info"; echo "$fw_version")" |
| |
| # Ignore known firmware images carried by updaters with multiple images |
| # TODO(hungte) Replace this by a "compatible list" in updater if such request |
| # becomes a common feature. |
| case "$(mosys platform name 2>/dev/null):$ecid" in |
| "ZGB:0.14" | "Alex:00VFA616" ) |
| TARGET_ECID="$ecid" |
| ;; |
| esac |
| |
| local notify_update=0 |
| if [ "$TARGET_FWID" != "$fwid" ] && |
| [ "$TARGET_FWID" != "IGNORE" ]; then |
| notify_update=1 |
| echo " |
| System firmware update available: [$TARGET_FWID] |
| Currently installed system firmware: [$fwid] |
| " >"$STDOUT" |
| fi |
| if [ "$TARGET_ECID" != "$ecid" ] && |
| [ "$TARGET_ECID" != "IGNORE" ]; then |
| notify_update=1 |
| echo " |
| EC firmware update available: [$TARGET_ECID] |
| Currently installed EC firmware: [$ecid] |
| " >"$STDOUT" |
| fi |
| if [ $notify_update -ne 0 ]; then |
| echo " |
| Firmware auto updating is disabled for developer mode. If you want to |
| manually update your firmware, please run the following command from a |
| root shell: |
| |
| sudo chromeos-firmwareupdate --force --mode=recovery |
| " >"$STDOUT" |
| fi |
| } |
| |
| # Prints a message telling the user that developer mode has been disabled for |
| # the device upon request by the device owner. Depending on hardware support, |
| # the system switches back to verified boot mode automatically or prompts the |
| # user to do so. The system reboots after the user confirms by pressing space or |
| # after timeout. |
| mode_block_devmode() { |
| local delay_secs=30 |
| |
| if has_virtual_dev_switch; then |
| show_assets_message_image "block_devmode_virtual" || |
| # The text by echo below is only fallback of localized assets message. |
| # Please sync with text there if you want to change the message. |
| echo " |
| The device owner has disabled Developer Mode for this device. Please ask |
| the device owner to remove the restriction if you want to use Developer |
| Mode. |
| |
| The system will reboot in Verified Mode. |
| " >"$STDOUT" |
| else |
| # Leave the notification on the screen for 5 minutes to increase chances |
| # the user actually sees it before shutting down the device. |
| delay_secs=300 |
| show_assets_message_image "block_devmode" || |
| # The text by echo below is only fallback of localized assets message. |
| # Please sync with text there if you want to change the message. |
| echo " |
| The device owner has disabled Developer Mode for this device. Please ask |
| the device owner to remove the restriction if you want to use Developer |
| Mode. |
| |
| Please toggle the Developer Switch and reboot the device to return to |
| Verified Mode. |
| " >"$STDOUT" |
| fi |
| |
| # Read a space bar or timeout. |
| local input=$(match_char_timeout "$delay_secs" 20 < "$STDOUT") |
| tput clear > "$STDOUT" |
| |
| if has_virtual_dev_switch; then |
| # Return to verified mode. |
| crossystem disable_dev_request=1 |
| reboot |
| else |
| # Shut down instead of rebooting in a loop. |
| halt |
| fi |
| |
| # To prevent the system from continuing to boot. |
| sleep infinity |
| } |
| |
| # Main initialization and dispatcher |
| main() { |
| # process args |
| if [ $# -lt 2 ]; then |
| usage_help |
| exit 1 |
| fi |
| local mode="$1" |
| # global |
| STDOUT="$2" |
| shift |
| shift |
| |
| # Wait until the boot-alert-ready abstract job has started, indicating that |
| # it's safe to display an alert onscreen. |
| if ! initctl status boot-alert-ready | grep -q running; then |
| initctl emit boot-alert-request |
| fi |
| |
| # Light up the screen if possible. |
| backlight_tool --set_brightness_percent=100 || true |
| |
| # Hides cursor and prevents console from blanking after long inactivity. |
| setterm -cursor off -blank 0 -powersave off -powerdown 0 >"$STDOUT" || true |
| |
| case "$mode" in |
| "warn_dev" | "enter_dev" | "leave_dev" | "dev_fwcheck" | \ |
| "update_firmware" | "wipe" | "power_wash" | "self_repair" | \ |
| "block_devmode" ) |
| mode_"$mode" "$@" |
| ;; |
| * ) |
| usage_help |
| exit 1 |
| ;; |
| esac |
| } |
| |
| # Main Entry |
| if [ -x /usr/sbin/board_boot_alert ]; then |
| # Allow overriding boot-alert behavior for headless devices. |
| /usr/sbin/board_boot_alert "$@" && exit |
| fi |
| main "$@" |