12

I've got a backup script written in Python which creates the destination directory before copying the source directory to it. I've configured it to use /external-backup as the destination, which is where I mount an external hard drive. I just ran the script without the hard drive being turned on (or being mounted) and found that it was working as normal, albeit making a backup on the internal hard drive, which has nowhere near enough space to back itself up.

My question is: how can I check whether the volume is mounted in the right place before writing to it? If I can detect that /external-backup isn't mounted, I can prevent writing to it.

The bonus question is why was this allowed, when the OS knows that directory is supposed to live on another device, and what would happen to the data (on the internal hard drive) should I later mount that device (the external hard drive)? Clearly there can't be two copies on different devices at the same path!

Thanks in advance!

Ben Hymers
  • 703
  • 2
  • 8
  • 12

7 Answers7

25

I would take a look at os.path.ismount().

pR0Ps
  • 265
  • 2
  • 7
Dennis Williamson
  • 62,149
  • 16
  • 116
  • 151
  • 1
    The only problem is that it returns a boolean & doesn't specify whether the right device is there. – McJeff May 18 '10 at 20:06
  • 3
    @McJeff: That's true it doesn't tell *which* it tells *if*. If no device is there, it'll return false and a write to that path will write to the underlying directory in the *parent* filesystem. So if it returns false, issue an error and don't write there. The directory `/external-backup` doesn't live on an external device, it lives on the parent filesystem. The system only knows what `mount` tells it, it doesn't have any idea what *ought* to be there. There's nothing special about a "mount point" on a Unix filesystem. It's just a regular directory. – Dennis Williamson May 19 '10 at 04:38
  • That does the job perfectly. I'm not going to protect against other volumes being mounted there, just that it's not the parent filesystem. Sorry to the other answerers, your answers may answer my question more exactly but I'm afraid I didn't quite know what to ask for in the first place as you might be able to tell ;) I've rated you all up anyway. – Ben Hymers May 19 '10 at 18:17
  • Good explanation! – McJeff May 19 '10 at 18:50
7

For a definitive answer to something only the kernel knows for sure, ask the kernel:

cat /proc/mounts

That file can be read / parsed as if it was a normal file, using any tools you like. Including Python. Quick-n-dirty example:

#!/usr/bin/python

d = {}

for l in file('/proc/mounts'):
    if l[0] == '/':
        l = l.split()
        d[l[0]] = l[1]

import pprint

pprint.pprint(d)
Insyte
  • 9,394
  • 3
  • 28
  • 45
4

The easiest way to check is to invoke mount via subprocess and see if it shows up there. For extra credit, use os.readlink() on the contents of /dev/disk/by-* to figure out which device it is.

Ignacio Vazquez-Abrams
  • 45,939
  • 6
  • 79
  • 84
  • As I see it the problem with that approach is that the output of `mount` is sloppily defined at best. What does `mount` output if I have mounted `/dev/evil device on tour` at `/directory on which I mount devices`? The parsing of the output might be unreliable in such cases... – skyking Oct 26 '18 at 20:21
2

Bonus answer. If external device is not mounted data is written to root partition at path /external-backup. If external device is mounted data on root partition is still there but it is not reachable because /external-backup is now pointing to external device.

Casual Coder
  • 1,216
  • 1
  • 11
  • 12
2

Old question, but I thought I'd contribute my solution (based on Dennis Williamson's and Ignacio Vazquez-Abrams's's answer) anyways. Since I'm using it on a non-Linux environment to check remote directories being mounted, /proc and mtab cannot be used and no additional checks have been implemented:

def is_mounted(special, directory):
    search_prefix = '{} on {}'.format(special, directory.rstrip('/'))

    if os.path.ismount(directory):
        mounts = subprocess.check_output(['mount']).split('\n')

        for line in mounts:
            if line[:len(search_prefix)] == search_prefix:
                return True;

    return False

Improvements welcome!

Magentron
  • 223
  • 2
  • 7
1

The /etc/mtab file exists to tell you what is currently mounted. There is a getmntent call, but I don't think it's exported in the os module. The quick and dirty? Open /etc/mtab and split. Ensure your device is present in column 0 and the destination mount point in column 1 is correct.

McJeff
  • 2,039
  • 13
  • 11
0

You can try this but it won't work in every case:

from pathlib import Path

def guess_mounted(path) -> bool:
    for p in [Path(path)] + list(Path(path).parents):
        if p == Path('/'):
            return False
        elif p.is_mount():
            return True
    return False

Then later in your code you can do:

if not guess_mounted(save_path):
    raise Exception('Not mounted')