Reputation: 4343
I am working on a bash script that is designed to tell whether or not a given drive is attached to the system, and if it is, to copy some data (backups that need to be taken off-site) to that drive.
What I'd like to do is identify the drive/partition by UUID, so that I can have a script that frequently scans for the presence of that drive, and when it's plugged in, copies data to it (via rsync, so I don't particularly care if that part runs more than once, because the later runs are I/O-cheap). I want this to be as simple as possible so that I can hand the drive in question to a non-technical person and say "plug it in here, then unplug it later and take it with you."
I can't seem to find any options in mount
that quite do this, and grepping through /etc/fstab
doesn't tell me whether a drive is actually mounted or not.
How can I tell, given a UUID, whether or not a drive with that UUID is mounted and what its mount point is?
Upvotes: 3
Views: 5475
Reputation: 11
First, I'm going to add a couple requirements for you: You say you want a non-technical user to remove the drive for offsite storage. So, also needed:
a) when rsync finishes, unmount the drive so it's safe to remove.
b) if drive is still connected at next run interval, mount the drive just prior to starting rsync.
Assuming we do (a) and (b), your last question is no longer relevant, as we only need to determine if one or more target uuid disk(s) are attached, and if so, script will mount it at a pre-determined mountpoint.
This basic example uses a single config file named backup.disks
. It should contain your target uuid on a single line. Optionally, can add multiple uuids, one per line, rsync will run to the first disk found.
DISKS=/path/backup.disks
MOUNTPOINT=/mnt/backup
SOURCE=/pathFilesToBackup/
TARGET=/$MOUNTPOINT/backupfolder
# Find whether a connected block device is a backup drive
for uuid in $(lsblk --noheadings --list --output uuid)
do
if grep --quiet --fixed-strings $uuid $DISKS; then
break
fi
uuid=
done
if [ ! $uuid ]; then
echo "No backup disk found, exiting"
exit 0
fi
echo "Disk $uuid is a backup disk"
partition_path=/dev/disk/by-uuid/$uuid
# drive is attached, we assume system is NOT automatically mounting disks and only this script will be mounting backup drives.
# if drive is not already mounted at designated mountpoint, then mount it. (if someone else already mounted it elsewhere then we have a problem)
findmnt $MOUNTPOINT >/dev/null || mount $partition_path $MOUNTPOINT
# create backup
rsync -av $SOURCE $TARGET
# ensure writes flushed to disk before unmounting
sync
umount $MOUNTPOINT
Giving credit to the Borg Backup project, from which above script is derived. Above script covers your question. The full script from Borg Backup offers additional options like creating a service to watch for specific UUID(s) and kick off backup immediately after a target UUID is attached. It's simple enough to replace the Borg commands with rsync.
Here's the Borg script: Borg Backup, Automated backups
Upvotes: 0
Reputation: 1823
/dev/disk/by-uuid/ is a symlink farm for attached volumes. It won't tell you if the volume is mounted or not but will tell you if it's plugged in - so might address your particular use case anyway.
$ ls -l /dev/disk/by-uuid/
total 0
lrwxrwxrwx 1 root root 10 Nov 22 10:08 b928a862-6b3c-45a8-82fe-8f1db2863be3 -> ../../dm-0
lrwxrwxrwx 1 root root 10 Dec 8 14:33 e37fab85-9b00-4d9b-b25e-0970d6eaa3fa -> ../../sdg1
$ readlink /dev/disk/by-uuid/b928a862-6b3c-45a8-82fe-8f1db2863be3
../../dm-0
Does that help?
Upvotes: 2
Reputation: 183
The best I've found for doing just this is to use blkid to convert the UUID to a block devise on the unix filesystem e.g.
:~# blkid -U '09b8f1ab-8d4b-4c5f-b395-40be09c090b0'
/dev/sdb1
then grep the mount command's output for that.
:~# mount | grep $(blkid -U '09b8f1ab-8d4b-4c5f-b395-40be09c090b0')
/dev/sdb1 on /media/WD_Disk_1 type ext3 (rw,nosuid,nodev,uhelper=udisks)
then grep that for the desired mount point
grep -qs '/media/WD_Disk_1 '
The full command is
:~# mount | grep $(blkid -U '09b8f1ab-8d4b-4c5f-b395-40be09c090b0') | grep '/media/WD_Disk_1 '
/dev/sdb1 on /media/WD_Disk_1 type ext3 (rw,nosuid,nodev,uhelper=udisks)
I put this into an if statement and hide the output replacing it with a nice little message :-).
if mount | grep $(blkid -U '09b8f1ab-8d4b-4c5f-b395-40be09c090b0') | grep '/media/WD_Disk_1 ' > /dev/null 2>&1;
then
rsync -az --delete /mnt/data/ /media/WD_Disk_1/current_working_data/;
echo "sync complete"
else
echo "couldn't find WD_Disk_1 filesystem"
exit 1
fi
Upvotes: 2
Reputation: 3000
A device can be mounted by its symlink. If this is the case, the mount command will refer to it by its symlink but you might have a reference by its real path, or worse another symlink.
This is compounded even more by the fact that multiple block device files can point to a single block device (!). This can be done by using the mknod command.
The only way I can find to accurately get this information is to compare the major and minor numbers of all entries in /proc/mounts
with the major and minor number of the UUID you are looking for.
Here is a function/script that will do this.
#!/bin/bash
# $1: should be a drive uuid, such as that reported by blkid
# return: return value of 0 if mounted, 1 if not mounted
function is_mounted_by_uuid() {
input_path=$(readlink -f /dev/disk/by-uuid/"$1")
input_maj_min=$(stat -c '%T %t' "$input_path")
cat /proc/mounts | cut -f-1 -d' ' | while read block_device; do
if [ -b "$block_device" ]; then
block_device_real=$(readlink -f "$block_device")
blkdev_maj_min=$(stat -c '%T %t' "$block_device_real")
if [ "$input_maj_min" == "$blkdev_maj_min" ]; then
return 255
fi
fi
done
if [ $? -eq 255 ]; then
return 0
else
return 1
fi
}
if is_mounted_by_uuid "$1"; then
echo $(readlink -f /dev/disk/by-uuid/$1) is mounted
else
echo $(readlink -f /dev/disk/by-uuid/$1) is not mounted
fi
Upvotes: 3