Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Linux でデバイスを接続している時だけ動くサービスを作る

Linux でデバイスを接続している時だけ動くサービスを作る

systemd と udev を使うと、とあるデバイスを接続すると動き始め、切断すると停止するようなサービスを作る事が出来る。

サンプルのサービスは何でも良いが 前に作った /usr/bin/timeserver.py を使う。

#!/usr/bin/env python
# Time server program

import socket
import datetime
import sys

HOST = ''                 # Symbolic name meaning all available interfaces
PORT = 50007              # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)

while True:
    conn, addr = s.accept()
    now = datetime.datetime.now().isoformat()
    print('Connected by %s at %s\n' % (addr, now))
    conn.sendall(now.encode())
    conn.close()

まず、サービスの動作に必要な動作を整理する。USB 機器としては、たまたま手元にあった USB BT ドングル (BT アダプタ) を使う。

  1. 標準で起動する (WantedBy で multi-user.true -> timeserver への依存を作る)
  2. BT アダプタが有効になるまで待つ。(systemd の After を使う)
  3. BT アダプタが無効になれば停止する。(systemd の BindsTo を使う)
  4. BT アダプタが再び有効になれば再起動する。(WantedBy で デバイス -> timeserver への依存を作る)

Systemd の世界では、「BT アダプタが存在する」事を示す unit がある。このようにデバイスに依存する unit を device と呼ぶ。systemctl list-units -t device で定義済のリストを見る事が出来る。

# systemctl list-units -t device
UNIT                                                                                                       LOAD   ACTIVE SUB     DESCRIPTION
...
sys-devices-pci0000:00-0000:00:11.0-0000:02:00.0-usb2-2\x2d2-2\x2d2.1-2\x2d2.1:1.0-bluetooth-hci0.device   loaded active plugged /sys/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.1/2-2.1:1.0/bluetooth/hci0
...
sys-subsystem-bluetooth-devices-hci0.device                                                                loaded active plugged /sys/subsystem/bluetooth/devices/hci0
...

BT アダプタを表す hci0 device は /lib/udev/rules/99-systemd.rules で定義されている。

SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k"

これは、もしも SUBSYSTEM=="bluetooth" にマッチするイベントが来たら TAG+="systemd" によって systemd device unit を作成し、ついでに ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k" によってエイリアスを作成するという意味だ。%k は hci0 に置換されるので、unit 名としては sys-subsystem-bluetooth-devices-hci0.device が出来上がる。
自分の監視したいデバイス用の unit が既存の udev ルールにお定義されていなければ自分でも定義出来る。

この unit を BindsTo, After, WantedBy に指定して /etc/systemd/system/timeserver.service を書けば良い。

[Unit]
Description=Some Time server
After=network.target

# 2. Stop the service when the BT is disconnected
BindsTo=sys-subsystem-bluetooth-devices-hci0.device

# 3. Wait until BT is connected
After=sys-subsystem-bluetooth-devices-hci0.device

[Service]
ExecStart=/usr/bin/python -u /usr/bin/timeserver.py
Restart=always
StandardOutput=journal
StandardError=journal

[Install]
# 1. Start by default
WantedBy=multi-user.target

# 4. Start when BT is connected
WantedBy=sys-subsystem-bluetooth-devices-hci0.device

[Install] セクションに書いた定義は systemctl enable を行うとはじめて有効になる。

# systemctl daemon-reload 
# systemctl enable timeserver
Created symlink /etc/systemd/system/multi-user.target.wants/timeserver.service → /etc/systemd/system/timeserver.service.
Created symlink /etc/systemd/system/sys-subsystem-bluetooth-devices-hci0.device.wants/timeserver.service → /etc/systemd/system/timeserver.service.

設定ファイルが書けたら start してみる。BT アダプタが無い場合は BT アダプタを接続するまで処理が止まる。その後 BT アダプタと連動して timeserver が再生停止を行う。

# systemctl start timeserver
... BT アダプタを挿すまで停止
# journalctl -f -u timeserver # timeserver の状態を観察
Oct 26 03:28:36 qemux86-64 systemd[1]: Started Some Time server.
Oct 26 03:28:49 qemux86-64 systemd[1]: Stopping Some Time server...
Oct 26 03:28:49 qemux86-64 systemd[1]: Stopped Some Time server.

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
10
Help us understand the problem. What are the problem?