#!/usr/bin/python
#
# automap2applemap
# This script converts sun-format NIS automount maps
# to the flat-file format required by Apple's automount program
#
# This script is distributed under the MIT LICENSE
#
# Copyright (c) 2004-2006 by Brian R. Chapados <chapados@sciencegeeks.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is furnished
# to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
###########################################################################

# imports
import sys
import os
import re
import getopt


class Usage(Exception):
    def __init__(self, msg):
        self.msg = msg

def main(argv=None):
    if argv is None:
        argv = sys.argv
    try:
        try:
            opts, args = getopt.getopt(argv[1:], "hm:e:", ["help","map=","exclude-file="])
            #print opts, args
        except getopt.error, msg:
             raise Usage(msg)
        # more code, unchanged
    except Usage, err:
        print >>sys.stderr, err.msg
        print >>sys.stderr, "for help use --help"
        return 2

    # default args
    excludefile = ""
    exclude_mounts = []
    for o, a in opts:
        if o in ("-m", "--map"):
            mapfile = a
        if o in ("-e", "--exclude-file"):
            excludefile = a
    for arg in args:
        map_node = arg
    if (args == []):
        map_node = mapfile.split(".")[1]

    # get mounts from automap file, read into a string
    mounts_fh = read_automap(mapfile)
    mount_points = mounts_fh.read()
    mounts_fh.close()

    # convert mount string to a list
    mount_list = mount_points.strip().split("\n")

    # get list of excluded mounts
    if excludefile:
        exclude_mounts = get_excludes(excludefile)

    # loop through mounts and process entries
    apple_mount_list = []
    for mount_entry in mount_list: 
        exclude_entry_p = 0
        (mount_target, mount_opts, mount_source) = parse_mount_entry(map_node, mount_entry)
        (mount_server, mount_source_path) = mount_source.split(":")
        # process excludes
        if (exclude_mounts != None):
            #print exclude_mounts
            for (exclude_type, exclude_value) in exclude_mounts:
                if (exclude_type == "server"):
                    if (exclude_value == mount_server):
                        exclude_entry_p = 1
                if (exclude_type == "dir"):
                    if (exclude_value in mount_source_path):
                        exclude_entry_p = 1

        if (exclude_entry_p == 0): 
            apple_mount_list.append("\t".join((mount_target, mount_opts, mount_source)))

    print "\n".join(apple_mount_list)
    return 0   

def get_excludes(exclude_file):
    # proces a file of mount points to exclude
    exclude_fh = open(exclude_file, 'r')
    exclude_string = exclude_fh.read().strip()
    exclude_fh.close()
    
    # excludes will be listed by: type, info
    # type can either be server, or mount_source
    exclude_list = exclude_string.split("\n")

    if (exclude_string == '' ):
        return None
    
    excludes = []
    for exclude_item in exclude_list:
        excludes.append(exclude_item.split('='))

    return excludes
        
def parse_mount_entry(mount_node, map_entry, default_opts="rw,intr,resvport,soft"):
    # parse 1 line of autofs map
    # return mount_target, mount_opts, mount_source

    mount_entry_list = map_entry.split()
    #mount_target = "/%s/%s" % (mount_node, mount_entry_list[0])
    mount_target = mount_entry_list[0]

    if ( len(mount_entry_list) == 3 ):
        mount_opts = default_opts
        existing_mount_opts = mount_entry_list[1].lstrip("-")
        for m_opt in existing_mount_opts.split(","):
            #print "proccessing opt=%s" % m_opt
            opt_match = re.search(m_opt, default_opts)
            if ( opt_match == None ):   
                mount_opts = "%s,%s" % (mount_opts,m_opt)
        mount_source = mount_entry_list[2]
    if ( len(mount_entry_list) == 2 ):
        mount_opts = default_opts
        mount_source = mount_entry_list[1]
 
    #print mount_entry_list
    #new_mount_target = "".join(mount_target.split("/")[2:])
    #new_mount_entry = "%s\t%s\t%s" % (mount_target, mount_opts, mount_source)
    return (mount_target, mount_opts, mount_source)

# function for calling ypcat and retreiving the mounts.byname NIS database
def read_automap(automap):
    exefile = "/usr/bin/ypcat -k"
    ypcat_command = "%s %s" % (exefile, automap)
    #print ypcat_command 
    # run command
    fh = os.popen(ypcat_command, "r")
    #print fh
    #fh.close()
    return fh 
## end of get_mountsbyname

if __name__ == "__main__":
    sys.exit(main())
