#!/usr/bin/env python

##
## This should be depricated by isi_diskinject -p.  If you need more, let's
## fix that instead.
##  Jonathan, 12/06
##

"""Kind of a sloppy, but useful script to calculate sector address from blocks
and v.v. This script makes some assumptions about the layout of the disk
(location of the 'e' slice, for example).

You can specify any number of sectors and blocks on the command line, along
with desired offsets, but ORDER MATTERS! All integer values may be specified in
any format recognized by int(value, 0). This includes hex, dec and oct values.

Non-verbose output is ordered: block sector offset cyl_offset

Verbose output is (currently) in the same order, but it's nicely labeled so who cares.

Example Usage:

# calcaddr.py -b16
16 0 2202360 16

# calcaddr.py -s2202360
16 0 2202360 16

# calcaddr.py -b16 -s2202360 -o1 -b0x10 -s 2202365 -s2202365 -b8023
16 0 2202360 16
16 0 2202360 16
16 1 2202361 16
16 5 2202365 16
16 5 2202365 16
8023 1 2330473 3927

# calcaddr.py -b16 -s2202360 -o1 -v -b0x10 -s 2202365 -x -s2202365 -b8023
16 0 2202360 16
16 0 2202360 16
Blk:           16 + Sect Off:    1 == Sect:         2202361 ; Cyl Off:   16
Blk:           16 + Sect Off:    5 == Sect:         2202365 ; Cyl Off:   16
Blk:         0x10 + Sect Off:  0x5 == Sect:        0x219afd ; Cyl Off: 0x0010
Blk:       0x1f57 + Sect Off:  0x1 == Sect:        0x238f69 ; Cyl Off: 0x0f57

"""

# If you don't like all the #end's in this code, just grep them out. I use them
# to help recover from messed up indentation after, for example, a
# cut-and-paste.
#
# grep -v ^[[:space:]]*#end

import sys
import getopt
import isi.sys.disk as disk

# **************************************************************************

class _data:
	efs_blk_size      = 8192
	cg_size           = 4096
	sector_size       = 512

	sectors_per_block = efs_blk_size / sector_size
#end class _data

# **************************************************************************

def usage(prog_name, exitval=None):
	"""usage: %s [options] [ -b N | -s N ] ... [ N ... ]

Integers may be in hex, octal or decimal formats.
options:
   -bBLOCK     convert from IFS block addr to disk sector
   -sSECTOR    convert from disk sector to IFS block addr
   -oOFFSET    sector offset into a block (default: 0)
   -x          return values in hex (default: off)
   -v          verbose output (default: off)

   -h          show this help message and exit

   See source for example usages.
"""
	print usage.__doc__ % prog_name

	if exitval != None:
		sys.exit(exitval)
	#end
#end usage()

# **************************************************************************

def get_e_part_offset(dname):
    """Returns the starting sector for the E partition."""

    offset = None
    try:
        offset = disk.ifs_partition_offset(dname)/512
    except:
	sys.stderr.write("No s1e partition on Disk\n")
	sys.exit(1)
    return offset 

#end get_e_part_start()

# **************************************************************************

def block2sect(block, offset, dname):
	"""Converts from an IFS block address to a disk sector address."""
	sector = get_e_part_offset(dname) + (block * _data.sectors_per_block) + offset
	cyl = block % 4096

	return { "block" : block, "sector" : sector, "cyl" : cyl, "offset" : offset }
#end block2sect()

# **************************************************************************

def sect2block(sector, offset, dname):
	"""Converts from a disk sector address to an IFS block address."""
	base_addr = sector - get_e_part_offset(dname)
	if base_addr < 0:
		sys.stderr.write("WARNING: Disk sector is not inside the 'e' slice\n")
	#end
	offset = base_addr % _data.sectors_per_block
	base_addr -= offset
	block = base_addr / _data.sectors_per_block
	cyl = block % 4096

	return { "block" : block, "sector" : sector, "cyl" : cyl, "offset" : offset }
#end sect2block()

# **************************************************************************

def main(prog_name, args):
	"""Who writes this crap?"""
	try:
		optlist, args = getopt.getopt(args, 'b:s:o:d:hvx')
	except getopt.GetoptError, msg:
		sys.stderr.write("Bad usage: %s\n\n" % msg)
		usage(prog_name, 1)
	#end

	offset  = 0
	verbose = 0
	hex_out = 0
	dname = None
	convert = { "-b" : block2sect, "-s" : sect2block }

	# This lame hack tries to catch uses which don't include any block or
	# sector addresses.
	ok_usage = 0

	# Format of the output
	out_format = [
		[ "%(block)i %(offset)i %(sector)i %(cyl)i",
		  "Blk: %(block)12i + Sect Off: %(offset)4i == Sect: %(sector)15i ; Cyl Off: %(cyl)4i"
		],
		[ "%(block)x %(offset)#x %(sector)#x %(cyl)#x",
		  "Blk: %(block)#12x + Sect Off: %(offset)#4x == Sect: %(sector)#15x ; Cyl Off: %(cyl)#06x"
		]
	]

	for o, a in optlist:
		if o in ("-d"):
			dname = a
	for o, a in optlist:
		if o in ("-b", "-s", "-o"):
			try:
				input = long(a, 0)
			except ValueError, msg:
				sys.stderr.write("Not a valid integer value: %s\n" % msg)
				sys.exit(1)
			#end

			if o in ("-b", "-s"):
				if not dname:
					sys.stderr.write("Disk name not specified\n")
					sys.exit(1)
				ok_usage = 1
				print out_format[hex_out][verbose] % convert[o](input, offset, dname)
			else: # o == "-o":
				offset = input
			#end
		elif o == "-x":
			hex_out = int(hex_out == 0)
		elif o == "-v":
			verbose = int(verbose == 0)
		elif o == "-h":
			usage(prog_name, 0)
		#end
	#end

	if not ok_usage:
		usage(prog_name, 1)
	#end
#end main()

# **************************************************************************

if __name__ == "__main__":
	main(sys.argv[0], sys.argv[1:])
#end
