Возможно ли в systemd/udev реализовать так, чтобы при появлении в системе модема
(/dev/ttyACM%i) запускался демон modem@%i.service, и чтобы при отключении модема демон
останавливался?
Готовый полный универсальный рабочий рецепт.
/etc/ppp/peers/modem
460800
defaultroute
usepeerdns
crtscts
lock
noauth
local
persist
modem
nopcomp
novjccomp
nobsdcomp
nodeflate
noaccomp
ipcp-accept-local
ipcp-accept-remote
noipdefault
connect "/usr/sbin/chat -t10 -f /etc/ppp/chatscripts/modem.chat"
/etc/ppp/chatscripts/modem.chat
В поле точки доступа "internet.mts.ru" или подставьте точку доступа своего провайдера
или оставьте такой, если у вас российский МТС. Большинство провайдеров игнорируют это
поле, и его вообще можно не указывать, но МТС её требует и без неё не соединяет.
ABORT 'BUSY'
ABORT 'NO CARRIER'
ABORT 'VOICE'
ABORT 'NO DIALTONE'
ABORT 'NO DIAL TONE'
ABORT 'NO ANSWER'
ABORT 'DELAYED'
REPORT CONNECT
TIMEOUT 5
'' 'ATQ0'
'OK-AT-OK' 'ATZ'
TIMEOUT 3
'OK-AT-OK' 'ATI'
'OK' 'ATZ'
'OK' 'ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0'
'OK' 'AT\^SYSCFG=2,2,3fffffff,0,1'
'OK-AT-OK' 'AT+CGDCONT=1,"IP","internet.mts.ru"'
'OK' 'ATDT*99#'
CONNECT
/usr/lib/systemd/system/modem@.service
[Unit]
Description=Modem /dev/ttyACM%i
BindsTo=dev-ttyACM%i.device
After=dev-ttyACM%i.device
Before=network.target
Wants=network.target
[Service]
ExecStart=/usr/sbin/pppd call modem /dev/ttyACM%i
[Install]
WantedBy=multi-user.target
/etc/udev/rules.d/90-modem.rules
KERNEL=="ttyACM[0-9]*", TAG+="systemd", ENV{SYSTEMD_WANTS}="modem@%n.service"
Затем перезагрузить конфигурацию systemd.
sudo systemctl daemon-reload
И теперь достаточно просто подключить любой телефон, кроме огрызка, с любым оператором
в режим не накопителя. (Nokia suite, Телефон, Модем, Синхронизация и т.д.)
Ну, конечно же, желательно убедиться, что у вас определяется модем и его файл устройства,
как у меня, /dev/ttyACM0 и udev на него ссылается как dev-ttyACM0.device, а не /dev/ttyUSB0
и dev-ttyUSB0.device или как-то иначе.
Цифру, обозначающую порядковый номер устройства (0) в демоне systemd заменяем на
%i, а в правилах udev на %n. Это даёт возможность не привязывать демон и правила только
к одному модему, а работать с неограниченным количеством модемов и корректно управлять
каждым модемом отдельно друг от друга.
systemctl list-units -tdevice -a | grep dev-tty
Телефон теперь всегда подключается к интернету при подключении к компьютеру, даже
если компьютер успешно подключён через ethernet или Wi-Fi к интернету. Правда, в этом
случае, когда в системе поднят (ifup) хоть 1 интерфейс, трафик идёт через него, а с
модемом лишь устанавливает соединение, но передачи данных не происходит.
Чтобы отключить автодозвон при подключении модема нужно просто замаскировать демон
sudo systemctl mask modem@0.service, а потом, когда понадобится модем размаскировать
sudo systemctl unmask modem@0.service
0 - это порядковый номер модема, если у вас их несколько, то можно отключить ненужные
или отключить все.
И самое не приятное, если ethernet и/или Wi-Fi подняты (ifup), то трафик не будет
идти через модем, пока все интерфейсы не будут опущены (ifdown) даже если к ним не
подключен кабель или нет выхода в интернет. Но это уже особенность модемной маршрутизации.
Ответы
Ответ 1
Правильнее будет, чтобы udev запускал/останавливал systemd.service — это его работа.
my.service
[Unit]
Description=Modem ppp0 <--> /dev/ttyACM0
BindsTo=dev-ttyACM0.device
After=dev-ttyACM0.device
Before=network.target
Wants=network.target
[Service]
ExecStart=/usr/sbin/pppd call modem
ExecStop=комманда на стоп
KillMode=none
Type=oneshot
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Список всех устройств, но со своим ты уже разобрался:
systemctl list-units --all --full | grep ".device"
90-my.rules в папку /etc/udev/rules.d/
KERNEL=="ttyACM*", ATTRS{serial}=="<СЕРИЙНИК>", TAG+="systemd", ENV{SYSTEMD_WANTS}="my.service"
Можно добавить SYMLINK=="gsmmodem", тогда появится симлинк /dev/gsmmodem.
А ATTR{serial} или подобные нужны, чтобы не спутать разные устройства.
Получить серийник и прочие аттрибуты: udevadm info -a -n /dev/ttyACM*
UPD
Можно сделать так, чтобы из KERNEL=="ttyACM*" передавался номер устройства (цифра
под звёздочкой) в сервис, которая бы потом дополняла бы строку запуска? 2.a Или будет
всё же проще и лучше написать 2 демона (modem0.service и modem1.service) для ACM0 и ACM1?
Для этого тебе нужен не просто сервис, а шаблонный сервис. Для этого переименуй my.service
в my@.service и запускать их мы будем как my@ttyACM0.service и my@ttyACM1.service,
тогда внутри файла тебе будут доступны такие переменные как %i %I (которые и будут
именем сервиса, тот что после @). Меняешь все упоминания ttyACMX на %I и наслаждаешься =)
Внутри udev доступны операторы %k and %n, это имя и номер соответственно (ты просил
именно %k). Соответственно, исправляешь ENV{SYSTEMD_WANTS}="my@%k.service" и будет
стартовать сервис my@ttyACM0.service.
По поводу отключения. Тут сложнее, потому что когда устройство отключается, то его
параметры становятся недоступны и уже сложно понять что же было отключено, можешь запустить
udevadm monitor --environment --udev и выдернуть устройство, должен увидеть что-то типа
#######REMOVE#######
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
UDEV [21800.789239] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/input/input75/mouse1
(input)
ACTION=remove
DEVLINKS=/dev/input/by-id/usb-Logitech_USB_Receiver-mouse /dev/input/by-path/pci-0000:00:1d.0-usb-0:1.3:1.0-mouse
DEVNAME=/dev/input/mouse1
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/input/input75/mouse1
ID_BUS=usb
ID_INPUT=1
ID_INPUT_MOUSE=1
ID_MODEL=USB_Receiver
ID_MODEL_ENC=USB\x20Receiver
ID_MODEL_ID=c51a
ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0
ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0
ID_REVISION=4100
ID_SERIAL=Logitech_USB_Receiver
ID_TYPE=hid
ID_USB_DRIVER=usbhid
ID_USB_INTERFACES=:030102:030000:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=Logitech
ID_VENDOR_ENC=Logitech
ID_VENDOR_ID=046d
MAJOR=13
MINOR=33
SEQNUM=3178
SUBSYSTEM=input
UDEV_LOG=3
USEC_INITIALIZED=21797014959
UDEV [21800.792866] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/input/input75/event6
(input)
ACTION=remove
DEVLINKS=/dev/input/by-id/usb-Logitech_USB_Receiver-event-mouse /dev/input/by-path/pci-0000:00:1d.0-usb-0:1.3:1.0-event-mouse
DEVNAME=/dev/input/event6
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/input/input75/event6
ID_BUS=usb
ID_INPUT=1
ID_INPUT_MOUSE=1
ID_MODEL=USB_Receiver
ID_MODEL_ENC=USB\x20Receiver
ID_MODEL_ID=c51a
ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0
ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0
ID_REVISION=4100
ID_SERIAL=Logitech_USB_Receiver
ID_TYPE=hid
ID_USB_DRIVER=usbhid
ID_USB_INTERFACES=:030102:030000:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=Logitech
ID_VENDOR_ENC=Logitech
ID_VENDOR_ID=046d
MAJOR=13
MINOR=70
SEQNUM=3179
SUBSYSTEM=input
UDEV_LOG=3
USEC_INITIALIZED=21797013896
UDEV [21800.797061] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/input/input75
(input)
ACTION=remove
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/input/input75
EV=17
ID_BUS=usb
ID_INPUT=1
ID_INPUT_MOUSE=1
ID_MODEL=USB_Receiver
ID_MODEL_ENC=USB\x20Receiver
ID_MODEL_ID=c51a
ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0
ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0
ID_REVISION=4100
ID_SERIAL=Logitech_USB_Receiver
ID_TYPE=hid
ID_USB_DRIVER=usbhid
ID_USB_INTERFACES=:030102:030000:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=Logitech
ID_VENDOR_ENC=Logitech
ID_VENDOR_ID=046d
KEY=ffff0000 0 0 0 0 0 0 0 0
MODALIAS=input:b0003v046DpC51Ae0111-e0,1,2,4,k110,111,112,113,114,115,116,117,118,119,11A,11B,11C,11D,11E,11F,r0,1,6,8,am4,lsfw
MSC=10
NAME="Logitech USB Receiver"
PHYS="usb-0000:00:1d.0-1.3/input0"
PRODUCT=3/46d/c51a/111
PROP=0
REL=143
SEQNUM=3180
SUBSYSTEM=input
UDEV_LOG=3
UNIQ=""
USEC_INITIALIZED=21796479085
UDEV [21800.797132] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/0003:046D:C51A.004D/hidraw/hidraw2
(hidraw)
ACTION=remove
DEVNAME=/dev/hidraw2
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/0003:046D:C51A.004D/hidraw/hidraw2
MAJOR=251
MINOR=2
SEQNUM=3181
SUBSYSTEM=hidraw
UDEV_LOG=3
USEC_INITIALIZED=21800796369
UDEV [21800.797172] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/0003:046D:C51A.004D
(hid)
ACTION=remove
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/0003:046D:C51A.004D
HID_ID=0003:0000046D:0000C51A
HID_NAME=Logitech USB Receiver
HID_PHYS=usb-0000:00:1d.0-1.3/input0
MODALIAS=hid:b0003g0001v0000046Dp0000C51A
SEQNUM=3182
SUBSYSTEM=hid
UDEV_LOG=3
USEC_INITIALIZED=21800796501
UDEV [21800.798537] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0
(usb)
ACTION=remove
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0
DEVTYPE=usb_interface
INTERFACE=3/1/2
MODALIAS=usb:v046DpC51Ad4100dc00dsc00dp00ic03isc01ip02in00
PRODUCT=46d/c51a/4100
SEQNUM=3183
SUBSYSTEM=usb
TYPE=0/0/0
UDEV_LOG=3
USEC_INITIALIZED=21800796538
UDEV [21800.814181] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/input/input76/event7
(input)
ACTION=remove
DEVLINKS=/dev/input/by-id/usb-Logitech_USB_Receiver-event-if01 /dev/input/by-path/pci-0000:00:1d.0-usb-0:1.3:1.1-event
DEVNAME=/dev/input/event7
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/input/input76/event7
ID_BUS=usb
ID_INPUT=1
ID_INPUT_KEY=1
ID_MODEL=USB_Receiver
ID_MODEL_ENC=USB\x20Receiver
ID_MODEL_ID=c51a
ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.1
ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_1
ID_REVISION=4100
ID_SERIAL=Logitech_USB_Receiver
ID_TYPE=hid
ID_USB_DRIVER=usbhid
ID_USB_INTERFACES=:030102:030000:
ID_USB_INTERFACE_NUM=01
ID_VENDOR=Logitech
ID_VENDOR_ENC=Logitech
ID_VENDOR_ID=046d
MAJOR=13
MINOR=71
SEQNUM=3184
SUBSYSTEM=input
UDEV_LOG=3
USEC_INITIALIZED=21797013933
XKBLAYOUT=de
XKBMODEL=pc105
UDEV [21800.816765] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/input/input76
(input)
ABS=1 0
ACTION=remove
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/input/input76
EV=1f
ID_BUS=usb
ID_INPUT=1
ID_INPUT_KEY=1
ID_MODEL=USB_Receiver
ID_MODEL_ENC=USB\x20Receiver
ID_MODEL_ID=c51a
ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.1
ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_1
ID_REVISION=4100
ID_SERIAL=Logitech_USB_Receiver
ID_TYPE=hid
ID_USB_DRIVER=usbhid
ID_USB_INTERFACES=:030102:030000:
ID_USB_INTERFACE_NUM=01
ID_VENDOR=Logitech
ID_VENDOR_ENC=Logitech
ID_VENDOR_ID=046d
KEY=4837fff 72ff32d bf544446 0 0 1 20f90 8b17c000 677bfa d9415fed 9ed680 4400 0 10000002
MODALIAS=input:b0003v046DpC51Ae0111-e0,1,2,3,4,k71,72,73,74,77,80,82,83,85,86,87,88,89,8A,8B,8C,8E,90,96,98,9B,9C,9E,9F,A1,A3,A4,A5,A6,A7,A8,A9,AB,AC,AD,AE,B0,B1,B2,B5,B6,CE,CF,D0,D1,D2,D4,D8,D9,DB,DF,E4,E7,E8,E9,EA,EB,F1,100,161,162,166,16A,16E,172,174,176,178,179,17A,17B,17C,17D,17F,180,182,183,185,188,189,18C,18D,18E,18F,190,191,192,193,195,198,199,19A,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA,1AB,1AC,1AD,1AE,1B0,1B1,1B7,1BA,r6,a20,m4,lsfw
MSC=10
NAME="Logitech USB Receiver"
PHYS="usb-0000:00:1d.0-1.3/input1"
PRODUCT=3/46d/c51a/111
PROP=0
REL=40
SEQNUM=3185
SUBSYSTEM=input
UDEV_LOG=3
UNIQ=""
USEC_INITIALIZED=21796482192
UDEV [21800.817249] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/usbmisc/hiddev1
(usbmisc)
ACTION=remove
DEVNAME=/dev/usb/hiddev1
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/usbmisc/hiddev1
MAJOR=180
MINOR=1
SEQNUM=3186
SUBSYSTEM=usbmisc
UDEV_LOG=3
USEC_INITIALIZED=21800816392
UDEV [21800.818490] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/0003:046D:C51A.004E/hidraw/hidraw3
(hidraw)
ACTION=remove
DEVNAME=/dev/hidraw3
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/0003:046D:C51A.004E/hidraw/hidraw3
MAJOR=251
MINOR=3
SEQNUM=3187
SUBSYSTEM=hidraw
UDEV_LOG=3
USEC_INITIALIZED=21800816472
UDEV [21800.818536] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/0003:046D:C51A.004E
(hid)
ACTION=remove
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1/0003:046D:C51A.004E
HID_ID=0003:0000046D:0000C51A
HID_NAME=Logitech USB Receiver
HID_PHYS=usb-0000:00:1d.0-1.3/input1
MODALIAS=hid:b0003g0001v0000046Dp0000C51A
SEQNUM=3188
SUBSYSTEM=hid
UDEV_LOG=3
USEC_INITIALIZED=21800816908
UDEV [21800.818580] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1
(usb)
ACTION=remove
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.1
DEVTYPE=usb_interface
INTERFACE=3/0/0
MODALIAS=usb:v046DpC51Ad4100dc00dsc00dp00ic03isc00ip00in01
PRODUCT=46d/c51a/4100
SEQNUM=3189
SUBSYSTEM=usb
TYPE=0/0/0
UDEV_LOG=3
USEC_INITIALIZED=21800816945
UDEV [21800.818645] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3 (usb)
ACTION=remove
BUSNUM=002
DEVNAME=/dev/bus/usb/002/038
DEVNUM=038
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3
DEVTYPE=usb_device
ID_BUS=usb
ID_MODEL=USB_Receiver
ID_MODEL_ENC=USB\x20Receiver
ID_MODEL_ID=c51a
ID_REVISION=4100
ID_SERIAL=Logitech_USB_Receiver
ID_USB_INTERFACES=:030102:030000:
ID_VENDOR=Logitech
ID_VENDOR_ENC=Logitech
ID_VENDOR_ID=046d
MAJOR=189
MINOR=165
PRODUCT=46d/c51a/4100
SEQNUM=3190
SUBSYSTEM=usb
TYPE=0/0/0
UDEV_LOG=3
UPOWER_VENDOR=Logitech, Inc.
USEC_INITIALIZED=21796488421
и понять что там к чему. Добавить к существующему правилу ACTION=="add" тогда оно
будет срабатывать только при подключении устройства. А вот что писать в ACTION=="remove"
что бы systemd стопил сервис - я не знаю. Но мне кажется, остановки с помощью BindsTo=
вполне достаточно.
Ответ на 3) При выполнении /usr/sbin/pppd call modem он разве не завершается? Там
другой процесс порождается демоном, но systemd об этом ничего не знает. Если хочется,
то можете попробывать заставить systemd мониторить процесс с помощью Type=forking и,
желательно, PIDFile=. Как там работает pppd я не в курсе, может поможет GuessMainPID=yes
(хотя если PIDFile пуст, то он по умолчанию вкл).
По управлению udev:
Может быть полезно сгенерировать различные события udev. Например, вы хотите симулировать
отключение USB-устройства на удаленной машине. В таких случаях, используйте udevadm
trigger: udevadm trigger -v -t subsystems -c remove -s usb -a "idVendor=id_поставщика"
У тебя соответственно -s ttyACM. Хотя тут я не уверен, потому что сам плохо знаю
этот момент.