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

Log in to Qiita Team
OrganizationEventAdvent CalendarQiitadon (β)
Qiita JobsQiita ZineQiita Blog
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))

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

まず、サービスの動作に必要な動作を整理する。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 を書けば良い。

Description=Some Time server

# 2. Stop the service when the BT is disconnected

# 3. Wait until BT is connected

ExecStart=/usr/bin/python -u /usr/bin/timeserver.py

# 1. Start by default

# 4. Start when BT is connected

[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
Help us understand the problem. What are the problem?