Различное поведение скрипта 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а также udevrules) сценарий 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
Другие вопросы по тегам