Mount external drive in cron job

An image of a cup of coffee at keyboard

The Problem:

You have a bash script that will backup your home directory to an external usb drive. You have that script set to run from your crontab. The cron job runs successfully if you are logged in and have mounted the external usb drive, otherwise it fails with an error about not being able to find the destination.

There are actually a couple issues at play here, and to get the desired result you need to address both. First, we need to be able to mount a file system as a non-root user. Second, we need to be able to script that in a cron job, so we need a solution that doesn't require manually entering the sudo password.

The Solution:

Udisks2 is the way your desktop applications (like Thunar File Manager, for example) are able to mount an external usb drive without requiring any authentication, so logically it would make sense that we should be able to use that in our backup script.

The following steps work on Fedora 39, and I suspect they will be the same on most other recent distros.

Step one is to identify the file system and mount point your system will use when Udisks2 mounts the external drive. To do that, open your File Manager and make sure that you have mounted the drive, then in a terminal session type the "df" command. You should see a list of drives with their usage info and mount points like this:

Filesystem      1K-blocks       Used  Available Use% Mounted on
/dev/sdb1      2930232316 1121812680 1808419636  39% /run/media/username/My Book

Udisks2 defaults to mount points starting with /run/media/username/ and then the name of the drive, in this example, /dev/sdb1 is a Western Digital "My Book". Your backup script will target some path on this mount point, for example you might have an rsync line like below (notice you must escape any spaces in the path):

rsync -rltiD --delete --exclude='skipped/' --exclude='.cache/' /home/username/ /run/media/username/My\ Book/Desktop/F39/username/

What we need to do in our backup script is check to see if the external drive is mounted, and if not, mount it. Let's first create a flag file on our external drive:

touch /run/media/username/My\ Book/flagfile.txt

Next place the below "if" block in your backup script after the shebang line but before the rsync line.

if [ ! -f /run/media/username/My\ Book/flagfile.txt ]; then
  udisksctl mount -b /dev/sdb1
fi

You would think that would be enough, and you're done, but there is one gotcha. By default the polkit policy for most udisks actions does not authorize operations from an "inactive" session, unless the user can authenticate as root. A cron job is never an active session, and has no way to get the user to provide authentication. So, the final piece of the solution is to create a polkit rule that will allow this to work in a cron job. 

Use your favorite editor to create the file /etc/polkit-1/rules.d/10-udisks.rules (you will need root permissions to access the rules.d directory and create that file). For example:

sudo vim /etc/polkit-1/rules.d/10-udisks.rules

and insert this and save the file:

polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.udisks2.filesystem-mount" && subject.user == "username") {
        return polkit.Result.YES;
    }
});

That should do it. Your cron job will now work without issues whether the external drive is already mounted or not.