blob: 49eaf4f24cfc9366e6361283a704b8254df783b5 [file] [log] [blame]
#!/bin/sh
# 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.
set -e
# Global variables
SELF="$(readlink -f "$0")"
# Set by make_temp function and removed by clean_temp
TMP_DIR=
# Decides if we need to print debug messages
IS_DEBUG=
# Tag file to prohibit updater execution
TAG_FILE_DISABLED='/root/.leave_firmware_alone'
# Set to True to bypass checking TAG_FILE_DISABLED
IS_FORCED=
# Set to true to prevent printing error alerts by error return value
IS_IGNORE_RC=
# Prints a message and return an error code ($1).
die_as() {
local ret="$1"
shift
echo "ERROR: $@" >&2
exit "$ret"
}
# Prints a message and return error as 1.
die() {
die_as 1 "$@"
}
# Prints messages if $IS_DEBUG is not empty.
debug() {
[ -z "$IS_DEBUG" ] || echo "$@" >&2
}
# Creates a temporary folder
make_temp() {
TMP_DIR="$(mktemp -d --tmpdir)" ||
die "Failed to create temporary folder"
trap clean_temp EXIT
}
# Creates a temporary folder with execution permission
make_exec_temp() {
make_temp
if [ "$(id -u)" = "0" ]; then
debug "bind and remount for allowing execution ..."
(mount --bind "$TMP_DIR" "$TMP_DIR" && mount -o remount,exec "$TMP_DIR") ||
die "Failed to enable execution permission of folder $TMP_DIR"
else
debug "Not running as root: assuming we can execute in /tmp"
fi
}
# Cleans temporary folders
clean_temp() {
debug "clean_temp: started."
if [ -d "$TMP_DIR" ]; then
umount -f "$TMP_DIR" >/dev/null 2>&1 || true
rm -rf "$TMP_DIR" >/dev/null 2>&1 || true
TMP_DIR=""
fi
}
# Extracts bundle content to specified location
extract_bundle() {
local destination="$1"
sh "$SELF" --unpack "$destination" >/dev/null ||
die "Cannot extract bundle content to: $destination"
}
# Executes the updater bundle
exec_bundle() {
local rc=0
make_exec_temp
extract_bundle "$TMP_DIR"
type futility >/dev/null 2>&1 || die "Missing program 'futility'."
debug "Start running updater: futility update -a ${TMP_DIR} $@"
(cd "$TMP_DIR" && futility update -a . "$@") || rc="$?"
if [ "$rc" -ne 0 -a -z "$IS_IGNORE_RC" ]; then
die_as "$rc" "Execution failed: (error code = $rc)"
fi
exit "$rc"
}
# Prepares for extraction with shar
prepare_shar_extract() {
local destination="$1"
if [ -z "$destination" ]; then
make_temp
destination="$TMP_DIR"
# Don't remove the temporary files
TMP_DIR=""
fi
echo "Extracting to: $destination"
cd "$destination" || die "Invalid destination: $destination"
exec >/dev/null # Prevent shar messages in stdout
set -- "-c" # Force shar to overwrite files
}
# Repacks current file ($SELF) by given source folder.
perform_shar_repack() {
local new_source="$1"
local cut_mark="$(sed -n '/^##CUTHERE##/=' "$SELF")"
local manifest="${new_source}/manifest.json"
[ "$cut_mark" -gt 0 ] || die "File corrupted: $SELF"
sed -i "$((cut_mark + 1)),\$d" "$SELF" ||
die "Failed to truncate existing data in $SELF"
if type futility >/dev/null 2>&1; then
futility update -a "${new_source}" --manifest >"${manifest}" ||
rm -f "${manifest}"
else
rm -f "${manifest}"
fi
# Use a standard timestamp for the version files so that we get the same
# exact sharball each time. Otherwise the changing timestamps creates small
# differences.
touch -t 201701010000 "${new_source}/VERSION" "${manifest}"
# Build shar content with files in sorted order for repeatability.
(cd "$new_source" &&
find . -type f | sort |
shar -Q -q -x -m --no-character-count -D --no-i18n -z -g 1 |
sed -r 's/^lock_dir=_sh.*/lock_dir=_fwupdate/;
s"^begin ([0-9]+) _sh[^/]*"begin \1 _fwupdate"
/^# Made on .* by/d;
/^# Source directory was /d') >>"$SELF" ||
die "Failed repacking from $new_source"
}
# Prints the VAR from '--param VAR' and '--param=VAR' format.
get_parameter_variable() {
local param="$1"
local param_name="${param%%=*}"
local param_value="${param#*=}"
if [ "$param" = "$param_name" ]; then
echo "$2"
else
echo "$param_value"
fi
}
# Main entry
main() {
local original_params="$*"
# The sb_* are kept for backward compatibility, especially for signing.
case "$1" in
--sb_extract | --sb_extract=* | --unpack | unpack=*)
local destination="$(get_parameter_variable "$@")"
prepare_shar_extract "$destination"
return # Let shar handle the remaining stuff
;;
--sb_repack | --repack )
local new_source="$(get_parameter_variable "$@")"
[ -d "$new_source" ] || die "Invalid source folder: $new_source"
echo "Repacking from: $new_source"
perform_shar_repack "$new_source"
exit 0
;;
-V)
# Read information
make_temp
extract_bundle "$TMP_DIR"
cat "$TMP_DIR/VERSION"*
echo "Package Content:"
(cd "${TMP_DIR}" && find . -type f -exec md5sum -b '{}' ';' )
echo "This is only for debugging and the format may change any time." >&2
echo "If you want to parse with programs, use --manifest instead." >&2
exit 0
;;
--manifest)
# Read information
make_temp
extract_bundle "$TMP_DIR"
if [ -s "${TMP_DIR}/manifest.json" ]; then
cat "$TMP_DIR/manifest.json"
else
echo "No manifest.json available" >&2
fi
exit 0
;;
-h | "-?" | --help)
echo "
USAGE: $SELF [bundle_option|--] [updater_options]
bundle_option (only one option can be selected):
-h,--help: Show usage help
-V: show version and content of bundle
--manifest: print JSON manifest if available
--force: force execution and ignore $TAG_FILE_DISABLED
--unpack [PATH]: extract bundle content to a temporary folder
--repack PATH: update bundle content from given folder
updater_options:
"
# Invoke script with -h for usage help
IS_IGNORE_RC=TRUE
exec_bundle "-h"
;;
--force)
# Pass this into updaters
IS_FORCED=TRUE
;;
--debug | --debug | -v)
# do not shift here because this needs to be passed into the script
IS_DEBUG=TRUE
;;
--)
shift
;;
esac
# Do nothing if the OS specifies that.
# TODO(hungte) move this flag to kernel command line, or updater bundle
# itself.
if [ -e "$TAG_FILE_DISABLED" ] && [ -z "$IS_FORCED" ]; then
echo "WARNING: $SELF is disabled by $TAG_FILE_DISABLED"
echo "To force execution, please prefix --force to your command:"
echo " sudo $SELF --force $original_params"
exit 0
fi
if type futility >/dev/null 2>&1; then
exec_bundle "$@"
else
die "Need 'futility' in PATH to execute updater."
fi
}
main "$@"
# Below are for shar execution. Don't put any code below main.
##CUTHERE##################################################################