#!/usr/local/bin/python

# Copyright C 2002-2004 by Isilon Systems, Inc. All rights not expressly
# granted herein are reserved.
# Created in the United States of America.
# 
# This digital media is protected by U.S. and international copyright and
# intellectual property laws. Unless otherwise specified, all information
# and screens appearing as part of this digital medium, including
# software, services, documents, text, images, icons, and logos design;
# the selection, assembly, arrangement, and design thereof; and the code
# that enables its presentation, are the sole property of Isilon Systems,
# Inc.
# 
# Except as otherwise required by applicable law, no part of any
# copyrighted material may be reproduced, modified, translated,
# distributed, published, or transmitted by any means, electronic or
# mechanical, for any purpose, without the prior written consent of Isilon
# Systems. 
#  
# Isilon and Isilon Systems are registered trademarks of Isilon Systems,
# Inc.  Legion is a trademark of Isilon Systems, Inc.  All other
# trademarks and registered trademarks are the property of their
# respective holders.

import getopt
import re
import sys
import isi.misc as misc
import isi.hw.imdd.devices as devices
import isi.hw.imdd.log as imddlog
import isi.hw.imdd.util as imddutil
import isi.hw.imdd.report as imddreport

imdds = []
unclaimed_parts = []
uninit_drives = []
uninit_slices = []

def usage():
    print >> sys.stderr, "usage: isi_imdd_status [-ah] [-d device]",
    print >> sys.stderr, "[-l disk]"
    print >> sys.stderr, ""
    print >> sys.stderr, "   -a: print status on all drives. Otherwise, only",
    print >> sys.stderr, "print status"
    print >> sys.stderr, "       on drives which are used by isi_drive_d"
    print >> sys.stderr, "   -d: print status of a specified imdd",
    print >> sys.stderr, "device(imdd0, imdd1...)."
    print >> sys.stderr, "   -l: print imdd partitions of a specified",
    print >> sys.stderr, "disk(twed0, da5...)."
    print >> sys.stderr, "   -h: help"
    sys.exit(0)

def print_detail_status(partition):
    print "%-13s:" % devices.device_strip(partition),

    part_c = partition[:partition.find('s1')] + 's1'
    cinfo = "[c:no_disklabel]"
    lines = imddutil.dd_popen("/sbin/disklabel -Ar " + part_c)
    if lines is not None:
        c_imdd_info = ""
        uuidre = re.compile(r"^imdd_uuid:\s+(0x\d+)")
        diskuidre = re.compile(r"^imdd_diskuid:\s+(\d+)")
        for line in lines:
            m = uuidre.match(line)
            if m != None:
                uuid, = m.groups()
                c_imdd_info += uuid
                continue
            m = diskuidre.match(line)
            if (m != None):
                diskuid, = m.groups()
                c_imdd_info += "," + diskuid
                continue
        if c_imdd_info:
            cinfo = "[c:" + c_imdd_info + "]"
        else:
            cinfo = "[c:no_imdd_info]"    
        
    lines = imddutil.dd_popen("/sbin/disklabel -Ar " + partition)
    if (lines == None):
        print "[failed to get disklabel] " + cinfo
        return
    
    flagsre = re.compile(r"^imddflags:\s(.*)")
    tstampre = re.compile(r"^imddtimestamp:\s+(\d+)")
    uuidre = re.compile(r"^imdd_uuid:\s+(0x\d+)")
    diskuidre = re.compile(r"^imdd_diskuid:\s+(\d+)")

    no_imdd_info = True
    for line in lines:
        m = flagsre.match(line)
        if (m != None):
            no_imdd_info = False
            flags, = m.groups()
            print flags + " :",
            continue
        m = tstampre.match(line)
        if (m != None):
            no_imdd_info = False
            tstamp, = m.groups()
            print tstamp + ",",
            continue
        m = uuidre.match(line)
        if (m != None):
            no_imdd_info = False
            uuid, = m.groups()
            print uuid + ",",
            continue
        m = diskuidre.match(line)
        if (m != None):
            no_imdd_info = False
            diskuid, = m.groups()
            print diskuid,
            continue
    if no_imdd_info: print " none  #0x0 :          0, 0x0, 0 " + cinfo
    else: print cinfo

class Imdd:
        def __init__(self, device):
            self.device = device
            self.partitions = []

        def append(self, part):
            self.partitions.append(part)
            
        def claimed(self, part):
            for p in self.partitions:
                if p == part:
                    return True
            return False
            
        def print_status(self, detail = True):
            print self.device + '\t\t',
            for partition in self.partitions:
                print partition + " ",
            print ''

            if detail:
                for partition in self.partitions:
                    print_detail_status(partition)
                print ''    

def claimed(part):
    for imdd in imdds:
        if imdd.claimed(part): return True
    return False
    
def probe(probe_all_disks):
    
    lines = imddutil.dd_popen("isi_imdd_config -i | tail +2")
    if (lines == None):
        print "Failed to get IMDD status"
        sys.exit(0)

    for line in lines:
        line = line.split()
        imdd = Imdd(line[0])
        for part in line[1:]:
            imdd.append(part)

        imdds.append(imdd)

    drives = {}
    if probe_all_disks:
        for d in misc.hd_drives():
            drives["/dev/%s" % d[0]] = d[1]

        lines = imddutil.dd_popen("/sbin/sysctl kern.disks")
        if (lines and len(lines) == 1):
            for disk in lines[0].split()[1:]:
                disk = "/dev/" + disk
                if drives.has_key(disk): continue
                drives[disk] = 1
    else:
        devices.get_disks(drives)

    for drive in drives.keys():
        status = devices.imdd_drive_status(drive)
        if (status != devices.IMDD_DRIVE_VALID):
            if (status == devices.IMDD_DRIVE_NO_INIT):
                uninit_drives.append(drive)    
            continue

        parts = devices.drive2parts(drive)
        if parts == None:
            uninit_slices.append(drive + "s1")
            continue
        
        for part in parts:
            if not claimed(part):
                unclaimed_parts.append(part)
            
if __name__ == "__main__":
    try:
        opts, args = getopt.getopt(sys.argv[1:], "ahd:l:", "")
    except:
        usage()
        
    if (not len(args) == 0):
        usage()

    imddlog.log_start(log_cons=False)
    imddreport.disable_report()

    dev = None
    probe_all_disks = False
    for opt in opts:
        if opt[0] == '-h':
            usage()
        elif opt[0] == '-d':
            dev = opt[1]
        elif opt[0] == '-a':
            probe_all_disks = True
        elif opt[0] == '-l':
            drive = "/dev/" + opt[1]
            if not devices.device_present(drive):
                print 'Invalid disk'
                sys.exit(6)
            parts = devices.drive2parts(drive)
            if parts is not None:
                for part in parts:
                    print_detail_status(part)
            sys.exit(0)

    probe(probe_all_disks)
    for imdd in imdds:
        if dev and not dev == imdd.device: continue
        imdd.print_status()

    if len(unclaimed_parts) > 0:
        print 'Unclaimed by IMDD:'
        for part in unclaimed_parts:  print_detail_status(part)
        print ''

    if len(uninit_slices) > 0:
        print 'Slices without labels:'
        for s in uninit_slices:  print s
        print ''

    if len(uninit_drives) > 0:
        print 'Drives without MBR:'
        for d in uninit_drives:  print d
        print ''

