Ubuntu. Русификация консоли в 2016 году

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

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



И присутствует в текущем релизе 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. Но… после загрузки вместо русских символов отображаются чёрные квадратики:



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

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



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



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

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


Здравый смысл подсказывает — бери стабильную 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. Даже на глаз видно, что шрифт изменился и теперь консоль отображает кириллицу:



Значит, в системе есть всё для отображения кириллицы, но при загрузке эти настройки не применяются. Посмотрим, что находится внутри пакета 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-Fixed8x16.psf". Посмотрим, какие шрифты у нас есть в /etc/console-setup/:

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

Таким образом, скрипт неправильно обрабатывет CODESET=«guess». Он должен был «догадаться» об используемом наборе символов. Так же неправильно обрабатывается FONTSIZE=«8x16», вероятно, должна оставаться бОльшая из цифр или последняя цифра. Но и это ещё не всё… Наш шрифт сжат и имеет расширение .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' и восьмёрка отбрасывается, и остаётся только одна цифра (высота шрифта). Например, было '8x14' — останется '14', а от '15x8' останется '15'. Если $FONTSIZE задан как две цифры '*x*':

*x*)
        a=${FONTSIZE%x*}
        b=${FONTSIZE#*x}
(a — первая цифра, b — вторая), то бОльшая цифра переставляется вперёд:
if [ "$a" -lt "$b" ]; then
            FONTSIZE=${b}x${a}
fi


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

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».

Обновлено 20.04.2016:
Сегодня, 20.04.2016, за один день до релиза, исправление вошло сначала в proposed, а затем, и в release ветку Ubuntu Xenial.
Для этого пришлось приложить некоторые усилия. В частности — создать на launchpad'е ветку пакета console-setup, внести в неё исправления и предложить (propose) эту ветку для слияния с релизной. Так же, я посмотрел кто последний загружал пакет console-setup и отправил ему просьбу рассмотреть ошибку и исправления. Через 2 недели исправленный пакет был рассмотрен, одобрен и принят в релиз. Спасибо тебе, Mathieu Trudel-Lapierre!
Поделиться публикацией
Комментарии 88
    +7
    Решал обычно как-то так:
    sudo apt-get install console-cyrillic
    echo cyr >> ~/.bashrc
    
      +1
      Если склероз подводит, это пакет не рекомендовался к использованию где-то с 11.хх. Причин, за давностью лет, не упомню — что-то он там то ли ломал, то ли не срабатывал.

      Потому, в своё время, прикрутил для той же цени setupcon и успокоился
        +3
        Всегда делал так: http://help.ubuntu.ru/wiki/russian_font_in_console
        На 16.04 тоже сработало.
        На той же странице Ваш «костыль» во вредных советах. И я с ними согласен.
          –1

          Автор, кажется, писал, что у него FRAMEBUFFER=y не заработало

            –1

            Упс, неверно распознал ветку.

        –5
        поддержал
          +6
          Вот жеж! И не лень было докопаться до истоков! Решительно плюсую.

          Меня хватает только на `dpkg-reconfigure console-setup` и вызов `setupcon` где-то в /etc/rc.local или даже в ~/.bashrc.

          Кстати, убунта этим страдает как минимум с 10.04 — ещё жив под рукой сервер, на котором проводились подобные «пляски с бубном»
            0
            8.04 тоже страдала, раньше — не припомню, но setupcon гуглился уже тогда легко, видимо проблема так же стара, как убунта
            –11
            Просто ад какой-то. В слаке всё гораздо проще. Дайте неграм Linux и они его извратят и усложнят до невозможности. Убунту второй виндовс и не нужен ни под каким соусом. Даже мята не спасает, один хрен дерьмом тянет.
              –14
              Я очень люблю Linux, но к сожалению, в актуальных версиях Windows нет таких проблем. Так что это даже не второй Windows. Это просто Ubuntu.
                +13
                В актуальных версиях Windows не просто дофига таких проблем, там их ещё больше, чем было в неактуальных. Ибо если во времена 9x было ansi и oem, читай windows-1251 и ibm866, то теперь ещё появились разные вариации юникода, в том числе utf-8 с bom (некорректный — в utf-8 не должно быть bom).

                Регулярно приходится отлавливать хрень в сообщении об ошибке в непонятно какой кодировке. Бывает, что в соседних строках, из которых составляется одна общая — разные кодировки. А ошибки эти надо решать.

                А апофеозом ситуации является IBM Lotus Domino, который мало того, что сам выдаёт сообщения в SMTP-сессию не в латинице (чего нельзя делать по стандарту — кодировка и язык на этом этапе не согласовываются), так ещё и некоторые системные сообщения выдаёт прям в SMTP-сессию в той кодировке, в которой ему отдала винда, то есть, не в той, в которой говорил сам. Когда его ставишь в линуксе, такой порнографии не видно.
                  0
                  Кто выдает эти сообщения об ошибках? Приложения, идущие в составе дистрибутива Windows или приложения сторонних разработчиков, как Lotus Domino?
                    0
                    Сообщения системные, типа «файл не найден». В Bacula, например, нет таких сообщений вообще.

                    То есть, возвращает ИМЕННО система.

                    Вообще, я вас обязан расстроить: чтобы это исправить, придётся отказаться от обратной совместимости и перевести всё — cmd тоже — на рельсы utf-8. И тогда куча уже имеющихся бинарников будет отображать кракозябры, но зато проблем типа «запустил dir > file.txt, открыл блокнотом — вижу кракозябры» не будет.
                      0
                      Ладно-ладно, хотел я вам ответить тут вчера, но моя новенькая Windows 10 на ноутбуке выдала красивый такой обновленный BSOD, когда я писал комментарий. Ждем Ubuntu 16.04. Посмотрим что будет в ней хорошего и какие недоделки останутся :)
                    0
                    > в utf-8 не должно быть bom
                    Почему? А как его отличить от различных вариантов UTF-16?
                      +1
                      У UTF-16 всегда есть сигнатура. Тем не менее для UTF-8 иногда полезно иметь BOM, ибо для обнаружения что перед нами документ в UTF-8 те ещё костыли в редакторах используют, которые не всегда срабатывают (если например в поток вкрались вдруг местами одиночные байты типа \x00 и прочий мусор).
                        +1
                        Пользователь должен явно сообщать приложению, читающему поток символов, какую кодировку использовать.
                        Как пользователь эту кодировку узнает — его проблемы, но класть подсказки внутрь самого текста (BOM) — одна из худших идей ever.
                          +1
                          Никак. Её просто не должно быть в интерфейсах. Просто, все интерфейсы, абсолютно все, должны быть в одной кодировке.

                          И UTF-16 не подходит уже потому, что она не имеет определённого порядка байтов. UTF-8 же его имеет (всегда «сетевой порядок»), поэтому BOM в ней быть не может. Какой может быть byte order mark в кодировке, в которой byte order однозначно зафиксирован?
                            0
                            Речь же о том, что
                            некорректный — в utf-8 не должно быть bom
                            так вот нет, utf-8 с BOM не является некорректным, символ BOM может быть в utf-8 по стандарту, хоть там и нет вариантов byte order.
                          +4
                          некорректный — в utf-8 не должно быть bom
                          Правильно будет: «в utf-8 может не быть bom». utf-8 с BOM — не является некорректным. BOM — это просто конкретный юникодный символ 0xFEFF, стандарт не мешает его использовать в utf-8 (хотя не рекомендуется), так же как не заставляет использовать в других кодировках юникода.
                            0
                            Хм, очень любопытно, всегда считал, что BOM это обязательный элемент UTF8, который нам позволяет понять собственно что за кодировка перед нами. Правда, ловил я много приколов с ним, например при (де)сериализации XML, небезызвестная ошибка Data at the root level is invalid. Line 1, position 1. заставляла использовать new UTF8Encoding(false), но в остальных случаях я все равно её использовал… Спасибо за информацию, буду теперь избегать бома.
                          0
                          Вас не затруднит объяснить, причем тут негры?
                            0

                            Очевидно, вот причём:


                            ubuntu |oǒ'boǒntoō|
                            
                            Ubuntu is an ancient African word meaning 'humanity to others'. It also means 'I am what I am because of who we all are'. The Ubuntu operating system brings the spirit of Ubuntu to the world of computers.
                          0
                          Может вопрос не совсем в тему, но тем не менее. Я когда последний раз на убунту смотрел, там переключение раскладки по Alt+Shift настроить нельзя было. И пару релизов ещё не работало оно. Что там сейчас? Починили?
                            +3
                            Да, починили.
                              0
                              А проблема с гаснущим NumLock при смене раскладки еще наблюдается, не знаете?
                              Судя по launchpad задача открыта…
                                0
                                Тут так уверенно ответить не смогу. Если на раскладку я обращал внимание, и знаю про что спрашивал poxu (сам страдал от этого) — то с NumLock никогда не воевал. Сижу на 14.04, проверил — всё ок, состояние сохраняется при смене раскладки.
                                  +1
                                  Не знал о таком) сейчас проверил на 14.04 — да, гаснет.
                                    +2
                                    К сожалению, проблема не в том, что гаснет, а в том, что потом цифровой блок ведет себя рандомно в разных приложениях.
                                    Где-то включен, где-то выключен, а где-то нечто среднее. Например, 2/4/6/8 работают как стрелки, а остальные — как цифры.
                                      0
                                      Предположу, что не сохраняется состояние регистра клавиатуры. Если у Вас есть доп клавиша «Fn», то тогда и выскакивают такие прелести.
                                        0
                                        Использую самую стандартную полноразмерную PS/2 клавиатуру на 104 клавиши…

                                        Есть подозрение на беспроводную мышь Logitech M570 (у нее навороченный приемник с возможностью подключения нескольких устройств). Надо будет попробовать откатит патченные пакеты и выдернуть мышь.
                                  0
                                  А еще вопрос аналогичный, можно ли сейчас в убунте назначить переключения отдельных раскладок на отдельные комбинации клавиш? Например для трех разных языков назначить Ctrl+1, Ctrl+2 и т.д.
                                    0
                                    Вы можете настроить произвольную фигню через custom shortcut, назначив комбинацию клавиш на самописную баш-команду.
                                      0
                                      System Settings — > Keyboard -> Shortcuts -> Custom Shortcuts

                                      создаем новый «Custom Shortcut», даем какое-то ему имя в поле «Name» (например,
                                      EN или RU), в поле «Command» прописываем:
                                      gsettings set org.gnome.desktop.input-sources current 0
                                      

                                      — эта команда будет переключать клавиатуру на раскладку которая идет первой (ну вернее нулевой), в списке All Settings -> Text Entry

                                      и назначаем ему сочетание клавиш, например Ctrl+1

                                      соотвественно следующие раскладки будут влючаться командами:
                                      gsettings set org.gnome.desktop.input-sources current 1
                                      gsettings set org.gnome.desktop.input-sources current 2
                                      gsettings set org.gnome.desktop.input-sources current 3
                                      

                                        0

                                        Раз тут такие крутые линуксоиды собрались, может мне кто-нибудь поможет?

                                          0
                                          Спасибо, попробовал в вируалке, отлично работает!
                                          ЗЫ Сорри, стрелкой вверх, увы не могу отметить такой подробный и качественный совет (
                                      0
                                      К слову, это всегда можно было прикрутить окольными путями:

                                      setxkbmap «us,ru» ",winkeys" «grp:alt_shift_toggle»
                                        0
                                        Сейчас это принято делать так:
                                        gsettings set org.gnome.desktop.wm.keybgdm3indings switch-input-source "['<Alt>Shift_L', '<Alt>Shift_R']"
                                        gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'ru')]"
                                        

                                        «здраствуй» gdm3
                                          +1
                                          Ну незнаааааю, нормальный gdm 3 как по мне :)

                                            0
                                            А оно научилось переключаться по клавишам-модификаторам?

                                            У меня когда-то был любимым левый Ctrl (да, наследие самописных драйверов клавиатуры под DOS). Сейчас на LXDE/Cinnamon прикручен Caps/Shift-Caps. В своё время отказался от Гнома и «родной» Убунты в частности и из-за этого…
                                              +1
                                              $  gsettings get org.gnome.desktop.input-sources xkb-options
                                              ['grp:shift_caps_toggle', 'misc:typo', 'lv3:ralt_switch', 'grp_led:scroll', 'keypad:oss']

                                              оно?

                                                0
                                                Почти. Надо `grp:shift_caps_switch`.

                                                Значит, примерно тем же костылём (setxkbmap в моём случае) достижимо. В гуе, как я понимаю, по-прежнему выбор ограничен. Ну, да нам оно и не страшно.

                                                Доедет предзаказанный планшет с убунтой — не придётся переучиваться ))
                                                0
                                                «Modifiers-only switch to next source», не?
                                                  0
                                                  Возможно.

                                                  Года три уже нигде нет «честного» гнома, чтобы попробовать — или cinnamon, или mate вместо него. В Mint/Cinnamon сейчас конфигуратор раскладок как из старого второго гнома, а у остальных, кажется, из гуя не было возможности нсатроить.

                                                  Надо, чтобы по Caps был английский, а по Shift-Caps — русский.
                                              +1
                                              ИМХО не самый правильный способ — привязан к конкретной граф. среде (gdm), а если гном не единственный в системе или его нет вообще?

                                              Правильнее класть это в конфигурацию иксов (к примеру /usr/share/X11/xorg.conf.d в моем дистрибутиве).
                                                +1
                                                Я с вами полностью согласен, мой комментарий был скорее саркастичным, чем показательным.

                                                Дело в том, что gnome3 по умолчанию игнорирует настройки xkb в xorg.
                                          +2
                                          Пропиарил баг. Спасибо за работу!
                                            +2
                                            О, блин… Они это что ли до сих пор не пофиксили? В 8.04 было еще...8 лет прошло.
                                            На вики даже 2 темы было.
                                            http://help.ubuntu.ru/wiki/Русификация_консоли и http://help.ubuntu.ru/wiki/russian_font_in_console
                                            Похоже нужно третью делать.
                                              +1
                                              Ох, Вы зря потратили кучу времени. Проблема решается просто: sudo dpkg-reconfigure locales.
                                              Он сам предложит выбрать кодировки, шрифт, как переключать и запустит locale-gen по завершении…
                                                +5

                                                Вот только упомянутую в статье проблему это не решает

                                                  0
                                                  Ок. Я нашел время на потестить. Тестировал на ubuntu версий 14.04, 15.10, 16.04 beta — нигде проблему не подтвердил. Вы уверены. что все делаете правильно? Я просто все три дистрибутива поставил в VirtualBox, и во время установки указал правильную локаль. После загрузки все было в порядке. Никаких дополнительных манипуляций производить не пришлось.
                                                    0

                                                    Рабочая система, Ubuntu 16.04 x64 с обновлениями по состоянию на прямо сейчас. Упомянутую вами команду применял как много раз в прошлом, так и только что специально чтобы перепроверить. В консоли квадратики. У меня и у многих других. У меня не VirtualBox, а на железе система, может, с этим что-то связано, не знаю.

                                                      0
                                                      Как минимум одну причину я знаю такой проблемы: drm-модуль видеокарты. Который грузится после настройки vconsole и создаёт новый фреймбуфер, который все настройки соответственно игнорирует. Это не все модули так получаются, потому не у всех проявляются, если хотите сравните с bosha какие модули грузятся. Но вообще не знаю та ли это проблема, и так же ли зловеще она решалась бы в дружественной убунте, как описано в статье, но в недружественном арче я в итоге решил двумя действиями — указанием модуля в прегрзку /etc/mkinitcpio.conf и регенерацией initramfs («mkinitcpio linux» итд).
                                                        0

                                                        А у меня nvidia blob кстати, возможно, это и есть причина

                                                        0
                                                        здесь идет речь о убунту сервере, а вы об убунте наверняка о десктоп (рабочая система)… там действительно нет этой проблемы.
                                                          0
                                                          Нет, это была ubuntu server.
                                                  +2
                                                  Вот интересно, есть волшебный файл /etc/vconsole.conf, который используется systemd для настройки шрифтов, почему просто им не воспользоваться?
                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                      +2
                                                      Например, чтобы видеть нормально в консоли названия файлов на русском, чтобы бывает просто необходимо.
                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                          +3
                                                          Ну суть-то описанной проблемы в том, что шрифт с юникодом не подцепляется. А без него, не только локализованные сообщения не будут работать(которые действительно не сильно-то кому нужны), но и все имена файлов содержащие символы, которых нет в стандартном шрифте, будут поломаны, что уже весьма неприятно. И кодировки тут не при чём в общем-то, как и то, что вы передаёте в LANG.
                                                        +2
                                                        Сегодня пишем на русском Хабре коммент по русски, завтра будем делать то же самое.
                                                        Зачем?
                                                        +2
                                                        Хороший труд! Спасибо.
                                                          +2
                                                          Молодец, а многие только ругаться и умничать могут…
                                                          В статье не хватает ссылки на рабочий пакет (в багрепорте слишком много ссылок) и подтверждение работы на 15.10/16.04. Не поленился, зарегился и всем советую.
                                                          –2
                                                          Использование только английского интерфейса решает многие проблемы… ;)
                                                          • НЛО прилетело и опубликовало эту надпись здесь
                                                              +2
                                                              Ага, и файлы с русскими именами не имеют прав на существование. А ведь русский — один из официальных языков ООН…
                                                                –5
                                                                Обхожусь без таких файлов лет 20, до сих пор жив… И да, названия файлов не на английском языке, на мой взгляд, плохая привычка. Нет русского или другого языка (я как подумаю про имя файла на иврите...) в названии файла — меньше проблем.
                                                                  +1
                                                                  Konsole на Ubuntu 14.04:

                                                                  Русский и иврит в консоли, в т.ч. имя файла в котором используются одновременно три языка и с написанием слева направо (англйский и русский) и справа налево (иврит)

                                                                  Без «ручных» настроек. Языки указанны в наборе клавиатур (Input soursed to use) и в Language Support, в настройках Konsole отмечено «Enable Bi-directional text rendering»
                                                                    +1
                                                                    Спасибо, всё равно буду использовать только английский (латиницу) для файлов. Проблем будет меньше.
                                                                    +3
                                                                    image
                                                                      0
                                                                      Получается, что в названии файла на иврите расширение идет в начале, а не в конце названия?
                                                                        0
                                                                        В Linux, строго говоря, нет расширений.
                                                                        В строке содержащей только буквы иврита вся строка будет ориентированна справа налево. Если мы напишем «расширение» на иврите, оно будет слева.
                                                                        Но, если в строке будут части которые представляют собой текст на языке в котором текст пишется слева направо (английский, русский), то вся строка будет располагаться слева направо, и вставки на иврите будут располагаться в этом же порядке, хотя внутри вставок порядок расположения букв будет обратным — справа налево. Т.е. пока мы пишем на английском буквы добавляются справа, переключились на иврит, они от первой ивритской буквы добавляются слева между первой ивритской буквой и английским текстом, переключились на английский — буквы будут добавляться опять справа.
                                                                        Что, имхо, логично
                                                                        image

                                                                        И так не только в именах файлов, но и вообще в тексте:

                                                                        image
                                                                        0
                                                                        Это прекрасно, но при работе в консоли жутко неудобно.
                                                                        Каждый раз переключать раскладку, как только нужно прочитать עִבְרִית.txt, очень быстро надоедает.
                                                                        А если его ещё и сравнивать придется, скажем, с العربية.txt, то там и вовсе запутаться недолго.
                                                                          –2
                                                                          Именно, по-этому только латиница в названиях файлов.
                                                                            +2
                                                                            Вам никогда файлы по электронной почте не приходят? Скачивать архивы не приходится? Вы совсем не пользуетесь софтом, который создаёт файлы в utf-8 кодировке, не задумываясь о том, какой там алфавит?
                                                                              0
                                                                              Речь о том, что делаю я, а не о том, что делают другие. Я работаю в международной компании, так что всё на английском даже внутри местного офиса.
                                                                  0
                                                                  В Debian testing на первой консоли тоже нету кириллицы. А вот на второй и дальше — есть.
                                                                  Это если с Plymouth, без него, по крайней мере в Jessie, было все ок, ЕМНИП.
                                                                    0
                                                                    Спасибо за статью, передумал переходить с 14.04 :)
                                                                      –7
                                                                      Ubuntu. Русификация консоли в 2016 году

                                                                      image
                                                                        0
                                                                        Вот так, с помощью навязшей на зубах картинки, можно высказать свою мысль. Но зачем?

                                                                        (А мятая сигарета на столе и болт размером с ширину троллейбуса странным образом не радуют, зато радуют рессоры на задней оси)
                                                                        0
                                                                        Всегда исправлял простым выставлением CODESET=«CyrKoi», про guess не знал.
                                                                          0
                                                                          Там же можно увеличить приоритет ошибки

                                                                          Даёшь хабраэффект!
                                                                            +1
                                                                            Ставил Ubuntu Server 16.04 Beta 2. После первой загрузки была такая же проблема. Но после apt-get update && apt-get upgrade и ребута — консоль сама поправилась.
                                                                              –4
                                                                              Устал читать. Грустно становится за опенсорч, в котором баги не исправляются по пять лет, а регрессии вносятся каждые полгода пачками. В таком положении развитиею опенсорча грозит захлебнуться в собственных проблемах.
                                                                                0
                                                                                Всегда решал «проблему» одной командой cyr в консоли, ещё с бородатых времён дебиана 5.
                                                                                  0
                                                                                  установил пакет по ссылке https://bugs.launchpad.net/ubuntu/+source/console-setup/+bug/1565542/+attachment/4625851/+files/keyboard-configuration_1.108ubuntu9_all-fixed.deb
                                                                                  подтверждаю, работает на ubuntu server 16.04 LTS (beta).
                                                                                  напоминаю, устанавливается так:
                                                                                  sudo dpkg -i keyboard-configuration_*.deb
                                                                                  sudo apt-mark hold keyboard-configuration
                                                                                    0
                                                                                    Т.к. текстовой консолью пользуюсь очень редко и пользователь один, просто добавил в ~/.bashrc
                                                                                    setupcon
                                                                                    

                                                                                    Спасибо за статью и багрепорт!

                                                                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                    Самое читаемое