Menulis layanan yang bergantung pada Xorg

30

Saya mencoba menulis layanan tingkat pengguna redshift, dan perlu menunggu sampai Xorg aktif dan berjalan. File layanan saya saat ini terlihat seperti ini:

[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

Namun, tampaknya itu mencoba untuk memulai sebelum Xorg naik, dan saya harus memulai layanan secara manual setelah itu. Saya kira saya menggunakan After=target yang salah . Ada petunjuk?

mkaito
sumber

Jawaban:

20

Saya sudah meneliti ini dan jawaban grawity sepertinya ketinggalan zaman. Anda sekarang dapat mengatur layanan pengguna dengan systemd yang dijalankan dengan sebagai bagian dari sesi pengguna. Mereka dapat mengatur DISPLAY dan XAUTHORITY (saat ini dalam Arch dan Debian Stretch).

Ini masuk akal dibandingkan rekomendasi sebelumnya untuk menggunakan file autostart desktop, karena Anda mendapatkan manajemen proses seperti halnya Anda menggunakan aplikasi tingkat sistem (restart, dll).

Dokumen terbaik saat ini adalah Arch wiki; Systemd / Pengguna

Versi TLDR;

  1. Buat file * .service yang diinginkan di ~/.config/systemd/user/
  2. Jalankan systemctl --user enable [service](kecualikan sufiks .service)
  3. Secara opsional jalankan systemctl --user start [service]untuk memulai sekarang
  4. Gunakan systemctl --user status [service]untuk memeriksa bagaimana kinerjanya

Beberapa perintah lain yang bermanfaat.

  • systemctl --user list-unit-files - lihat semua unit pengguna
  • s ystemctl --user daemon-reload- jika Anda mengedit file layanan

- Nanti ...

Saya memutakhirkan dan mengonversikan sebagian besar daemon sesi saya ke file serviced systemd. Jadi saya bisa menambahkan beberapa catatan tambahan.

Tidak ada kait default untuk menjalankan layanan saat login, jadi Anda harus memicunya sendiri. Saya melakukannya dari file ~ / .xsession saya.

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

Baris pertama mengimpor beberapa variabel lingkungan ke dalam sesi pengguna systemd dan yang kedua memulai target. File xsession.target saya;

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

Xbindkeys.service saya sebagai contoh.

[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
sumber
2
Jika Anda dapat memberikan contoh file unit, dan menjelaskan bagaimana agar unit dapat menggunakan DISPLAY dan XAUTHORITY, saya akan dengan senang hati mengganti jawaban yang diterima.
mkaito
@mkaito saya akan melihat bahwa setelah Debian merilis Stretch. Saya menjalankan stabil Debian dan menunggu sampai saat itu untuk bermain lebih banyak.
John Eikenberry
@mkaito Di github.com/systemd/systemd/blob/v219/NEWS#L194 tertulis " Skrip sesi X11 sekarang dikirimkan yang mengunggah $ DISPLAY dan $ XAUTHORITY ke dalam lingkungan systemd - daemon pengguna jika suatu sesi dimulai. Ini harus meningkatkan kompatibilitas dengan aplikasi yang diaktifkan X11 berjalan sebagai layanan pengguna systemd. "
josch
Saya masih ingin melihat contoh file unit, hanya untuk memperjelas jika ada sesuatu yang diperlukan khusus.
mkaito
11

Petunjuk yang biasa adalah "jangan". redshiftbukan layanan seluruh sistem - itu akan memiliki contoh terpisah untuk setiap sesi , dan perlu tahu tentang bagaimana menghubungkan ke Xorg sesi tertentu itu.

(Xorg juga bukan layanan sistem - hanya pengelola layar , dan juga meluncurkan Xorg terpisah untuk setiap sesi. // graphical.targetakan memberi tahu Anda ketika pengelola layar siap, tetapi tidak mengatakan kapan DM memulai sebenarnya. pertama - atau semua - tampilan.)

Memulai dengan boot saja DISPLAY=:0tidak cukup, karena tidak ada jaminan bahwa hanya ada satu tampilan pada waktu tertentu, juga tidak selalu :0(misalnya, jika Xorg crash meninggalkan lockfile basi, yang berikutnya akan berjalan :1seperti itu akan berpikir :0masih sibuk); Anda juga perlu mengatur path ke XAUTHORITYfile Anda karena X11 memerlukan otentikasi; dan pastikan redshiftakan dimulai kembali jika Anda pernah keluar & masuk lagi.

Jadi bagaimana memulainya? Hampir selalu, lingkungan desktop memiliki beberapa metode untuk memulai layanan sesi sendiri . Lihat posting lama yang sudah menggambarkan dua yang biasa; yang ~/.xprofilescript dan ~/.config/autostart/*.desktoplokasi.

Jika Anda menggunakan startx , Anda dapat menggunakannya ~/.xinitrcuntuk memulai hal-hal seperti itu. Manajer jendela mandiri seringkali memiliki skrip startup / init sendiri; misalnya ~/.config/openbox/autostartuntuk Openbox.

Apa yang umum untuk semua metode ini adalah bahwa program dimulai dari dalam sesi - menghindari semua masalah yang tercantum di atas.

grawity
sumber
Sementara redshift bukan layanan seluruh sistem dalam banyak kasus, masuk akal untuk menjadi layanan pengguna yang persis apa yang coba OP lakukan.
simotek
5

Inilah yang baru saja saya buat sebagai solusi untuk yang belum tersedia graphical-session.target(Pada sistem Kubuntu 16.04 saya):

  1. Buat pseudo systemd unit pengguna yang membawa graphical-session.target naik dan turun.

Buat ~/.config/systemd/user/xsession.targetdengan konten berikut:

[Satuan]
Keterangan = Xsession aktif dan berjalan
BindsTo = graphical-session.target

Beri tahu systemd tentang unit baru ini:

$> systemctl --user daemon-reload
  1. Buat skrip autostart dan shutdown yang mengontrol xsession.targetvia mekanisme desktop Ubuntu 16.04 yang saat ini tersedia.

Buat ~/.config/autostart-scripts/xsession.target-login.shdengan konten berikut:

#! / bin / bash

jika! systemctl --user is-active xsession.target &> / dev / null
kemudian
  / bin / systemctl --user import-environment DISPLAY XAUTHORITY
  / bin / systemctl --user mulai xsession.target
fi

Buat ~/.config/plasma-workspace/shutdown/xsession.target-logout.shdengan konten berikut:

#! / bin / bash

jika systemctl --user adalah xsession.target aktif &> / dev / null
kemudian
  / bin / systemctl --user stop xsession.target
fi

Jadikan skrip dapat dieksekusi:

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

Catatan: dua file ini ditempatkan di mana KDE akan mengambilnya untuk mulai otomatis dan mematikan. File mungkin ditempatkan di tempat lain untuk lingkungan desktop lain (misalnya Gnome) - tapi saya tidak tahu tentang lingkungan itu.

Catatan: Solusi ini kurang mendukung sesi multi desktop. Ini hanya menangani dengan graphical-session.targetbenar selama hanya satu sesi X11 aktif dijalankan pada mesin (tapi itu kasus bagi kebanyakan dari kita pengguna linux).

  1. Buat unit pengguna systemd Anda sendiri yang bergantung pada graphical-session.targetdan menjalankannya dengan bersih saat sedang login di desktop Anda.

Sebagai contoh, unit @ mkaito akan terlihat seperti ini:

[Satuan]
Deskripsi = Pergeseran Merah
PartOf = graphical-session.target

[Layanan]
ExecStart = / bin / redshift -l 28: -13 -t 5300: 3300 -b 0,80: 0,91 -m randr
Mulai ulang = selalu

(Jangan lupa lakukan daemon-reloadsetelah mengedit unit Anda!)

  1. Nyalakan ulang mesin Anda, masuk dan verifikasi unit Anda dimulai seperti yang diharapkan
$> systemctl - status pengguna graphical-session.target
● graphical-session.target - Sesi pengguna grafis saat ini
   Dimuat: dimuat (/usr/lib/systemd/user/graphical-session.target; statis; preset vendor: diaktifkan)
   Aktif: aktif sejak Don 2017-01-05 15:08:42 CET; 47 menit yang lalu
     Documents: man: systemd.special (7)
$> systemctl - status pengguna unit Anda ...

Di masa mendatang (apakah itu Ubuntu 17.04?) Solusi saya menjadi usang karena sistem akan menangani dengan graphical-session.targetbenar. Pada hari itu cukup hapus script autostart dan shutdown dan juga xsession.target- unit pengguna khusus Anda mungkin tetap tidak tersentuh dan hanya berfungsi.

gue
sumber
Saya tahu ini adalah komentar lama tetapi Anda juga dapat menambahkan skrip startup / login melalui aplikasi Pengaturan sistem di bawah Workspace> Startup and Shutdown> Autostart, jika Anda ingin meletakkan skrip-skrip tersebut di tempat Anda akan mengingatnya.
AmbientCyan
2

Solusi ini tepat seperti yang ditanyakan oleh penulis pertanyaan:

perlu menunggu sampai Xorg aktif dan berjalan

Meskipun mungkin ada cara yang lebih baik untuk melakukannya, seperti yang sudah dijawab oleh pengguna lain, ini adalah pendekatan lain untuk masalah ini.

Ini mirip dengan systemd -networkd-wait-online.service systemd yang memblokir sampai kriteria tertentu dipenuhi. Layanan lain yang bergantung padanya akan diluncurkan segera setelah layanan ini mulai berhasil atau habis.

Per manual (bagian "File"), X server akan membuat soket UNIX /tmp/.X11-unix/Xn(di mana nadalah nomor tampilan).

Dengan memantau keberadaan soket ini, kami dapat menentukan bahwa server untuk tampilan tertentu telah dimulai.

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

Sekarang, aktifkan x_server_started.serviceuntuk memulai pada saat yang sama dengan server X.

Buat layanan lain (yang memerlukan X server untuk memulai) untuk bergantung x_server_started.service

unit tergantung:

[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

Jika X server mulai tanpa masalah, sistem x_server_started.serviceakan segera dimulai dan systemd akan melanjutkan untuk memulai semua unit yang bergantung x_server_started.service.

VL-80
sumber
Ini bekerja dengan baik. Layanan ekstra adalah sentuhan yang bagus. Anda juga dapat menggunakan ExecStartPre di layanan target Anda. Saya harus menambahkan 'sleep 1' tambahan sebelum 'exit 0', agaknya terlalu cepat untuk mencoba dan menangkap X segera.
TTimo