#!/usr/local/bin/python

import sys
import os
import string
import stat
import grp
import statvfs

def traverse(table_ent,level,file='.',priorpath=''):
	if priorpath[0:2] == '//':
		priorpath=priorpath[1:]
	stat_ok = 1
	try:
		# follow symlinks at the very first level, but no others.
		# I had this at 2 before when we were treating /data
		# as one monolithic "filesystem", but we're no longer
		# doing this
		if level < 1:
			s = os.stat(file)
		else:
			s = os.lstat(file)
	except:
		stat_ok = 0
	if stat_ok:
		# if not in a desired device, stop descending
		#if not devs.has_key(s[stat.ST_DEV]):
		#	return
		if stat.S_ISDIR(s[stat.ST_MODE]):
			# recurse
			os.chdir(file)
			files = os.listdir('.')
			files.sort()
			for filename in files:
				if filename <> '.' and filename <> '..':
					traverse(table_ent,level+1,filename,priorpath+file+'/')
			if file <> '.':
				# only backup a level, if we actually descended a level previously!
				# otherwise, we chmod something a level too high in the tree...
				os.chdir('..')
		elif stat.S_ISREG(s[stat.ST_MODE]):
			filename=priorpath+file
			group = s[stat.ST_GID]
			if table_ent.has_key(group):
				table_ent[group] += s[stat.ST_SIZE]
			else:
				table_ent[group] = s[stat.ST_SIZE]

def last_part(s):
	fields=string.splitfields(s,'/')
	return fields[-1:][0]

def pad(s):
	width=11
	return (string.strip(s)+' '*width)[:width]

def gigs(n):
	bytes=float(n)
	kilobytes=bytes/1024.0
	megabytes=kilobytes/1024.0
	gigabytes=megabytes/1024.0
	gig10=gigabytes*10.0
	gig10_int=int(gig10)
	gigabytes=float(gig10)/10.0
	#s = '%5.1f' % gigabytes
	#return s
	return gigabytes

def percent(numerator,denominator):
	quotient = float(numerator)/float(denominator)
	q1000 = float(int(quotient*1000))
	#return str(q1000/10.0)+'%'
	return q1000/10.0

def main():
	#dirs = ['/home','/ptmp','/data_mnt/gfs044','/data_mnt/gfs041','/data_mnt/gfs045','/datashare']
	dirs = ['/home','/ptmp','/ptmp2','/datashare', '/data']
	#dirs = ['/data_mnt/gfs045']
	#dirs = ['/home/esmf04m/strombrg/rm-me']
	#dirs = ['/ptmp']
	#dirs = ['/tmp']
	table={}
	for dir in dirs:
		table[dir] = {}
	for dir in dirs:
		os.chdir(dir)
		traverse(table[dir],0,dir)
	# build a sorted list of all groups across all dir hierarchies checked
	gid_dict={}
	for dir in dirs:
		for gid in table[dir].keys():
			try:
				group = grp.getgrgid(gid)[0]
			except:
				group = '#' + str(gid)
			gid_dict[group] = gid
	groups=gid_dict.keys()
	groups.sort()
	print 'Units are gigabytes.\n'
	sys.stdout.write(pad('group'))
	for dir in dirs:
		sys.stdout.write(pad(last_part(dir)))
	print
	total={}
	for dir in dirs:
		total[dir] = 0.0
	for group in groups:
		if group[:1] == '#':
			gid = string.atoi(group[1:])
		else:
			gid = gid_dict[group]
		sys.stdout.write(pad(group))
		for dir in dirs:
			if table[dir].has_key(gid):
				gb=gigs(table[dir][gid])
				total[dir] += gb
				sys.stdout.write(pad('%5.1f' % gb))
			else:
				sys.stdout.write(pad(''))
		print
	sys.stdout.write(pad('totals'))
	for dir in dirs:
		sys.stdout.write(pad(('%5.1f' % total[dir])))

	print '\n\n'
	sys.stdout.write(pad('group'))
	for dir in dirs:
		sys.stdout.write(pad(last_part(dir)))
	print
	fssize={}
	for dir in dirs:
		fsinfo=os.statvfs(dir)
		# there's some question as to which is better to use.
		# For esmf04m:/home with aix 5.1, they had the same value.
		# F_BSIZE: Preferred file system block size.
		# F_FRSIZE: Fundamental file system block size.
		fssize[dir] = fsinfo[statvfs.F_FRSIZE] * fsinfo[statvfs.F_BLOCKS]
	total={}
	for dir in dirs:
		total[dir] = 0.0
	for group in groups:
		if group[:1] == '#':
			gid = string.atoi(group[1:])
		else:
			gid = gid_dict[group]
		sys.stdout.write(pad(group))
		for dir in dirs:
			if table[dir].has_key(gid):
				per = percent(table[dir][gid],fssize[dir])
				total[dir] += per
				sys.stdout.write(pad(str(per)+'%'))
			else:
				sys.stdout.write(pad(''))
		print
	sys.stdout.write(pad('totals'))
	for dir in dirs:
		sys.stdout.write(pad(('%5.1f' % total[dir])+'%'))
	print '\n\nTotals may not add up due to rounding error, internal'
	print 'filesystem fragmentation and other filesystem overhead.'

main()

