LINUX.ORG.RU

RFC HOWTO: автологин в иксовую сессию с помощью systemd

 , ,


16

1

Добрый вечер, господа. Это тред-howto о том, как сделать корректный автологин в иксы «на чистом systemd». В вики мне писать влом, да и никто её не читает, а тут и теги указать можно, и людей скастовать. Собственно, да: border-radius, ecko.

В чём вообще проблема? Проблема в том, что значительное количество людей делают это через банальнейшие костыли, настраивая автологин в текстовую консоль и запуская иксы из bashrc (или, чего хуже, из bash_profile). Это плохо по трём причинам:

  • не залогиниться в другую физическую консоль в текстовом режиме
  • оверхед на проделывание цепочки такого вида:
    systemd
    /bin/agetty
    /bin/login
    PAM
    /bin/bash
    ~/.bashrc
    /bin/startx
    
  • в конце концов, это само по себе костыль.

Я предлагаю написать getty-подобный юнит, который будет запускать иксы от фиксированного пользователя с фиксированным номером дисплея на произвольном VT. (Почему так много хардкода? Потому что systemd — не дисплейный менеджер.)

Это тоже неидеальное решение. Например, нафиг идёт мультисит и возникают гонки между запуском иксов и обнаружением видеоустройств. Но этими недостатками мы пренебрежём.

Параграф один. logind, autovt и getty-подобные юниты. Getty могут запускаться двумя способами.

  • Первый — по требованию, через logind. При переключении на ttyN logind запускает юнит autovt@ttyN.service, который засимлинкен на getty@.service. Эта логика работает для tty2-tty6.
  • Второй — статически. Юнит getty@tty1.service включен по умолчанию и втягивается через getty.target. Это даёт нам всегда запущенный getty на tty1.

Соответственно, допустим, у нас есть юнит xorg@.service, который запускает иксы на указанном VT.
Его нужно либо симлинкнуть под именем autovt@ttyN.service, переопределив шаблонный юнит (тогда при переключении на выбранный VT иксы будут запускаться вместо getty — первый способ), либо отключить getty@tty1.service и включить вместо него xorg@tty1.service (тогда мы вместо всегда запущенного getty будем иметь всегда запущенные иксы — второй способ).

Параграф два. Xorg вместо getty. Итак, имеем юнит для иксов, написанный по аналогии с getty@.service: /etc/systemd/system/xorg@.service.

User=<впишитеюзера>
PAMName=login

-- это аналог su.

Conflicts=getty@%i.service
After=getty@%i.service

-- это некоторая защита от одновременного запуска getty на том же терминале.

StandardOutput=tty
StandardInput=tty-fail

-- это указание systemd запускать иксы подсоединёнными напрямую к терминалу, а не к логгеру (нужно для того, чтобы иксы можно было запускать не от рута... ах да, работает только с 1.16 и выше).

ExecStart=/etc/systemd/scripts/startx -D :0

-- это мой велосипед вместо startx с нескучным синтаксисом и exec xinit в конце, что важнее.

Дело в том, что systemd из-за вероятного бага при остановке юнита отправляет SIGTERM/SIGKILL не всем процессам в дереве, начиная с startx, а только самому startx. А поскольку он написан на шелле, то он радостно игнорирует SIGTERM и ждёт завершения xinit, которому никакого сигнала не приходит. Следовательно, проблему решаем переписыванием startx так, чтобы он в конце не запускал xinit подпроцессом, а делал exec xinit, заменяя им собственный процесс. Тогда сигнал приходит xinit'у, а он его корректно ловит и убивает иксы.

Всё остальное скопипащено из getty@.service.

Да, дисплей захардкожен в :0. Пара слов о назначении VT: процесс startx получает номер VT в переменной $XDG_VTNR (её устанавливает pam_systemd), а из startx запускается /etc/X11/xinit/xserverrc, который об этой переменной знает и передаёт X-серверу параметр vt$XDG_VTNR.

Параграф три. Запускаем. Итак, помещаем юнит в /etc/systemd/system/xorg@.service, startx в /etc/systemd/scripts/startx (можно куда угодно) и делаем:

systemctl daemon-reload
systemctl disable getty@tty1
systemctl enable xorg@tty1

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

Как-то так. Сейчас три часа семнадцать минут по московскому времени, поэтому прошу меня извинить за упрт стиль изложения, краткость, неконсистентное использование форматирования и так далее.

★★★★★

Ответ на: комментарий от X10Dead

Нет, конечно. To recap, я сделал три вещи:

  • заставил startx exec'ать xinit
  • дописал User= и PAMName=login в getty-юнит
  • дописал StandardInput=tty и StandardOutput=tty в тот же юнит

Вся идея в минимальной дивергенции от апстрима.

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от X10Dead

С другой стороны, startx сам по себе костыль, потому что нужно юзать нормальный дисплейный менеджер. Если рассматривать с этой позиции — то конечно, всё костыль.

intelfx ★★★★★ ()
Ответ на: комментарий от intelfx

потому что нужно юзать нормальный дисплейный менеджер

This. В них и реализуется автологин.

Extraterrestrial ★★★★★ ()

Сначала придумать себе колоссальные проблемы (читай systemd), а потом героически их решать (читай сооружать колоссальные костыли).

daemonpnz ★★★★★ ()

Спасибо за каст! Вечером буду дома — непременно прочту.

Deleted ()
Ответ на: комментарий от x3al

Systemd/User

Он не предназначен для запуска per-session приложений, таких, как иксы. Эта статья во многом устарела и уже нерелевантна.

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от daemonpnz

Ты упорот? Напротив, использование systemd позволяет сильно уменьшить градус костылирования в тех случаях, когда юзер по тем или иным причинам не хочет юзать дисплейный менеджер. Об этом и топик.

Костыль, связанный с systemd, тут только один (собственный startx), но это по-хорошему имеет смысл и без systemd, т. к. лишний процесс шелла, висящий в памяти и ждущий завершения иксов, — не комильфо.

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от X10Dead

Extraterrestrial

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

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)

Спасибо, все работает! Пожалуй, буду использовать у себя (раньше делал логин через agetty --autologin).

Замеченные баги фичи:

  • При запуске терминала (шелл - zsh) не применяются настройки ~/.zshrc, ~/.zprofile (а дефолтный zsh еще хуже чем bash). Очевидно, при таком способе запуска их просто некому применять. Решилось добавлением в ~/.xinitrc строчек
    source ~/.zprofile
    source ~/.zshrc
    
  • Все программы (в т.ч. терминал) запускаются с $PWD=/ вместо /home/user. Решил добавлением в юнит:
    WorkingDirectory=/home/user
    

Так и не удалось запустить rootless X. Остановился на запуске иксов просто через xinit:

ExecStart=/usr/bin/xinit -- /usr/bin/X -nolisten tcp :0

Ушел пилить systemd user session

mtk ()
Последнее исправление: mtk (всего исправлений: 1)
Ответ на: комментарий от intelfx

использование systemd позволяет сильно уменьшить градус костылирования

Нет, это

Ты упорот

devl547 ★★★★★ ()

Прочёл. Надо будет попробовать на виртуалке. Но мне кажется, что пост на лорвики лучше таки запилить.

Deleted ()
Ответ на: комментарий от mtk

Поправка: для запуска иксов через xinit надо явно указать vtX, иначе logind ломается (иксы запускаются на новом tty):

ExecStart=/usr/bin/xinit -- /usr/bin/X -nolisten tcp :0 vt${XDG_VTNR}

mtk ()
Ответ на: комментарий от intelfx

т. к. лишний процесс шелла, висящий в памяти и ждущий завершения иксов, — не комильфо.

Эталонный велосипедист. Прочитай уже про fork и cow страниц процесса в ядре чтоли.

nanoolinux ★★★★ ()
Ответ на: комментарий от nanoolinux

В предложенном варианте шелла в памяти в принципе не остается (ни одного процесса в дереве), т. ч. твой аргумент некорректен. А про механику fork(2) я знаю, спасибо.

intelfx ★★★★★ ()
Ответ на: комментарий от mtk

Да, кстати, действительно... ведь получается, что можно выкинуть мой startx-велосипед.

intelfx ★★★★★ ()

Збазибо (дос заложен), приеду вечером - попробую впилить эту схему в Асгард. Только как этот юнит его сконфигурить уже enabled by default при сборке?

border-radius ()
Ответ на: комментарий от intelfx

Это и есть rootless

Действительно, забыл сделать chmod -s /usr/bin/Xorg, без suid запускается от пользователя.

mtk ()
Ответ на: комментарий от border-radius
rm -f $DESTDIR/etc/systemd/system/getty.target.wants/getty@tty1.service
ln -sf ../xorg@.service $DESTDIR/etc/systemd/system/graphical.target.wants/xorg@tty1.service

Под $DESTDIR понимается будущий корень системы.

intelfx ★★★★★ ()
Ответ на: комментарий от mtk

Кстати,

не применяются настройки ~/.zshrc

Разве .zshrc не читается каждым интерактивным шеллом самостоятельно? Насчёт .zprofile — да, его надо подтягивать из .xinitrc, так и делается.

intelfx ★★★★★ ()
Ответ на: комментарий от LongLiveUbuntu

Какие нафиг костыли? Где ты здесь видишь хотя бы один костыль (если учесть, что мой startx-велосипед на самом деле не нужен, mtk привёл строку запуска через xinit)?

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от daemonpnz

Ты какой угодно, но не адекватный. Посмотри своё исходное сообщение. Где там хоть один пруф «колоссальной проблемы», появившейся в связи с использованием systemd?

Я не люблю разговаривать по-быдляцки, но то, что ты сделал, на этом наречии называется «пёрнуть в лужу».

intelfx ★★★★★ ()
Ответ на: комментарий от intelfx

Все верно. Просто у меня в zshrc source $ZSH/*.zsh, а $ZSH определялась в zprofile.

mtk ()
Ответ на: комментарий от intelfx

Сам systemd и есть колосальная проблема.

Все лужи уже заметанированны последователями поца, нам бедным обычным пользователям ни одной лужицы не осталось.

daemonpnz ★★★★★ ()
Последнее исправление: daemonpnz (всего исправлений: 1)
Ответ на: комментарий от daemonpnz

Сам systemd и есть колосальная проблема.

Мимо.

Где в этом треде описывается «героическое решение» проблемы, появившейся вследствие использования systemd?

intelfx ★★★★★ ()
Ответ на: комментарий от LongLiveUbuntu

Во-первых, при чём здесь запуск сферических демонов в вакууме, если мы обсуждаем конкретную фичу (и про «костыли через жопу» ты начал говорить в её контексте)? Во-вторых, конечно, может.

intelfx ★★★★★ ()
Ответ на: комментарий от LongLiveUbuntu

Во-первых, ExecStart=. Во-вторых,

ExecStart=/etc/init.d/cpupower start
ExecStop=/etc/init.d/cpupower stop

И в-третьих,

Type=forking

В четвёртых, при чём здесь это, мать вашу?

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от LongLiveUbuntu

В systemd есть встроенные средства совместимости с sysvinit (генератор юнитов по сервисам sysvinit). Рекомендую заюзать его (если дистрибутив, конечно, это позволяет; в арче,например, это выпилено). В противном случае — ну да, конвертировать самому.

intelfx ★★★★★ ()
Ответ на: комментарий от Medar

I don't give a fuck. Если нужны иксы от рута — ну сделай его бинарь suid-ным или поправь настройки Xwrapper'а (зависит от дистра; никогда этим не занимался, сказать ничего не могу).

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

А, ну у меня в customize_airootfs.sh можно и systemctl вписывать, я забыл же.

Короче, вот в таком виде вроде как даже работает (щас пересобираю, чтобы точно убедиться - persistent storage таки балует):

# Licensed under GPLv3.
# Ivan Shapovalov <intelfx100@gmail.com>
# modded by plugnburn (http://github.com/plugnburn/)

[Unit]
Description=Xorg server on %I
Documentation=man:Xorg(1)
After=systemd-user-sessions.service

Conflicts=getty@%i.service
After=getty@%i.service

[Service]
User=asgard
PAMName=login

StandardOutput=tty
StandardInput=tty-fail

ExecStart=/usr/bin/xinit -- /usr/bin/X -nolisten tcp :0 vt${XDG_VTNR}
Type=simple
Restart=always
RestartSec=0
UtmpIdentifier=:0
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
IgnoreSIGPIPE=no

[Install]
WantedBy=multi-user.target
border-radius ()

не залогиниться в другую физическую консоль в текстовом режиме

одно это перечёркивает всё плюсы

dhampire ★★★ ()
Ответ на: комментарий от intelfx

ничего не знаю у меня на tty1 запускается getty, в .zprofile прописано

[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && exec start
после логина в tty1 - запускаются иксы автоспавн getty на tty{2-5} отключён в конфиге, на tty6 спавнится getty - в нём при логине - иксы соотв не стартуют.

если вкл. автологин на tty1 - иксы будут пониматься сразу, пароль будет спрашивать wm.

в описанном тобой методе явно фигурирует замена autovt@.service на xorg@.service, чисто из логики я не вижу как сделать так что бы иксы стартовали только на tty1, а на tty6 getty? и вот почему

systemctl status autovt@tty6
● getty@tty6.service - Getty on tty6
   Loaded: loaded (/usr/lib/systemd/system/getty@.service; enabled)
   Active: active (running) since Пт 2014-09-12 02:03:46 MSK; 2 days ago
     Docs: man:agetty(8)
           man:systemd-getty-generator(8)
           http://0pointer.de/blog/projects/serial-console.html
 Main PID: 27429 (agetty)
   CGroup: /system.slice/system-getty.slice/getty@tty6.service
           └─27429 /sbin/agetty --noclear tty6 linux

dhampire ★★★ ()
Ответ на: комментарий от dhampire

[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]]

Это тот самый дополнительный костыль. Если не проверять XDG_VTNR — будет запускаться на каждом VT.

в описанном тобой методе явно фигурирует замена autovt@.service на xorg@.service

Ты не прав. Я написал:

Его нужно либо симлинкнуть под именем autovt@ttyN.service

Таким образом, на xorg@.service будет переопределена только инстанция для ttyN; остальные останутся на getty@.service.

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
1 ноября 2014 г.
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.