Index: trunk/pyHesiodFS/hesiod.py
===================================================================
--- trunk/pyHesiodFS/hesiod.py (revision 38)
+++ trunk/pyHesiodFS/hesiod.py (revision 38)
@@ -0,0 +1,61 @@
+import DNS
+
+DNS.DiscoverNameServers()
+
+dnsreq = DNS.Request(qtype="txt")
+
+class HesiodParseError(Exception):
+ pass
+
+class HesiodLookup:
+ """A generic Hesiod lookup"""
+ def __init__(self, name, type, realm="athena.mit.edu"):
+ if "@" in name:
+ name, realm = name.rsplit("@", 1)
+ self.dnsname = ("%s.%s.ns.%s" % (name, type, realm))
+ self.dnsresult = dnsreq.req(name=self.dnsname)
+ self.parseRecords()
+ def parseRecords(self):
+ self.entries = []
+ for answer in self.dnsresult.answers:
+ if answer['name'] == self.dnsname:
+ if isinstance(answer['data'],list):
+ self.entries.extend(answer['data'])
+ else:
+ self.entries.append(answer['data'])
+ def getRawEntries(self):
+ return self.entries
+
+class FilsysLookup(HesiodLookup):
+ def __init__(self, name, realm="athena.mit.edu"):
+ HesiodLookup.__init__(self, name, "filsys", realm)
+ def parseRecords(self):
+ HesiodLookup.parseRecords(self)
+ self.filsysPointers = []
+ if len(self.entries) > 1:
+ multiRecords = True
+ else:
+ multiRecords = False
+ for entry in self.entries:
+ priority = 0
+ if multiRecords:
+ entry, priority = entry.rsplit(" ", 1)
+ priority = int(priority)
+ parts = entry.split(" ")
+ type = parts[0]
+ if type == 'AFS':
+ self.filsysPointers.append({'type': type, 'location': parts[1], 'mode': parts[2], 'mountpoint': parts[3], 'priority': priority})
+ elif type == 'NFS':
+ self.filsysPointers.append({'type': type, 'remote_location': parts[1], 'server': parts[2], 'mode': parts[3], 'mountpoint': parts[4], 'priority': priority})
+ elif type == 'ERR':
+ parts = entry.split(" ", 1)
+ self.filsysPointers.append({'type': type, 'message': parts[1], 'priority': priority})
+ elif type == 'UFS':
+ self.filsysPointers.append({'type': type, 'device': parts[1], 'mode': parts[2], 'mountpoint': parts[3], 'priority': priority})
+ elif type == 'LOC':
+ self.filsysPointers.append({'type': type, 'location': parts[1], 'mode': parts[2], 'mountpoint': parts[3], 'priority': priority})
+ else:
+ raise HesiodParseError("Unknown filsys type: "+type)
+ self.filsysPointers.sort(key=lambda x: x['priority'])
+ def getFilsys(self):
+ return self.filsysPointers
Index: trunk/pyHesiodFS/edu.mit.sipb.mit-automounter.plist
===================================================================
--- trunk/pyHesiodFS/edu.mit.sipb.mit-automounter.plist (revision 38)
+++ trunk/pyHesiodFS/edu.mit.sipb.mit-automounter.plist (revision 38)
@@ -0,0 +1,20 @@
+
+
+
+
+ Label
+ edu.mit.sipb.mit-automounter
+ OnDemand
+
+ ProgramArguments
+
+ /usr/local/bin/pyHesiodFS.py
+ -f
+ /mit
+
+ RunAtLoad
+
+ StandardErrorPath
+ /var/log/mit-automounter.log
+
+
Index: trunk/pyHesiodFS/pyHesiodFS.py
===================================================================
--- trunk/pyHesiodFS/pyHesiodFS.py (revision 38)
+++ trunk/pyHesiodFS/pyHesiodFS.py (revision 38)
@@ -0,0 +1,134 @@
+#!/usr/bin/python2.5
+
+# pyHesiodFS:
+# Copyright (C) 2007 Quentin Smith
+# "Hello World" pyFUSE example:
+# Copyright (C) 2006 Andrew Straw
+#
+# This program can be distributed under the terms of the GNU LGPL.
+# See the file COPYING.
+#
+
+import sys, os, stat, errno
+import fuse
+from fuse import Fuse
+
+import hesiod
+
+if not hasattr(fuse, '__version__'):
+ raise RuntimeError, \
+ "your fuse-py doesn't know of fuse.__version__, probably it's too old."
+
+fuse.fuse_python_api = (0, 2)
+
+hello_path = '/README.txt'
+hello_str = 'This is the pyhesiodfs FUSE autmounter. To access a Hesiod filsys, just access %s/name.\n'
+
+class MyStat(fuse.Stat):
+ def __init__(self):
+ self.st_mode = 0
+ self.st_ino = 0
+ self.st_dev = 0
+ self.st_nlink = 0
+ self.st_uid = 0
+ self.st_gid = 0
+ self.st_size = 0
+ self.st_atime = 0
+ self.st_mtime = 0
+ self.st_ctime = 0
+
+class PyHesiodFS(Fuse):
+
+ def __init__(self, *args, **kwargs):
+ Fuse.__init__(self, *args, **kwargs)
+ self.fuse_args.add("allow_other", True)
+ self.fuse_args.add("noappledouble", True)
+ self.fuse_args.add("noapplexattr", True)
+ self.fuse_args.add("fsname", "pyHesiodFS")
+ self.fuse_args.add("volname", "pyHesiodFS automounter")
+ self.mounts = {}
+
+ def getattr(self, path):
+ st = MyStat()
+ if path == '/':
+ st.st_mode = stat.S_IFDIR | 0755
+ st.st_nlink = 2
+ elif path == hello_path:
+ st.st_mode = stat.S_IFREG | 0444
+ st.st_nlink = 1
+ st.st_size = len(hello_str)
+ elif '/' not in path[1:]:
+ if self.findLocker(path[1:]):
+ st.st_mode = stat.S_IFLNK | 0777
+ st.st_nlink = 1
+ st.st_size = len(self.findLocker(path[1:]))
+ else:
+ return -errno.ENOENT
+ else:
+ return -errno.ENOENT
+ return st
+
+ def getCachedLockers(self):
+ return self.mounts.keys()
+
+ def findLocker(self, name):
+ """Lookup a locker in hesiod and return its path"""
+ if name in self.mounts:
+ return self.mounts[name]
+ else:
+ filsys = hesiod.FilsysLookup(name)
+ # FIXME check if the first locker is valid
+ if len(filsys.getFilsys()) >= 1:
+ pointers = filsys.getFilsys()
+ pointer = pointers[0]
+ if pointer['type'] != 'AFS' and pointer['type'] != 'LOC':
+ print >>sys.stderr, "Unknown locker type "+pointer.type+" for locker "+name+" ("+repr(pointer)+" )"
+ return None
+ else:
+ self.mounts[name] = pointer['location']
+ print >>sys.stderr, "Mounting "+name+" on "+pointer['location']
+ return pointer['location']
+ else:
+ print >>sys.stderr, "Couldn't find filsys for "+name
+ return None
+
+ def readdir(self, path, offset):
+ for r in ['.', '..', hello_path[1:]]+self.getCachedLockers():
+ yield fuse.Direntry(r)
+
+ def readlink(self, path):
+ return self.findLocker(path[1:])
+
+ def open(self, path, flags):
+ if path != hello_path:
+ return -errno.ENOENT
+ accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
+ if (flags & accmode) != os.O_RDONLY:
+ return -errno.EACCES
+
+ def read(self, path, size, offset):
+ if path != hello_path:
+ return -errno.ENOENT
+ slen = len(hello_str)
+ if offset < slen:
+ if offset + size > slen:
+ size = slen - offset
+ buf = hello_str[offset:offset+size]
+ else:
+ buf = ''
+ return buf
+
+def main():
+ usage="""
+Userspace hello example
+
+""" + Fuse.fusage
+ server = PyHesiodFS(version="%prog " + fuse.__version__,
+ usage=usage,
+ dash_s_do='setsingle')
+
+ server.parse(errex=1)
+ server.main()
+
+if __name__ == '__main__':
+ main()
Index: trunk/pyHesiodFS/MANIFEST
===================================================================
--- trunk/pyHesiodFS/MANIFEST (revision 38)
+++ trunk/pyHesiodFS/MANIFEST (revision 38)
@@ -0,0 +1,3 @@
+hesiod.py
+pyHesiodFS.py
+setup.py
Index: trunk/pyHesiodFS/setup.py
===================================================================
--- trunk/pyHesiodFS/setup.py (revision 38)
+++ trunk/pyHesiodFS/setup.py (revision 38)
@@ -0,0 +1,8 @@
+from distutils.core import setup
+setup(name='pyHesiodFS',
+ version='1.0',
+ author='Quentin Smith',
+ author_email='pyhesiodfs@mit.edu',
+ py_modules=['hesiod'],
+ scripts=['pyHesiodFS.py'],
+ data_files=[('/Library/LaunchDaemons', ('edu.mit.sipb.mit-automounter.plist',))])