[Из песочницы] Ubuntu. Русификация консоли в 2016 году

Для меня было некоторым откровением узнать, что в 2016 году, в одном из крупных дистрибутивов GNU/Linux существуют проблемы с локализацией. А точнее, с локализацией текстовой консоли. Кто пользуется текстовой консолью в 2016 году? Не надо забывать, что есть множество дистрибутивов, базирующихся на Ubuntu и не все из них используют графическое окружение. Назову два примера: Ubuntu Server и Clonezilla.

Выглядит проблема так:

defb919b33cd44f4bb39ffca2902e726.png

И присутствует в текущем релизе Ubuntu 15.10 и в бета-версии Ubuntu 16.04. Тем, кому интересно узнать причины проблемы и как можно её решить — прошу под хабракат.

Лирическое вступление


Всё началось с Clonezilla. Это такой Linux Live CD/USB с программой Clonezilla для копирования дисков. Делаю, я, значит, себе загрузочную флешку с различными утилитами и, по-возможности, включаю русификацию, там где это возможно, так как хочу поделиться флешкой с коллегами, а они не все хорошо владеют английским. Только-что закончил настраивать GParted Live. Думаю, что всё должно быть похоже — оба дистрибутива поддерживают live-config. Задаю параметры для русификации — добавляю к параметрам ядра следующие значения:

locales=ru_RU.UTF-8
keyboard-layouts=us,ru
keyboard-options=grp:ctrl_shift_toggle,lctrl_shift_toggle

Первый параметр задаёт язык, на котором система будет с нами общаться и кодировку. Второй параметр задаёт раскладки клавиатур, которые мы будем использовать. И третий задаёт способ переключения раскладок клавишами CTRL+SHIFT. На самом деле, язык и раскладку можно выбрать после запуска Clonezilla, но нельзя выбрать две раскладки и способ переключения — будет только русская или только английская клавиатура. Эти параметры корректно отработали в GParted Live и я ожидаю такого же поведения от Clonezilla. Но… после загрузки вместо русских символов отображаются чёрные квадратики:

3bef1d20029541389fd57dec50545cc7.png

Вспоминаю, что Clonezilla предлагает две ветки дистрибутива: стабильная базируется на Debian и альтернативная на Ubuntu. Альтернативная содержит несвободное ПО, такое как прошивка (firmware) некоторого оборудования (например, WiFi-карт), поэтому, я скачал её — для большей универсальности.

Ради хохмы качаю стабильную версию, основанную на Debian, запускаю с русской локалью — всё отображается корректно.

49887cf7e9b545bf971f5437fee9c278.png

Подозрения падают на родительский дистрибутив — Ubuntu 15.10. Как раз у меня такой, думаю я и переключаюсь на текстовую консоль (Ctrl+Alt+F1) и запускаю `date`:

defb919b33cd44f4bb39ffca2902e726.png

На-ка, говорит Убунта.

Поворот не туда


Здравый смысл подсказывает — бери стабильную Clonezilla и работай дальше. Но. Впереди выходные, Dota 2 меня «отпустила», а память подсказывает что проблемы с локализацией текстовой консоли в Ubuntu существуют давно, решаются с переменным успехом и хочется всё-таки разобраться.

Гуглим проблему и обнаруживаем, что с подобным сталкиваются начиная с Ubuntu 11.10. Есть несколько решений разной степени полезности, самое популярное — включить опцию FRAMEBUFFER=y для initramfs и пересобрать initrd командой update-initramfs. Со словами «только бы не думать, и наша возьмет!» добавляю строку FRAMEBUFFER=y в конец файла initramfs.conf, обновляю образ initrd и перезагружаюсь:

echo FRAMEBUFFER=y | sudo tee -a /etc/initramfs-tools/initramfs.conf
sudo update-initramfs -u
sudo reboot


После перезагрузки изменений нет, всё те-же квадратики вместо кириллицы. На форумах многие так же жалуются на то, что этот способ им не помог.

Начнём сначала


Откатил все изменения назад, пораскинул мозгами. За настройку консоли в Ubuntu отвечает пакет console-setup, который хранит настройки в /etc/default/console-setup и применяет их через команду setupcon. Настройки можно изменить просто отредактировав файл или через dpkg-reconfigure console-setup. Проверяем настройки консоли:

cat /etc/default/console-setup
ACTIVE_CONSOLES="/dev/tty[1-6]"
CHARMAP="UTF-8"
CODESET="guess"
FONTFACE="Fixed"
FONTSIZE="8x16"

В текстовой консоли даём команду setupcon. Даже на глаз видно, что шрифт изменился и теперь консоль отображает кириллицу:

79074b72015c4e2da038215b85562fef.png

Значит, в системе есть всё для отображения кириллицы, но при загрузке эти настройки не применяются. Посмотрим, что находится внутри пакета console-setup:

mkdir console-setup && cd console-setup
apt-get download console-setup
dpkg-deb -R *.deb ./


Помимо уже упомянутых двух файлов (console-setup и setupcon) интерес представляет файл console-font.conf, устанавливаемый в /etc/init/. Этот файл представляет из себя скрипт systemd, системы начальной загрузки linux, заменившей system v init. Посмотрим на содержимое:

# console-font - set console font
#
# Set the console font, in case the similar udev rule races with Plymouth
# and thus fails to do it.

description     "set console font"

start on starting plymouth-splash

task

exec /lib/udev/console-setup-tty fbcon


Судя по заголовку и описанию это похоже на то, что надо — установка шрифта консоли при загрузке системы. Задача по установке шрифта перекладывается на скрипт /lib/udev/console-setup-tty. Приведу самые интересные части этого скрипта:

...
# Based on setupcon, but stripped down for use in a udev rule.
...
. /etc/default/console-setup
...
if [ "$1" = fbcon ]; then
    # Technically we have to wait for /dev/tty[1-6] to appear; but these are
    # created in vty_init, so I think it will always be early enough.  If
    # I'm wrong, then the -w test will fail and we end up with the wrong
    # fonts on some virtual consoles; the user can run setupcon to fix it.
    for console in $ACTIVE_CONSOLES; do
        if [ -w "$console" ]; then
            setup_font "$console"
        fi
    done
else
    if [ -w "$1" ]; then
        setup_unicode "$1"
        setup_font "$1"
        setup_keyboard_mode "$1"
    fi
fi


Я пока пропустил все функции, которые определены внутри скрипта, чтобы обратить внимание на самое важное. Первый комментарий говорит, что скрипт основан на setupcon, но урезан, чтобы соответствовать правилу udev. Допустим. Ниже идёт включение файла настроек (. /etc/default/console-setup). Дальше идёт проверка первого параметра, переданного скрипту, как раз с таким параметром (fbcon) скрипт вызывается из /etc/init/сonsole-font.conf. Для каждой активной консоли (указаны в /etc/default/console-setup) делается проверка на возможность записи в неё и, для каждой консоли вызывается функция setup_font. При этом, автор скрипта пишет, что к моменту вызова скрипта консоли должны быть созданы, а если нет, то тест на запись в консоль не сработает и эта консоль останется не настроенной. А пользователь сам может вызвать setupcon потом. Возьмём это на заметку и рассмотрим функцию setup_font из файла /lib/udev/console-setup-tty:

setup_font () {
    # Set the font and ACM.  setfont will silently do nothing for a console
    # in graphics mode.
    SETFONT_ARGS=
    if [ "$FONT" ]; then
        FONT="/etc/console-setup/${FONT##*/}"
        FONT="${FONT%.gz}"
    else
        FONT="/etc/console-setup/$CODESET-$FONTFACE$FONTSIZE.psf"
    fi
    if [ -f "$FONT" ]; then
        SETFONT_ARGS="${SETFONT_ARGS:+$SETFONT_ARGS }$FONT"
    fi
    if [ "$ACM" ]; then
        ACM="/etc/console-setup/${ACM##*/}"
        ACM="${ACM%.gz}"
    else
        ACM="/etc/console-setup/$CHARMAP.acm"
    fi
    if [ -f "$ACM" ]; then
        SETFONT_ARGS="${SETFONT_ARGS:+$SETFONT_ARGS }-m $ACM"
    fi
    if [ "$SETFONT_ARGS" ]; then
        setfont -C "$1" $SETFONT_ARGS
    fi
}


Вооот. Вот он косяк. Переменная $FONT у нас не задана, срабатывает строка

FONT="/etc/console-setup/$CODESET-$FONTFACE$FONTSIZE.psf"

Напомню настройки консоли:
CHARMAP="UTF-8"
CODESET="guess"
FONTFACE="Fixed"
FONTSIZE="8x16"

Переменные $CODESET, $FONTFACE, $FONTSIZE берутся напрямую из файла конфигурации и больше не изменяются. Выходит, что FONT=»/etc/console-setup/guess-Fixed8×16.psf». Посмотрим, какие шрифты у нас есть в /etc/console-setup/:

ls /etc/console-setup/*.psf*
/etc/console-setup/Uni2-Fixed16.psf.gz


Таким образом, скрипт неправильно обрабатывет CODESET=«guess». Он должен был «догадаться» об используемом наборе символов. Так же неправильно обрабатывается FONTSIZE=»8×16», вероятно, должна оставаться бОльшая из цифр или последняя цифра. Но и это ещё не всё… Наш шрифт сжат и имеет расширение .gz. Как оказалось, команда setfont, которая вызывается дальше, сама добавит расширение .gz если не найдёт файл *.psf и загрузит шрифт. Но вот проверка на наличие файла с именем $FONT

if [ -f "$FONT" ];


не пройдёт и, переменная $SETFONT_ARGS останется пустой — соответственно, блок, непосредственно устанавливающий шрифт,

if [ "$SETFONT_ARGS" ]; then
        setfont -C "$1" $SETFONT_ARGS
fi


не будет выполнен.

Зная эту информацию, мы можем подстроиться под систему и вручную задать $CODESET=«Uni2» и
$FONTSIZE=»16» или, вместо этого задать переменную $FONT=«Uni2-Fixed16.psf». Кроме того, нам нужно файл шрифта распаковать:

cd /etc/console-setup
sudo gunzip -k Uni2-Fixed16.psf.gz


После перезагрузки шрифт будет установлен, но при смене шрифта через dpkg-reconfigure console-setup нам придётся опять вносить исправления вручную.

Продолжаем разговор


Вспоминаем про скрипт setupcon, который был упомянут в комментариях и на котором базируется /lib/udev/console-setup-tty. Смотрим, что у него внутри:

#     setupcon -- setup the font and keyboard on the Linux console
…
###########################################################################
### INITIALIZATION AND DEFAULT VALUES
###########################################################################
…
# CODESET
[ "$CODESET" != guess ] || CODESET=''
if [ -z "$CODESET" ]; then
    case "$CHARMAP" in
        UTF-8)            CODESET=Uni2;;
        ARMSCII-8)        CODESET=Armenian ;;
        CP1251)           CODESET=CyrSlav ;;
        CP1255)           CODESET=Hebrew ;;
        CP1256)           CODESET=Arabic ;;
        GEORGIAN-ACADEMY) CODESET=Georgian ;;
        GEORGIAN-PS)      CODESET=Georgian ;;
        IBM1133)          CODESET=Lao ;;
        ISIRI-3342)       CODESET=Arabic ;;
        ISO-8859-1)       CODESET=Lat15 ;;
        ISO-8859-2)       CODESET=Lat2 ;;
        ISO-8859-3)       CODESET=Lat38 ;;
        ISO-8859-4)       CODESET=Lat7 ;; # sometimes Lat15
        ISO-8859-5)       CODESET=CyrSlav ;;
        ISO-8859-6)       CODESET=Arabic ;;
        ISO-8859-7)       CODESET=Greek ;;
        ISO-8859-8)       CODESET=Hebrew ;;
        ISO-8859-9)       CODESET=Lat15 ;;
        ISO-8859-10)      CODESET=Lat15 ;;
        ISO-8859-11)      CODESET=Thai ;;
        ISO-8859-13)      CODESET=Lat7 ;;
        ISO-8859-14)      CODESET=Lat38 ;;
        ISO-8859-15)      CODESET=Lat15 ;;
        ISO-8859-16)      CODESET=Lat2 ;;
        KOI8-R)           CODESET=CyrKoi ;;
        KOI8-U)           CODESET=CyrKoi ;;
        TIS-620)          CODESET=Thai ;;
        VISCII)           CODESET=Vietnamese ;;
        *)
            if [ "$do_font" ]; then
                echo Unsupported charmap $CHARMAP >&2
                exit 1
            fi
            ;;
    esac
    if [ "$kernel" = freebsd ]; then
        # 512 character fonts are not supported on FreeBSD
        case "$CODESET" in
            Uni*|Vietnamese|Arabic|Ethiopian) CODESET=Lat15 ;;
        esac
    fi
fi
…
# FONTSIZE
if [ -z "$FONTSIZE" -o "$FONTSIZE" = guess ]; then
    FONTSIZE=16
fi
case "$FONTSIZE" in
    8x*)
        FONTSIZE=${FONTSIZE#*x}
        ;;
    *x8)
        FONTSIZE=${FONTSIZE%x*}
        ;;
    *x*)
        a=${FONTSIZE%x*}
        b=${FONTSIZE#*x}
        if [ "$a" -lt "$b" ]; then
            FONTSIZE=${b}x${a}
        fi
        ;;
esac



Скрипт содержит код для Linux и FreeBSD, всё что относится к BSD можно смело пропускать. Я оставил только самое интересное — обработку $CODESET и $FONTSIZE. Как раз в этом скрипте есть обработка ситуации, когда $CODESET не задана или имеет значение 'guess'. В этом случае, $CODESET принимает значение, зависящее от $CHARMAP. В нашем случае $CODESET=Uni2.

$FONTSIZE так же проверяется на незаданное значение или 'guess' и жестко устанавливается в '16', если это так. Если $FONTSIZE задан как 8x* или *x8, то знак 'x' и восьмёрка отбрасывается, и остаётся только одна цифра (высота шрифта). Например, было '8×14' — останется '14', а от '15×8' останется '15'. Если $FONTSIZE задан как две цифры '*x*':

*x*)
        a=${FONTSIZE%x*}
        b=${FONTSIZE#*x}

(a — первая цифра, b — вторая), то бОльшая цифра переставляется вперёд:

if [ "$a" -lt "$b" ]; then
            FONTSIZE=${b}x${a}
fi



Например, было '10×20' — стало '20×10', а '22×11' меняться не будет. Посмотрим, как называются шрифты, доступные в системе:

ls /usr/share/consolefonts/
…
/usr/share/consolefonts/Uni2-Fixed13.psf.gz
/usr/share/consolefonts/Uni2-Fixed14.psf.gz
…
/usr/share/consolefonts/Uni2-Terminus22x11.psf.gz
/usr/share/consolefonts/Uni2-Terminus24x12.psf.gz
…
/usr/share/consolefonts/Uni2-TerminusBold28x14.psf.gz
/usr/share/consolefonts/Uni2-TerminusBold32x16.psf.gz
…


Сходится. Теперь, если добавить такую обработку параметров $CODESET и $FONTSIZE в скрипт /lib/udev/console-setup-tty, а так же добавить в этот скрипт проверку на существование сжатого файла *.psf.gz (а заодно и *.acm.gz):

    if [ -f "$FONT" ]  || [ -f "$FONT.gz" ]; then
        SETFONT_ARGS="${SETFONT_ARGS:+$SETFONT_ARGS }$FONT"
    fi
…
    if [ -f "$ACM" ] || [ -f "$ACM.gz" ]; then
        SETFONT_ARGS="${SETFONT_ARGS:+$SETFONT_ARGS }-m $ACM"
    fi


то скрипт отработает правильно.

Тёплые потроха


Продолжаем потрошить скрипты. Ищем, откуда (из какого пакета) растут ноги у /lib/udev/console-setup-tty:

sudo apt-get install apt-file
apt-file update
apt-file search /lib/udev/console-setup-tty

keyboard-configuration: /lib/udev/console-setup-tty


Скачиваем и распаковываем пакет keyboard-configuration:

apt-get download keyboard-configuration
dpkg-deb -R keyboard-configuration_1.108ubuntu9_all.deb ./


Смотрим, в каких скриптах используется файл настроек /etc/default/console-setup:

grep -rm 1 etc/default/console-setup ./

./lib/udev/console-setup-tty:. /etc/default/console-setup
./usr/share/doc/keyboard-configuration/README.Debian:(/etc/default/keyboard and /etc/default/console-setup) perhaps it will
./usr/share/apport/package-hooks/source_console-setup.py:        report, '/etc/default/console-setup', 'ConsoleSetup')
./usr/share/initramfs-tools/scripts/panic/console_setup:[ -r /etc/default/console-setup ] || exit 0
./usr/share/initramfs-tools/scripts/init-top/console_setup:[ -r /etc/default/console-setup ] || exit 0
./usr/share/initramfs-tools/hooks/console_setup:[ -r /etc/default/console-setup ] || exit 0
./DEBIAN/config:OLDCONFIGFILE=/etc/default/console-setup


Из них интерес представляют только:

./lib/udev/console-setup-tty
./usr/share/initramfs-tools/scripts/panic/console_setup
./usr/share/initramfs-tools/scripts/init-top/console_setup
./usr/share/initramfs-tools/hooks/console_setup


Все они содержат код, похожий на тот, что мы разобрали выше — из /lib/udev/console-setup-tty, без корректной обработки $CODESET и $FONTSIZE. А эти два файла

./usr/share/initramfs-tools/scripts/panic/console_setup
./usr/share/initramfs-tools/scripts/init-top/console_setup


отличаюся только одной строкой:
OPTION=FRAMEBUFFER

Знакомая опция, подумал я… Три интересующих нас скрипта расположены в папке initramfs-tools. Пакет initramfs-tools отвечает за сборку образа initrd, который загружается в память при загрузке ядра и используется им в тот момент, пока не доступна основная файловая система. В initrd обычно содержатся модули ядра, необходимые для его работы на нашем оборудовании и для подключения файловых систем, а так же, скрипты инициализации и их конфигурационные файлы. Собирается образ скриптом update-initramfs, который, в итоге, вызывает скрипт mkinitramfs. Как всегда, посмотрим что внутри у mkinitramfs:

…
CONFDIR="/etc/initramfs-tools"
...
. "${CONFDIR}/initramfs.conf"
…
# add existant boot scripts
for b in $(cd /usr/share/initramfs-tools/scripts/ && find . \
        -regextype posix-extended -regex '.*/[[:alnum:]\._-]+$' -type f); do
        option=$(sed '/^OPTION=/!d;$d;s/^OPTION=//;s/[[:space:]]*$//' "/usr/share/initramfs-tools/scripts/${b}")
        [ -z "${option}" ] || eval test -n \"\${$option}\" -a \"\${$option}\" != \"n\" || continue

        [ -d "${DESTDIR}/scripts/$(dirname "${b}")" ] \
                || mkdir -p "${DESTDIR}/scripts/$(dirname "${b}")"
        cp -p "/usr/share/initramfs-tools/scripts/${b}" \
                "${DESTDIR}/scripts/$(dirname "${b}")/"
done


Здесь всё выглядит довольно сложно, я попробую показать с примерами. Этот блок проходит по всем файлам в /usr/share/initramfs-tools/scripts/ и подпапках, и ищет внутри них строку, содержащую 'OPTION='. Например, в файле /usr/share/initramfs-tools/scripts/init-top/console_setup есть строка

OPTION=FRAMEBUFFER

Если 'OPTION' отсутствует или не задана — файл (скрипт) копируется в initrd. Если 'OPTION' присутствует, берут значение этой опции как имя переменной и проверяют установлена ли она и не равна ли 'n'. В нашем примере проверяется переменная $FRAMEBUFFER. Эту переменную мы устанавливали в FRAMEBUFFER=y в самом начале, в файле initramfs.conf. Так как само значение переменной FRAMEBUFFER в скриптах, относящихся к setup-console не используется, оно действует как триггер и можем задать ему любое значение, не обязательно 'y'. Даже 'no' или 'none' отработает так же как 'y'. Итак, если FRAMEBUFFER определена и не равна 'n', скрипт будет помещён в образ initrd. Таких скриптов 8:

cd /usr/share/initramfs-tools/scripts
grep -rl FRAMEBUFFER ./
./init-premount/brltty
./panic/plymouth
./init-bottom/plymouth
./init-top/keymap
./init-top/framebuffer
./init-top/console_setup
./init-top/brltty
./init-top/plymouth


Этими скриптами запускается и настраивается фреймбуфер (framebuffer) — грубо говоря, текстовая консоль переводится в графический режим. После этого появляется возможность отрисовывать в ней изображения и нестандартные шрифты. Вот как раз console_setup и устанавливает шрифт для консоли. Вероятно, из-за того, что пользователь может выбрать нестандартный шрифт, этот скрипт привязан к запуску фреймбуфера и без установленого параметра 'FRAMEBUFFER=y' не добавляется в initrd.

Таким образом, при активации фреймбуфера, так же будет происходить настройка консоли с установкой шрифта, но на более раннем этапе.

Но вернёмся к нашим скриптам из keyboard-configuration

./lib/udev/console-setup-tty
./usr/share/initramfs-tools/scripts/panic/console_setup
./usr/share/initramfs-tools/scripts/init-top/console_setup
./usr/share/initramfs-tools/hooks/console_setup


Скрипт …/init-top/console_setup копируется в образ initrd при установленном параметре 'FRAMEBUFFER=y'.

Скрипт …/panic/console_setup копируется в initrd всегда, т. к. не содержит заданную переменную 'OPTION'. Скрипты из каталога panic вызываются функцией panic из скрипта init (который включает функции из файла /usr/share/initramfs-tools/scripts/functions). Сама же функция panic вызывается в случае, когда скрипт инициализации init не может продолжить выполнение (не найдена корневая файловая система и т.п.). Значит, скрипт…/panic/console_setup предназначен для настройки консоли в режиме panic, чтобы вывести сообщения в родной для пользователя кодировке.

Скрипт …/hooks/console_setup вызывается из скрипта mkinitramfs, при создании образа initrd:

...
CONFDIR="/etc/initramfs-tools"
...
run_scripts_optional /usr/share/initramfs-tools/hooks
run_scripts_optional "${CONFDIR}"/hooks


Этот скрипт занимается тем, что копирует файлы, необходимые для настройки консоли (файл шрифта, таблицу перекодировки шрифта (acm) и файл раскладки клавиатуры (keymap)) в initrd. Соответственно, даже если мы исправим init-top/console_setup, но забудем внести изменения в hooks/console_setup, настройка консоли на этом этапе не произойдёт из-за отсутствия необходимых файлов.

Вносим исправления


Теперь, зная каким образом происходит настройка консоли и где допущены ошибки, можно внести правки в код. Качаем исходный код пакета keyboard-configuration, так же, скачаем все зависимости для пересборки пакета:

apt-get source keyboard-configuration
sudo apt-get build-dep keyboard-configuration


Но вместо keyboard-configuration у нас скачался пакет console-setup, из которого, как оказалось собирается несколько deb-файлов, в том числе console-setup и keyboard-configuration. Заходим в корень исходников, и смотрим в каких файлах используется переменная FONT:

grep -rl \$FONT ./
./debian/font-switch
./debian/console-setup.config
./debian/console-setup.postinst
./debian/console-setup.initramfs-hook
./debian/console-setup.initramfs-top
./console-setup-tty
./setupcon


После их изучения, понятно что нам интересны только

./debian/console-setup.initramfs-hook
./debian/console-setup.initramfs-top
./console-setup-tty
./setupcon


Первые три надо исправить, а последний нам послужит донором, так как содержит код, обрабатывающий $CODESET и $FONTSIZE.
Исправление заключается в добавлении следующего кода:

# CODESET
[ "$CODESET" != guess ] || CODESET=''
if [ -z "$CODESET" ]; then
    case "$CHARMAP" in
        UTF-8)            CODESET=Uni2;;
        ARMSCII-8)        CODESET=Armenian ;;
        CP1251)           CODESET=CyrSlav ;;
        CP1255)           CODESET=Hebrew ;;
        CP1256)           CODESET=Arabic ;;
        GEORGIAN-ACADEMY) CODESET=Georgian ;;
        GEORGIAN-PS)      CODESET=Georgian ;;
        IBM1133)          CODESET=Lao ;;
        ISIRI-3342)       CODESET=Arabic ;;
        ISO-8859-1)       CODESET=Lat15 ;;
        ISO-8859-2)       CODESET=Lat2 ;;
        ISO-8859-3)       CODESET=Lat38 ;;
        ISO-8859-4)       CODESET=Lat7 ;; # sometimes Lat15
        ISO-8859-5)       CODESET=CyrSlav ;;
        ISO-8859-6)       CODESET=Arabic ;;
        ISO-8859-7)       CODESET=Greek ;;
        ISO-8859-8)       CODESET=Hebrew ;;
        ISO-8859-9)       CODESET=Lat15 ;;
        ISO-8859-10)      CODESET=Lat15 ;;
        ISO-8859-11)      CODESET=Thai ;;
        ISO-8859-13)      CODESET=Lat7 ;;
        ISO-8859-14)      CODESET=Lat38 ;;
        ISO-8859-15)      CODESET=Lat15 ;;
        ISO-8859-16)      CODESET=Lat2 ;;
        KOI8-R)           CODESET=CyrKoi ;;
        KOI8-U)           CODESET=CyrKoi ;;
        TIS-620)          CODESET=Thai ;;
        VISCII)           CODESET=Vietnamese ;;
        *)            ;;
    esac
fi

# FONTSIZE
if [ -z "$FONTSIZE" -o "$FONTSIZE" = guess ]; then
    FONTSIZE=16
fi
case "$FONTSIZE" in
    8x*)
        FONTSIZE=${FONTSIZE#*x}
        ;;
    *x8)
        FONTSIZE=${FONTSIZE%x*}
        ;;
    *x*)
        a=${FONTSIZE%x*}
        b=${FONTSIZE#*x}
        if [ "$a" -lt "$b" ]; then
            FONTSIZE=${b}x${a}
        fi
        ;;
esac


в каждый из файлов, после подключения конфигурационного файла и проверок, например:

...
[ -r /etc/default/console-setup ] || exit 0
. /etc/default/console-setup

[ "$ACTIVE_CONSOLES" ] || exit 0

# CODESET
[ "$CODESET" != guess ] || CODESET=''
if [ -z "$CODESET" ]; then
...


Так же нужно добавить проверку на сжатый файлы:

    if [ -f "$FONT" ]  || [ -f "$FONT.gz" ]; then
        SETFONT_ARGS="${SETFONT_ARGS:+$SETFONT_ARGS }$FONT"
    fi
…
    if [ -f "$ACM" ] || [ -f "$ACM.gz" ]; then
        SETFONT_ARGS="${SETFONT_ARGS:+$SETFONT_ARGS }-m $ACM"
    fi


После внесения правок можем пересобрать пакет — заходим в корень исходников и выполняем:

dpkg-buildpackage -uc -b

Устанавливаем исправленный пакет и запрещаем ему обновления, иначе Ubuntu заменит его текущим (неисправленным) пакетом из репозитория:

sudo dpkg -i keyboard-configuration_*.deb
sudo apt-mark hold keyboard-configuration


Всё, теперь при загрузке ОС будет корректно настраиваться текстовая консоль.

Скачать патч и исправленный пакет можно на странице с багрепортом на ланчпаде. Там же можно увеличить приоритет ошибки, зарегистрировавшись и нажав «This bug affects me».

© Habrahabr.ru