Pisanie usługi zależnej od Xorg

29

Próbuję napisać usługę na poziomie użytkownika redshifti musi ona poczekać, aż Xorg będzie gotowy do działania. Mój aktualny plik usługi wygląda następująco:

[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

Wygląda jednak na to, że próbuje się uruchomić, zanim Xorg się uruchomi, a potem muszę ręcznie uruchomić usługę. Chyba używam niewłaściwego After=celu. Jakieś wskazówki?

mkaito
źródło

Odpowiedzi:

19

Badałem to i odpowiedź grawitacji wydaje się nieaktualna. Możesz teraz skonfigurować usługi użytkownika w systemie, które działają w ramach sesji użytkownika. Mogą mieć ustawiony WYŚWIETLACZ i XAUTHORITY (obecnie w Arch i Debian Stretch).

Ma to sens w porównaniu z poprzednimi zaleceniami używania plików autostartu na pulpicie, ponieważ zarządzanie procesem jest takie samo, jak w przypadku aplikacji na poziomie systemu (restart itp.).

Najlepszymi dokumentami w tej chwili są Arch Arch; Systemd / Użytkownik

Wersja TLDR;

  1. Utwórz żądany plik * .service w ~/.config/systemd/user/
  2. Uruchom systemctl --user enable [service](wyklucz sufiks .service)
  3. Opcjonalnie uruchom, systemctl --user start [service]aby rozpocząć teraz
  4. Służy systemctl --user status [service]do sprawdzania, jak sobie radzi

Kilka innych przydatnych poleceń.

  • systemctl --user list-unit-files - zobacz wszystkie jednostki użytkownika
  • s ystemctl --user daemon-reload- jeśli edytujesz plik .service

-- Później...

Zaktualizowałem i przekonwertowałem większość moich demonów sesji do systemowych plików .service. Mogę więc dodać kilka dodatkowych notatek.

Nie było domyślnego haka do uruchamiania usług przy logowaniu, więc musisz sam je uruchomić. Robię to z mojego pliku ~ / .xsession.

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

Pierwszy wiersz importuje niektóre zmienne środowiskowe do systemowej sesji użytkownika, a drugi rozpoczyna cel. Mój plik xsession.target;

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

Mój xbindkeys.service jako przykład.

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

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

[Install]
WantedBy=xsession.target
John Eikenberry
źródło
2
Jeśli możesz podać przykładowy plik jednostki i wyjaśnić, w jaki sposób jednostka może używać DISPLAY i XAUTHORITY, chętnie zmienię przyjętą odpowiedź.
mkaito
@mkaito Zajmę się tym, gdy Debian wyda Stretch. Używam stabilnej wersji Debiana i do tego czasu czekałem na więcej.
John Eikenberry,
@mkaito Na github.com/systemd/systemd/blob/v219/NEWS#L194 napisano: „Dostarczony jest teraz skryptlet sesji X11, który przesyła $ DISPLAY i $ XAUTHORITY do środowiska demona systemd --user, jeśli sesja się rozpocznie. Powinno to poprawić zgodność z aplikacjami obsługującymi X11 działającymi jako usystematyzowane usługi użytkownika. ”
josch
Nadal chciałbym zobaczyć przykładowy plik jednostki, aby wyjaśnić, czy jest coś specjalnego.
mkaito,
11

Zwykła wskazówka to „nie”. redshiftnie jest usługą ogólnosystemową - miałby osobną instancję dla każdej sesji i musi wiedzieć, jak połączyć się z Xorgiem konkretnej sesji.

(Xorg też nie jest usługą systemową - jest tylko menedżer wyświetlania i uruchamia osobny Xorg dla każdej sesji. // graphical.targetpowie ci, kiedy menedżer wyświetlania jest gotowy, ale nie mówi nic o tym, kiedy DM faktycznie uruchamia pierwszy - lub wszystkie - wyświetla).

Samo uruchomienie przy rozruchu DISPLAY=:0nie wystarcza, ponieważ nie ma gwarancji, że w danym momencie jest dokładnie jeden ekran, ani że zawsze tak jest :0(na przykład, jeśli Xorg ulegnie awarii, pozostawiając nieaktualny plik blokujący, następny uruchomi się, :1gdy pomyślałby, że :0wciąż jest zajęty); musisz także ustawić ścieżkę do XAUTHORITYpliku, ponieważ X11 wymaga uwierzytelnienia; i upewnij się, że redshiftzostanie ponownie uruchomiony, jeśli kiedykolwiek się wylogujesz i zalogujesz ponownie.

Jak więc zacząć? Prawie zawsze środowisko pulpitu ma kilka metod uruchamiania własnych usług sesji . Zobacz starszy post, który już opisuje dwa zwykłe; ~/.xprofileskrypt i ~/.config/autostart/*.desktoplokalizacja.

Jeśli używasz startx , możesz użyć ~/.xinitrcdo uruchomienia takich rzeczy. Samodzielne menedżery okien często mają własne skrypty startowe / init; np. ~/.config/openbox/autostartdla Openbox.

Wspólne dla wszystkich tych metod jest to, że program jest uruchamiany z poziomu sesji - unikając wszystkich problemów wymienionych powyżej.

grawitacja
źródło
Chociaż redshift nie jest usługą ogólnosystemową, w wielu przypadkach sensowne jest bycie usługą użytkownika, która jest dokładnie tym, co OP chce zrobić.
simotek
5

Oto, co właśnie stworzyłem jako obejście niedostępnego graphical-session.target(w moim systemie Kubuntu 16.04):

  1. Utwórz pseudo systemową jednostkę użytkownika, która podnosi i obniża wartość elementu graficznego.

Utwórz ~/.config/systemd/user/xsession.targetz następującą zawartością:

[Jednostka]
Opis = Xsession działa i działa
BindsTo = graphical-session.target

Poinformuj systemd o tym nowym urządzeniu:

$> systemctl --user daemon-reload
  1. Twórz skrypty autostartu i zamykania, które kontrolują za xsession.targetpośrednictwem obecnie dostępnej mechaniki pulpitu Ubuntu 16.04.

Utwórz ~/.config/autostart-scripts/xsession.target-login.shz następującą zawartością:

#! / bin / bash

Jeśli ! systemctl --user is-active xsession.target &> / dev / null
następnie
  / bin / systemctl --user import-environment WYŚWIETL XAUTHORITY
  / bin / systemctl --user start xsession.target
fi

Utwórz ~/.config/plasma-workspace/shutdown/xsession.target-logout.shz następującą zawartością:

#! / bin / bash

jeśli systemctl --user jest aktywny xsession.target &> / dev / null
następnie
  / bin / systemctl --user stop xsession.target
fi

Spraw, by skrypty były wykonywalne:

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

Uwaga: te dwa pliki są umieszczane tam, gdzie KDE je pobierze w celu automatycznego uruchomienia i zamknięcia. Pliki mogą być umieszczone gdzie indziej dla innych środowisk pulpitu (np. Gnome) - ale nie wiem o tych środowiskach.

Uwaga: w tym obejściu brakuje obsługi wielu sesji pulpitu. Obsługuje tylko graphical-session.targetpoprawnie, o ile tylko jedna aktywna sesja X11 jest uruchomiona na komputerze (ale tak jest w przypadku większości użytkowników Linuksa).

  1. Twórz własne systemowe jednostki użytkownika, które zależą od graphical-session.targetnich, i dbaj o to, aby działały bez zakłóceń podczas logowania na komputerze.

Jako przykład jednostka @ mkaito powinna wyglądać następująco:

[Jednostka]
Opis = Redshift
PartOf = graphical-session.target

[Usługa]
ExecStart = / bin / redshift -l 28: -13 -t 5300: 3300 -b 0,80: 0,91 -m randr
Uruchom ponownie = zawsze

(Nie zapomnij zrobić daemon-reloadpo edycji jednostek!)

  1. Uruchom ponownie komputer, zaloguj się i sprawdź, czy Twoje jednostki są uruchomione zgodnie z oczekiwaniami
$> systemctl - status użytkownika graphic-session.target
● graphical-session.target - Bieżąca graficzna sesja użytkownika
   Załadowano: załadowano (/usr/lib/systemd/user/graphical-session.target; statyczny; preset dostawcy: włączony)
   Aktywny: aktywny od Don 2017-01-05 15:08:42 CET; 47min temu
     Dokumenty: man: systemd.special (7)
$> systemctl - status użytkownika twoja jednostka ...

W przyszłości (czy będzie to Ubuntu 17.04?) Moje obejście stanie się przestarzałe, ponieważ system graphical-session.targetsam sobie poradzi . Tego dnia po prostu usuń skrypt autostartu i zamykania, a także xsession.target- twoje niestandardowe jednostki użytkownika mogą pozostać nietknięte i po prostu działać.

gue
źródło
Wiem, że to stary komentarz, ale możesz także dodawać skrypty uruchamiania / logowania za pomocą aplikacji Ustawienia systemowe w obszarze roboczym> Uruchamianie i zamykanie> Autostart, jeśli chcesz umieścić te skrypty w miejscu, w którym je zapamiętasz.
AmbientCyan
2

To rozwiązanie robi dokładnie to, o co pyta autor pytania:

musi poczekać, aż Xorg uruchomi się

Chociaż mogą istnieć lepsze sposoby, jak już odpowiedzieli inni użytkownicy, jest to inne podejście do tego problemu.

Jest podobny do systemd- systemd-networkd-wait-online.service, który blokuje do spełnienia określonych kryteriów. Inne usługi, które od niego zależą, zostaną uruchomione, gdy tylko usługa uruchomi się pomyślnie lub upłynie limit czasu.

Zgodnie z instrukcją (sekcja „Pliki”) serwer X utworzy gniazdo UNIX /tmp/.X11-unix/Xn(gdzie njest wyświetlany numer).

Monitorując obecność tego gniazda, możemy ustalić, że serwer dla konkretnego wyświetlacza został uruchomiony.

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

Teraz włącz x_server_started.serviceuruchamianie w tym samym czasie z serwerem X.

Zależy od innych usług (które wymagają uruchomienia serwera X) x_server_started.service

jednostka zależna:

[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

Jeśli serwer X uruchomi się bez problemu, x_server_started.serviceuruchomi się prawie natychmiast, a systemd przystąpi do uruchomienia wszystkich jednostek zależnych x_server_started.service.

VL-80
źródło
To działa ładnie. Dodatkowa usługa to miły akcent. Możesz także po prostu użyć ExecStartPre w usłudze docelowej. Musiałem jednak dodać dodatkowe „uśpienie 1” przed „wyjściem 0”, wydaje się, że było trochę za szybko, aby po prostu spróbować złapać X od razu.
TTimo,