Для меня было некоторым откровением узнать, что в 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».

Комментарии (81)


  1. ertaquo
    07.04.2016 14:52
    +7

    Решал обычно как-то так:

    sudo apt-get install console-cyrillic
    echo cyr >> ~/.bashrc
    


    1. av0000
      07.04.2016 15:11
      +1

      Если склероз подводит, это пакет не рекомендовался к использованию где-то с 11.хх. Причин, за давностью лет, не упомню — что-то он там то ли ломал, то ли не срабатывал.

      Потому, в своё время, прикрутил для той же цени setupcon и успокоился


    1. EvgenT
      07.04.2016 15:59
      +3

      Всегда делал так: http://help.ubuntu.ru/wiki/russian_font_in_console
      На 16.04 тоже сработало.
      На той же странице Ваш «костыль» во вредных советах. И я с ними согласен.


      1. kekekeks
        07.04.2016 19:43
        -1

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


        1. kekekeks
          07.04.2016 19:48
          -1

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


  1. BasilSnowman
    07.04.2016 14:52
    -5

    поддержал


  1. av0000
    07.04.2016 15:08
    +6

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

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

    Кстати, убунта этим страдает как минимум с 10.04 — ещё жив под рукой сервер, на котором проводились подобные «пляски с бубном»


    1. Rondo
      07.04.2016 15:26

      8.04 тоже страдала, раньше — не припомню, но setupcon гуглился уже тогда легко, видимо проблема так же стара, как убунта


  1. denis_l_eryomin
    07.04.2016 15:30
    -11

    Просто ад какой-то. В слаке всё гораздо проще. Дайте неграм Linux и они его извратят и усложнят до невозможности. Убунту второй виндовс и не нужен ни под каким соусом. Даже мята не спасает, один хрен дерьмом тянет.


    1. PavelSandovin
      07.04.2016 15:39
      -14

      Я очень люблю Linux, но к сожалению, в актуальных версиях Windows нет таких проблем. Так что это даже не второй Windows. Это просто Ubuntu.


      1. merlin-vrn
        07.04.2016 17:06
        +13

        В актуальных версиях Windows не просто дофига таких проблем, там их ещё больше, чем было в неактуальных. Ибо если во времена 9x было ansi и oem, читай windows-1251 и ibm866, то теперь ещё появились разные вариации юникода, в том числе utf-8 с bom (некорректный — в utf-8 не должно быть bom).

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

        А апофеозом ситуации является IBM Lotus Domino, который мало того, что сам выдаёт сообщения в SMTP-сессию не в латинице (чего нельзя делать по стандарту — кодировка и язык на этом этапе не согласовываются), так ещё и некоторые системные сообщения выдаёт прям в SMTP-сессию в той кодировке, в которой ему отдала винда, то есть, не в той, в которой говорил сам. Когда его ставишь в линуксе, такой порнографии не видно.


        1. PavelSandovin
          07.04.2016 18:33

          Кто выдает эти сообщения об ошибках? Приложения, идущие в составе дистрибутива Windows или приложения сторонних разработчиков, как Lotus Domino?


          1. merlin-vrn
            07.04.2016 21:18

            Сообщения системные, типа «файл не найден». В Bacula, например, нет таких сообщений вообще.

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

            Вообще, я вас обязан расстроить: чтобы это исправить, придётся отказаться от обратной совместимости и перевести всё — cmd тоже — на рельсы utf-8. И тогда куча уже имеющихся бинарников будет отображать кракозябры, но зато проблем типа «запустил dir > file.txt, открыл блокнотом — вижу кракозябры» не будет.


            1. PavelSandovin
              08.04.2016 10:25

              Ладно-ладно, хотел я вам ответить тут вчера, но моя новенькая Windows 10 на ноутбуке выдала красивый такой обновленный BSOD, когда я писал комментарий. Ждем Ubuntu 16.04. Посмотрим что будет в ней хорошего и какие недоделки останутся :)


        1. hdfan2
          07.04.2016 18:42

          > в utf-8 не должно быть bom
          Почему? А как его отличить от различных вариантов UTF-16?


          1. EvilFox
            07.04.2016 20:47
            +1

            У UTF-16 всегда есть сигнатура. Тем не менее для UTF-8 иногда полезно иметь BOM, ибо для обнаружения что перед нами документ в UTF-8 те ещё костыли в редакторах используют, которые не всегда срабатывают (если например в поток вкрались вдруг местами одиночные байты типа \x00 и прочий мусор).


          1. Cheater
            08.04.2016 12:54
            +1

            Пользователь должен явно сообщать приложению, читающему поток символов, какую кодировку использовать.
            Как пользователь эту кодировку узнает — его проблемы, но класть подсказки внутрь самого текста (BOM) — одна из худших идей ever.


          1. merlin-vrn
            11.04.2016 08:41
            +1

            Никак. Её просто не должно быть в интерфейсах. Просто, все интерфейсы, абсолютно все, должны быть в одной кодировке.

            И UTF-16 не подходит уже потому, что она не имеет определённого порядка байтов. UTF-8 же его имеет (всегда «сетевой порядок»), поэтому BOM в ней быть не может. Какой может быть byte order mark в кодировке, в которой byte order однозначно зафиксирован?


        1. barker
          07.04.2016 19:07
          +4

          некорректный — в utf-8 не должно быть bom
          Правильно будет: «в utf-8 может не быть bom». utf-8 с BOM — не является некорректным. BOM — это просто конкретный юникодный символ 0xFEFF, стандарт не мешает его использовать в utf-8 (хотя не рекомендуется), так же как не заставляет использовать в других кодировках юникода.


        1. anonymous
          00.00.0000 00:00


    1. ComodoHacker
      08.04.2016 11:17

      Вас не затруднит объяснить, причем тут негры?


      1. igorp1024
        08.04.2016 13:18

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


        ubuntu |oo'boontoo|
        
        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.


  1. poxu
    07.04.2016 15:36

    Может вопрос не совсем в тему, но тем не менее. Я когда последний раз на убунту смотрел, там переключение раскладки по Alt+Shift настроить нельзя было. И пару релизов ещё не работало оно. Что там сейчас? Починили?


    1. Sild
      07.04.2016 15:48
      +3

      Да, починили.


      1. SabMakc
        07.04.2016 16:05

        А проблема с гаснущим NumLock при смене раскладки еще наблюдается, не знаете?
        Судя по launchpad задача открыта…


        1. Sild
          07.04.2016 16:08

          Тут так уверенно ответить не смогу. Если на раскладку я обращал внимание, и знаю про что спрашивал poxu (сам страдал от этого) — то с NumLock никогда не воевал. Сижу на 14.04, проверил — всё ок, состояние сохраняется при смене раскладки.


        1. prostofilya
          07.04.2016 17:30
          +1

          Не знал о таком) сейчас проверил на 14.04 — да, гаснет.


          1. SabMakc
            07.04.2016 17:48
            +2

            К сожалению, проблема не в том, что гаснет, а в том, что потом цифровой блок ведет себя рандомно в разных приложениях.
            Где-то включен, где-то выключен, а где-то нечто среднее. Например, 2/4/6/8 работают как стрелки, а остальные — как цифры.


            1. Sykoku
              08.04.2016 13:24

              Предположу, что не сохраняется состояние регистра клавиатуры. Если у Вас есть доп клавиша «Fn», то тогда и выскакивают такие прелести.


              1. SabMakc
                08.04.2016 13:56

                Использую самую стандартную полноразмерную PS/2 клавиатуру на 104 клавиши…

                Есть подозрение на беспроводную мышь Logitech M570 (у нее навороченный приемник с возможностью подключения нескольких устройств). Надо будет попробовать откатит патченные пакеты и выдернуть мышь.


      1. Duke_kz
        07.04.2016 20:44

        А еще вопрос аналогичный, можно ли сейчас в убунте назначить переключения отдельных раскладок на отдельные комбинации клавиш? Например для трех разных языков назначить Ctrl+1, Ctrl+2 и т.д.


        1. Sild
          07.04.2016 20:47

          Вы можете настроить произвольную фигню через custom shortcut, назначив комбинацию клавиш на самописную баш-команду.


        1. ageyev
          08.04.2016 00:36

          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
          


          1. dbanet
            08.04.2016 15:25

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


          1. Duke_kz
            09.04.2016 18:34

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


    1. Sild
      07.04.2016 16:13

      К слову, это всегда можно было прикрутить окольными путями:

      setxkbmap «us,ru» ",winkeys" «grp:alt_shift_toggle»


      1. kvaps
        07.04.2016 17:27

        Сейчас это принято делать так:

        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. Prototik
          07.04.2016 18:24
          +1

          Ну незнаааааю, нормальный gdm 3 как по мне :)


          1. av0000
            08.04.2016 09:32

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

            У меня когда-то был любимым левый Ctrl (да, наследие самописных драйверов клавиатуры под DOS). Сейчас на LXDE/Cinnamon прикручен Caps/Shift-Caps. В своё время отказался от Гнома и «родной» Убунты в частности и из-за этого…


            1. develop7
              08.04.2016 09:50
              +1

              $  gsettings get org.gnome.desktop.input-sources xkb-options
              ['grp:shift_caps_toggle', 'misc:typo', 'lv3:ralt_switch', 'grp_led:scroll', 'keypad:oss']

              оно?


              1. av0000
                08.04.2016 09:58

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

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

                Доедет предзаказанный планшет с убунтой — не придётся переучиваться ))


            1. Prototik
              08.04.2016 13:45

              «Modifiers-only switch to next source», не?


              1. av0000
                08.04.2016 15:02

                Возможно.

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

                Надо, чтобы по Caps был английский, а по Shift-Caps — русский.


        1. Cheater
          08.04.2016 13:08
          +1

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

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


          1. kvaps
            09.04.2016 12:18
            +1

            Я с вами полностью согласен, мой комментарий был скорее саркастичным, чем показательным.

            Дело в том, что gnome3 по умолчанию игнорирует настройки xkb в xorg.


  1. PavelSandovin
    07.04.2016 15:37
    +2

    Пропиарил баг. Спасибо за работу!


  1. susnake
    07.04.2016 16:01
    +2

    О, блин… Они это что ли до сих пор не пофиксили? В 8.04 было еще...8 лет прошло.
    На вики даже 2 темы было.
    http://help.ubuntu.ru/wiki/Русификация_консоли и http://help.ubuntu.ru/wiki/russian_font_in_console
    Похоже нужно третью делать.


  1. bosha
    07.04.2016 16:08
    +1

    Ох, Вы зря потратили кучу времени. Проблема решается просто: sudo dpkg-reconfigure locales.
    Он сам предложит выбрать кодировки, шрифт, как переключать и запустит locale-gen по завершении…


    1. nazarpc
      07.04.2016 17:55
      +5

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


  1. Gorthauer87
    07.04.2016 16:17
    +2

    Вот интересно, есть волшебный файл /etc/vconsole.conf, который используется systemd для настройки шрифтов, почему просто им не воспользоваться?


  1. NLO
    07.04.2016 16:45

    НЛО прилетело и опубликовало эту надпись здесь


    1. kotomyava
      07.04.2016 17:09
      +2

      Например, чтобы видеть нормально в консоли названия файлов на русском, чтобы бывает просто необходимо.


      1. NLO
        07.04.2016 17:14

        НЛО прилетело и опубликовало эту надпись здесь


        1. kotomyava
          07.04.2016 17:25
          +3

          Ну суть-то описанной проблемы в том, что шрифт с юникодом не подцепляется. А без него, не только локализованные сообщения не будут работать(которые действительно не сильно-то кому нужны), но и все имена файлов содержащие символы, которых нет в стандартном шрифте, будут поломаны, что уже весьма неприятно. И кодировки тут не при чём в общем-то, как и то, что вы передаёте в LANG.


    1. Chumicheff
      08.04.2016 11:23
      +2

      Сегодня пишем на русском Хабре коммент по русски, завтра будем делать то же самое.
      Зачем?


  1. mortimoro
    07.04.2016 16:45
    +2

    Хороший труд! Спасибо.


    1. midaw1
      07.04.2016 17:17
      +2

      Молодец, а многие только ругаться и умничать могут…
      В статье не хватает ссылки на рабочий пакет (в багрепорте слишком много ссылок) и подтверждение работы на 15.10/16.04. Не поленился, зарегился и всем советую.


  1. maksasila
    07.04.2016 17:41
    -2

    Использование только английского интерфейса решает многие проблемы… ;)


    1. izzholtik
      07.04.2016 18:24
      +4

      Скорее, маскирует.


    1. PavelSandovin
      07.04.2016 18:35
      +2

      Ага, и файлы с русскими именами не имеют прав на существование. А ведь русский — один из официальных языков ООН…


      1. maksasila
        07.04.2016 20:01
        -5

        Обхожусь без таких файлов лет 20, до сих пор жив… И да, названия файлов не на английском языке, на мой взгляд, плохая привычка. Нет русского или другого языка (я как подумаю про имя файла на иврите...) в названии файла — меньше проблем.


        1. ageyev
          08.04.2016 04:15
          +1

          Konsole на Ubuntu 14.04:

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

          Без «ручных» настроек. Языки указанны в наборе клавиатур (Input soursed to use) и в Language Support, в настройках Konsole отмечено «Enable Bi-directional text rendering»


          1. maksasila
            08.04.2016 10:19
            +1

            Спасибо, всё равно буду использовать только английский (латиницу) для файлов. Проблем будет меньше.


        1. ageyev
          08.04.2016 04:21
          +3

          image


          1. f0rk
            08.04.2016 12:05

            Получается, что в названии файла на иврите расширение идет в начале, а не в конце названия?


            1. ageyev
              10.04.2016 00:55

              В Linux, строго говоря, нет расширений.
              В строке содержащей только буквы иврита вся строка будет ориентированна справа налево. Если мы напишем «расширение» на иврите, оно будет слева.
              Но, если в строке будут части которые представляют собой текст на языке в котором текст пишется слева направо (английский, русский), то вся строка будет располагаться слева направо, и вставки на иврите будут располагаться в этом же порядке, хотя внутри вставок порядок расположения букв будет обратным — справа налево. Т.е. пока мы пишем на английском буквы добавляются справа, переключились на иврит, они от первой ивритской буквы добавляются слева между первой ивритской буквой и английским текстом, переключились на английский — буквы будут добавляться опять справа.
              Что, имхо, логично
              image

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

              image


          1. sledopit
            08.04.2016 17:35

            Это прекрасно, но при работе в консоли жутко неудобно.
            Каждый раз переключать раскладку, как только нужно прочитать ????????.txt, очень быстро надоедает.
            А если его ещё и сравнивать придется, скажем, с ???????.txt, то там и вовсе запутаться недолго.


            1. maksasila
              11.04.2016 21:31
              -2

              Именно, по-этому только латиница в названиях файлов.


              1. merlin-vrn
                12.04.2016 07:15
                +2

                Вам никогда файлы по электронной почте не приходят? Скачивать архивы не приходится? Вы совсем не пользуетесь софтом, который создаёт файлы в utf-8 кодировке, не задумываясь о том, какой там алфавит?


                1. maksasila
                  12.04.2016 09:56

                  Речь о том, что делаю я, а не о том, что делают другие. Я работаю в международной компании, так что всё на английском даже внутри местного офиса.


  1. Magister7
    07.04.2016 19:04

    В Debian testing на первой консоли тоже нету кириллицы. А вот на второй и дальше — есть.
    Это если с Plymouth, без него, по крайней мере в Jessie, было все ок, ЕМНИП.


  1. Invision70
    07.04.2016 21:24

    Спасибо за статью, передумал переходить с 14.04 :)


  1. iGusev
    08.04.2016 03:42
    -7

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

    image


    1. achekalin
      08.04.2016 10:28

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

      (А мятая сигарета на столе и болт размером с ширину троллейбуса странным образом не радуют, зато радуют рессоры на задней оси)


  1. psycho_zs
    08.04.2016 07:43

    Всегда исправлял простым выставлением CODESET=«CyrKoi», про guess не знал.


  1. 1KoT1
    08.04.2016 08:47

    Там же можно увеличить приоритет ошибки

    Даёшь хабраэффект!


  1. BVadim
    08.04.2016 13:42
    +1

    Ставил Ubuntu Server 16.04 Beta 2. После первой загрузки была такая же проблема. Но после apt-get update && apt-get upgrade и ребута — консоль сама поправилась.


  1. webhamster
    10.04.2016 22:24
    -4

    Устал читать. Грустно становится за опенсорч, в котором баги не исправляются по пять лет, а регрессии вносятся каждые полгода пачками. В таком положении развитиею опенсорча грозит захлебнуться в собственных проблемах.


  1. Frankenstine
    12.04.2016 11:41

    Всегда решал «проблему» одной командой cyr в консоли, ещё с бородатых времён дебиана 5.


  1. midaw1
    12.04.2016 13:43

    установил пакет по ссылке 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


  1. anonymous
    00.00.0000 00:00