kstep 28.03.2014 14:40

Tips & tricksЕщё одно лёгковесное автомонтирование USB через Systemd

Казалось бы, зачем ещё один костыль, если есть udisks, udisks2 итп? Я ими и пользовался долгое время на десктопных компах, но недавно решил запилить домашний сервер на старом ноутбуке. Свежий арчик, минимальная установка dnsmasq/nginx/transmission/mpd-light, минимум зависисмостей, никаких иксов, никаких графических либ, гномов и прочего мусора.


В таких условиях решения на базе udisks оказались неприемлемы, т.к. тянут за собой кучу нежелательных зависимостей. Для меня это вопрос идеологический, ничего лишнего на сервере быть не должно.

Но ведь есть udev, казалось бы достаточно просто запилить пару правил в нём и сделать RUN+="/usr/bin/mount". Однако это неправильно (см. man udev):

Starting daemons or other long-running processes is not appropriate for udev; the forked processes, detached or not, will be unconditionally killed after the event handling
has finished.


Да, прямой подход будет работать, если монтирование происходит с использованием модуля из ядра, типа ext3, btrfs или reiserfs, но любая fs на базе fuse будет убита, т.к. предполагает запуск демона в юзерспейсе, а монтировать хочется и ntfs-диски на горячую, а это ntfs-3g.

После долгого гугления и чтения мануалов я нашёл другое, более правильное © решение.

Дело в том, что если udev провесит правильные параметры на устройство, то systemd запустит произвольный сервис.

Итак, делаем раз:

/etc/systemd/system/usb-mount.service
1
2
3
4
5
6
[Unit]
Description=Automount for %i

[Service]
Type=oneshot
ExecStart=/bin/sh -c "exec /bin/mount -o x-mount.mkdir UUID=$(echo '%I' | sed -e 's#/#-#g' -e 's# # /media/#')"



Делаем два:

/etc/udev/rules.d/99-automount.rules
 1
2
3
4
5
6
7
8
9
10
ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", DRIVERS=="usb-storage", GOTO="automount_go"
ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", DRIVERS=="usb-storage", RUN{program}+="/bin/rmdir /media/%E{AUTOMOUNT_NAME}"
GOTO="automount_end"

LABEL="automount_go"
ENV{AUTOMOUNT_NAME}="%E{ID_FS_UUID}"
ENV{ID_FS_LABEL}!="", ENV{AUTOMOUNT_NAME}="%E{ID_FS_LABEL}"
GROUP="usb", TAG+="systemd", ENV{SYSTEMD_WANTS}="usb-mount@%E{ID_FS_UUID}\x20%E{AUTOMOUNT_NAME}.service"

LABEL="automount_end"



Делаем три:
1
2
$ sudo systemctl daemon-reload
$ sudo systemctl reload systemd-udevd



Втыкаем флешку и радуемся жизни.

Теперь что здесь и как:

Условия в файле 99-automount.rules получены экспериментально с помощью udevadm monitor, перетыкания флешки и udevadm info --path path/to/device --attr.

Строчки, выставляющие AUTOMOUNT_NAME настраивают имя точки монтирования, сначала беру UUID диска, а если у него есть label, то юзаю его.

Параметр -o x-mount.mkdir при монтировании заставляет mount создавать каталог для монтирования если его ещё нет.

Сложное sed-выражение в вызове mount нужно для приведения разескейпеной строки из %I. Дело в том, что всё, что после собаки в имени сервиса systemd передаёт в параметрах %i (как есть) и %I (разескейпенный вариант). Правила перекодирования таковы: все дефисы (-) меняются на слеши (/), все строки \xNN меняются на соответствующие символы с хекс-кодом NN.

Например монтирование диска с UUID 9354-BF14 и лейблом My-Disk вызовет systemd-сервис usb-mount@9354-BF14\x20My-Disk, внутри сервис-файла %I будет заменено на строку "9354/BF14 My/Disk", а sed проеобразует эту строку в "9354-BF14 /media/My-Disk", в итоге выполнится команда "mount -o x-mount.mkdir UUID=9354-BF14 /media/My-Disk", что мне и нужно.

Решение проверено и работает, хоть и сделано на коленке. Любые предложения и замечаения приветствуются.


Тэги: systemd usb автомонтирование сервер
+ 3 -
Похожие Поделиться

brestows 28.03.2014 21:34 #
я для автомантирования юзаю вот это: https://github.com/LemonBoy/ldm
это конечно требует установки но работает тоже стабильно и хорошо.Хотя Ваш вариант получается решается вообще стандартными средствами большинства дистрибутивов.
mr.lupoalberto@gmail.com 29.03.2014 11:07 #
Каким образом происходит извлечение (отмонтирование) флешки? Как я понимаю, для корректного извлечения всё равно нужно подключаться к консоли?
dront78 29.03.2014 15:52 #
резонно. аналог автомаунт демона systemd не предоставляет случайно? типа зашел в папку замонтировало, вышел - по таймауту отрубило
kstep 31.03.2014 01:37 #
Размонтирование по таймауту сделать можно, но нет смысла в моём случае. Размонтирование через события udev сделать нельзя по определению (на событие "remove" устройства уже нет в системе, размонтировать уже поздно да и нечего). Для размонтирования можно юзать красивые средства типа Ajenti.
dront78 31.03.2014 11:17 #
вот оно что) прикольная штука
dront78 29.03.2014 16:52 #
kstep 31.03.2014 01:35 #
Да, про эту штуку я знаю. Проблема с ней, что нужно заранее прописывать конкретные устройства и пути монтирования. Моя задача стояла иначе: количество возможно подключённых устройств и их имена в системе неизвестны (и фактически случайны), имена точек монтирования управляются свойствами этих устройств. Такую гибкость "автомонтирование" системд не предоставляет.
shisoid 29.03.2014 22:24 #
спасибо, но это и даром не нать.
тем более овер говнецо ака systemd
kstep 31.03.2014 01:36 #
Это с некоторых пор дефолтный инитд в арчике. Вкратце: не нравится — не ешь, тебя никто не заставляет.
shisoid 31.03.2014 14:58 #
так мне и арч даром не нать.
лучше генты пока ничего не придумали :3.
а в ней всегда есть выбор, ибо
dront78 01.04.2014 12:10 #
наличие свободы не повод обсирать мнение других.
ваши комменты "даром не нать" :D
kstep 31.03.2014 01:39 #
Кстати, небольшое дополнение. Чтобы этот костылик работал с fuse-демонами корректно, в service-файле вместо Type=oneshot надо прописать Type=forking, а то системд убивает fuse-демона =(
kstep 31.03.2014 02:11 #
Последняя доступная версия костылика вот здесь: https://gist.github.com/kstep/9828979
cppmm 02.04.2014 05:03 #
Я так и не понял проблему с ntfs-дисками. При чём тут демоны и как они будут прибиты? По твоей логике выходит, что если я в консоли примонтирую через ntfs-3g какой-нибудь диск, после закрытия терминала, диск отпадёт.
dront78 03.04.2014 13:09 #
я так понимаю требуется поправочка

если я в консоли примонтирую средствами udev через ntfs-3g
cppmm 03.04.2014 19:04 #
Нет, не требуется поправочки. udev, что, теперь не умеет делать форк? Или это очередное нововведение системд, которое как обычно не даёт ничего полезного и только ломает уже работающий функционал?
dront78 03.04.2014 19:07 #
Ну давайте вместе вслух man почитаем) Я настолько же не в курсе, как и вы
cppmm 03.04.2014 19:57 #
Не, я про демонов в мане читал. Я не понимаю, причём здесь ntfs-3g. Процесс запустился и ушёл себе. Удев даже не знает о том, что там дальше происходит. Он не является родителем.
dront78 04.04.2014 19:06 #
то есть будет работать?
dront78 03.04.2014 19:09 #
Просто ТС сделал по man'у все, что есть видимо Ъ
ну и быстрый гуглеж показывает, что для разных сервисов есть разные типы запуска.

Или это очередное нововведение системд, которое как обычно не даёт ничего полезного и только ломает уже работающий функционал?


я бы не был так категоричен. разные велосипеды работают по разному
cppmm 03.04.2014 20:00 #
Повторюсь, каких сервисов? Где сервисы? Что, fstab запускает демонов? Нет же, просто монтирует. А у меня там ntfs-3g был прописан раньше. Почему удев этого не может? Может. Нормально монтирует и нормально работает. Поэтому мне и непонятна суть статьи и единственное различие между системой из статьи и моей системой - это systemd. Поэтому и спрашиваю.
dront78 04.04.2014 19:06 #
я вас не понимаю. если считаете, что работает - напишите что работает)
cppmm 08.04.2014 05:54 #
Всегда работало и сейчас работает. С какого перепуга оно вдруг должно было перестать работать - неясно. Причём, работать оно может кучей разных способов. Сам я вообще не пользуюсь автомонтированием, у меня udev при подключении девайса создаёт строку в fstab и директорию в media, а при отключении всё это дело убирает.

Но специально для тебя я скомпилял ntfs-3g и написал костыль для автомонтирования.
1
2
└─> cat /etc/udev/rules.d/automount.rules 
ACTION=="add", ENV{DEVTYPE}=="partition", RUN+="mount %N"


Содержимое /lib/udev/mount:
1
2
3
4
5
6
7
8
9
#!/bin/sh

MUID='1000'
MGID='1000'
DEV=$1
UUID=`blkid -o value -s UUID $DEV`
DIR="/media/$UUID"
mkdir -p $DIR
mount -o uid=$MUID,gid=$MGID $DEV $DIR


Здесь стоит пояснить, чтобы не пугались. По сути, можно было вообще одну строчку сюда вписать без всяких переменных и опций. И уже бы работало. Или же наоборот, можно здесь сделать определение типа fs, поиск метки(чтобы точку монтирования не по UUID'у делать), после монтирования открытие какого-нить файл-манагера и т.д. и т.п.
Я привожу простой пример, демонстрирующий только одно: любые фс спокойно монтируются.
Собственно, втыкаю флешку.

└─> tailf /var/log/messages
Apr 8 08:50:00 fugitive kernel: [ 2265.835177] usb usb1: usb wakeup-resume
Apr 8 08:50:00 fugitive kernel: [ 2265.835188] usb usb1: usb auto-resume
Apr 8 08:50:00 fugitive kernel: [ 2265.835194] ehci-pci 0000:00:12.2: resume root hub
Apr 8 08:50:00 fugitive kernel: [ 2265.835230] hub 1-0:1.0: hub_resume
Apr 8 08:50:00 fugitive kernel: [ 2265.835275] ehci-pci 0000:00:12.2: GetStatus port:5 status 001803 0 ACK POWER sig=j CSC CONNECT
Apr 8 08:50:00 fugitive kernel: [ 2265.835284] hub 1-0:1.0: port 5: status 0501 change 0001
Apr 8 08:50:00 fugitive kernel: [ 2265.936094] hub 1-0:1.0: state 7 ports 6 chg 0020 evt 0000
Apr 8 08:50:00 fugitive kernel: [ 2265.936202] hub 1-0:1.0: port 5, status 0501, change 0000, 480 Mb/s
Apr 8 08:50:00 fugitive kernel: [ 2265.987159] ehci-pci 0000:00:12.2: port 5 reset complete, port enabled
Apr 8 08:50:00 fugitive kernel: [ 2265.987171] ehci-pci 0000:00:12.2: GetStatus port:5 status 001005 0 ACK POWER sig=se0 PE CONNECT
Apr 8 08:50:00 fugitive kernel: [ 2266.038133] usb 1-5: new high-speed USB device number 8 using ehci-pci
Apr 8 08:50:00 fugitive kernel: [ 2266.089138] ehci-pci 0000:00:12.2: port 5 reset complete, port enabled
Apr 8 08:50:00 fugitive kernel: [ 2266.089150] ehci-pci 0000:00:12.2: GetStatus port:5 status 001005 0 ACK POWER sig=se0 PE CONNECT
Apr 8 08:50:00 fugitive kernel: [ 2266.153318] usb 1-5: default language 0x0409
Apr 8 08:50:00 fugitive kernel: [ 2266.155061] usb 1-5: udev 8, busnum 1, minor = 7
Apr 8 08:50:00 fugitive kernel: [ 2266.155068] usb 1-5: New USB device found, idVendor=1307, idProduct=0163
Apr 8 08:50:00 fugitive kernel: [ 2266.155072] usb 1-5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Apr 8 08:50:00 fugitive kernel: [ 2266.155076] usb 1-5: Product: Flash Disk
Apr 8 08:50:00 fugitive kernel: [ 2266.155080] usb 1-5: Manufacturer: USB 2.0
Apr 8 08:50:00 fugitive kernel: [ 2266.155083] usb 1-5: SerialNumber: 3c311e42304415
Apr 8 08:50:00 fugitive kernel: [ 2266.155231] usb 1-5: usb_probe_device
Apr 8 08:50:00 fugitive kernel: [ 2266.155237] usb 1-5: configuration #1 chosen from 1 choice
Apr 8 08:50:00 fugitive kernel: [ 2266.156555] usb 1-5: adding 1-5:1.0 (config #1, interface 0)
Apr 8 08:50:00 fugitive kernel: [ 2266.156637] usb-storage 1-5:1.0: usb_probe_interface
Apr 8 08:50:00 fugitive kernel: [ 2266.156647] usb-storage 1-5:1.0: usb_probe_interface - got id
Apr 8 08:50:00 fugitive kernel: [ 2266.156654] usb-storage 1-5:1.0: USB Mass Storage device detected
Apr 8 08:50:00 fugitive kernel: [ 2266.164808] scsi8 : usb-storage 1-5:1.0
Apr 8 08:50:01 fugitive kernel: [ 2267.167209] scsi 8:0:0:0: Direct-Access USB 2.0 Flash Disk 0.00 PQ: 0 ANSI: 2
Apr 8 08:50:01 fugitive kernel: [ 2267.167534] sd 8:0:0:0: Attached scsi generic sg2 type 0
Apr 8 08:50:01 fugitive kernel: [ 2267.169466] sd 8:0:0:0: [sdc] 1007616 512-byte logical blocks: (515 MB/492 MiB)
Apr 8 08:50:01 fugitive kernel: [ 2267.171334] sd 8:0:0:0: [sdc] Write Protect is off
Apr 8 08:50:01 fugitive kernel: [ 2267.171343] sd 8:0:0:0: [sdc] Mode Sense: 00 00 00 00
Apr 8 08:50:01 fugitive kernel: [ 2267.173126] sd 8:0:0:0: [sdc] Asking for cache data failed
Apr 8 08:50:01 fugitive kernel: [ 2267.173133] sd 8:0:0:0: [sdc] Assuming drive cache: write through
Apr 8 08:50:01 fugitive kernel: [ 2267.178580] sd 8:0:0:0: [sdc] Asking for cache data failed
Apr 8 08:50:01 fugitive kernel: [ 2267.178589] sd 8:0:0:0: [sdc] Assuming drive cache: write through
Apr 8 08:50:01 fugitive kernel: [ 2267.286856] sdc: sdc1
Apr 8 08:50:01 fugitive kernel: [ 2267.292059] sd 8:0:0:0: [sdc] Asking for cache data failed
Apr 8 08:50:01 fugitive kernel: [ 2267.292067] sd 8:0:0:0: [sdc] Assuming drive cache: write through
Apr 8 08:50:01 fugitive kernel: [ 2267.292073] sd 8:0:0:0: [sdc] Attached SCSI removable disk
Apr 8 08:50:02 fugitive ntfs-3g[22493]: Version 2013.1.13 external FUSE 29
Apr 8 08:50:02 fugitive ntfs-3g[22493]: Mounted /dev/sdc1 (Read-Write, label "", NTFS 3.1)
Apr 8 08:50:02 fugitive ntfs-3g[22493]: Cmdline options: rw,uid=1000,gid=1000
Apr 8 08:50:02 fugitive ntfs-3g[22493]: Mount options: rw,allow_other,nonempty,relatime,default_permissions,fsname=/dev/sdc1,blkdev,blksize=4096
Apr 8 08:50:02 fugitive ntfs-3g[22493]: Global ownership and permissions enforced, configuration type 1
^C
└─> df -h
Файловая система Размер Использовано Дост Использовано% Cмонтировано в
/dev/sda2 4,8G 114M 4,5G 3% /
devtmpfs 875M 0 875M 0% /dev
tmpfs 176M 444K 175M 1% /run
cgroup_root 10M 0 10M 0% /sys/fs/cgroup
shm 876M 0 876M 0% /dev/shm
/dev/sda1 504M 21M 459M 5% /boot
/dev/sda5 30G 5,8G 23G 21% /usr
/dev/sda6 4,8G 323M 4,3G 7% /var
/dev/sda7 4,8G 11M 4,6G 1% /tmp
/dev/sda8 100G 385M 95G 1% /home
/dev/sdc1 491M 3,0M 489M 1% /media/0F046AE27A051872