diff --git a/.gitignore b/.gitignore
index c4be61019c5532dbfcd3666da29931d50c4a1da6..7206da09056b4ff6434406dd39a8dec6010273e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ bin/
 lib/
 share/
 local/
+config.toml
diff --git a/config.example.toml b/config.example.toml
index 4d15a1237fb2a449e67d7f31bd83d4f016ee2660..d57f31d94f5f6eb5337f62a57ccab3a26cb27586 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -2,6 +2,7 @@
 [[volume]]
     volume_group = "exports"
     name = "pub"
+    path = ".snapshots"
 
     [[volume.keep]]
         number   = 24
diff --git a/lvmsnapshot.py b/lvmsnapshot.py
index 74d3dc941ae8a42bd4d2cb73ebb4609cf65a58e5..87765064a0d4de16fe1ae95121c300d8277eccd3 100644
--- a/lvmsnapshot.py
+++ b/lvmsnapshot.py
@@ -31,17 +31,56 @@ import json
 from contextlib import contextmanager
 from collections import OrderedDict
 
-SNAPSHOT_BASE_DIR = "/snapshots"
-TIMESTAMP_FORMAT = "%Y-%m-%d-%H-%M"
-PERIOD_KEYS = OrderedDict([
-    ("y", 365 * 86400),
-    ("m",  31 * 86400),
-    ("d",       86400),
-    ("H",        3600),
-    ("M",          60),
-])
+class Config:
+    snapshot_base_dir = "/snapshots"
+    timestamp_format = "%Y-%m-%d-%H-%M"
+    period_keys = OrderedDict([
+        ("y", 365 * 86400),
+        ("m",  31 * 86400),
+        ("d",       86400),
+        ("H",        3600),
+        ("M",          60),
+    ])
+    min_interval = None
+    volumes = {}
+    periods = {}
+
+    @staticmethod
+    def load():
+        import toml
+        config_path = "config.toml"
+        global_config_path = "/etc/lvm-snapshot.toml"
+        ENV_VAR = "LVM_SNAPSHOT_CONFIG"
+        if not os.path.isfile(config_path) and os.path.isfile(global_config_path):
+            config_path = global_config_path
+        if ENV_VAR in os.environ:
+            config_path = os.environ[ENV_VAR]
+        with open(config_path, "r") as config_file:
+            return toml.load(config_file)
+
+    @staticmethod
+    def parse(config):
+        periods = {}
+        min_interval = None
+        for volume_conf in config["volume"]:
+            name = volume_conf["name"]
+            volume_group = volume_conf["volume_group"]
+            path = volume_conf.get("path")
+            volume = Volume(volume_group, name, path)
+            Config.volumes[volume.get_full_name()] = volume
+            periods[volume] = []
+            for raw_period in volume_conf["keep"]:
+                interval = Period.parse_interval(raw_period["interval"])
+                if min_interval is None or interval < min_interval:
+                    min_interval = interval
+                number = int(raw_period["number"])
+                periods[volume].append(
+                    Period(target_number=number, interval=interval))
+        Config.min_interval = min_interval
+        Config.periods = periods
 
 def run_process(command, check=True):
+    logging.debug("running command {}".format(command))
     result = sp.run(command, check=check, stdout=sp.PIPE, stderr=sp.PIPE)
     if result.stdout:
         logging.info(result.stdout.decode("utf-8").strip())
@@ -64,12 +103,20 @@ def freeze_xfs(mountpoint, freeze):
     run_process(command, check=True)
 
 class Volume:
-    def __init__(self, volume_group, name):
+    def __init__(self, volume_group, name, snapshot_dir=None):
         self.volume_group = volume_group
         self.name = name
+        if snapshot_dir is None:
+            if self.get_full_name() in Config.volumes:
+                snapshot_dir = Config.volumes[self.get_full_name()].snapshot_dir
+            else:
+                snapshot_dir = os.path.join(Config.snapshot_base_dir, name)
+        if not os.path.isabs(snapshot_dir):
+            snapshot_dir = os.path.join(self.get_mountpoint(), snapshot_dir)
+        self.snapshot_dir = snapshot_dir
     
     def __repr__(self):
-            return self.get_full_name()
+        return self.get_full_name()
 
     def __eq__(self, other):
         return hash(self) == hash(other)
@@ -85,6 +132,7 @@ class Volume:
 
     def get_mountpoint(self):
         mapper_device = self.get_mapper_device()
+        logging.debug("searching volume mountpoint for {}".format(mapper_device))
         command = [
             "/bin/findmnt",
             "--source", mapper_device,
@@ -110,7 +158,7 @@ class Snapshot:
         return self.get_name()
 
     def get_timestamp_str(self):
-        return self.timestamp.strftime(TIMESTAMP_FORMAT)
+        return self.timestamp.strftime(Config.timestamp_format)
 
     def get_name(self):
         return "{}-snapshot-{}".format(
@@ -120,7 +168,7 @@ class Snapshot:
     @staticmethod
     def parse_name(name):
         parent_name, _, timestamp_str = name.split("-", 2)
-        timestamp = datetime.strptime(timestamp_str, TIMESTAMP_FORMAT)
+        timestamp = datetime.strptime(timestamp_str, Config.timestamp_format)
         return parent_name, timestamp
 
     def get_full_volume(self):
@@ -128,12 +176,30 @@ class Snapshot:
 
     def get_mountpoint(self):
         return os.path.join(
-            SNAPSHOT_BASE_DIR, self.parent_volume.name, self.get_timestamp_str()
+            self.parent_volume.snapshot_dir, self.get_timestamp_str()
         )
 
     def create_mountpoint(self):
+        logging.debug("creating mountpoint {}".format(self.get_mountpoint()))
         os.makedirs(self.get_mountpoint(), mode=0o755, exist_ok=True)
 
+    def find_mountpoint(self):
+        logging.debug("searching snapshot mountpoint for {}".format(self.get_name()))
+        command = [
+            "/bin/findmnt",
+            "--source", self.get_mapper_device(),
+            "--json",
+        ]
+        try:
+            result = sp.check_output(command).decode("utf-8")
+            data = json.loads(result)
+            filesystems = data["filesystems"]
+            if len(filesystems) < 1:
+                return None
+            return filesystems[0]["target"]
+        except sp.CalledProcessError:
+            return None
+
     def get_mapper_device(self):
         return "/dev/mapper/{}-{}".format(
             self.parent_volume.volume_group,
@@ -149,6 +215,7 @@ class Snapshot:
             self.get_mapper_device())
 
     def create(self):
+        logging.debug("creating snapshot {}".format(self.get_name()))
         parent_mountpoint = self.parent_volume.get_mountpoint()
         #with xfs_freeze(parent_mountpoint): # not necessary, lvm does this
         create_command = [
@@ -162,7 +229,9 @@ class Snapshot:
         self.mount()
 
     def mount(self):
+        logging.debug("mounting snapshot {}".format(self.get_name()))
         if self.check_mount():
+            logging.debug("already mounted")
             return
         activate_command = [
             "/sbin/lvchange",
@@ -193,6 +262,7 @@ class Snapshot:
             return False
 
     def remove(self):
+        logging.debug("removing snapshot {}".format(self.get_name()))
         self.unmount()
         remove_command = [
             "/sbin/lvremove",
@@ -201,12 +271,17 @@ class Snapshot:
         run_process(remove_command, check=True)
 
     def unmount(self):
-        if self.check_mount():
-            unmount_command = [
-                "/bin/umount",
-                self.get_mountpoint()
-            ]
-            run_process(unmount_command, check=True)
+        logging.debug("unmounting snapshot {}".format(self.get_name()))
+        mountpoint = self.find_mountpoint()
+        if mountpoint is not None:
+            if self.check_mount():
+                unmount_command = [
+                    "/bin/umount",
+                    mountpoint
+                ]
+                run_process(unmount_command, check=True)
+            if os.path.isdir(mountpoint):
+                os.rmdir(mountpoint)
         deactivate_command = [
             "/sbin/lvchange",
             "--activate", "n",
@@ -215,7 +290,6 @@ class Snapshot:
         ]
         run_process(deactivate_command, check=True)
         self.active = False
-        os.rmdir(self.get_mountpoint())
 
     @staticmethod
     def list_snapshots():
@@ -272,17 +346,14 @@ class Period:
         return datetime.now() - self.target_number * self.interval
     
     @staticmethod
-    def build_regex(period_keys=None):
-        if period_keys is None:
-            period_keys = PERIOD_KEYS
-        parts = [r"(?:(?P<{0}>\d+){0})?".format(key) for key in period_keys]
+    def build_regex():
+        parts = [r"(?:(?P<{0}>\d+){0})?".format(key) for key in Config.period_keys]
         return "".join(parts)
 
     @staticmethod
-    def parse_interval(text, period_keys=None):
-        if period_keys is None:
-            period_keys = PERIOD_KEYS
-        regex = Period.build_regex(period_keys)
+    def parse_interval(text):
+        period_keys = Config.period_keys
+        regex = Period.build_regex()
         match = re.fullmatch(regex, text)
         if match is None:
             raise Exception("Invalid interval config: '{}', "
@@ -294,36 +365,6 @@ class Period:
                 seconds += period_keys[key] * int(groups[key])
         return timedelta(seconds=seconds)
 
-def load_config():
-    import sys
-    import toml
-    config_path = "config.toml"
-    global_config_path = "/etc/lvm-snapshot.toml"
-    ENV_VAR = "LVM_SNAPSHOT_CONFIG"
-    if not os.path.isfile(config_path) and os.path.isfile(global_config_path):
-        config_path = global_config_path
-    if ENV_VAR in os.environ:
-        config_path = os.environ[ENV_VAR]
-    with open(config_path, "r") as config_file:
-        return toml.load(config_file)
-
-def parse_config(config):
-    periods = {}
-    min_interval = None
-    for volume_conf in config["volume"]:
-        name = volume_conf["name"]
-        volume_group = volume_conf["volume_group"]
-        volume = Volume(volume_group, name)
-        periods[volume] = []
-        for raw_period in volume_conf["keep"]:
-            interval = Period.parse_interval(raw_period["interval"])
-            if min_interval is None or interval < min_interval:
-                min_interval = interval
-            number = int(raw_period["number"])
-            periods[volume].append(
-                Period(target_number=number, interval=interval))
-    return periods, min_interval
-
 def mark_snapshots(snapshots, periods, min_interval):
     all_snapshots = set(snapshots)
     marked_snapshots = set()
@@ -342,29 +383,28 @@ def mark_snapshots(snapshots, periods, min_interval):
     unmarked_snapshots = all_snapshots - marked_snapshots
     return unmarked_snapshots
 
-def list_snapshots(**kwargs):
+def list_snapshots():
     snapshots = Snapshot.list_snapshots()
     for volume in snapshots:
         print("volume: {}".format(str(volume)))
         for snapshot in snapshots[volume]:
             print(" {}".format(str(snapshot)))
 
-def mount_snapshots(**kwargs):
+def mount_snapshots():
     snapshots = Snapshot.list_snapshots()
     for volume in snapshots:
         for snapshot in snapshots[volume]:
             snapshot.mount()
 
-def unmount_snapshots(**kwargs):
+def unmount_snapshots():
     snapshots = Snapshot.list_snapshots()
     for volume in snapshots:
         for snapshot in snapshots[volume]:
             snapshot.unmount()
 
 def update_snapshots():
-    config = load_config()
     snapshots = Snapshot.list_snapshots()
-    periods, min_interval = parse_config(config)
+    periods, min_interval = Config.periods, Config.min_interval
     for volume in set(periods.keys()) - set(snapshots.keys()):
         logging.warn("Warning: Volume {} is configured but does not exist or has no snapshots.".format(volume))
     for volume in set(snapshots.keys()) - set(periods.keys()):
@@ -372,8 +412,10 @@ def update_snapshots():
         snapshots.pop(volume)
     for volume in snapshots:
         unmarked_snapshots = mark_snapshots(snapshots[volume], periods[volume], min_interval)
+        logging.info("removing snapshots {}".format(unmarked_snapshots))
         for snapshot in unmarked_snapshots:
             snapshot.remove()
+        logging.info("creating new snapshot")
         new_snapshot = Snapshot(volume, datetime.now())
         new_snapshot.create()
 
@@ -386,14 +428,20 @@ operations = {
 
 def main():
     import argparse
-    parser = argparse.ArgumentParser()
-    parser.add_argument("command", help="list|update|mount|unmount")
-    parser.add_argument("--verbose", action="store_true", help="do not redirect the command output to /dev/null")
+    parser = argparse.ArgumentParser(description="Manage snapshots of thin LVM volumes")
+    parser.add_argument("command", choices=["list", "update", "mount", "unmount"], default="list")
+    parser.add_argument("--verbose", "-v", action="count", help="do not redirect the command output to /dev/null")
     args = parser.parse_args()
-    loglevel = logging.ERROR
-    if args.verbose:
-        loglevel = logging.INFO
+    loglevels = {
+        0: logging.ERROR,
+        1: logging.WARNING,
+        2: logging.INFO,
+        3: logging.DEBUG
+    }
+    loglevel = loglevels[min(3, max(0, args.verbose))]
     logging.basicConfig(level=loglevel)
+    Config.parse(Config.load())
+
     operations[args.command]()
     
 if __name__ == "__main__":