#!/usr/bin/python

from snack import *
import sys, getopt, string, socket, os, stat, tempfile

def Usage():
	print "tftptool 1.1 (C) 1999, 2000 Red Hat, Inc."
	print "Usage:"
	print "  %s [ -e MACADDR ] [ -h HOSTNAME ] [ -t TYPE ] [ -i IMAGENAME ]" % sys.argv[0]
	print "where:"
	print "MACADDR   is ethernet MAC address of the client in format"
	print "		 XX:XX:XX:XX:XX:XX where X is a hex digit. MAC"
	print "          usually starts with 08:00:20: for Sun computers"
	print "HOSTNAME  is either IP number of hostname of the client"
	print "TYPE      is one of SUN4, SUN4C, SUN4D, SUN4M, SUN4U"
	print "IMAGENAME is a filename (without path) of the image which"
	print "          should be served to the client. By default this"
	print "		 is either tftp32.img or tftp64.img"
	sys.exit(1)

def CheckMac(mac):
	if len(mac) != 17:
	    return 0
	for i in [ 0, 3, 6, 9, 12 ]:
	    if mac[i] in string.hexdigits and mac[i+1] in string.hexdigits and mac[i+2] == ':':
		continue
	    return 0
	if not mac[i] in string.hexdigits or not mac[i+1] in string.hexdigits:
	    return 0
	if mac[:9] == '08:00:20:':
	    return 2
	return 1

(options, args) = getopt.getopt(sys.argv[1:], "e:h:t:i:", ["eth=", "host=", "type=", "image="])

if args:
	Usage()

mac = None
host = None
type = None
imgname = None

for (option, value) in options:
    if option == '-e' or option == '--eth':
	if not CheckMac(value):
	    Usage()
	mac = value
    elif option == '-h' or option == '--host':
	host = value
    elif option == '-i' or option == '--image':
	imgname = value
    elif option == '-t' or option == '--type':
	type = string.lower(value)
	if type[:4] != 'sun4':
	    Usage()
	type = type[4:]
	if len(type) > 1 or len(type) and not (type[0] in 'cdmu'):
	    Usage()

screen = SnackScreen()

def checkCancel(ret):
    if ret == 'cancel':
	screen.finish()
	sys.exit(0)

screen.drawRootText (0, 0, "Red Hat TFTP tool for Sparc network boots (C) 1999 Red Hat, Inc.")
screen.pushHelpLine ("  <Tab>/<Alt-Tab> between elements   |  <Space> selects   |  <F12> next screen")

done = 0
if host and host != "":
    try:
	ip = socket.gethostbyname(host)
    except:
	pass
    else:
	if mac and CheckMac(mac):
	    done = 1

while not done:
    if not host:
	host = ""
    if not mac:
	mac = "08:00:20:"

    hoste = Entry(30, host)
    mace = Entry(30, mac)

    x = EntryWindow(screen, "Client machine",
		    "Please enter the hostname and Ethernet MAC address "
		    "of the SPARC client machine to be booted from this server.\n"
		    "Enter either a hostname or IP number.\n"
		    "Ethernet MAC address should be 6 pairs of hexadecimal digits "
		    "separated by `:'. Sun MAC addresses usually start with "
		    "08:00:20:",
		    [ ("Hostname", hoste), ("MAC address", mace) ])
    checkCancel(x[0])

    host = x[1][0]
    mac = x[1][1]
    try:
	ip = socket.gethostbyname(host)
    except:
	x = ButtonChoiceWindow(screen, "Could not resolve hostname",
			       "Hostname `%s' could not be resolved.\n"
			       "Either enter IP number if the host is not in DNS,"
			       "or check if the name is correct.\n"
			       "Would you like to try again?" % host)
	checkCancel(x)
	continue
    if not CheckMac(mac):
	x = ButtonChoiceWindow(screen, "Invalid MAC",
			       "MAC address `%s' is invalid.\n"
			       "Would you like to try again?" % mac)
	checkCancel(x)
	continue
    done = 1

if not type:
    x = ListboxChoiceWindow(screen, "Type of client machine",
			    "Please select the model or architecture "
			    "of the client machine", [
			    ( "sun4 architecture", "sun4" ),
			    ( "sun4c architecture", "sun4c" ),
			    ( "sun4m architecture", "sun4m" ),
			    ( "sun4d architecture", "sun4d" ),
			    ( "sun4u architecture", "sun4u" ),
			    ( "4/260", "sun4" ),
			    ( "4/110", "sun4" ),
			    ( "4/280", "sun4" ),
			    ( "4/150", "sun4" ),
			    ( "SPARCstation 1", "sun4c" ),
			    ( "SPARCserver 1", "sun4c" ),
			    ( "SPARCstation 330", "sun4" ),
			    ( "SPARCserver 330", "sun4" ),
			    ( "4/310", "sun4" ),
			    ( "4/350", "sun4" ),
			    ( "4/360", "sun4" ),
			    ( "SPARCstation 370", "sun4" ),
			    ( "SPARCserver 370", "sun4" ),
			    ( "4/380", "sun4c" ),
			    ( "SPARCserver 390", "sun4" ),
			    ( "SPARCstation 470", "sun4" ),
			    ( "SPARCserver 470", "sun4" ),
			    ( "SPARCserver 490", "sun4" ),
			    ( "SPARCstation SLC", "sun4c" ),
			    ( "SPARCstation IPC", "sun4c" ),
			    ( "SPARCstation 1+", "sun4c" ),
			    ( "SPARCserver 1+", "sun4c" ),
			    ( "SPARCstation SLC", "sun4c" ),
			    ( "SPARCstation 2", "sun4c" ),
			    ( "SPARCserver 2", "sun4c" ),
			    ( "SPARCstation ELC", "sun4c" ),
			    ( "SPARCstation IPX", "sun4c" ),
			    ( "SPARCengine 1", "sun4c" ),
			    ( "SPARCserver 630MP", "sun4m" ),
			    ( "SPARCserver 670MP", "sun4m" ),
			    ( "SPARCserver 690MP", "sun4m" ),
			    ( "SPARCclassic", "sun4m" ),
			    ( "SPARCclassic Server", "sun4m" ),
			    ( "SPARCstation LC", "sun4m" ),
			    ( "SPARCclassic X", "sun4m" ),
			    ( "SPARCstation LX/ZX", "sun4m" ),
			    ( "SPARCstation Voyager", "sun4m" ),
			    ( "SPARCstation 4", "sun4m" ),
			    ( "SPARCstation 5", "sun4m" ),
			    ( "SPARCstation 10", "sun4m" ),
			    ( "SPARCserver 10", "sun4m" ),
			    ( "SPARCcenter 2000", "sun4d" ),
			    ( "SPARCserver 1000", "sun4d" ),
			    ( "SPARCserver 20", "sun4m" ),
			    ( "SPARCserver 1000e", "sun4d" ),
			    ( "Ultra 1", "sun4u" ),
			    ( "Ultra 2", "sun4u" ),
			    ( "Ultra 5", "sun4u" ),
			    ( "Ultra 10", "sun4u" ),
			    ( "Ultra 30", "sun4u" ),
			    ( "Ultra 60", "sun4u" ),
			    ( "Ultra 80", "sun4u" ),
			    ( "Ultra AX", "sun4u" ),
			    ( "Ultra AXi", "sun4u" ),
			    ( "Sun Enterprise 2", "sun4u" ),
			    ( "Sun Enterprise Ultra 5S", "sun4u" ),
			    ( "Sun Enterprise Ultra 10S", "sun4u" ),
			    ( "Sun Enterprise 250", "sun4u" ),
			    ( "Sun Enterprise 450", "sun4u" ),
			    ( "Sun Enterprise 3000", "sun4u" ),
			    ( "Sun Enterprise 4000", "sun4u" ),
			    ( "Sun Enterprise 5000", "sun4u" ),
			    ( "Sun Enterprise 6000", "sun4u" ),
			    ( "Sun Enterprise 3500", "sun4u" ),
			    ( "Sun Enterprise 4500", "sun4u" ),
			    ( "Sun Enterprise 5500", "sun4u" ),
			    ( "Sun Enterprise 6500", "sun4u" ),
			    ( "Sun Enterprise 10000", "sun4u" )],
			    scroll = 1, height = screen.height - 18)
    checkCancel(x[0])

type = x[1]
ips = string.split(ip, '.')
iphex = "%02X%02X%02X%02X" % (string.atoi(ips[0]), string.atoi(ips[1]), string.atoi(ips[2]), string.atoi(ips[3]))
if type != 'sun4u':
    iphex = iphex + "." + string.upper(type)

maketftpboot = 0
copyfile = 0
enabletftp = 0

if type == 'sun4u':
    archsize = 64
else:
    archsize = 32
if not imgname:
    imgname = "tftp%d.img" % archsize

try:
    st = os.stat("/tftpboot")
except os.error:
    maketftpboot = 1
else:
    if not stat.S_ISDIR(st[stat.ST_MODE]):
	maketftpboot = 1

if maketftpboot:
    copyfile = 1
else:
    try:
	st = os.stat("/tftpboot/%s" % imgname)
    except:
	copyfile = 1

f = open ("/etc/inetd.conf", "r")
lines = f.readlines()
f.close()
for line in lines:
    words = string.split(line)
    if words[0] == "#tftp":
	enabletftp = 1
	break
    elif words[0] == "tftp":
	break

image = None
if copyfile:
    # First check if we're run from a known tree
    # where we can look for the image without
    # user intervention.
    try:
	cddir = os.path.dirname(sys.argv[0])
        st = os.stat(cddir + "/../RedHat")
	f = open(cddir + "/../images/%s" % imgname, "r")
	image = f.read()
	f.close()
    except:
	image = None

    while not image:
	x = ButtonChoiceWindow(screen, "%s required" % imgname,
			       "The %s image is needed to boot the client machine.\n"
			       "You can install it from your Red Hat Linux/SPARC CD-ROM, "
			       "from another location on the filesytem, or cancel."
			       % imgname, buttons = [ "CD", "Filesystem", "Cancel" ])
	checkCancel(x)
	if x == 'cd':
	    ButtonChoiceWindow(screen, "Insert CD-ROM",
			       "Please insert your Red Hat Linux/SPARC CD-ROM.", [ "Ok" ])

	    for i in range(10):
	        dir = tempfile.mktemp("tftp-cdmnt")
	        try:
		    os.mkdir (dir, 0755)
		except:
		    dir = None
		    continue
		else:
		    break
	    if dir:
		childpid = os.fork()
		if not childpid:
		    fd = os.open("/dev/null", os.O_RDWR)
		    os.dup2(fd, 1)
		    os.dup2(fd, 2)
		    os.close(fd)
		    os.execv("/bin/mount", [ "mount", "-t", "iso9660", "/dev/cdrom", dir ])
		(pid, status) = os.waitpid(childpid, 0)
		if status:
		    try:
			os.rmdir (dir)
		    except:
			pass
		    dir = None
	    if not dir:
		ButtonChoiceWindow(screen, "Error",
				   "Could not mount the CD-ROM", [ "Ok" ])
	    else:
		try:
		    f = open(dir + "/images/%s" % imgname, "r")
		    image = f.read()
		    f.close()
		except:
		    ButtonChoiceWindow(screen, "Error",
				       "Could not find /images/%s on the CD-ROM. "
				       "Make sure you inserted a correct media.", [ "Ok" ])
		os.system("/bin/umount %s" % dir)
		os.rmdir(dir)
	else:
	    x = EntryWindow(screen, "Enter path to %s" % imgname,
			    "Please enter the path where %s can be found." % imgname,
			    [ "Path" ], buttons = [ "Ok" ], entryWidth = 35)
	    dir = x[1][0]
	    try:
		f = open(dir + "/%s" % imgname, "r")
		image = f.read()
		f.close()
	    except:
		ButtonChoiceWindow(screen, "Error",
				   "Could not find or read %s/%s." % (dir, imgname), [ "Ok" ])

maketftpboota = ""
if maketftpboot:
    maketftpboota = "Create /tftpboot directory\n"
copyfilea = ""
if copyfile:
    copyfilea = "Create /tftpboot/%s image\n" % imgname
enabletftpa = ""
if enabletftp:
    enabletftpa = "Enable tftp service in /etc/inetd.conf and restart inetd\n"
x = ButtonChoiceWindow(screen, "About to setup tftp booting",
		       "Would you like to:\n"
		       "%s%s%sCreate symlink /tftpboot/%s -> %s\n"
		       "Update rarp and permanent arp tables for the client." %
		       (maketftpboota, copyfilea, enabletftpa, iphex, imgname))
checkCancel(x)

if maketftpboot:
    try:
	os.mkdir("/tftpboot")
    except:
	ButtonChoiceWindow(screen, "Error",
			   "Could not create /tftpboot directory", [ "Ok" ])
	screen.finish()
	sys.exit(1)

if copyfile:
    try:
	f = open("/tftpboot/%s" % imgname, "w")
	f.write(image)
	f.close()
    except:
	ButtonChoiceWindow(screen, "Error",
			   "Could not create or write /tftpboot/%s file" % imgname, [ "Ok" ])
	screen.finish()
	sys.exit(1)

if enabletftp:
    try:
	f = open("/etc/inetd.conf", "r")
	g = open("/etc/inetd.conf-", "w")
	lines = f.readlines()
	f.close()
	for line in lines:
	    words = line.split()
	    if words[0] == "#tftp" and words[6] == "in.tftpd":
		ind = string.find(line, "#tftp") + 1
		line = line[ind:]
	    g.write(line)
	g.close()
    except:
	ButtonChoiceWindow(screen, "Error",
			   "Could not update /etc/inetd.conf", [ "Ok" ])
	screen.finish()
	sys.exit(1)
    else:
	os.system("/usr/bin/killall -1 inetd")

try:
    os.remove("/tftpboot/" + iphex)
except:
    pass
try:
    os.symlink(imgname, "/tftpboot/" + iphex)
except:
    ButtonChoiceWindow(screen, "Error",
		       "Could not create symlink /tftpboot/%s -> %s" % (iphex, imgname), [ "Ok" ])
    screen.finish()
    sys.exit(1)

if os.system("/sbin/rarp -s %s %s" % (ip, mac)) or os.system("/sbin/arp -s %s %s" % (ip, mac)):
    ButtonChoiceWindow(screen, "Error",
		       "Could not update rarp and arp tables for %s %s" % (ip, mac), [ "Ok" ])
    screen.finish()
    sys.exit(1)

ButtonChoiceWindow(screen, "Success",
		   "You can now boot your client SPARC machine from this server.\n"
		   "Type either `boot net' or `b le()' on the PROM command line "
		   "depending on your PROM version.", [ "Ok" ])

screen.finish()
sys.exit(0)
