Перехват события udev
События udev возникают при изменении статуса подключенных устройств. Наиболее употребительные события:
- подключение устройства (событие "add");
- отключение устройства (событие "remove").
Перехват событий осуществлятся с помощью сценариев обработки. Файлы со сценариями - обработчиками событий udev располагаются в каталогах /etc/udev/rules.d/ и /lib/udev/rules.d/.
Стандартно имя каждого файла - сценария начинается с двух цифр, и имеет расширение .rules.
При обработке события файлы выполняются в порядке алфавитной сортировки независимо от каталога, к котором они размещены.
Пример файла перехвата события /etc/udev/rules.d/99-local.rules:
/etc/udev/rules.d/99-local.rules
KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/bin/systemctl stop usb-mount@%k.servic"
Этот перехватчик обрабатывает события подключения/отключения дисковых устройств, однако не выполняет при этом прямых действий, а вызывает для выполнения этих действия системную службу usb-mount@%k.service, то есть вызывает сценарий обработки события как системную службу.
Как организовать такую службу описано ниже.
Для того, чтобы новый сценарий обработки был зарегистрирован системой и начал работать, необходимо перезагрузить правила udev командой
Вызов сценария обработки события как системного сервиса
Итак, сценарий обработки вызывается как системный сервис. Для вызова сервисов используются так называемы "юниты", специальные сценарии запуска сервисов, расположенные в каталоге /etc/systemd/system/.
Пример сценария для вышеуказанного /etc/systemd/system/usb-mount@.service обработчика события:
/etc/systemd/system/usb-mount@.service
[Unit]
Description=Mount USB Drive on %i
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/bin/usb-mount.sh add %i
ExecStop=/usr/local/bin/usb-mount.sh remove %i
Этот сценарий умеет обрабатывать две команды - старт и стоп, но сам опять ничего не делает, а вызывает исполнимый файл сценария обработки события /usr/local/bin/usb-mount.sh
.
Сценарий обработки события
Сценарий обработки события в принципе может размещаться где угодно, для примера используем файл /usr/local/bin/usb-mount.sh
/usr/local/bin/usb-mount.sh
#!/bin/bash
# Этот сценарий вызывается из системного юнита как сценарий обработки подключения/отключения накопителей.
usage() {
echo "Использование: $0 {add|remove} device_name (e.g. sdb1)"
exit 1
}
if [[ $# -ne 2 ]]; then
usage
fi
ACTION=$1
DEVBASE=$2
DEVICE="/dev/${DEVBASE}"
# Проверяем, не примонтировано ли уже устройство
MOUNT_POINT=$(/bin/mount | /bin/grep ${DEVICE} | /usr/bin/awk '{ print $3 }')
do_mount() {
if [[ -n ${MOUNT_POINT} ]]; then
echo "Предупреждение: ${DEVICE} уже смонтировано в ${MOUNT_POINT}"
exit 1
fi
# Получаем информацию об устройстве : метка $ID_FS_LABEL, идентификатоп $ID_FS_UUID, и тип файловой системы $ID_FS_TYPE
eval $(/sbin/blkid -o udev ${DEVICE})
# Создаём точку монтирования:
LABEL=${ID_FS_LABEL}
if [[ -z "${LABEL}" ]]; then
LABEL=${DEVBASE}
elif /bin/grep -q " /media/${LABEL} " /etc/mtab; then
# Если точка монтирования уже существует изменяем имя:
LABEL+="-${DEVBASE}"
fi
MOUNT_POINT="/media/${LABEL}"
echo "Точка монтирования: ${MOUNT_POINT}"
/bin/mkdir -p ${MOUNT_POINT}
# Глобальные опции монтирования
OPTS="rw,relatime"
# Специфические опции монтирования:
if [[ ${ID_FS_TYPE} == "vfat" ]]; then
OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
fi
if ! /bin/mount -o ${OPTS} ${DEVICE} ${MOUNT_POINT}; then
echo "Ошибка монтирования ${DEVICE} (статус = $?)"
/bin/rmdir ${MOUNT_POINT}
exit 1
fi
echo "**** Устроййство ${DEVICE} смонтировано в ${MOUNT_POINT} ****"
}
do_unmount() {
if [[ -z ${MOUNT_POINT} ]]; then
echo "Предупреждение: ${DEVICE} не смонтировано"
else
/bin/umount -l ${DEVICE}
echo "**** Отмонтировано ${DEVICE}"
fi
# Удаление пустых каталогов
for f in /media/* ; do
if [[ -n $(/usr/bin/find "$f" -maxdepth 0 -type d -empty) ]]; then
if ! /bin/grep -q " $f " /etc/mtab; then
echo "**** Удаление точки монтирования $f"
/bin/rmdir "$f"
fi
fi
done
}
case "${ACTION}" in
add)
do_mount
;;
remove)
do_unmount
;;
*)
usage
;;
esac
После создания файла сценария не забыть сделать его исполнимым:
/usr/local/bin/usb-mount.sh
Приёмы отладки
Включение вывода отладочных сообщений в файл /var/log/syslog
Тестовая отработка правил udev без их загрузки: