Моё решение проблемы шрифта в консоли

Наконец и я налетел на проблему несвоевременной установки консольного шрифта :)

Проявляется эта пакость в тех случаях, когда загрузка модулей DRM/KMS, и соответственно, инициализация фреймбуфера, происходит уже ПОСЛЕ загрузки шрифта. Так как шрифт для конфоли загружается не в виде имени или файла, а путём загрузки непосредственно содержимого файла, ядро не знает, какой шрифт у вас был установлен ДО фреймбуфера, и после запуска графической консоли просто ставит свой дефолтный шрифт, в котором, как водится, русским и не пахнет.

Раньше я счастливо избегал этой проблемы, так как фреймбуфер всегда старался активировать как можно раньше – из загрузчика для VESA-режимов на nVidia, или включением DRM-модуля i915 в initcpio для intel.

И вот теперь, в процессе настройки systemd в переносной системе на флешке, в которой проблематично заранее встроить всё необходимое в initcpio, я обнаружил, что systemd ухитряется настроить консоль РАНЬШЕ, чем udev успевает загрузить DRM-модуль, который в свою очередь, возвращает дефолтный шрифт.

Так как запуск фреймбуфера – это работа ядра и udev, пытаться поймать этот момент через зависимости юнитов я не стал, и вместо этого использовал udev, который для того и предназначен, чтобы отслеживать события устройств, в том числе и их появление :)

Сначала вышел конфуз с локалью, которую утилита systemd-vconsole-setup не хотела читать из конфига, и я уже думал, что придётся применять скрипты, но решение было найдено.
Всё просто – не надо изобретать велосипеды, они и так уже изобретены.
Не надо специальной утилиты или скрипта для загрузки шрифта, прописанного в конфиге – udev САМ может прочесть этот конфиг, потому что /etc/vconsole.conf сделан именно в виде ПЕРЕМЕННАЯ=значение.

Получилось вот такое правило:
/etc/udev/rules.d/96-fb-setfont.rules
# Set font for a new framebuffer device
KERNEL=="fb*", ACTION=="add", IMPORT{file}="/etc/vconsole.conf", RUN+="/usr/bin/setfont $env{FONT}"
Шрифт в консоли восстанавливается непосредственно в момент переключения режима :)
Причём именно тот, который прописан в /etc/vconsole.conf
Запчастей от systemd не используется, так что будет работать и хоть с ним, хоть без него.

Первоначально хотел использовать /usr/lib/systemd/systemd-vconsole-setup из комплекта systemd-tools , но штучка оказалась с подвохом – читала текущую локаль из окружения, а не из конфига. Однако, это удалось исправить, ведь udev может прочесть и локаль:
/etc/udev/rules.d/96-fb-vconsole-setup.rules
# Setup vconsole for a new framebuffer device
KERNEL=="fb*", ACTION=="add", IMPORT{file}="/etc/locale.conf", RUN+="/usr/lib/systemd/systemd-vconsole-setup"
Этот вариант универсальный, поскольку читает не только FONT, но и FONT_MAP и FONT_UNIMAP, хотя у нас они обычно не требуются.

На этот раз всё проверил тщательно, наученный прошлым конфузом – работает, и мгновенно. Русский на месте :)

Вариант третий – расширенная версия первого:
/etc/udev/rules.d/96-fb-setfontmap.rules
# Set font and map for a new framebuffer device
KERNEL=="fb*", ACTION=="add", GOTO="fb_set"
GOTO="fb_end"
LABEL="fb_set"
IMPORT{file}="/etc/vconsole.conf"
ENV{.setfont}="/usr/bin/setfont $env{FONT}"
ENV{FONT_MAP}=="?*", ENV{.setfont}+=" -m $env{FONT_MAP}"
ENV{FONT_UNIMAP}=="?*", ENV{.setfont}+=" -u $env{FONT_UNIMAP}"
RUN+="$env{.setfont}"
LABEL="fb_end"
Даже не знаю, как смотреть на него после первых двух, я сделал его исключительно из принципа :)
С фонтмапом не проверял, но по идее должен тоже работать универсально.

Добавлено 22.08.2012 :
Выяснилось, что в некоторых, особо тяжких случаях модуль DRM/KMS может загружаться даже ПОСЛЕ getty, то есть после инициализации второй и следующих консолей. В этом случае все описанные выше правила, к сожалению, сработают в лучшем случае для одной из консолей, а остальные останутся с дефолтным шрифтом.

Чтобы избежать этого, пришлось усложнить метод, и всё-таки сделать скрипт, так как выполнять циклы udev, увы, пока не научился:
/etc/udev/rules.d/96-fb-all-vcs-setup.rules :
# Setup all vconsoles for a new framebuffer device
KERNEL=="fb*", ACTION=="add", RUN+="/bin/sh /etc/udev/all-vcs-set.sh"
/etc/udev/all-vcs-set.sh :
#!/bin/sh
# We must load locale for $VCS util
. /etc/locale.conf
export LANG
VCS=/usr/lib/systemd/systemd-vconsole-setup
# Setup the "real" (current) console first
$VCS
# Setup all other active consoles
for VC in /dev/vcs[0-9]*
do $VCS /dev/tty${VC#/dev/vcs}
done
В таком виде правило и скрипт работают так, что даже если модуль DRM с фреймбуфером не был загружен изначально, и его запустили руками через modprobe, это всё равно приведёт к загрузке шрифта для всех имеющихся консолей, сколько бы их ни было прописано в inittab или конфиге systemd , а все не инициализированные консоли будут проигнорированы.
Как раз собирался заняться решением проблемы со шрифтами на системд, а тут и готовое решение дали, благодарю!)))
А хуки не сработали?
Псевдографический инсталлятор Arch Linux ver. 3.8.2
Благодарности принимаются на ЯД 410012815723874
nafanja
А хуки не сработали?
Которые?
consolefont и keymap
работоспособность этих хуков в некоторых случаях зависит от расположения в HOOKS= !!!
Псевдографический инсталлятор Arch Linux ver. 3.8.2
Благодарности принимаются на ЯД 410012815723874
nafanja
consolefont и keymap
работоспособность этих хуков в некоторых случаях зависит от расположения в HOOKS= !!!
Если имеются в виду хуки mkinitcpio, то они замечательно работают, но ТОЛЬКО если вызываются ПОСЛЕ запуска фреймбуфера, то есть в initcpio ДОЛЖЕН быть добавлен соответствующий вашей видеокарте модуль DRM, как то nouveau, или i915, или что там ещё бывает. На стационарных системах у меня так и сделано, и этой проблемы никогда не возникало.

А сейчас я делал это НА ФЛЕШКЕ, которая должна грузиться на самых разных машинах, и делать это автоматически, а значит все модули должны грузиться в общем порядке через udev, и момент загрузки модуля, тем более на заранее неизвестном железе, предсказать затруднительно. А мне нужно, чтобы консоль была настроена обязательно ПОСЛЕ загрузки этого модуля, а не до. Значит, надо чтобы сам udev её и запустил, и проще всего это сделать по факту появления устройства фреймбуфера :)
Странно, из коробки, с настроенной как обычно консолью и без установки всяких доп дров для видио и вообще без X-ов, консоль работала без сбоев, даже без хуков.
Проверял на более 30 разных машинах.
Псевдографический инсталлятор Arch Linux ver. 3.8.2
Благодарности принимаются на ЯД 410012815723874
nafanja
Странно, из коробки, с настроенной как обычно консолью и без установки всяких доп дров для видио и вообще без X-ов, консоль работала без сбоев, даже без хуков.
Проверял на более 30 разных машинах.
С хуками, без хуков – оно могло работать, а могло и не случиться.
Так как процесс загрузки модулей для найденного железа в udev идёт параллельно и независимо от продолжающейся в то же самое время загрузки юзерспейса, вы никак не можете заранее предсказать, что произойдёт раньше – загрузка DRM-модуля из udev, или загрузка консольного шрифта в systemd или initscripts. Даже на одной и той же машине это может зависеть от различных меняющихся со временем факторов, не говоря о других, на которых ещё не пробовали.

Видимо, вам пока везло, и мне везло, с флешкой, пока на ней был только initscripts. А как установил systemd, так он и начал грузить шрифт в консоль раньше, чем udev загрузит модуль.

Никакие “особые дополнительные драйверы” в этом деле не участвуют, только штатные модули ядра, однако и их вполне достаточно :)
А “иксы” тут вообще ни при чём – никак не может иксовый драйвер поменять шрифт в графической консоли. Вот в текстовой – да, может, потому что она аппаратная, и шрифт хранится аппаратно.
Ну тогда это серьезная недоработка, по идее такого ни в коем случае не должно получаться!
А так как systemd используют десятки тысяч людей, и даже больше, в тех дистрах которые давно на него перешли, то это уже должно было засветиться, и мог быть придуман какой нибудь универсальный метод.

Если не затруднит, можешь попробовать сделать так
/etc/systemd/system/systemd-vconsole-setup.service
.include /usr/lib/systemd/system/systemd-vconsole-setup.service
[Unit]
Requires=systemd-udev-settle.service
After=systemd-udev-settle.service
[Install]
WantedBy=sysinit.target
(вместо Requires думаю можно использовать Wants)
ну и потом
systemctl enable systemd-vconsole-setup.service

Не исправит ли это проблему?
Псевдографический инсталлятор Arch Linux ver. 3.8.2
Благодарности принимаются на ЯД 410012815723874
pacman -Qo /etc/systemd/system/systemd-vconsole-setup.service 
ошибка: Ни один пакет не содержит /etc/systemd/system/systemd-vconsole-setup.service
cat /etc/systemd/system/systemd-vconsole-setup.service 
.include /usr/lib/systemd/system/systemd-vconsole-setup.service
[Unit]
After=systemd-modules-load.service
[Install]
WantedBy=sysinit.target
во те раз, я то точно не создавал этот юнит. Перевел основные маны, и только щас понял, что надо просто немного позже запустить юнит, чем создавать дополнительный. Сейчас проверю вариант nafanja. Если сработает предлагаю написать меинтейнеру юнита.
Лозунг у них был такой: "Познание бесконечности требует бесконечного времени". С этим я не спорил, но они делали из этого неожиданный вывод: "А потому работай не работай — все едино". И в интересах неувеличения энтропии Вселенной они не работали. (с)
 
Зарегистрироваться или войдите чтобы оставить сообщение.