| #!/bin/sh | |
| # Copyright 2012 The ChromiumOS Authors | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| # This script can maintain a log file across stateful partition wiping | |
| # transition. | |
| CLOBBER_LOG_FILE="clobber.log" | |
| # Temp folder is always accessible (by tmpfs), but stateful partition may be not | |
| # available. To verify that, check the existence of STATEFUL_LOG_FOLDER. | |
| STATEFUL_LOG_FOLDER="/mnt/stateful_partition/unencrypted/" | |
| STATEFUL_LOG_PATH="${STATEFUL_LOG_FOLDER}/${CLOBBER_LOG_FILE}" | |
| TMP_LOG_PATH="/tmp/${CLOBBER_LOG_FILE}" | |
| PSTORE_PATH="/sys/fs/pstore" | |
| RAMOOPS_LOG="${PSTORE_PATH}/console-ramoops" | |
| MAX_KEEP_LOG_LINES=1024 | |
| RAMOOPS_DUMP_LINES=128 | |
| mount_pstore() { | |
| # Copied from pstore.conf. clobber-state is always executed before | |
| # boot-services so pstore.conf won't be ready at that time and we have to | |
| # mount now. | |
| if ! mountpoint -q "${PSTORE_PATH}"; then | |
| mount -n -t pstore -o nodev,nosuid,noexec pstore "${PSTORE_PATH}" || true | |
| fi | |
| } | |
| log_prefix() { | |
| echo "$(date --utc '+%Y/%m/%d %H:%M:%S') UTC" | |
| } | |
| preserve_log() { | |
| # Try to copy log from stateful partition to tmp. | |
| local source_path="${STATEFUL_LOG_PATH}" | |
| local dest_path="${TMP_LOG_PATH}" | |
| # TODO(hungte) store log in some special place, like last sector of stateful | |
| # partition so that logs won't be lost if user interrupts during wiping. | |
| if [ -s "${source_path}" ]; then | |
| tail -n "${MAX_KEEP_LOG_LINES}" "${source_path}" >"${dest_path}" | |
| else | |
| echo "No prior clobber-log found" >>"${dest_path}" | |
| fi | |
| echo "$(log_prefix) (preserve log): $*" >>"${dest_path}" | |
| } | |
| restore_log() { | |
| # Try to copy log from tmp back to stateful partition. | |
| local source_path="${TMP_LOG_PATH}" | |
| local dest_path="${STATEFUL_LOG_PATH}" | |
| # the mode should be matched to chromeos_startup. | |
| mkdir -p -m 0755 "${STATEFUL_LOG_FOLDER}" | |
| if [ -s "${source_path}" ]; then | |
| cp "${source_path}" "${dest_path}" | |
| fi | |
| echo "$(log_prefix) (restore log): $*" >>"${dest_path}" | |
| } | |
| find_log_path() { | |
| # Always use log in stateful partition, otherwise create in temp. | |
| local dest_path="${STATEFUL_LOG_PATH}" | |
| if [ ! -d "${STATEFUL_LOG_FOLDER}" ]; then | |
| dest_path="${TMP_LOG_PATH}" | |
| fi | |
| echo "${dest_path}" | |
| } | |
| append_log() { | |
| # Add one line of log into the clobber log file. | |
| local dest_path | |
| dest_path="$(find_log_path)" | |
| echo "$(log_prefix) $*" >>"${dest_path}" | |
| } | |
| append_logfile() { | |
| # Add MAX_KEEP_LOG_LINES from file into log. | |
| local dest_path="$(find_log_path)" | |
| local source_path="$1" | |
| if [ ! -f "${source_path}" ]; then | |
| echo "File not found: ${source_path}" | |
| return | |
| fi | |
| echo "-- $(basename ${source_path}) --" >> "${dest_path}" | |
| tail -n ${MAX_KEEP_LOG_LINES} "${source_path}" >> "${dest_path}" | |
| echo "-- end of logfile --" >> "${dest_path}" | |
| echo "$(log_prefix) (append_logfile): $@" >>"$dest_path" | |
| } | |
| repair_log() { | |
| # Report detail messages for the status of stateful partition. | |
| local dest_path="${TMP_LOG_PATH}" | |
| # TODO(hungte) try to recover logs from some where - see preserve_log. | |
| if [ ! -b "$1" ]; then | |
| echo "$(log_prefix) repair: $1: invalid device file." >>"${dest_path}" | |
| return | |
| fi | |
| echo "$(log_prefix) (repair): $*" >>"${dest_path}" | |
| # "fsck -n" and "mount -v" may also help. | |
| dumpe2fs -fh "$1" >>"${dest_path}" 2>&1 | |
| mount_pstore | |
| echo "-- Ramoops (logs from last boot):" >>"${dest_path}" | |
| # There might be more than one record, so grab them all with a glob. | |
| # Plus, for <linux-3.19, it's named "console-ramoops", but for newer | |
| # versions, it's named "console-ramoops-#". | |
| local ramoops | |
| for ramoops in "${RAMOOPS_LOG}"*; do | |
| if [ -f "${ramoops}" ]; then | |
| echo "${ramoops}" | |
| tail -n "${RAMOOPS_DUMP_LINES}" "${ramoops}" >>"${dest_path}" 2>/dev/null | |
| else | |
| echo "(No ramoops found, sorry)" >>"${dest_path}" | |
| fi | |
| done | |
| # try to dump first several blocks | |
| ( | |
| echo "-- File system $1 block data (gz+base64):" | |
| dd if="$1" bs=1M count=1 | gzip -c | base64 2>/dev/null | |
| echo "-- File system $1 block data dump complete." | |
| ) >>"${dest_path}" | |
| # to read back the block data, extract to a file and do | |
| # cat block | base64 -d | gunzip -c -d > block.bin | |
| } | |
| # Process the very limited commands | |
| case "$1" in | |
| --preserve ) | |
| shift | |
| preserve_log "$@" | |
| ;; | |
| --restore ) | |
| shift | |
| restore_log "$@" | |
| ;; | |
| --repair ) | |
| shift | |
| repair_log "$@" | |
| ;; | |
| --append_logfile ) | |
| shift | |
| append_logfile "$@" | |
| ;; | |
| -- ) | |
| shift | |
| append_log "$@" | |
| ;; | |
| * ) | |
| append_log "$@" | |
| ;; | |
| esac |