diff options
Diffstat (limited to 'modules.d/10i18n')
-rw-r--r-- | modules.d/10i18n/10-console.rules | 2 | ||||
-rw-r--r-- | modules.d/10i18n/README | 124 | ||||
-rwxr-xr-x | modules.d/10i18n/console_init.sh | 89 | ||||
-rwxr-xr-x | modules.d/10i18n/module-setup.sh | 297 | ||||
-rwxr-xr-x | modules.d/10i18n/parse-i18n.sh | 36 |
5 files changed, 548 insertions, 0 deletions
diff --git a/modules.d/10i18n/10-console.rules b/modules.d/10i18n/10-console.rules new file mode 100644 index 0000000..640b1db --- /dev/null +++ b/modules.d/10i18n/10-console.rules @@ -0,0 +1,2 @@ +# Console initialization - keyboard, font, etc. +KERNEL=="tty0", RUN+="/sbin/initqueue --onetime --unique --name console_init_$name /lib/udev/console_init $root/$name" diff --git a/modules.d/10i18n/README b/modules.d/10i18n/README new file mode 100644 index 0000000..6cbbae9 --- /dev/null +++ b/modules.d/10i18n/README @@ -0,0 +1,124 @@ +dracut i18n module +------------------ + +INDEX + +0. Introduction +1. Hostonly vs Generic +2. Configuration + 2.1. Variables + 2.2. Setting up mappings + 2.3. Additional settings +3. Kernel parameters + +~ + +0. Introduction + +i18n module provides internationalization for initramfs at runtime. It +is intended to be generic across different GNU/Linux distributions. + +i18n and keyboard settings are stored in different files among +distributions. To deal with it avoiding hardcoding those differences in +the installation script we handle it by mappings between variables used +by dracut and the ones in the system. Package maintainer is expected to +create those for his/her distribution and it's appreciated to share it +with us, so we can include it in source package. + + +1. Hostonly vs Generic + +If you invoke dracut with '-H' option, i18n module install script will +gather variables values from your configuration files using mappings +provided in "/etc/dracut.conf.d/<foo>.conf". Those variables will be +put in "etc/vconsole.conf" and "etc/locale.conf" files inside initramfs +image. Next it will install only declared font, keymaps and so. + +When building generic image (dracut without '-H' option), install script +copies all content of directories: consolefonts, consoletrans, unimaps +and keymaps to image. Take into account that's about 4 MiB. + + +2. Configuration + +2.1. Variables + +The following variables are used by i18n install script and at initramfs +runtime: + + KEYMAP - keyboard translation table loaded by loadkeys + KEYTABLE - base name for keyboard translation table; if UNICODE is + true, Unicode version will be loaded. Overrides KEYMAP. + EXT_KEYMAPS - list of extra keymaps to bo loaded (sep. by space) + UNICODE - boolean, indicating UTF-8 mode + FONT - console font + FONT_MAP - see description of '-m' parameter in setfont manual + FONT_UNIMAP - see description of '-u' parameter in setfont manual + +The following are appended to EXT_KEYMAPS only during build time: + + UNIKEYMAP + GRP_TOGGLE + +They were used in 10redhat-i18n module, but not sure of its purpose. +I'm leaving it in case... The following are taken from the environment: + + LANG + LC_ALL + +If UNICODE variable is not provided, script indicates if UTF-8 should be +used on the basis of LANG value (if it ends with ".utf8" or similar). + + +2.2. Setting up mappings + +Mappings between variables listed in 2.1. and the ones spread around +your system are set up in /etc/dracut.conf.d/<foo>.conf. You need to +assign mappings to i18n_vars. Here's an example: + +i18n_vars="/etc/conf.d/keymaps:KEYMAP,EXTENDED_KEYMAPS-EXT_KEYMAPS /etc/conf.d/consolefont:CONSOLEFONT-FONT,CONSOLETRANSLATION-FONT_MAP /etc/rc.conf:UNICODE" + +First we've got name of file in host file system tree. After colon +there's mapping: <from>-<to>. If both variables have the same name you +can enter just a single, but it's important to specify it! The module +will source only variables you've listed. + +Below there's detailed description in BNF: + +<list> ::= <element> | <element> " " <list> +<element> ::= <conf-file-name> ":" <map-list> +<map-list> ::= <mapping> | <mapping> "," <map-list> +<mapping> ::= <src-var> "-" <dst-var> | <src-var> + +We assume no whitespace are allowed between symbols. +<conf-file-name> is a file holding <src-var> in your system. +<src-var> is a variable holding value of meaning the same as <dst-var>. +<dst-var> is a variable which will be set up inside initramfs. +If <dst-var> has the same name as <src-var> we can omit <dst-var>. + +Example: +/etc/conf.d/keymaps:KEYMAP,extended_keymaps-EXT_KEYMAPS +<list> = /etc/conf.d/keymaps:KEYMAP,extended_keymaps-EXT_KEYMAPS +<element> = /etc/conf.d/keymaps:KEYMAP,extended_keymaps-EXT_KEYMAPS +<conf-file-name> = /etc/conf.d/keymaps +<map-list> = KEYMAP,extended_keymaps-EXT_KEYMAPS +<mapping> = KEYMAP +<src-var> = KEYMAP +<mapping> = extended_keymaps-EXT_KEYMAPS +<src-var> = extended_keymaps +<dst-var> = EXT_KEYMAPS + + +2.3. Additional settings + +If you encounter following error message: "Directories consolefonts, +consoletrans, keymaps, unimaps not found.", you can provide path where +those directories lie in your system by setting kbddir in configuration +file (the same where you put mappings). + + +3. Kernel parameters + +If you create generic initramfs you can set up i18n by kernel +parameters using variables listed in 2.1. (except of UNIKEYMAP +and GRP_TOGGLE) The recommended minimum is: FONT and KEYMAP. diff --git a/modules.d/10i18n/console_init.sh b/modules.d/10i18n/console_init.sh new file mode 100755 index 0000000..3ca0ac1 --- /dev/null +++ b/modules.d/10i18n/console_init.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +[ -n "$DRACUT_SYSTEMD" ] && exit 0 + +if [ -x "$systemdutildir"/systemd-vconsole-setup ]; then + "$systemdutildir"/systemd-vconsole-setup "$@" +fi + +[ -e /etc/vconsole.conf ] && . /etc/vconsole.conf + +DEFAULT_FONT=eurlatgr +DEFAULT_KEYMAP=/etc/sysconfig/console/default.kmap + +set_keyboard() { + local param + + [ "${UNICODE}" = 1 ] && param=-u || param=-a + kbd_mode ${param} +} + +set_terminal() { + local dev="$1" + + if [ "${UNICODE}" = 1 ]; then + printf '\033%%G' >&7 + stty -F "${dev}" iutf8 + else + printf '\033%%@' >&7 + stty -F "${dev}" -iutf8 + fi +} + +set_keymap() { + local utf_switch + + if [ -z "${KEYMAP}" ]; then + [ -f "${DEFAULT_KEYMAP}" ] && KEYMAP=${DEFAULT_KEYMAP} + fi + + [ -n "${KEYMAP}" ] || return 1 + + [ "${UNICODE}" = 1 ] && utf_switch=-u + + # shellcheck disable=SC2086 + loadkeys -q ${utf_switch} ${KEYMAP} ${EXT_KEYMAPS} +} + +set_font() { + setfont "${FONT-${DEFAULT_FONT}}" \ + -C "${1}" \ + ${FONT_MAP:+-m "${FONT_MAP}"} \ + ${FONT_UNIMAP:+-u "${FONT_UNIMAP}"} +} + +dev_close() { + exec 6>&- + exec 7>&- +} + +dev_open() { + local dev="$1" + + exec 6< "${dev}" \ + && exec 7>> "${dev}" +} + +dev=/dev/${1#/dev/} + +[ -c "${dev}" ] || { + echo "Usage: $0 device" >&2 + exit 1 +} + +dev_open "${dev}" + +for fd in 6 7; do + if ! [ -t ${fd} ]; then + echo "ERROR: File descriptor not opened: ${fd}" >&2 + dev_close + exit 1 + fi +done + +set_keyboard +set_terminal "${dev}" +set_font "${dev}" +set_keymap + +dev_close diff --git a/modules.d/10i18n/module-setup.sh b/modules.d/10i18n/module-setup.sh new file mode 100755 index 0000000..ac45611 --- /dev/null +++ b/modules.d/10i18n/module-setup.sh @@ -0,0 +1,297 @@ +#!/bin/bash + +# called by dracut +check() { + [[ "$mount_needs" ]] && return 1 + + require_binaries setfont loadkeys kbd_mode || return 1 + + return 0 +} + +# called by dracut +depends() { + return 0 +} + +# called by dracut +install() { + declare -A KEYMAPS + + if dracut_module_included "systemd"; then + unset FONT + unset KEYMAP + # shellcheck disable=SC1090 + [[ -f "$dracutsysrootdir"/etc/vconsole.conf ]] && . "$dracutsysrootdir"/etc/vconsole.conf + fi + + KBDSUBDIRS=(consolefonts consoletrans keymaps unimaps) + DEFAULT_FONT="${i18n_default_font:-eurlatgr}" + I18N_CONF="/etc/locale.conf" + VCONFIG_CONF="/etc/vconsole.conf" + + findkeymap() { + local -a MAPS + local MAPNAME + local INCLUDES + local MAP + local CMD + local FN + + if [[ -f $dracutsysrootdir$1 ]]; then + MAPS=("$1") + else + MAPNAME=${1%.map*} + + mapfile -t -d '' MAPS < <( + find "${dracutsysrootdir}${kbddir}"/keymaps/ -type f \( -name "${MAPNAME}" -o -name "${MAPNAME}.map*" \) -print0 + ) + fi + + for MAP in "${MAPS[@]}"; do + [[ -f $MAP ]] || continue + [[ -v KEYMAPS["$MAP"] ]] && continue + + KEYMAPS["$MAP"]=1 + + case "$MAP" in + *.gz) CMD="zgrep" ;; + *.bz2) CMD="bzgrep" ;; + *) CMD="grep" ;; + esac + + readarray -t INCLUDES < <("$CMD" '^include ' "$MAP" | while read -r _ a _ || [ -n "$a" ]; do echo "${a//\"/}"; done) + + for INCL in "${INCLUDES[@]}"; do + local -a FNS + mapfile -t -d '' FNS < <(find "${dracutsysrootdir}${kbddir}"/keymaps/ -type f -name "${INCL}*" -print0) + for FN in "${FNS[@]}"; do + [[ -f $FN ]] || continue + [[ -v KEYMAPS["$FN"] ]] || findkeymap "$FN" + done + done + done + } + + # Function gathers variables from distributed files among the tree, maps to + # specified names and prints the result in format "new-name=value". + # + # $@ = list in format specified below (BNF notation) + # + # <list> ::= <element> | <element> " " <list> + # <element> ::= <conf-file-name> ":" <map-list> + # <map-list> ::= <mapping> | <mapping> "," <map-list> + # <mapping> ::= <src-var> "-" <dst-var> | <src-var> + # + # We assume no whitespace are allowed between symbols. + # <conf-file-name> is a file holding <src-var> in your system. + # <src-var> is a variable holding value of meaning the same as <dst-var>. + # <dst-var> is a variable which will be set up inside initramfs. + # If <dst-var> has the same name as <src-var> we can omit <dst-var>. + # + # Example: + # /etc/conf.d/keymaps:KEYMAP,extended_keymaps-EXT_KEYMAPS + # <list> = /etc/conf.d/keymaps:KEYMAP,extended_keymaps-EXT_KEYMAPS + # <element> = /etc/conf.d/keymaps:KEYMAP,extended_keymaps-EXT_KEYMAPS + # <conf-file-name> = /etc/conf.d/keymaps + # <map-list> = KEYMAP,extended_keymaps-EXT_KEYMAPS + # <mapping> = KEYMAP + # <src-var> = KEYMAP + # <mapping> = extended_keymaps-EXT_KEYMAPS + # <src-var> = extended_keymaps + # <dst-var> = EXT_KEYMAPS + gather_vars() { + local item map value + + # FIXME: double check + # shellcheck disable=SC2068 + for item in "$@"; do + read -r -a item <<< "${item/:/ }" + for map in ${item[1]//,/ }; do + read -r -a map <<< "${map//-/ }" + if [[ -f "$dracutsysrootdir${item[0]}" ]]; then + value=$(grep "^${map[0]}=" "$dracutsysrootdir${item[0]}") + value=${value#*=} + echo "${map[1]:-${map[0]}}=${value}" + fi + unset map + done + done + } + + install_base() { + inst_multiple setfont loadkeys kbd_mode stty + + if ! dracut_module_included "systemd"; then + inst "${moddir}"/console_init.sh /lib/udev/console_init + inst_rules "${moddir}"/10-console.rules + inst_hook cmdline 20 "${moddir}/parse-i18n.sh" + fi + + if [[ ${kbddir} != "/usr/share" ]]; then + inst_dir /usr/share + for _src in "${KBDSUBDIRS[@]}"; do + [ ! -e "${initdir}/usr/share/${_src}" ] && ln -s "${kbddir}/${_src}" "${initdir}/usr/share/${_src}" + done + fi + } + + install_all_kbd() { + local _src _line + + for _src in "${KBDSUBDIRS[@]}"; do + inst_dir "${kbddir}/$_src" + $DRACUT_CP -L -t "${initdir}/${kbddir}/$_src" "${dracutsysrootdir}${kbddir}/$_src"/* + done + + # remove unnecessary files + rm -f -- "${initdir}${kbddir}/consoletrans/utflist" + find "${initdir}${kbddir}/" -name README\* -delete + find "${initdir}${kbddir}/" -name '*.gz' -print -quit \ + | while read -r _line || [ -n "$_line" ]; do + inst_multiple gzip + done + + find "${initdir}${kbddir}/" -name '*.bz2' -print -quit \ + | while read -r _line || [ -n "$_line" ]; do + inst_multiple bzip2 + done + } + + install_local_i18n() { + local map + + # shellcheck disable=SC2086 + eval "$(gather_vars ${i18n_vars})" + # shellcheck disable=SC1090 + [ -f "$dracutsysrootdir"$I18N_CONF ] && . "$dracutsysrootdir"$I18N_CONF + # shellcheck disable=SC1090 + [ -f "$dracutsysrootdir"$VCONFIG_CONF ] && . "$dracutsysrootdir"$VCONFIG_CONF + + shopt -q -s nocasematch + if [[ ${UNICODE} ]]; then + if [[ ${UNICODE} == YES || ${UNICODE} == 1 ]]; then + UNICODE=1 + elif [[ ${UNICODE} == NO || ${UNICODE} == 0 ]]; then + UNICODE=0 + else + UNICODE='' + fi + fi + if [[ ! ${UNICODE} && ${LANG} =~ .*\.UTF-?8 ]]; then + UNICODE=1 + fi + shopt -q -u nocasematch + + # Gentoo user may have KEYMAP set to something like "-u pl2", + KEYMAP=${KEYMAP#-* } + + # openSUSE user may have KEYMAP set to something like ".gz" + KEYMAP=${KEYMAP/.gz/} + + # KEYTABLE is a bit special - it defines base keymap name and UNICODE + # determines whether non-UNICODE or UNICODE version is used + + if [[ ${KEYTABLE} ]]; then + if [[ ${UNICODE} == 1 ]]; then + [[ ${KEYTABLE} =~ .*\.uni.* ]] || KEYTABLE=${KEYTABLE%.map*}.uni + fi + KEYMAP=${KEYTABLE} + fi + + # I'm not sure of the purpose of UNIKEYMAP and GRP_TOGGLE. They were in + # original redhat-i18n module. Anyway it won't hurt. + EXT_KEYMAPS+=\ ${UNIKEYMAP}\ ${GRP_TOGGLE} + + [[ ${KEYMAP} ]] || { + dinfo 'No KEYMAP configured.' + return 1 + } + + findkeymap "${KEYMAP}" + + for map in ${EXT_KEYMAPS}; do + ddebug "Adding extra map: ${map}" + findkeymap "${map}" + done + + for keymap in "${!KEYMAPS[@]}"; do + inst_opt_decompress "${keymap}" + done + + inst_opt_decompress "${kbddir}"/consolefonts/"${DEFAULT_FONT}".* + + if [[ ${FONT} ]] && [[ ${FONT} != "${DEFAULT_FONT}" ]]; then + if [[ -f "${kbddir}"/consolefonts/"${FONT}" ]]; then + inst_opt_decompress "${kbddir}"/consolefonts/"${FONT}" + else + FONT=${FONT%.psf*} + inst_opt_decompress "${kbddir}"/consolefonts/"${FONT}".* + fi + fi + + if [[ ${FONT_MAP} ]]; then + FONT_MAP=${FONT_MAP%.trans} + # There are three different formats that setfont supports + inst_simple "${kbddir}"/consoletrans/"${FONT_MAP}" \ + || inst_simple "${kbddir}"/consoletrans/"${FONT_MAP}".trans \ + || inst_simple "${kbddir}"/consoletrans/"${FONT_MAP}"_to_uni.trans \ + || dwarn "Could not find FONT_MAP ${FONT_MAP}!" + fi + + if [[ ${FONT_UNIMAP} ]]; then + FONT_UNIMAP=${FONT_UNIMAP%.uni} + inst_simple "${kbddir}"/unimaps/"${FONT_UNIMAP}".uni + fi + + if dracut_module_included "systemd" && [[ -f $dracutsysrootdir${I18N_CONF} ]]; then + inst_simple ${I18N_CONF} + else + mksubdirs "${initdir}"${I18N_CONF} + print_vars LC_ALL LANG >> "${initdir}"${I18N_CONF} + fi + + if ! dracut_module_included "systemd"; then + mksubdirs "${initdir}"${VCONFIG_CONF} + print_vars KEYMAP EXT_KEYMAPS UNICODE FONT FONT_MAP FONT_UNIMAP >> "${initdir}"${VCONFIG_CONF} + fi + + return 0 + } + + checks() { + for kbddir in ${kbddir} /usr/lib/kbd /lib/kbd /usr/share /usr/share/kbd; do + if [[ -d "$dracutsysrootdir${kbddir}" ]]; then + for dir in "${KBDSUBDIRS[@]}"; do + [[ -d "$dracutsysrootdir${kbddir}/${dir}" ]] && continue + false + done && break + fi + kbddir='' + done + + [[ "$kbddir" ]] || return 1 + + [[ -f $dracutsysrootdir$I18N_CONF && -f $dracutsysrootdir$VCONFIG_CONF ]] \ + || [[ ! ${hostonly} || ${i18n_vars} ]] || { + derror 'i18n_vars not set! Please set up i18n_vars in ' \ + 'configuration file.' + } + return 0 + } + + if checks; then + install_base + + # https://github.com/dracutdevs/dracut/issues/796 + if dracut_module_included "systemd" && [[ -f $dracutsysrootdir${VCONFIG_CONF} ]]; then + inst_simple ${VCONFIG_CONF} + fi + + if [[ ${hostonly} ]] && ! [[ ${i18n_install_all} == "yes" ]]; then + install_local_i18n || install_all_kbd + else + install_all_kbd + fi + fi +} diff --git a/modules.d/10i18n/parse-i18n.sh b/modules.d/10i18n/parse-i18n.sh new file mode 100755 index 0000000..2deb2c4 --- /dev/null +++ b/modules.d/10i18n/parse-i18n.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +inst_key_val() { + local _value + local _file + local _default + _file="$1" + shift + _key="$1" + shift + _default="$1" + shift + _value="$(getarg "$@")" + [ -z "${_value}" ] && _value=$_default + if [ -n "${_value}" ]; then + printf -- '%s="%s"\n' "${_key}" "${_value}" >> "$_file" + fi + unset _file + unset _value +} + +inst_key_val /etc/vconsole.conf KEYMAP '' rd.vconsole.keymap KEYMAP -d KEYTABLE +inst_key_val /etc/vconsole.conf FONT '' rd.vconsole.font FONT -d SYSFONT +inst_key_val /etc/vconsole.conf FONT_MAP '' rd.vconsole.font.map FONT_MAP -d CONTRANS +inst_key_val /etc/vconsole.conf FONT_UNIMAP '' rd.vconsole.font.unimap FONT_UNIMAP -d UNIMAP +inst_key_val /etc/vconsole.conf UNICODE 1 rd.vconsole.font.unicode UNICODE vconsole.unicode +inst_key_val /etc/vconsole.conf EXT_KEYMAP '' rd.vconsole.keymap.ext EXT_KEYMAP + +inst_key_val /etc/locale.conf LANG '' rd.locale.LANG LANG +inst_key_val /etc/locale.conf LC_ALL '' rd.locale.LC_ALL LC_ALL + +if [ -f /etc/locale.conf ]; then + . /etc/locale.conf + export LANG + export LC_ALL +fi |