Index: trunk/packages/attach/attach =================================================================== --- trunk/packages/attach/attach (revision 53) +++ trunk/packages/attach/attach (revision 53) @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +import sys +import os +import getopt +import hesiod + +usage = """Usage: attach [options] filesystem ... [options] filesystem ... + attach -l filesystem + attach -H host + attach +""" + +if len(sys.argv) > 1 and sys.argv[1] == '-Padd': + os.execv('/usr/local/bin/attach-add.py', sys.argv[2:]) + +try: + optlist, args = getopt.getopt(sys.argv[1:], 'vqplvngazhrwm:Mxet:o:NSOLH', ['verbose', 'quiet', 'printpath', 'lookup', 'map', 'nomap', 'remap', 'noremap', 'zephyr', 'nozephyr', 'readonly', 'write', 'mountpoint=', 'master', 'noexplicit', 'explicit', 'type', 'mountoptions', 'nosetuid', 'nosuid', 'setuid', 'suid', 'override', 'lock', 'host=']); +except getopt.GetoptError: + sys.stderr.write(usage) + sys.exit(1) + +print_usage = False +noise_level = 'verbose' +for o, a in optlist: + if o == '-l' or o == '--lookup': + noise_level = 'lookup' + if o == '-v' or o == '--verbose': + noise_level = 'verbose' + if o == '-q' or o == '--quiet': + noise_level = 'quiet' + if o == '-p' or o == '--printpath': + noise_level = 'path' + if o == '-m' or o == '--mountpoint': + if a[0:5] == '/mit/': + sys.stderr.write('Sorry. The MacAthena attach program does not support alternate mount points within /mit\n') + sys.exit(1) + elif len(args) != 1: + print_usage = True + else: + filsys = hesiod.FilsysLookup(args[0]) + if filsys: + os.symlink(filsys.getFilsys()[0]['location'], a) + sys.exit(0) + else: + sys.stderr.write('%s: Locker unknown' % args[0]) + sys.exit(2) + if o == '-H' or o == '--host': + sys.stderr.write('Sorry. The MacAthena attach program does not keep an attachtab\n') + sys.exit(1) + +exit_code = 0 + +for arg in args: + try: + os.stat('/mit/%s' % arg) + os.system('/usr/bin/aklog /mit/%s' % arg) + except OSError: + sys.stderr.write('%s: Locker unknown\n' % arg) + exit_code = 2 + if noise_level == 'verbose': + filsys = hesiod.FilsysLookup(args[0]) + print 'attach: %s attached to /mit/%s for filesystem %s' % (filsys.getFilsys()[0]['location'], arg, arg) + elif noise_level == 'path': + print '/mit/%s' % arg + elif noise_level == 'lookup': + print '%s resolves to:' % arg + os.system('hesinfo %s filsys' % arg) + +sys.exit(exit_code) Index: trunk/packages/add/attach-add.py =================================================================== --- trunk/packages/add/attach-add.py (revision 53) +++ trunk/packages/add/attach-add.py (revision 53) @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +import os +import sys +import getopt + +usage = """Usage: add [-vfrpwbq] [-P $athena_path] [-a attachflags] [lockername ...] + add [-dfrb] [-P $athena_path] pathname ... +""" + +if '-a' in sys.argv[1:]: + (add_options, attach_options) = sys.argv[1:].split('-a') +else: + add_options = sys.argv[1:] + attach_options = [] + +try: + optlist, args = getopt.getopt(add_options, 'frwpP:abqh'); +except getopt.GetoptError: + sys.stderr.write(usage) + sys.exit(1) + +front = False +remove_locker = False +shell = 'csh' +for o, a in optlist: + if o == '-f': front = True + if o == '-r': remove_locker = True + if o == '-b': shell = 'bash' + +if os.environ.has_key('PATH'): + path = os.environ['PATH'].split(':') +else: path = [] + +if os.environ.has_key('MANPATH'): + manpath = os.environ['MANPATH'].split(':') +else: manpath = [] + +if os.environ.has_key('INFOPATH'): + infopath = os.environ['INFOPATH'].split(':') +else: infopath = [] + +for arg in args: + if '/' == arg[0] or '.' == arg[0]: + if remove_locker: path.remove(arg) + elif front: path = [arg] + path + else: path.append(arg) + else: + locker = '/mit/%s' % arg + + bin_pipe = os.popen('/usr/local/bin/athdir %s bin' % locker) + new_bin = bin_pipe.read().strip() + if bin_pipe.close() != None: + if not os.access(locker, os.F_OK): + sys.stderr.write("%s: Locker unknown\n" % arg) + continue + if new_bin in path: + path.remove(new_bin) + if front: path.insert(0, new_bin) + elif not remove_locker: path.append(new_bin) + + man_pipe = os.popen('/usr/local/bin/athdir %s man' % locker) + new_man = man_pipe.read().strip() + if man_pipe.close() == None: + if new_man in manpath: + manpath.remove(new_man) + if front: manpath.insert(0, new_man) + elif not remove_locker: manpath.append(new_man) + + info_pipe = os.popen('/usr/local/bin/athdir %s info' % locker) + new_info = info_pipe.read().strip() + if info_pipe.close() == None: + if new_info in infopath: + infopath.remove(new_info) + if front: infopath.insert(0, new_info) + elif not remove_locker: infopath.append(new_info) + +if shell == 'bash': + print 'PATH="%s"; export PATH; MANPATH="%s"; export MANPATH; INFOPATH="%s"; export INFOPATH' % (':'.join(path), ':'.join(manpath), ':'.join(infopath)) +elif shell == 'csh': + print 'setenv PATH "%s"; setenv MANPATH "%s"; setenv INFOPATH "%s"' % (':'.join(path), ':'.join(manpath), ':'.join(infopath)) Index: trunk/packages/pyhesiodfs/hesiod.py =================================================================== --- trunk/packages/pyhesiodfs/hesiod.py (revision 38) +++ trunk/packages/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/packages/pyhesiodfs/pyHesiodFS.py =================================================================== --- trunk/packages/pyhesiodfs/pyHesiodFS.py (revision 41) +++ trunk/packages/pyhesiodfs/pyHesiodFS.py (revision 41) @@ -0,0 +1,140 @@ +#!/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 +%(mountpoint)s/name. + +If you're using the Finder, try pressing Cmd+Shift+G and then entering +%(mountpoint)s/name""" + +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", "MIT") + 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(): + global hello_str + usage=""" +pyHesiodFS + +""" + Fuse.fusage + server = PyHesiodFS(version="%prog " + fuse.__version__, + usage=usage, + dash_s_do='setsingle') + + server.parse(errex=1) + hello_str = hello_str % {'mountpoint': server.parse(errex=1).mountpoint} + server.main() + +if __name__ == '__main__': + main() Index: trunk/packages/pyhesiodfs/configure.in =================================================================== --- trunk/packages/pyhesiodfs/configure.in (revision 39) +++ trunk/packages/pyhesiodfs/configure.in (revision 39) @@ -0,0 +1,5 @@ +AC_INIT() + +AC_PROG_CC + +AC_OUTPUT(edu.mit.sipb.mit-automounter.plist) Index: trunk/packages/pyhesiodfs/setup.py =================================================================== --- trunk/packages/pyhesiodfs/setup.py (revision 38) +++ trunk/packages/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',))]) Index: trunk/packages/pyhesiodfs/edu.mit.sipb.mit-automounter.plist.in =================================================================== --- trunk/packages/pyhesiodfs/edu.mit.sipb.mit-automounter.plist.in (revision 39) +++ trunk/packages/pyhesiodfs/edu.mit.sipb.mit-automounter.plist.in (revision 39) @@ -0,0 +1,20 @@ + + + + + Label + edu.mit.sipb.mit-automounter + OnDemand + + ProgramArguments + + @prefix@/bin/pyHesiodFS.py + -f + /mit + + RunAtLoad + + StandardErrorPath + @prefix@/var/log/mit-automounter.log + +