Различное поведение скрипта bash в udev
Я создал небольшой образец сценария, который является уменьшенной версией моего реального сценария и выглядит в основном следующим образом:
#!/bin/bash
echo "start" > /home/myName/log.txt
#get list with all attached devices
for i in $(lsblk -lo name,fstype,hotplug,type|grep '1 part$'|tr -s ' ' ' '|sed 's/ 1 part$//'|grep ' ..*$'|tr ' ' '_')
do
echo $i >> /home/myName/log.txt
done
Если я вызываю скрипт прямо в терминале, все работает правильно. Итак, возврат в лог-файле примерно такой.
start
sdc1_vfat
Но как только скрипт вызывается из правила udev, цикл больше не работает. Вывод в файле журнала только
start
Цикл больше не работает.
Правило в /dev/udev/ выглядит следующим образом
SUBSYSTEM=="usb", ACTION=="add", RUN+="/bin/bash /usr/bin/myScript.sh"
Кто-нибудь знает, в чем может быть причина?
Вот еще немного информации и, как было предложено, переработанная версия, основанная на ваших ответах.
Вот правило udev:
# check usb sdb1 plugged unplugged
SUBSYSTEM=="block", ACTION=="add", RUN+="/bin/bash /usr/bin/usb_mount.sh"
SUBSYSTEM=="block", ACTION=="remove", RUN+="/bin/bash /usr/bin/usb_unmount.sh"
Сценарий монтирования теперь выглядит следующим образом:
#!/bin/bash
#general definitions
MNT_PATH="/media/USB_DRIVE"
DEV_ID="sdc1"
# check connected device
udevadm info -q all "/dev/$DEV_ID" | tr '\n' ' ' | grep "/dev/$DEV_ID" | grep "ID_FS_VERSION=FAT32"
# check return
if [ $? -eq 0 ]
then
# create folder and mount
mkdir -p $MNT_PATH
mount -o rw,user,exec,umask=0000 "/dev/$DEV_ID" $MNT_PATH
exit
fi
Если я проверю команду монтирования,
exit code is 0
так что он был обработан успешно. Папка создается правильно, но диск не монтируется. Если скрипт вызывается прямо в терминале, все работает как положено. Но если он вызывается, он не монтируется.
Я до сих пор не вижу проблемы:
- Это проблема времени - даже если
udevadm info -q all /dev/sdb*
возвращает подключенное устройство? - Это проблема разрешения или пути?
Любые идеи, как я могу найти причину?
Дополнительная информация
Только что выяснил, что в
syslog
ан
exit code 127
сообщается. Так что, похоже, проблема с разрешением. Но как я могу обеспечить
udev
скрипт работает как root?
1 ответ
Поведение Баша такое же… Просто
lsblk
возвращает пустую строку… Причина в том, что ваш диск не становится доступным до тех пор, пока он не завершит обработку всех правил, запущенных при подключении того же диска.
Таким образом, ваш подход к мониторингу и монтированию этого раздела диска просто не сработает.
Кроме того, вы можете достичь своей цели одним из двух способов, указанных ниже.
Мониторинг определенного имени раздела на любом диске
Это довольно более портативный (независимый от
udisks
а также
udev
rules) сценарий bash, который при запуске будет отслеживать определенный раздел диска USB(или иным образом), указанный вами (например,
/dev/sdb1
предполагая
/dev/sdb
всегда свободен и зарезервирован для первого вставленного USB-диска), смонтируйте его в точку монтирования, указанную вами, когда USB-диск подключен, и отключите его, когда USB-диск отключен, со всеми событиями, зарегистрированными в файле журнала, который вы укажете ... Прочтите комментарии к сценарию за помощью.
Скрипт нужно запускать с правами администратора... так что либо:
- Запустите его с
sudo /bin/bash scriptfile
. - Добавьте cron-job(его нужно запустить только один раз после завершения процесса загрузки), чтобы он мог работать с crontab root с помощью
sudo crontab -e
. - Добавьте службу systemd (и включите службу), чтобы запустить ее.
#!/bin/bash
# Set the name of the partition to be monitored.
mpartition="/dev/sdb1"
# Set the full path to the mount-point.
mount_point="/home/user/USB_DRIVE"
# Set the full path to the logfile(will be created if it doesn't exist)
log_file="/home/user/usb_mount.log"
# Start "inotifywait"(need be installed first with "sudo apt install inotify-tools") to monitor the partition
inotifywait -q -m --include "$mpartition" -e create -e delete /dev/ |
while read -r directory event partition; do
if [ "$event" == "CREATE" ]; then
note=$(/usr/bin/mount -v -o rw "$directory$partition" "$mount_point" 2>&1) # If needed, add extra options after -o like "-o rw,umask=000" to allow all write and read
status="$?"
if [ "$status" -eq 0 ]; then
echo "$(date): Successful mount with exit code $status [$note]" >> "$log_file"
else
echo "$(date): Failed mount with exit code $status [$note]" >> "$log_file"
fi
elif [ "$event" == "DELETE" ]; then
note=$(/usr/bin/umount -v "$mount_point" 2>&1)
status="$?"
if [ "$status" -eq 0 ]; then
echo "$(date): Successful un-mount with exit code $status [$note]" >> "$log_file"
else
echo "$(date): Failed un-mount with exit code $status [$note]" >> "$log_file"
fi
fi
done
Мониторинг определенного раздела на определенном диске
Есть много способов идентифицировать определенный раздел на определенном диске ... Наиболее подходящий из них - подключить USB-диск, который вы хотите использовать, а затем посмотреть в разделе
/dev/disk/
найти другие способы идентификации дисков в системе... сделать
ls /dev/disk/
и вы получите:
$ ls /dev/disk/
by-id by-label by-partlabel by-partuuid by-path by-uuid
Каждый из вышеперечисленных представляет собой каталог, содержащий символические ссылки на ваши диски, и имя говорит само за себя, и все, что вам остается, это выбрать, как идентифицировать ваш диск ... более надежным методом будет
by-id
поскольку предполагается, что это уникальная фиксированная строка, содержащая название производителя и серийный номер самого дискового устройства, за которой будет следовать номер раздела для разделов на диске ... полезно то, что USB-диски также имеют префикс
usb-
... так что
ls /dev/disk/by-id/
даст что-то вроде этого:
usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0
usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0-part1
Как только вы определите этот идентификатор для своего устройства, вы можете просто проверить, подключено ли оно к чему-то вроде:
$ [ "$(readlink -e /dev/disk/by-id/usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0)" ] && echo "connected"
connected
и знать его имя под
/dev
с
readlink
вот так:
$ readlink -f /dev/disk/by-id/usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0
/dev/sdb
Итак, сценарий становится таким:
#!/bin/bash
# Set the ID of the partition to be monitored.
mpartition="usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0-part1"
# Set the full path to the mount-point.
mount_point="/home/user/USB_DRIVE"
# Set the full path to the logfile(will be created if it doesn't exist)
log_file="/home/user/usb_mount.log"
# Start "inotifywait"(need be installed first with "sudo apt install inotify-tools") to monitor the partition
inotifywait -q -m --include "$mpartition" -e create -e delete /dev/disk/by-id/ |
while read -r directory event partition; do
if [ "$event" == "CREATE" ]; then
device=$(/usr/bin/readlink -f "$mpartition")
note=$(/usr/bin/mount -v -o rw "$device" "$mount_point" 2>&1) # If needed, add extra options after -o like "-o rw,umask=000" to allow all write and read
status="$?"
if [ "$status" -eq 0 ]; then
echo "$(date): Successful mount with exit code $status [$note]" >> "$log_file"
else
echo "$(date): Failed mount with exit code $status [$note]" >> "$log_file"
fi
elif [ "$event" == "DELETE" ]; then
note=$(/usr/bin/umount -v "$mount_point" 2>&1)
status="$?"
if [ "$status" -eq 0 ]; then
echo "$(date): Successful un-mount with exit code $status [$note]" >> "$log_file"
else
echo "$(date): Failed un-mount with exit code $status [$note]" >> "$log_file"
fi
fi
done