blob: adac76779d72bbd78a0d6f31ac364cb3cf62d1c3 [file] [log] [blame]
#!/bin/sh
# Copyright 2015 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.
# This script provides easy access to data contained in cros-regions.json (the
# region database for Chromium OS).
# The CROS_VPD_CACHE is defined in dump_vpd_log "filtered_file".
: ${CROS_VPD_CACHE:=/mnt/stateful_partition/unencrypted/cache/vpd/filtered.txt}
: ${CROS_VPD_SYS_RO:=/sys/firmware/vpd/ro}
: ${CROS_REGIONS_DATABASE=/usr/share/misc/cros-regions.json}
load_vpd_cache() {
# There are multiple ways to read from VPD. The best approach is probably
# to call dump_vpd_log directly, but this script may be executed in
# boot-time (before stateful partition was mounted) or inside initramfs
# so we cannot use that. Instead we have to try the cache and then read via
# command 'vpd'.
if [ -d "${CROS_VPD_SYS_RO}" ]; then
# Use sysfs (supported by ARM since kernel 3.18 and x86 since kernel 4.4).
CROS_VPD_CACHE=""
elif [ ! -f "${CROS_VPD_CACHE}" ]; then
CROS_VPD_CACHE="$(mktemp)"
trap "rm ${CROS_VPD_CACHE}" EXIT
vpd -i RO_VPD -l >"${CROS_VPD_CACHE}"
fi
}
get_data_from_vpd() {
local name="$1"
if [ -z "${CROS_VPD_CACHE}" ]; then
# Use sysfs. All keys used by cros_region_data should live in RO partition.
local value_file="${CROS_VPD_SYS_RO}/${name}"
if [ -f "${value_file}" ]; then
cat "${value_file}"
fi
else
sed -nr 's/^"'"${name}"'"="(.*)"$/\1/p' "${CROS_VPD_CACHE}"
fi
}
get_legacy_value_from_vpd() {
local data_name="$1"
local select_first="$2"
local name value entry
# There are some legacy VPD values that should override region data.
local legacy_map="
locales=initial_locale
time_zones=initial_timezone
keyboards=keyboard_layout"
for entry in ${legacy_map}; do
name="${entry%=*}"
if [ "${name}" != "${data_name}" ]; then
continue
fi
name="${entry#*=}"
value="$(get_data_from_vpd "${name}")"
if [ -n "${value}" ]; then
# Legacy values were defined in CSV so we have to convert output.
if ${select_first}; then
echo "${value%%,*}"
else
echo "${value}" | tr ',' '\n'
fi
return 0
fi
done
return 1
}
lookup_data() {
local name="$1"
local region="$2"
local select_first="$3"
local output=""
local pattern='.[$region][$name]'
# Check value type and modify pattern for array.
output="$(jq -c -r --arg region "${region}" --arg name "${name}" \
"${pattern}|arrays" "${CROS_REGIONS_DATABASE}")"
if [ -n "${output}" ]; then
if ${select_first}; then
pattern="${pattern}[0]"
else
pattern="${pattern}[]"
fi
fi
output="$(jq -c -r --arg region "${region}" --arg name "${name}" \
"${pattern}" "${CROS_REGIONS_DATABASE}")"
if [ "${output}" != "null" ]; then
echo "${output}"
fi
}
# Use legacy VPD data to look up region code.
reverse_lookup_region_by_timezone() {
local value="$1"
local region="$(jq -c -r --arg "timezone" "${value}" \
'map(select(.time_zones == [$timezone]).region_code)[0]' \
"${CROS_REGIONS_DATABASE}")"
if [ "${region}" != "null" ]; then
echo "${region}"
fi
}
report_available_fields() {
if [ ! -f "${CROS_REGIONS_DATABASE}" ]; then
return
fi
echo "Available fields in current system:"
# Region 'us' should be always available.
jq -c -r ".us|keys[]" "${CROS_REGIONS_DATABASE}" | sed 's/^/\t/'
}
usage() {
echo "Usage: $1 [-s] data_name [region]
-s: Selects only the first element (if value is list).
data_name: Name of field inside ${CROS_REGIONS_DATABASE}.
region: Region code to query. Read from VPD if omitted.
" >&2
report_available_fields >&2
}
main() {
local region="" data_name=""
local value=""
local select_first=false
local myname="$0"
if [ "$1" = "-s" ]; then
select_first=true
shift
fi
case "$#" in
1)
data_name="$1"
;;
2)
data_name="$1"
region="$2"
;;
*)
usage "${myname}"
exit 1
;;
esac
if [ -z "${region}" ]; then
load_vpd_cache
region="$(get_data_from_vpd region)"
if get_legacy_value_from_vpd "${data_name}" ${select_first} ; then
# Already printed.
exit 0
fi
if [ -z "${region}" ]; then
region="$(reverse_lookup_region_by_timezone \
"$(get_data_from_vpd initial_timezone)")"
fi
fi
lookup_data "${data_name}" "${region}" ${select_first}
}
set -e
main "$@"