Skip to content

Instantly share code, notes, and snippets.

@kotnik
Created April 4, 2013 14:48
Show Gist options
  • Save kotnik/5310987 to your computer and use it in GitHub Desktop.
Save kotnik/5310987 to your computer and use it in GitHub Desktop.
Monitors changes in mounts (/proc/mounts file).
import re
import logging
from collections import OrderedDict
import gevent
log = logging.getLogger(__name__)
logging.basicConfig(
format="%(asctime)s %(name)s %(levelname)s %(message)s",
level=logging.INFO
)
# Checking frequency in seconds.
frequency = 0.1
def get_current_mounts():
""" Get the currently mounted filesystems.
Reading from /proc/mounts is only consistent within a single read(3) call.
Unfortuately, the maximum amount of data you can get from this file in a
single call is hardcoded by the kernel to PAGE_SIZE (4096 bytes on x86). As
a consequence, there is no way to read from this file in a consistent
manner.
As a (arguably ugly) workaround, we read from /proc/mounts until we get two
reads in a row that are consistent with each other.
We also acquire the volume lock, so that at least we are not trying to run
mount/umount concurrently with reading /proc/mounts.
"""
previous_data = None
data = None
while True:
with open("/proc/mounts", "rb") as f:
data = f.read()
if data == previous_data:
break
else:
previous_data = data
mounts = OrderedDict()
for line in data.split("\n"):
line = line.strip()
if len(line) == 0:
continue
info = {}
cols = re.split("\s+", line)
info["source"] = cols[0].rstrip("/")
info["mount-point"] = cols[1]
info["fs-type"] = cols[2]
info["options"] = cols[3]
info["dump"] = cols[4]
info["pass"] = cols[5]
mounts[info["mount-point"]] = info
return mounts
previous = OrderedDict()
def monitor():
global previous
while True:
current = get_current_mounts()
for path, info in current.iteritems():
if path not in previous:
log.info("mount: %s", path)
else:
if info["options"] != previous[path]["options"]:
log.info(
"options: %s -> %s",
previous[path]["options"],
info["options"]
)
for path, info in previous.iteritems():
if path not in current:
log.info("umount: %s", path)
previous = current
gevent.sleep(frequency)
g = gevent.spawn(monitor)
g.join()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment