Python: Get Mount Point on Windows or Linux

Python: Get Mount Point on Windows or Linux

Windows didn't use to call them "mount points" [edit: it now does, see below!], and the two typical/traditional syntaxes you can find for them are either a drive letter, e.g. Z:, or else \\hostname (with two leading backslashes: escape carefully or use r'...' notation in Python fpr such literal strings).

edit: since NTFS 5.0 mount points are supported, but according to this post the API for them is in quite a state -- "broken and ill-documented", the post's title says. Maybe executing the microsoft-supplied mountvol.exe is the least painful way -- mountvol drive:path /L should emit the mounted volume name for the specified path, or just mountvol such list all such mounts (I have to say "should" because I can't check right now). You can execute it with subprocess.Popen and check its output.

How to find the mountpoint a file resides on?

You may either call the mount command and parse its output to find the longest common prefix with your path, or use the stat system call to get the device a file resides on and go up the tree until you get to a different device.

In Python, stat may be used as follows (untested and may have to be extended to handle symlinks and exotic stuff like union mounts):

def find_mount_point(path):
path = os.path.abspath(path)
orig_dev = os.stat(path).st_dev

while path != '/':
dir = os.path.dirname(path)
if os.stat(dir).st_dev != orig_dev:
# we crossed the device border
break
path = dir
return path

Edit: I didn't know about os.path.ismount until just now. This simplifies things greatly.

def find_mount_point(path):
path = os.path.abspath(path)
while not os.path.ismount(path):
path = os.path.dirname(path)
return path

Is it possible to get the mountpoint of a pendrive knowing its serialnumber using python?

To do that on Linux you will need to parse /proc/mounts to determine mapping of device names to mountpoints, i.e. /dev/sdc2 -> /var/run/media/myaut/hyperx.

The trick is to find out what device name has required serial number. Easiest approach to do so is to use udev - it uses serial when generates symlinks in /dev/disk/by-id:

/dev/disk/by-id/usb-Generic_Flash_Disk_12345678-0:0 -> ../../sdd

But we didn't seek for easiest solutions, are we? The trick is that udev rules may be altered, and sysfs (which come from kernel) is more reliable. I implemented a script that does that:

import os
import sys
import glob

SYS_USB_DEVICES = '/sys/bus/usb/devices'
SYS_BLOCK_DEVICES = '/sys/class/block'

try:
serial = sys.argv[1]
except IndexError:
print >> sys.stderr, "Usage: findflash.py SERIAL"
sys.exit(1)

# PASS 1 Find USB node with corresponding to serial

for usbid in os.listdir(SYS_USB_DEVICES):
usbserpath = os.path.join(SYS_USB_DEVICES, usbid, 'serial')
if not os.path.exists(usbserpath):
continue
with open(usbserpath) as f:
usb_serial = f.read().strip()

if serial == usb_serial:
# Found it!
break
else:
print >> sys.stderr, "Cannot find usb device with serial {0}".format(serial)
sys.exit(1)

# Find SCSI ids corresponding to this device
# I didn't check SYSFS documentation, but tested it on openSUSE 13.1
# The form of path is:
# <SUBDEVICE>/host<SCSI_HOST_ID>/target<SCSI_TARGET_ID>/<CTRL><CHANNEL>:<TGT>:<LUN>
# We need only basename

devs = glob.glob(os.path.join(SYS_USB_DEVICES, usbid,
'*/host*/target*/*:*:*:*'))

devs = map(os.path.basename, devs)

# PASS 2 - find mountpoints for devices with SCSI ids we discover earlier

# Parse mountpoint formatted as "/dev/... /path/to/mntpt ..."
def parse_mntpt(line):
dev, mntpt, _ = line.split(None, 2)
dev = os.path.basename(dev)
return dev, mntpt

mntpts = {}
with open('/proc/mounts') as f:
mntpts = dict(map(parse_mntpt, f.readlines()))

# List of ('scsi id', 'dev name', 'mnt pt (if exists)')
devlist = []

def create_dev(scsiid, devname):
global mntpts
devlist.append((scsiid, devname, mntpts.get(devname)))

for devname in os.listdir(SYS_BLOCK_DEVICES):
devpath = os.path.join(SYS_BLOCK_DEVICES, devname)
devlink = os.path.join(devpath, 'device')

# Node is "virtual", i.e. partition, ignore it
if not os.path.islink(devlink):
continue

scsiid = os.path.basename(os.readlink(devlink))
if scsiid not in devs:
continue

create_dev(scsiid, devname)

# Find partition names
parts = glob.glob(os.path.join(devpath, '*/partition'))

for partpath in parts:
partname = os.path.basename(os.path.dirname(partpath))
create_dev(scsiid, partname)

# END - print results
fmtstr = '{0:8} {1:5} {2}'
print fmtstr.format('SCSI ID', 'DEV', 'MOUNT POINT')
for scsiid, devname, mntpt in devlist:
print fmtstr.format(scsiid, devname, mntpt)

Here is example output:

$ python findflash.py 12345678
SCSI ID DEV MOUNT POINT
8:0:0:0 sdd None
8:0:0:0 sdd1 /var/run/media/myaut/Debian\040wheezy\04020140723-17:30
8:0:0:0 sdd2 None
8:0:0:0 sdd5 None
8:0:0:1 sr0 None

I can't say that on Windows that would be easy. I have a code (in C/WinAPI) that able to collect all disk devices from system, but it's logic is far away from filesystems representation, so I still didn't find a solution for that.

Complexity of Windows come from that:

  • There is set of functions like SetupDi* that allow you enumerate disk devices. Their names are come in PnP style, unrelated to volume names.
  • There is DOS-style API (i.e. working on level of A: and C:)
  • There is WinNT-style API that knows about volumes, and probably, mountpoints.

Of course linking that three layers is not obvious (there is approach to match partitions by their size/offset, but that is crazy). I'm still scared to implement it in my library :(

Give the mount point of a path

df takes the path as parameter, so something like this should be fairly robust;

df "$path" | tail -1 | awk '{ print $6 }'

Check if a directory is a mount point with python 2.7

There is an os.path.ismount(path).

Return True if pathname path is a mount point: a point in a file
system where a different file system has been mounted. The function
checks whether path‘s parent, path/.., is on a different device than
path, or whether path/.. and path point to the same i-node on the same
device — this should detect mount points for all Unix and POSIX
variants.

import os
os.path.ismount(dir_name) # returns boolean

You may also refer to implementation (if you're on POSIX system). Check macpath.py or ntpath.py for other platforms.

In Python, how can I get the file system of a given file path

Here is a slightly modified version of a recipe found here.
os.path.realpath was added so symlinks are handled correctly.

import os
def getmount(path):
path = os.path.realpath(os.path.abspath(path))
while path != os.path.sep:
if os.path.ismount(path):
return path
path = os.path.abspath(os.path.join(path, os.pardir))
return path


Related Topics



Leave a reply



Submit