-
Notifications
You must be signed in to change notification settings - Fork 39
/
fmount.py
executable file
·111 lines (95 loc) · 3.74 KB
/
fmount.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#! /usr/bin/env python3
import sys
import os
import argparse
import configparser
import subprocess
CONFIG = os.path.expanduser("~/.config/fmount.conf")
DEFAULT_MOUNTPATH = os.path.expanduser("~/mnt")
# we just strip spaces in the mntopts string
def reformat_mntopts(mntopts):
mntopts = mntopts.split(",")
options = []
for opt in mntopts:
options.append("=".join(tk.strip() for tk in opt.split("=")))
return ",".join(set(options))
def mount(name, mountpath, config):
mountpoint = os.path.join(mountpath, name)
host = config.get(name, "host", fallback=name)
path = config.get(name, "path", fallback="")
user = config.get(name, "user", fallback=None)
port = config.get(name, "port", fallback=None)
mntopts = config.get(name, "mntopts", fallback="")
mntopts = reformat_mntopts(mntopts)
uhd = host + ":" + path
if user:
uhd = user + "@" + uhd
cmd = ["sshfs", uhd, mountpoint]
if mntopts:
cmd += ["-o", mntopts]
if port:
cmd += ["-p", port]
print("Mounting at '{}'...".format(mountpoint))
# the mountpoint might exist after an error or automatic unmount
os.makedirs(mountpoint, exist_ok=True)
subprocess.run(cmd, check=True)
def umount(mntpoint):
if os.path.ismount(path):
cmd = ["fusermount3", "-u", mntpoint]
subprocess.run(cmd, check=True)
clean(mntpoint)
def clean(path):
if not os.path.ismount(path) and len(os.listdir(path)) == 0:
print("Removing empty mountpoint '{}'...".format(path))
os.rmdir(path)
def cleanAll(mountpath):
for file in os.listdir(mountpath):
path = os.path.join(mountpath, file)
if os.path.isdir(path):
clean(path)
def writeDefaultConfig():
cfile = open(CONFIG, mode="w", encoding="utf-8")
print("""\
# globals live in the DEFAULT section
[DEFAULT]
mountpath = {mountpath}
#mntopts = opt1=val1, opt2=val2, ... # optional
#[remote_name]
#host = ... # optional, equal to remote_name by default
#path = ... # optional, sshfs defaults to remote $HOME
#user = ... # optional, .ssh/config is honoured
#port = ... # optional, .ssh/config is honoured
#mntopts = opt1=val1, opt2=val2, ... # optional""".format(mountpath=DEFAULT_MOUNTPATH), file=cfile)
cfile.close()
if __name__ == "__main__":
config = configparser.ConfigParser()
if not os.path.exists(CONFIG):
writeDefaultConfig()
config.read(CONFIG)
parser = argparse.ArgumentParser(description="wrapper for sshfs with a config file")
parser.add_argument("-u", action="store_true", dest="umount", help="unmount given host or path")
parser.add_argument("host", nargs="+", help="remote name specified in the config file")
args = parser.parse_args()
mountpath = os.path.expanduser(config.get("DEFAULT", "mountpath", fallback=DEFAULT_MOUNTPATH))
if args.umount:
for host in args.host:
if os.path.isdir(host):
# not a host, but a path
path = host
else:
path = os.path.join(mountpath, host)
if not os.path.isdir(path):
print("Note: path '{}' does not exist.".format(path), file=sys.stderr)
if os.path.ismount(path):
umount(path)
elif os.path.isdir(path):
print("Note: path '{}' is not a mount point.".format(path), file=sys.stderr)
else:
for host in args.host:
if config.has_section(host):
if os.path.ismount(os.path.join(mountpath, host)):
parser.error("Host '{}' is already mounted.".format(host))
mount(host, mountpath, config)
else:
parser.error("Section '{}' does not exist in the config file.".format(host))
cleanAll(mountpath)