7

I created a small sample-script which is reduced version of my real script and it looks basically as follows:

#!/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

If i call the script directly in the terminal, everything works correctly. So the return in the logfile is something like that.

start
sdc1_vfat

But as soon as the script is called from a udev rule, the loop does not work anymore. The output in the logfile is only

start

The loop does not work anymore.

The rule in the /dev/udev/ looks as follows

SUBSYSTEM=="usb", ACTION=="add", RUN+="/bin/bash /usr/bin/myScript.sh"

Anyone an idea what the cause could be?


Here some more information and as suggested a reworked version.based on your answers.

Here the udev rule:

# 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"

The mounting scriupt does now looks as follows:

#!/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

If I check the mounting command, the exit code is 0 so it has been processed successfully. The folder is getting created correctly, but the drive is not mounted. If the script is called directly in the terminal, everything works as expected. But if it's called by the udev it is not mounted.

I still don't now the problem:

  • Is it a timing problem - even if the udevadm info -q all /dev/sdb* returns a connected device?
  • Is it a permission or path problem?

Any ideas how I can find the cause?


Additional Information

Just figured out, that in the syslog an exit code 127 is reported. So it seems to be a permission problem. But how can I ensure the udev script runs as root?

muru
  • 207,228
hafisch
  • 135

1 Answers1

4

Bash behavior is the same … It’s just lsblk returns an empty string … The reason is that udev doesn’t make your disk available under /dev until it finishes processing all the rules triggered by plugging in the same disk.

So, your approach to monitoring and mounting that disk partition is simply not going to work.

Alternatively, you can achieve your goal in one of two ways below.

Monitor for a certain partition name on any disk

This is a rather more portable(independent from udisks and udev rules) bash script that when run will monitor for a certain USB(or otherwise) disk partition that you specify(like e.g. /dev/sdb1 assuming /dev/sdb is always free and reserved for first USB disk inserted), mount it to the mount-point that you specify when the USB disk is plugged and un-mount it when the USB disk is unplugged with all events logged to a log file that you specify ... Read the comments in the script for help.

The script needs to be run with administrator permissions ... so either:

  • Run it with sudo /bin/bash scriptfile.
  • Add a cron-job(it only needs to be run once after boot process completes) for it to root's crontab with sudo crontab -e.
  • Add a systemd service(and enable the service) to run it.
#!/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

Monitor for a certain partition on a certain disk

There are many ways to identify a certain partition on a certain disk ... The one most suitable is to connect the USB disk you want to use then look under /dev/disk/ to find other ways disks are identified on the system ... do ls /dev/disk/ and you will get:

$ ls /dev/disk/
by-id  by-label  by-partlabel  by-partuuid  by-path  by-uuid

Each one of the above is a directory containing symbolic links to your disks and the name says it all and all there is left is for you to chose how to identify your disk ... a rather more reliable method would be by-id as this is supposed to be a unique fixed string containing the manufacture's name and serial number for the disk device itself and will be followed by the partition number for the partitions on the disk ... a useful thing is that USB disks are also prefixed with usb- ... so an ls /dev/disk/by-id/ would yield something like this:

usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0
usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0-part1

Once you identify that ID for your device, you can simply check if it's connected or not with something like:

$ [ "$(readlink -e /dev/disk/by-id/usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0)" ] && echo "connected"
connected

and know its name under /dev with readlink like so:

$ readlink -f /dev/disk/by-id/usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0
/dev/sdb  

So, the script becomes like this:

#!/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 /dev/disk/by-id/"$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

Raffa
  • 34,963