-
Ludovico de Nittis authored
Fixes #5 Signed-off-by:
Ludovico de Nittis <ludovico.denittis@collabora.com>
Ludovico de Nittis authoredFixes #5 Signed-off-by:
Ludovico de Nittis <ludovico.denittis@collabora.com>
pressure-vessel-locale-gen 9.19 KiB
#!/bin/sh
# Copyright © 2019 Collabora Ltd.
#
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
set -e
set -u
me="$0"
me="$(readlink -f "$0")"
here="${me%/*}"
me="${me##*/}"
opt_output_dir=.
opt_verbose=
# Look for try-setlocale helper executable next to this script
PATH="${here}:${PATH}"
LOCALE_ALIAS="/usr/share/locale/locale.alias"
if ! [ -f "$LOCALE_ALIAS" ]; then
LOCALE_ALIAS=
fi
# We currently only look for I18NDIR data in /usr/share/i18n, the
# glibc default path.
#
# Instead of just /usr/share/i18n/SUPPORTED, we also try to parse
# /etc/locale.gen because in some distributions, e.g. Arch Linux,
# /usr/share/i18n/SUPPORTED might not be present.
#
# If we discover that some distros use a different default, then we
# should enhance this script to iterate through a search path.
#
# Please keep this in sync with srt_system_info_get_locale_issues().
SUPPORTED="/etc/locale.gen /usr/share/i18n/SUPPORTED"
log () {
printf '%s\n' "$me: $*" >&2
}
verbose () {
if [ -n "$opt_verbose" ]; then
log "$@"
fi
}
# Return nonzero if the given locale cannot be generated normally.
can_generate () {
local locale="$1"
case "$locale" in
(C|C.UTF-8|C.utf8|POSIX|"")
return 1
;;
(*..*|*/*)
log "Avoiding potential path traversal in '$locale'"
return_ex_config=1
return 1
;;
(*)
return 0
;;
esac
}
generate_locale () {
local at_modifier=
local codeset=
local language=
local list=
local locale="$1"
local modifier=
local supported_codeset=
local territory=
local underscore_territory=
local without_codeset=
local status=
language="$locale"
case "$language" in
(*@*)
modifier="${language##*@}"
at_modifier="@${modifier}"
language="${language%@*}"
;;
esac
case "$language" in
(*.*)
codeset="${language##*.}"
language="${language%.*}"
;;
esac
case "$language" in
(*_*)
territory="${language##*_}"
underscore_territory="_${territory}"
language="${language%_*}"
;;
esac
# Speed up locale generation a bit by making e.g. en_GB.utf8 a
# symlink to en_GB.UTF-8
if [ "${codeset}" = 'utf8' ]; then
codeset="UTF-8"
locale="${language}${underscore_territory}.UTF-8${at_modifier}"
ln -fns "$locale" \
"${opt_output_dir}/${language}${underscore_territory}.utf8${at_modifier}"
if [ -d "$opt_output_dir/$locale" ]; then
return 0
fi
fi
if [ -n "$codeset" ]; then
# We don't really need to parse $SUPPORTED to find out that
# en_US.UTF-8 is a UTF-8 locale. Do nothing. In particular,
# this works on distributions like Arch Linux that do not
# normally install $SUPPORTED.
:
else
for list in $SUPPORTED; do
if supported_codeset="$(
while read -r supported codeset; do
case "$supported" in
(\#*)
continue
;;
esac
if [ "$supported" = "$locale" ]; then
printf '%s' "$codeset"
fi
done < "$list"
)"; then
if [ -n "$supported_codeset" ]; then
break
fi
else
supported_codeset=
verbose "Unable to read $list"
fi
done
if [ -n "$supported_codeset" ]; then
codeset="$supported_codeset"
else
log "Unable to find $locale in $SUPPORTED"
log "Assuming UTF-8 and hoping that works..."
codeset="UTF-8"
fi
fi
without_codeset="${language}${underscore_territory}${at_modifier}"
if localedef \
${LOCALE_ALIAS+-A "${LOCALE_ALIAS}"} \
--no-archive \
-c \
-f "$codeset" \
-i "$without_codeset" \
"${opt_output_dir}/${locale}" \
; then
log "Generated locale $locale successfully"
else
status="$?"
if [ "$status" = 1 ]; then
log "Generated locale $locale, with warnings"
else
log "Unable to generate locale $locale: $status"
fi
fi
if ! LOCPATH="${opt_output_dir}" pressure-vessel-try-setlocale "$locale"; then
log "Warning: $locale was generated but does not appear to work!"
fi
}
usage () {
local code="$1"
shift
if [ "$code" -ne 0 ]; then
exec >&2
fi
echo "Usage: $me [OPTIONS] [LOCALE...]"
echo
echo "Generate the locales required by the locale environment"
echo "variables, and any extra locales from the command line,"
echo "in the current working directory."
echo
echo "Options:"
echo "--output-dir DIR, -o DIR"
echo " Create locales in the given directory [default: .]"
echo "--verbose Be more verbose"
echo
echo "Arguments:"
echo "LOCALE Zero or more locales in POSIX format,"
echo " such as en_US.UTF-8, be_BY@latin"
exit "$code"
}
getopt_temp="help"
getopt_temp="${getopt_temp},output-dir:,output-directory:"
getopt_temp="${getopt_temp},verbose"
getopt_temp="$(getopt -o 'o:' --long "$getopt_temp" -n "$me" -- "$@")"
eval "set -- $getopt_temp"
unset getopt_temp
while [ "$#" -gt 0 ]; do
case "$1" in
(-o | --output-dir | --output-directory)
opt_output_dir="$2"
shift 2
;;
(--help)
usage 0
# not reached
;;
(--verbose)
opt_verbose=yes
shift
;;
(--)
shift
break
;;
(-*)
log "Unknown option: $1"
usage 64 # EX_USAGE from sysexits.h
# not reached
;;
(*)
break
;;
esac
done
one_missing=
for var in \
LC_ADDRESS \
LC_CTYPE \
LC_COLLATE \
LC_IDENTIFICATION \
LC_MEASUREMENT \
LC_MESSAGES \
LC_MONETARY \
LC_NUMERIC \
LC_NAME \
LC_PAPER \
LC_TELEPHONE \
LC_TIME \
\
HOST_LC_ALL \
LANG \
LC_ALL \
; do
locale="$(eval "printf '%s' \${${var}-}")"
if [ -z "$locale" ] || ! can_generate "$locale"; then
continue
fi
if ! pressure-vessel-try-setlocale "$locale"; then
one_missing=yes
break
fi
done
for locale in en_US.UTF-8 "$@"; do
if ! can_generate "$locale" ; then
continue
fi
if ! pressure-vessel-try-setlocale "$locale"; then
verbose "Missing locale $locale"
one_missing=yes
break
fi
done
if [ -z "$one_missing" ]; then
verbose "No locales need to be generated"
exit 0
fi
# We have to generate all the locales we want, not just the ones that
# were missing, because they might have been in a locale archive,
# and setting LOCPATH disables use of the locale archive.
return_ex_cantcreat=
return_ex_config=
for var in \
LC_ADDRESS \
LC_CTYPE \
LC_COLLATE \
LC_IDENTIFICATION \
LC_MEASUREMENT \
LC_MESSAGES \
LC_MONETARY \
LC_NUMERIC \
LC_NAME \
LC_PAPER \
LC_TELEPHONE \
LC_TIME \
\
HOST_LC_ALL \
LANG \
LC_ALL \
; do
locale="$(eval "printf '%s' \${${var}-}")"
if [ -z "$locale" ] || ! can_generate "$locale" ; then
continue
fi
if ! [ -d "$locale" ]; then
verbose "Generating locale $locale..."
generate_locale "$locale" || return_ex_cantcreat=yes
fi
done
for locale in en_US.UTF-8 "$@"; do
if ! can_generate "$locale" ; then
continue
fi
if ! [ -d "$locale" ]; then
verbose "Generating locale $locale..."
generate_locale "$locale" || return_ex_cantcreat=yes
fi
done
if [ -n "$return_ex_config" ]; then
exit 78 # EX_CONFIG, "configuration error", from sysexits.h
elif [ -n "$return_ex_cantcreat" ]; then
exit 73 # EX_CANTCREATE, "can't create (user) output file"
else
exit 72 # EX_OSFILE, "OS file missing"
fi
# vim:set sw=4 sts=4 et: