การเขียนบริการที่ขึ้นอยู่กับ 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=เป้าหมาย คำใบ้ใด ๆ

คำตอบ:


20

ฉันค้นคว้าสิ่งนี้แล้วและคำตอบของ grawity นั้นล้าสมัยแล้ว ตอนนี้คุณสามารถตั้งค่าบริการผู้ใช้ด้วย systemd ที่ทำงานด้วยเป็นส่วนหนึ่งของเซสชันของผู้ใช้ พวกเขาสามารถตั้งค่า DISPLAY และ XAUTHORITY (ปัจจุบันอยู่ใน Arch และ Debian Stretch)

สิ่งนี้มีเหตุผลมากกว่าคำแนะนำก่อนหน้านี้ของการใช้ไฟล์ autostart แบบเดสก์ท็อปเนื่องจากคุณได้รับการจัดการกระบวนการเหมือนกับแอพระดับระบบ (รีสตาร์ท ฯลฯ )

เอกสารที่ดีที่สุดตอนนี้คือ Arch wiki; Systemd / ผู้ใช้

รุ่น TLDR;

  1. สร้างไฟล์ * .service ที่ต้องการใน ~/.config/systemd/user/
  2. เรียกใช้systemctl --user enable [service](ไม่รวมส่วนต่อท้ายบริการ.)
  3. เลือกที่systemctl --user start [service]จะเริ่มทันที
  4. ใช้systemctl --user status [service]เพื่อตรวจสอบว่ามันทำงานอย่างไร

คำสั่งที่มีประโยชน์อื่น ๆ

  • systemctl --user list-unit-files - ดูหน่วยผู้ใช้ทั้งหมด
  • s ystemctl --user daemon-reload- หากคุณแก้ไขไฟล์. service

- ต่อมา ...

ฉันอัปเกรดและแปลง daemons เซสชันส่วนใหญ่เป็นไฟล์ systemd .service ดังนั้นฉันสามารถเพิ่มบันทึกเพิ่มเติมสองสามรายการ

ไม่มี hook เริ่มต้นให้เรียกใช้บริการเมื่อเข้าสู่ระบบดังนั้นคุณต้องเรียกใช้ด้วยตนเอง ฉันทำจากไฟล์ ~ / .xsession ของฉัน

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

บรรทัดแรกนำเข้าตัวแปรสภาพแวดล้อมบางอย่างในเซสชั่นผู้ใช้ systemd และที่สอง kicks ปิดเป้าหมาย ไฟล์ 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 ฉันใช้เดเบียนเสถียรและรอจนกว่าจะได้เล่นกับมันมากกว่านี้
John Eikenberry

@mkaito ที่github.com/systemd/systemd/blob/v219/NEWS#L194กล่าวว่า "สคริปต์เซสชัน X11 ได้ถูกส่งไปแล้วซึ่งอัปโหลด $ DISPLAY และ $ XAUTHORITY ลงในสภาพแวดล้อมของ systemd --user daemon หากมีการเริ่มต้นเซสชัน สิ่งนี้ควรปรับปรุงความเข้ากันได้กับแอปพลิเคชันที่เปิดใช้งาน X11 ซึ่งทำงานในฐานะผู้ใช้บริการ systemd
josch

ฉันยังต้องการดูไฟล์ตัวอย่างเพียงเพื่อให้ชัดเจนหากมีสิ่งใดที่ต้องการเป็นพิเศษ
mkaito

11

คำใบ้ปกติคือ "ไม่" redshiftไม่ใช่บริการทั่วทั้งระบบ - มันจะมีอินสแตนซ์แยกต่างหากสำหรับแต่ละเซสชันและจำเป็นต้องรู้เกี่ยวกับวิธีเชื่อมต่อกับ Xorg ของเซสชันนั้น ๆ

(Xorg ไม่ใช่บริการระบบเช่นเดียวกับdisplay managerเท่านั้นและจะเปิดตัว Xorg แยกต่างหากสำหรับแต่ละเซสชัน // graphical.targetจะบอกคุณเมื่อตัวจัดการการแสดงผลพร้อมใช้งาน ครั้งแรก - หรือ - ทั้งหมด - แสดง)

เพียงแค่เริ่มต้นด้วยการบูทด้วยDISPLAY=:0ก็ไม่เพียงพอเพราะไม่มีการรับประกันว่าจะมีหนึ่งจอแสดงผลในเวลาที่กำหนดหรือไม่ว่าจะเป็นเสมอ:0(ตัวอย่างเช่นหาก Xorg ล่มออกจากไฟล์ล็อคเก่าค้างอีกอันหนึ่งจะทำงาน:1ทันที จะคิดว่า:0ยังคงครอบครองอยู่); คุณต้องตั้งค่าพา ธ ไปยังXAUTHORITYไฟล์ของคุณเนื่องจาก X11 ต้องการการรับรองความถูกต้อง และตรวจสอบให้แน่ใจว่าredshiftได้รับการเริ่มต้นใหม่ถ้าคุณเคยออกจากระบบ & เข้าสู่ระบบอีกครั้ง

ดังนั้นจะเริ่มอย่างไร เกือบตลอดเวลาสภาพแวดล้อมเดสก์ท็อปมีหลายวิธีในการเริ่มบริการเซสชันของตนเอง ดูโพสต์เก่าซึ่งอธิบายสองปกติแล้ว; ~/.xprofileสคริปต์และ~/.config/autostart/*.desktopสถานที่ตั้ง

หากคุณใช้startxคุณสามารถใช้~/.xinitrcเพื่อเริ่มสิ่งต่าง ๆ ตัวจัดการหน้าต่างแบบสแตนด์อโลนมักจะมีสคริปต์เริ่มต้น / เริ่มต้นของตนเอง เช่น~/.config/openbox/autostartOpenbox

สิ่งที่พบได้ทั่วไปในวิธีการทั้งหมดนี้คือโปรแกรมเริ่มจากภายในเซสชัน - หลีกเลี่ยงปัญหาทั้งหมดที่กล่าวข้างต้น


ในขณะที่ redshift ไม่ใช่บริการทั่วทั้งระบบในหลาย ๆ กรณีมันสมเหตุสมผลที่จะเป็นบริการผู้ใช้ซึ่งเป็นสิ่งที่ OP พยายามทำ
simotek

5

นี่คือสิ่งที่ฉันเพิ่งสร้างขึ้นเป็นวิธีแก้ปัญหาสำหรับยังไม่พร้อมใช้งานgraphical-session.target(บนระบบ Kubuntu 16.04 ของฉัน):

  1. สร้างหน่วยผู้ใช้หลอก systemdซึ่งทำให้กราฟิก -session.target ขึ้นและลง

สร้าง~/.config/systemd/user/xsession.targetด้วยเนื้อหาดังต่อไปนี้:

[Unit]
คำอธิบาย = Xsession ขึ้นและทำงาน
BindsTo = graphical-session.target

บอก systemd เกี่ยวกับยูนิตใหม่นี้:

$> systemctl --user daemon-reload
  1. สร้างautostart และสคริปต์ shutdownซึ่งควบคุมxsession.targetผ่านกลไกที่มีอยู่ในปัจจุบันของ Ubuntu 16.04 desktop

สร้าง~/.config/autostart-scripts/xsession.target-login.shด้วยเนื้อหาดังต่อไปนี้:

#! / bin / ทุบตี

ถ้า! systemctl --user is-active xsession.target &> / dev / null
แล้วก็
  / bin / systemctl - ผู้ใช้นำเข้าสภาพแวดล้อม DISPLAY XAUTHORITY
  / bin / systemctl --user เริ่ม xsession.target
Fi

สร้าง~/.config/plasma-workspace/shutdown/xsession.target-logout.shด้วยเนื้อหาดังต่อไปนี้:

#! / bin / ทุบตี

ถ้า systemctl --user is-active xsession.target &> / dev / null
แล้วก็
  / bin / systemctl - ผู้ใช้หยุด xsession.target
Fi

ทำให้สคริปต์เรียกทำงานได้:

$> chmod + x ~ / .config / autostart-สคริปต์ / xsession.target-login.sh
$> chmod + x ~ / .config / plasma-workspace / ปิดระบบ / xsession.target-logout.sh

หมายเหตุ:ไฟล์ทั้งสองนี้จะถูกวางไว้ที่ KDE จะไปรับพวกเขาเพื่อเริ่มอัตโนมัติและปิด ไฟล์อาจถูกวางไว้ที่อื่นสำหรับสภาพแวดล้อมเดสก์ทอปอื่น ๆ (เช่น Gnome) - แต่ฉันไม่รู้เกี่ยวกับสภาพแวดล้อมเหล่านั้น

หมายเหตุ:วิธีแก้ปัญหานี้ขาดการสนับสนุนเซสชันหลายเดสก์ท็อป มันจัดการgraphical-session.targetได้อย่างถูกต้องตราบเท่าที่มีการใช้งานเซสชัน X11 เพียงครั้งเดียวเท่านั้นที่ทำงานบนเครื่อง (แต่นั่นเป็นกรณีสำหรับผู้ใช้ linux ส่วนใหญ่ของเรา)

  1. สร้างหน่วยผู้ใช้ systemd ของคุณเองซึ่งขึ้นอยู่กับgraphical-session.targetและให้มันทำงานได้อย่างสมบูรณ์ในขณะที่ล็อกอินบนเดสก์ท็อปของคุณ

ดังตัวอย่างของหน่วย @ mkaito ควรมีลักษณะเช่นนี้:

[Unit]
คำอธิบาย = Redshift
partof = graphical-session.target

[บริการ]
ExecStart = / bin / redshift -l 28: -13 -t 5300: 3300 -b 0.80: 0.91 -m randr
เริ่มต้นใหม่ = เสมอ

(อย่าลืมทำการdaemon-reloadแก้ไขหลังจากหน่วยของคุณ!)

  1. รีบูตเครื่องของคุณเข้าสู่ระบบและยืนยันหน่วยของคุณจะเริ่มตามที่คาดไว้
$> systemctl --user status graphics-session.target
● graphics-session.target - เซสชันผู้ใช้แบบกราฟิกปัจจุบัน
   โหลดแล้ว: โหลดแล้ว (/usr/lib/systemd/user/graphical-session.target; static; preset ของผู้ขาย: เปิดใช้งาน)
   ใช้งานอยู่: เปิดใช้งานตั้งแต่ดอน 2017-01-05 15:08:42 CET; 47 นาทีที่แล้ว
     Docs: man: systemd.special (7)
$> systemctl - ผู้ใช้ระบุสถานะหน่วยของคุณ ...

ในอนาคตบางวัน (จะเป็น Ubuntu 17.04?) วิธีแก้ปัญหาของฉันล้าสมัยเนื่องจากระบบจะจัดการgraphical-session.targetอย่างถูกต้องเอง ในวันนั้นเพียงแค่ลบ autostart และ shutdown script และxsession.target- ผู้ใช้ที่กำหนดเองของคุณอาจไม่ถูกแตะต้องและใช้งานได้


ฉันรู้ว่านี่เป็นความคิดเห็นเก่า แต่คุณสามารถเพิ่มสคริปต์เริ่มต้น / เข้าสู่ระบบผ่านทางแอปการตั้งค่าระบบภายใต้พื้นที่ทำงาน> เริ่มต้นและปิด> เริ่มอัตโนมัติถ้าคุณต้องการใส่สคริปต์เหล่านั้นในสถานที่ที่คุณจะจำได้
AmbientCyan

2

วิธีการแก้ปัญหานี้ทำในสิ่งที่ผู้เขียนคำถามถาม:

มันต้องรอจนกว่า Xorg เปิดใช้งาน

ในขณะที่อาจมีวิธีที่ดีกว่าในการทำตามที่ผู้ใช้รายอื่นตอบแล้วนี่เป็นอีกวิธีหนึ่งในการแก้ไขปัญหานี้

มันคล้ายกับ systemd ของsystemd-networkd-wait-online.serviceซึ่งบล็อกจนกว่าจะถึงเกณฑ์ที่แน่นอน บริการอื่น ๆ ซึ่งขึ้นอยู่กับบริการจะเปิดตัวทันทีที่บริการนี้เริ่มต้นสำเร็จหรือหมดเวลา

ตามคู่มือ (ส่วน "ไฟล์") เซิร์ฟเวอร์ 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 server ในการเริ่มต้น) เพื่อพึ่งพา 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_server_started.serviceจะเริ่มต้นเกือบจะในทันทีและ systemd x_server_started.serviceจะดำเนินการเริ่มต้นทุกหน่วยงานที่ขึ้นอยู่กับ


มันใช้งานได้ดี บริการเสริมเป็นสัมผัสที่ดี คุณยังสามารถใช้ ExecStartPre ในบริการเป้าหมายของคุณ ฉันต้องเพิ่ม 'sleep 1' ก่อนหน้า 'exit 0' แต่ดูเหมือนว่ามันเร็วเกินไปที่จะลองและจับ X ได้ทันที
TTimo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.