| #!/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. |
| |
| UNDO_MOUNTS= |
| cleanup_mounts() |
| { |
| # On failure unmount all saved mount points and repair stateful |
| for mount_point in ${UNDO_MOUNTS}; do |
| umount -n ${mount_point} |
| done |
| # Leave /mnt/stateful_partition mounted for clobber-state to handle. |
| chromeos-boot-alert self_repair /dev/tty1 |
| clobber-log --repair "$STATE_DEV" "Self-repair incoherent stateful partition" |
| exec clobber-state "fast keepimg" |
| } |
| remember_mount() |
| { |
| UNDO_MOUNTS="$1 ${UNDO_MOUNTS}" |
| } |
| mount_or_fail() |
| { |
| local mount_point |
| if mount "$@" ; then |
| # Last parameter contains the mount point |
| shift $(( $# - 1 )) |
| # Push it on the undo stack if we fail later |
| remember_mount "$1" |
| return |
| fi |
| cleanup_mounts |
| } |
| # The kernel mounts /proc, /sys and /dev during initialization, prior |
| # to starting init. |
| |
| mount -n -t tmpfs -o nodev,noexec,nosuid tmp /tmp |
| # Mount debugfs as crossystem requires chromeos_arm driver interface. |
| mount -n -t debugfs debugfs /sys/kernel/debug |
| |
| # bootstat writes timings to both tmpfs and debugfs. |
| bootstat pre-startup |
| |
| IS_FACTORY_MODE= |
| if [ -f /root/.factory_test -o -f /root/.factory_installer ]; then |
| IS_FACTORY_MODE=1 |
| fi |
| |
| mkdir -p /dev/shm /dev/pts |
| mount -n -t tmpfs -o nodev,noexec,nosuid shmfs /dev/shm |
| mount -n -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts |
| |
| # Prepare to mount stateful partition |
| ROOT_DEV=$(rootdev -s) |
| ROOTDEV_RET_CODE=$? |
| ROOTDEV_TYPE=${ROOT_DEV%[0-9]*} |
| # Check if we are booted on physical media. rootdev will fail if we are in |
| # an initramfs or tmpfs rootfs (used for x86 factory images). When using |
| # initrd+tftpboot (used for ARM factory images), ROOTDEV_TYPE will be |
| # /dev/ram. |
| if [ "$ROOTDEV_RET_CODE" = "0" -a "$ROOTDEV_TYPE" != "/dev/ram" ]; then |
| # Find our stateful partition. It's always partition 1. |
| STATE_DEV=${ROOTDEV_TYPE}1 |
| |
| # For factory install shim, we never want to write to the SDCard. |
| # In some cases, we boot the factory install shim directly from removable |
| # media like an SDCard. In those cases we don't want to write to that |
| # removable media. |
| if [ -f /root/.factory_installer ]; then |
| mount -n -t tmpfs -o nodev,noexec,nosuid,mode=0755 tmp \ |
| /mnt/stateful_partition |
| # Fetch our writeable lsb-release from the stateful |
| # partition if available. |
| TMP_STATEFUL="$(mktemp -d)" |
| FACTORY_LSB_REL="dev_image/etc/lsb-factory" |
| mkdir -p /mnt/stateful_partition/dev_image/etc |
| mount -n -t ext4 -o nodev,noexec,nosuid,commit=600 \ |
| "$STATE_DEV" "$TMP_STATEFUL" |
| if [ -f "${TMP_STATEFUL}/${FACTORY_LSB_REL}" ]; then |
| cp -a "${TMP_STATEFUL}/${FACTORY_LSB_REL}" \ |
| /mnt/stateful_partition/${FACTORY_LSB_REL} |
| fi |
| umount "$TMP_STATEFUL" |
| rmdir "$TMP_STATEFUL" |
| |
| # For all other cases, mount stateful partition from STATE_DEV. |
| elif ! mount -n -t ext4 -o nodev,noexec,nosuid,commit=600 \ |
| "$STATE_DEV" /mnt/stateful_partition; then |
| # Try to rebuild the stateful partition by clobber-state |
| # (for security concern, we don't use fast mode) |
| chromeos-boot-alert self_repair /dev/tty1 |
| clobber-log --repair "$STATE_DEV" "Self-repair corrupted stateful partition" |
| exec clobber-state "keepimg" |
| fi |
| |
| # Mount the OEM partition. |
| # mount_or_fail isn't used since this partition only has a filesystem |
| # on some boards. |
| OEM_DEV=${ROOTDEV_TYPE}8 |
| mount -n -t ext4 -o nodev,noexec,nosuid,commit=600,ro \ |
| "$OEM_DEV" /usr/share/oem |
| fi |
| |
| # Sanity check the date (crosbug.com/13200) |
| if [ $(date +%Y) -lt 1970 ]; then |
| date 010200001970.00 |
| fi |
| |
| # DEV_MODE is used to determine if we're booted in developer mode, |
| # by checking only the developer and recovery switch states. |
| # Values: |
| # 0=recovery/non-dev mode, |
| # 1=dev (SSD) mode, |
| # 2=we've rebooted to handle a request for stateful wipe because of |
| # factory or power wash. |
| # Of these the check below assigns 0 or 1. The remaining value(s) will |
| # be assigned later. |
| crossystem "devsw_boot?1" && ! crossystem "mainfw_act?recovery" |
| DEV_MODE=$((! $?)) |
| |
| # CROS_DEBUG equals one if we've booted in developer mode or we've booted a |
| # developer image. |
| crossystem "cros_debug?1" |
| CROS_DEBUG=$((! $?)) |
| |
| # Check if we need to perform firmware update: only if fwupdate_tries is |
| # non-zero or if not using normal (ex, developer or recovery) firmware. |
| FIRMWARE_UPDATE_SCRIPT=/usr/sbin/chromeos-firmwareupdate |
| if ! crossystem "fwupdate_tries?0" "mainfw_type?normal" && |
| [ -x "$FIRMWARE_UPDATE_SCRIPT" ]; then |
| # This file will be collected by chromeos-setgoodkernel |
| FIRMWARE_UPDATE_LOGS=/mnt/stateful_partition/update_firmware.log |
| tries="$(crossystem fwupdate_tries || echo 0)" |
| |
| # Special updating rules for legacy systems. |
| case "$(mosys platform name 2>/dev/null)" in |
| Alex | ZGB ) |
| if [ "$(crossystem mainfw_type)" = developer ]; then |
| tries=0 # Prevents updates if we're in developer mode |
| chromeos-boot-alert dev_fwcheck /dev/tty1 |
| fi |
| ;; |
| esac |
| |
| if [ $tries -gt 0 ]; then |
| crossystem fwupdate_tries=$((tries - 1)) |
| # More messages on console for developer mode and dev builds. |
| [ "$CROS_DEBUG" = "1" ] && |
| FIRMWARE_UPDATE_LOGS="/dev/tty1 $FIRMWARE_UPDATE_LOGS" || true |
| chromeos-boot-alert update_firmware /dev/tty1 |
| (date && "$FIRMWARE_UPDATE_SCRIPT" --mode=startup 2>&1) | |
| tee -a $FIRMWARE_UPDATE_LOGS |
| # Sends "clear screen" terminal command to clear TTY frame buffer, to |
| # prevent user seeing the messages again on system shutdown. |
| [ "$CROS_DEBUG" = 1 ] && tput clear >/dev/tty1 || true |
| fi |
| fi |
| |
| # If we've switched from verified mode to developer mode, clobber the state. |
| # The reverse is not possible to detect reliably, but we try. |
| # In addition, normal and unsupported are treated are equivalent otherwise |
| # booting the first time on a legacy device would clobber state for no reason. |
| # (NOTE, this will not be triggered in recovery mode.) |
| |
| # File used to trigger a stateful reset |
| RESET_FILE="/mnt/stateful_partition/factory_install_reset" |
| |
| # File defined by clobber-state |
| DEV_MODE_FILE="/mnt/stateful_partition/.developer_mode" |
| |
| # If in factory mode or a wipe process is already scheduled, |
| # set DEV_MODE to 2 so that the right thing happens later. |
| if [ -n "$IS_FACTORY_MODE" -o -O "$RESET_FILE" ]; then |
| DEV_MODE=2 |
| fi |
| |
| if [ ${DEV_MODE} -eq 1 ]; then |
| FW_TYPE=$(crossystem mainfw_type) |
| # For platforms using separated normal/developer firmware, we need to display |
| # an extra page for developer mode warning. |
| if [ "${FW_TYPE}" != "developer" ]; then |
| chromeos-boot-alert warn_dev /dev/tty1 |
| fi |
| fi |
| |
| # Transition to devmode |
| if [ ${DEV_MODE} -eq 1 -a ! -O ${DEV_MODE_FILE} ]; then |
| # Delay the first developer mode boot by 5 minutes unless the images is a |
| # developer image. We check the dev image here to avoid a stat(2) on normal |
| # boots |
| # TODO(wad) just have the dev_mode build stamp the stateful. |
| if [ ! -f /root/.dev_mode ]; then |
| # TODO(wad) Throw up a splash. |
| chromeos-boot-alert enter_dev /dev/tty1 |
| # TODO(wad,wfrichar) Have user input sudo/vt2 password here. |
| echo "keepimg" > ${RESET_FILE} |
| clobber-log -- "Enter developer mode" |
| fi |
| |
| # Transition from devmode |
| elif [ ${DEV_MODE} -eq 0 -a -O ${DEV_MODE_FILE} ]; then |
| # When coming back from developer mode, we don't need to clobber |
| # as aggressively. Fast will do the trick. |
| if [ ! -f /root/.dev_mode ]; then |
| chromeos-boot-alert leave_dev /dev/tty1 |
| echo "fast keepimg" > ${RESET_FILE} |
| clobber-log -- "Leave developer mode" |
| fi |
| fi |
| |
| # Check if we have an update to stateful pending. |
| # Note: THIS MUST BE DONE BEFORE CLOBBER STATE. |
| STATEFUL_UPDATE="/mnt/stateful_partition/.update_available" |
| if [ -f "$STATEFUL_UPDATE" ] ; then |
| # To remain compatible with the prior update_stateful tarballs, expect |
| # the "var_new" unpack location, but move it into the new "var_overlay" |
| # target location. |
| VAR_TARGET="/mnt/stateful_partition/var" |
| VAR_NEW="${VAR_TARGET}_new" |
| VAR_OLD="${VAR_TARGET}_old" |
| VAR_TARGET="${VAR_TARGET}_overlay" |
| DEVELOPER_TARGET="/mnt/stateful_partition/dev_image" |
| DEVELOPER_NEW="${DEVELOPER_TARGET}_new" |
| DEVELOPER_OLD="${DEVELOPER_TARGET}_old" |
| STATEFUL_UPDATE_ARGS=$(cat "$STATEFUL_UPDATE") |
| # Remove old state in case this process got interrupted by a reset, this is |
| # usually a no-op. |
| rm -rf "$DEVELOPER_OLD" "$VAR_OLD" |
| # The moves can fail if they were previously interrupted mid-op. |
| mv "$DEVELOPER_TARGET" "$DEVELOPER_OLD" || true |
| mv "$VAR_TARGET" "$VAR_OLD" || true |
| mv "$DEVELOPER_NEW" "$DEVELOPER_TARGET" || true |
| mv "$VAR_NEW" "$VAR_TARGET" || true |
| # Check for clobber. |
| if [ "$STATEFUL_UPDATE_ARGS" = "clobber" ]; then |
| # Removes all dirs except the new dev_image and var_overlay. |
| find /mnt/stateful_partition -mindepth 1 -maxdepth 1 | |
| grep -v -e dev_image\$ -e var_overlay\$ | |
| xargs -d "\n" rm -rf |
| # Let's really be done before coming back. |
| sync |
| else |
| # Backgrounded to take off boot path. |
| rm -rf "$STATEFUL_UPDATE" "$DEVELOPER_OLD" "$VAR_OLD" & |
| fi |
| fi |
| |
| # Check if the stateful partition has requested self-destruction. If DEV_MODE is |
| # 0 or 1, we've already displayed the correct localized image earlier. The only |
| # case we've to handle is when DEV_MODE is 2. |
| # If it's after factory finalization, then the wipe_splash.png should be used |
| # to display the message. This image will contain the text to display as per |
| # the factory's locale. Otherwise, we display the powerwash message. |
| if [ -O "$RESET_FILE" ]; then |
| if [ ${DEV_MODE} -eq 2 ]; then |
| ALTERNATE_WIPE_SCREEN=/mnt/stateful_partition/wipe_splash.png |
| if [ -O "$ALTERNATE_WIPE_SCREEN" ]; then |
| chromeos-boot-alert wipe /dev/tty1 "$ALTERNATE_WIPE_SCREEN" |
| else |
| chromeos-boot-alert power_wash /dev/tty1 |
| fi |
| fi |
| ARGS="$(cat ${RESET_FILE})" |
| exec clobber-state "$ARGS" |
| fi |
| |
| # Make sure unencrypted stateful partition has the needed directories. |
| for d in home home/chronos home/root home/user \ |
| unencrypted/cache unencrypted/preserve; do |
| mkdir -p -m 0755 /mnt/stateful_partition/$d |
| done |
| |
| # Mount /home. This mount inherits nodev,noexec,nosuid from |
| # /mnt/stateful_partition above. |
| mount_or_fail -n --bind /mnt/stateful_partition/home /home |
| |
| # Create, possibly migrate from, the unencrypted stateful partition, |
| # and bind mount the /var and /home/chronos mounts from the encrypted |
| # filesystem /mnt/stateful_partition/encrypted, all managed by the |
| # "mount-encrypted" helper. |
| # Since /var is managed by mount-encrypted, it should not be created |
| # in the unencrypted stateful partition. Its mount point in the root |
| # filesystem exists already from the rootfs image. |
| # Since /home is still mounted from the unencrypted stateful partition, |
| # having /home/chronos already doesn't matter. It will be created by |
| # mount-encrypted if it is missing. |
| # These mounts inherit nodev,noexec,nosuid from the encrypted filesystem |
| # /mnt/stateful_partition/encrypted. |
| remember_mount /var |
| remember_mount /home/chronos |
| mount-encrypted ${IS_FACTORY_MODE:+factory} >/tmp/mount-encrypted.log 2>&1 |
| if [ $? -ne 0 ]; then |
| cleanup_mounts |
| fi |
| |
| # Make sure required /var subdirectories exist. |
| mkdir -p -m 0755 /var/cache /var/db /var/empty /var/lib/ureadahead \ |
| /var/lock /var/log/metrics /var/log/window_manager \ |
| /var/run /var/tmp |
| |
| # /var/tmp must be world-writable and sticky |
| chmod 1777 /var/tmp |
| # /home/root must be group-writable and sticky |
| chmod 1771 /home/root |
| # Selected directories must belong to the chronos user. |
| chown chronos:chronos /home/chronos /var/log/metrics /var/log/window_manager |
| # rsyslog needs to be able to create new logfiles, but not delete other logs |
| chgrp syslog /var/log |
| chmod 1775 /var/log |
| |
| mount_or_fail -n -t tmpfs -o mode=0755,nodev,noexec,nosuid varrun /var/run |
| touch /var/run/.ramfs # TODO: Is this needed? |
| mount_or_fail -n -t tmpfs -o mode=1777,nodev,noexec,nosuid varlock /var/lock |
| touch /var/lock/.ramfs # TODO: Is this needed? |
| mount -n -t tmpfs -o nodev,noexec,nosuid media /media |
| |
| # Mount stateful partition for dev packages |
| # TODO(arkaitzr@chromium.org) - Only use CROS_DEBUG when cros_debug is |
| # correctly set in a test VM after updating itself to itself (that is, it does |
| # not fail cros_au_test_harness). |
| if [ "$CROS_DEBUG" = "1" -o -f /root/.dev_mode ]; then |
| # Capture a snapshot of "normal" mount state here, for auditability, |
| # before we start applying devmode-specific changes. |
| cat /proc/mounts > /var/log/mount_options.log |
| # Create dev_image directory in base images in developer mode. |
| if [ ! -d /mnt/stateful_partition/dev_image ]; then |
| mkdir -p -m 0755 /mnt/stateful_partition/dev_image |
| fi |
| # Mount and then remount to enable exec/suid. |
| mount_or_fail -n --bind /mnt/stateful_partition/dev_image /usr/local |
| mount -n -o remount,exec,suid /usr/local |
| |
| # Set up /var elements needed by gmerge. |
| # TODO(keescook) Use dev/test package installs instead of piling more |
| # things here (crosbug.com/14091). |
| BASE=/mnt/stateful_partition/var_overlay |
| if [ -d ${BASE} ]; then |
| # Keep this list in sync with the var_overlay elements in the DIRLIST |
| # found in chromeos-install from chromeos-base/chromeos-installer. |
| DIRLIST=" |
| db/pkg |
| lib/portage |
| " |
| for DIR in ${DIRLIST}; do |
| if [ ! -d ${BASE}/${DIR} ]; then |
| continue |
| fi |
| DEST=/var/${DIR} |
| if [ -e ${DEST} ]; then |
| continue |
| fi |
| PARENT=$(dirname ${DEST}) |
| mkdir -p ${PARENT} |
| ln -sf ${BASE}/${DIR} ${DEST} |
| done |
| fi |
| fi |
| |
| # Enable crash reporting for all future exec'd processes, even those that have |
| # gone through setuid. |
| echo 2 > /proc/sys/fs/suid_dumpable |
| |
| # Check for extra steps needed for OOBE. These steps are expensive |
| # so they only happen once; when OOBE is complete the OOBE_COMPLETE |
| # file gets created to block this code from running again. |
| # |
| # We also skip the extra steps for factory images (check for |
| # ROOTDEV). |
| |
| OOBE_COMPLETE=/home/chronos/.oobe_completed |
| if [ "$ROOTDEV_RET_CODE" = "0" -a ! -e $OOBE_COMPLETE ]; then |
| # This script dumps VPD RO/RW data into /var/log/vpd_2.0.txt |
| # so that OOBE process can read the default locale setting |
| # from VPD. |
| if [ -x /usr/sbin/dump_vpd_log ]; then |
| /usr/sbin/dump_vpd_log |
| fi |
| |
| # TODO(yjlou): We are developing a more generic hook mechanism |
| # (i.e. pre-OOBE-oem.sh), and will move this block |
| # to new hook point. |
| # |
| # The activate_date script is installed in partner's |
| # board-specific private overlay. Hence the vpd utility |
| # dependency is described in private overlay, instead of |
| # chromeos-init. |
| # |
| # If the activate date script is executable (installed from |
| # the private overlay), run it. |
| if [ -x /usr/sbin/activate_date ]; then |
| # Since this script will invoke flash read/write (around 20 secs), |
| # run it in background. |
| (/usr/sbin/activate_date ; /usr/sbin/dump_vpd_log --force) & |
| fi |
| fi |
| |
| # |
| # Note that ureadahead depends on some of the operations above. |
| # Notably, the command requires /var to be mounted, because the pack |
| # file is located in /var/lib/ureadahead, and ureadahead tracing |
| # requires /sys/kernel/debug be mounted. |
| # |
| ureadahead & |
| |
| bootstat post-startup |
| |
| # Always return success to avoid killing init |
| exit 0 |