Написание сервиса, который зависит от Xorg

30

Я пытаюсь написать сервис уровня пользователя redshift, и ему нужно подождать, пока Xorg не заработает. Мой текущий служебный файл выглядит так:

[Unit]
Description=Redshift
After=graphical.target

[Service]
Environment=DISPLAY=:0
ExecStart=/bin/redshift -l 28:-13 -t 5300:3300 -b 0.80:0.91 -m randr
Restart=always

[Install]
WantedBy=default.target

Однако, похоже, что он пытается запуститься до того, как Xorg будет запущен, и я должен вручную запустить службу после этого. Я предполагаю, что использую не ту After=цель. Есть намеки?

mkaito
источник

Ответы:

20

Я исследовал это, и ответ Гравити кажется устаревшим. Теперь вы можете настроить пользовательские сервисы с помощью systemd, которые выполняются как часть сеанса пользователя. Для них могут быть установлены DISPLAY и XAUTHORITY (в настоящее время это Arch и Debian Stretch).

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

Лучшие документы прямо сейчас - это Arch wiki; Systemd / Пользователь

Версия TLDR;

  1. Создайте нужный файл * .service в ~/.config/systemd/user/
  2. Выполнить systemctl --user enable [service](исключить суффикс .service)
  3. При желании запустить, systemctl --user start [service]чтобы начать сейчас
  4. Используйте, systemctl --user status [service]чтобы проверить, как это происходит

Пара других полезных команд.

  • systemctl --user list-unit-files - просмотреть все пользовательские блоки
  • s ystemctl --user daemon-reload- если вы редактируете файл .service

-- Потом...

Я обновил и преобразовал большинство моих сессионных демонов в файлы systemd .service. Так что я могу добавить пару дополнительных заметок.

По умолчанию не было подключений для запуска служб при входе в систему, поэтому вы должны запустить его самостоятельно. Я делаю это из моего файла ~ / .xsession.

systemctl --user import-environment PATH DBUS_SESSION_BUS_ADDRESS
systemctl --no-block --user start xsession.target

Первая строка импортирует некоторые переменные окружения в сеанс пользователя systemd, а вторая запускает цель. Мой файл xsession.target;

[Unit]
Description=Xsession running
BindsTo=graphical-session.target

Мой xbindkeys.service в качестве примера.

[Unit]
Description=xbindkeys
PartOf=graphical-session.target

[Service]
ExecStart=/usr/bin/xbindkeys -n -f ${HOME}/projects/dotfiles/.xbindkeysrc
Restart=always

[Install]
WantedBy=xsession.target
Джон Эйкенберри
источник
2
Если вы можете предоставить пример файла модуля и объяснить, как устройство может использовать DISPLAY и XAUTHORITY, я буду рад переключить принятый ответ.
mkaito
@mkaito Я посмотрю на это, как только Debian выпустит Stretch. У меня работает стабильная версия Debian, и я ждал до тех пор, чтобы поиграть с ней больше.
Джон Эйкенберри
@mkaito На github.com/systemd/systemd/blob/v219/NEWS#L194 говорится: «Теперь поставляется скрипт сценария сеанса X11, который загружает $ DISPLAY и $ XAUTHORITY в среду демона systemd --user, если сеанс начинается. Это должно улучшить совместимость с приложениями с поддержкой X11, работающими как пользовательские службы systemd. "
josch
Я все еще хотел бы увидеть пример файла модуля, просто чтобы было ясно, есть ли что-то особенное необходимое.
mkaito
11

Обычный намек - «не надо». redshiftэто не общесистемная служба - у нее будет отдельный экземпляр для каждого сеанса , и ему нужно знать, как подключиться к Xorg этого конкретного сеанса.

(Xorg также не является системной службой - есть только диспетчер дисплеев , и он также запускает отдельный Xorg для каждого сеанса. // graphical.targetсообщит вам, когда диспетчер дисплеев готов, но ничего не говорит о том, когда DM фактически запускает первый - или все - отображает.)

DISPLAY=:0Недостаточно просто запустить его при загрузке с помощью , поскольку нет никакой гарантии, что в каждый момент времени будет отображаться только один дисплей, или он всегда есть :0(например, если Xorg дает сбой, оставляя устаревший файл блокировки, следующий запускается так, :1как он подумал бы :0еще занято); вам также нужно указать путь к XAUTHORITYфайлу, поскольку X11 требует аутентификации; и убедитесь, что redshiftперезапустите, если вы когда-нибудь выйдете из системы и войдите снова.

Так с чего начать? Почти всегда в среде рабочего стола есть несколько способов запуска собственных сервисов сессий . Смотрите более старый пост, который уже описывает два обычных; ~/.xprofileсценарий и ~/.config/autostart/*.desktopместо.

Если вы используете startx , вы можете использовать ~/.xinitrcдля запуска таких вещей. Автономные оконные менеджеры часто имеют свои собственные сценарии запуска / инициализации; например ~/.config/openbox/autostartдля Openbox.

Общим для всех этих методов является то, что программа запускается изнутри сессии, избегая всех проблем, перечисленных выше.

grawity
источник
Хотя во многих случаях redshift не является общесистемной услугой, имеет смысл быть пользовательской службой, и это именно то, что пытается сделать OP.
simotek
5

Вот то, что я только что создал как обходной путь для еще не доступных graphical-session.target(В моей системе Kubuntu 16.04):

  1. Создайте псевдосистемный пользовательский модуль, который поднимает и опускает графическую цель.

Создать ~/.config/systemd/user/xsession.targetсо следующим содержанием:

[Единица измерения]
Описание = Xsession запущен и работает
BindsTo = graphical-session.target

Расскажите systemd об этом новом модуле:

$> systemctl --user daemon-reload
  1. Создайте сценарии автозапуска и завершения работы, которые управляют с xsession.targetпомощью доступной в настоящее время механики рабочего стола Ubuntu 16.04.

Создать ~/.config/autostart-scripts/xsession.target-login.shсо следующим содержанием:

#! / Bin / Баш

если ! systemctl --user is-active xsession.target &> / dev / null
тогда
  / bin / systemctl - пользовательская среда импорта DISPLAY XAUTHORITY
  / bin / systemctl --user start xsession.target
фи

Создать ~/.config/plasma-workspace/shutdown/xsession.target-logout.shсо следующим содержанием:

#! / Bin / Баш

если systemctl --user is-active xsession.target &> / dev / null
тогда
  / bin / systemctl --user stop xsession.target
фи

Сделайте скрипты исполняемыми:

$> chmod + x ~ / .config / autostart-scripts / xsession.target-login.sh
$> chmod + x ~ / .config / plasma-workspace / shutdown / xsession.target-logout.sh

Примечание: эти два файла размещены там, где KDE подберет их для автоматического запуска и завершения работы. Файлы могут быть размещены где-то еще для других сред рабочего стола (например, Gnome) - но я не знаю об этих средах.

Примечание. В этом обходном пути отсутствует поддержка нескольких рабочих столов. Он graphical-session.targetкорректно обрабатывает только то время, пока на машине запущен только один активный сеанс X11 (но это относится к большинству из нас, пользователей Linux).

  1. Создайте свои собственные пользовательские модули systemd, от которых они зависят, graphical-session.targetи обеспечьте их бесперебойную работу при входе в систему на рабочем столе.

Например, модуль @ mkaito должен выглядеть так:

[Единица измерения]
Описание = RedShift
PartOf = graphical-session.target

[Обслуживание]
ExecStart = / bin / redshift -l 28: -13 -t 5300: 3300 -b 0,80: 0,91 -m randr
Restart = всегда

(Не забудьте сделать daemon-reloadпосле редактирования ваших единиц!)

  1. Перезагрузите компьютер, войдите в систему и убедитесь, что ваши устройства запущены, как и ожидалось
$> systemctl - пользовательский статус graphical-session.target
● graphical-session.target - текущий графический пользовательский сеанс
   Загружен: загружен (/usr/lib/systemd/user/graphical-session.target; статический; предустановка поставщика: включена)
   Активен: активен с Дона 2017-01-05 15:08:42 CET; 47 мин. Назад
     Документы: man: systemd.special (7)
$> systemctl - статус пользователя your-unit ...

В какой-то будущий день (это будет Ubuntu 17.04?) Мой обходной путь устареет, поскольку система graphical-session.targetсама справится с этим правильно. В этот день просто удалите скрипт автозапуска и завершения работы, а также xsession.target- ваши пользовательские пользовательские блоки могут остаться нетронутыми и просто работать.

GUE
источник
Я знаю, что это старый комментарий, но вы также можете добавить сценарии запуска / входа в систему через приложение «Системные настройки» в разделе «Рабочая область»> «Запуск и завершение работы»> «Автозапуск», если вы хотите поместить эти сценарии в место, которое вы их запомните.
AmbientCyan
2

Это решение делает именно то, что задает автор вопроса:

нужно подождать, пока Xorg не заработает

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

Это похоже на systemd -networkd-wait-online.service systemd, который блокирует, пока не будут выполнены определенные критерии. Другие сервисы, которые зависят от него, будут запущены, как только этот сервис запустится успешно или истечет время ожидания.

Согласно инструкции (раздел «Файлы»), X-сервер создаст сокет UNIX /tmp/.X11-unix/Xn(где nнаходится номер дисплея).

Контролируя наличие этого сокета, мы можем определить, что сервер для определенного дисплея запущен.

confirm_x_started.sh:

#!/bin/bash
COUNTER=0

while [ 1 ]
do
  # Check whether or not socket exists
  if [ -S /tmp/.X11-unix/X0 ]
  then
    exit 0
  fi

  ((++COUNTER))

  if [ $COUNTER -gt 20 ]
  then
    exit 1
  fi

  sleep 0.5
done

x_server_started.service:

[Unit]
Description=Monitor X server start

[Service]
Type=oneshot
ExecStart=/path/to/confirm_x_started.sh

[Install]
WantedBy=example.target

Теперь включите одновременный x_server_started.serviceзапуск с X-сервером.

Сделайте так, чтобы другие службы (для которых требуется запуск X-сервера) зависели от x_server_started.service

зависимая единица:

[Unit]
Description=Service that needs to have the X server started
Requires=x_server_started.service
After=x_server_started.service

[Service]
ExecStart=/path/to/binary

[Install]
WantedBy=example.target

Если X-сервер запускается без проблем, x_server_started.serviceон запустится почти сразу, и systemd продолжит запуск всех модулей, от которых зависит x_server_started.service.

VL-80
источник
Это хорошо работает. Дополнительный сервис приятный штрих. Вы также можете просто использовать ExecStartPre в вашей целевой службе. Мне пришлось добавить дополнительный «сон 1» перед «выходом 0», хотя, кажется, это было слишком быстро, чтобы просто попытаться поймать Х сразу.
TTimo