Chris PeBenito 17de1b7
#!/usr/bin/python
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
#  Author(s): Donald Miner <dminer@tresys.com>
Chris PeBenito 17de1b7
#             Dave Sugar <dsugar@tresys.com>
Chris PeBenito 17de1b7
#             Brian Williams <bwilliams@tresys.com>
Chris PeBenito 56e1b3d
#             Caleb Case <ccase@tresys.com>
Chris PeBenito 17de1b7
#
Chris PeBenito 17de1b7
# Copyright (C) 2005 - 2006 Tresys Technology, LLC
Chris PeBenito 17de1b7
#      This program is free software; you can redistribute it and/or modify
Chris PeBenito 17de1b7
#      it under the terms of the GNU General Public License as published by
Chris PeBenito 17de1b7
#      the Free Software Foundation, version 2.
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
"""
Chris PeBenito 17de1b7
	This script generates XML documentation information for layers specified
Chris PeBenito 17de1b7
	by the user.
Chris PeBenito 17de1b7
"""
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
import sys
Chris PeBenito 17de1b7
import os
Chris PeBenito 17de1b7
import glob
Chris PeBenito 17de1b7
import re
Chris PeBenito 56e1b3d
import getopt
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
# GLOBALS
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
# Default values of command line arguments:
Chris PeBenito 17de1b7
warn = False
Chris PeBenito 17de1b7
meta = "metadata"
Chris PeBenito 17de1b7
third_party = "third-party"
Chris PeBenito 17de1b7
layers = {}
Chris PeBenito 17de1b7
tunable_files = []
Chris PeBenito 17de1b7
bool_files = []
Chris PeBenito 17de1b7
xml_tunable_files = []
Chris PeBenito 17de1b7
xml_bool_files = []
Chris PeBenito 17de1b7
output_dir = ""
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
# Pre compiled regular expressions:
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
# Matches either an interface or a template declaration. Will give the tuple:
Chris PeBenito 17de1b7
#	("interface" or "template", name)
Chris PeBenito 17de1b7
# Some examples:
Chris PeBenito 17de1b7
#	"interface(`kernel_read_system_state',`"
Chris PeBenito 17de1b7
#	 -> ("interface", "kernel_read_system_state")
Chris PeBenito 17de1b7
#	"template(`base_user_template',`"
Chris PeBenito 17de1b7
#	 -> ("template", "base_user_template")
Chris PeBenito 17de1b7
INTERFACE = re.compile("^\s*(interface|template)\(`(\w*)'")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
# Matches either a gen_bool or a gen_tunable statement. Will give the tuple:
Chris PeBenito 17de1b7
#	("tunable" or "bool", name, "true" or "false")
Chris PeBenito 17de1b7
# Some examples:
Chris PeBenito 17de1b7
#	"gen_bool(secure_mode, false)"
Chris PeBenito 17de1b7
#	 -> ("bool", "secure_mode", "false")
Chris PeBenito 17de1b7
#	"gen_tunable(allow_kerberos, false)"
Chris PeBenito 17de1b7
#	 -> ("tunable", "allow_kerberos", "false")
Chris PeBenito 17de1b7
BOOLEAN = re.compile("^\s*gen_(tunable|bool)\(\s*(\w*)\s*,\s*(true|false)\s*\)")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
# Matches a XML comment in the policy, which is defined as any line starting
Chris PeBenito 17de1b7
#  with two # and at least one character of white space. Will give the single
Chris PeBenito 17de1b7
#  valued tuple:
Chris PeBenito 17de1b7
#	("comment")
Chris PeBenito 17de1b7
# Some Examples:
Chris PeBenito 17de1b7
#	"## <summary>"
Chris PeBenito 17de1b7
#	 -> ("<summary>")
Chris PeBenito 17de1b7
#	"##		The domain allowed access.	"
Chris PeBenito 17de1b7
#	 -> ("The domain allowed access.")
Chris PeBenito 17de1b7
XML_COMMENT = re.compile("^##\s+(.*?)\s*$")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
# FUNCTIONS
Chris PeBenito 17de1b7
def getModuleXML(file_name):
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
	Returns the XML data for a module in a list, one line per list item.
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
Chris PeBenito 56e1b3d
	# Gather information.
Chris PeBenito 56e1b3d
	module_dir = os.path.dirname(file_name)
Chris PeBenito 56e1b3d
	module_name = os.path.basename(file_name)
Chris PeBenito 56e1b3d
	module_te = "%s/%s.te" % (module_dir, module_name)
Chris PeBenito 56e1b3d
	module_if = "%s/%s.if" % (module_dir, module_name)
Chris PeBenito 56e1b3d
Chris PeBenito 17de1b7
	# Try to open the file, if it cant, just ignore it.
Chris PeBenito 17de1b7
	try:
Chris PeBenito 56e1b3d
		module_file = open(module_if, "r")
Chris PeBenito 17de1b7
		module_code = module_file.readlines()
Chris PeBenito 17de1b7
		module_file.close()
Chris PeBenito 17de1b7
	except:
Chris PeBenito 17de1b7
		warning("cannot open file %s for read, skipping" % file_name)
Chris PeBenito 17de1b7
		return []
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	module_buf = []
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Infer the module name, which is the base of the file name.
Chris PeBenito 17de1b7
	module_buf.append("<module name=\"%s\" filename=\"%s\">\n" 
Chris PeBenito 56e1b3d
		% (os.path.splitext(os.path.split(file_name)[-1])[0], module_if))
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	temp_buf = []
Chris PeBenito 17de1b7
	interface = None
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# finding_header is a flag to denote whether we are still looking
Chris PeBenito 17de1b7
	#  for the XML documentation at the head of the file.
Chris PeBenito 17de1b7
	finding_header = True
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Get rid of whitespace at top of file
Chris PeBenito 17de1b7
	while(module_code and module_code[0].isspace()):
Chris PeBenito 17de1b7
		module_code = module_code[1:]
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Go line by line and figure out what to do with it.
Chris PeBenito 17de1b7
	line_num = 0
Chris PeBenito 17de1b7
	for line in module_code:
Chris PeBenito 17de1b7
		line_num += 1
Chris PeBenito 17de1b7
		if finding_header:
Chris PeBenito 17de1b7
			# If there is a XML comment, add it to the temp buffer.
Chris PeBenito 17de1b7
			comment = XML_COMMENT.match(line)
Chris PeBenito 17de1b7
			if comment:
Chris PeBenito 17de1b7
				temp_buf.append(comment.group(1) + "\n")
Chris PeBenito 17de1b7
				continue
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
			# Once a line that is not an XML comment is reached,
Chris PeBenito 17de1b7
			#  either put the XML out to module buffer as the
Chris PeBenito 17de1b7
			#  module's documentation, or attribute it to an
Chris PeBenito 17de1b7
			#  interface/template.
Chris PeBenito 17de1b7
			elif temp_buf:
Chris PeBenito 17de1b7
				finding_header = False
Chris PeBenito 17de1b7
				interface = INTERFACE.match(line)
Chris PeBenito 17de1b7
				if not interface:
Chris PeBenito 17de1b7
					module_buf += temp_buf
Chris PeBenito 17de1b7
					temp_buf = []
Chris PeBenito 17de1b7
					continue
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
		# Skip over empty lines
Chris PeBenito 17de1b7
		if line.isspace():
Chris PeBenito 17de1b7
			continue
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
		# Grab a comment and add it to the temprorary buffer, if it
Chris PeBenito 17de1b7
		#  is there.
Chris PeBenito 17de1b7
		comment = XML_COMMENT.match(line)
Chris PeBenito 17de1b7
		if comment:
Chris PeBenito 17de1b7
			temp_buf.append(comment.group(1) + "\n")
Chris PeBenito 17de1b7
			continue
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
		# Grab the interface information. This is only not true when
Chris PeBenito 17de1b7
		#  the interface is at the top of the file and there is no
Chris PeBenito 17de1b7
		#  documentation for the module.
Chris PeBenito 17de1b7
		if not interface:
Chris PeBenito 17de1b7
			interface = INTERFACE.match(line)
Chris PeBenito 17de1b7
		if interface:
Chris PeBenito 17de1b7
			# Add the opening tag for the interface/template
Chris PeBenito 17de1b7
			groups = interface.groups()
Chris PeBenito 17de1b7
			module_buf.append("<%s name=\"%s\" lineno=\"%s\">\n" % (groups[0], groups[1], line_num))
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
			# Add all the comments attributed to this interface to
Chris PeBenito 17de1b7
			#  the module buffer.
Chris PeBenito 17de1b7
			if temp_buf:
Chris PeBenito 17de1b7
				module_buf += temp_buf
Chris PeBenito 17de1b7
				temp_buf = []
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
			# Add default summaries and parameters so that the
Chris PeBenito 17de1b7
			#  DTD is happy.
Chris PeBenito 17de1b7
			else:
Chris PeBenito 17de1b7
				warning ("unable to find XML for %s %s()" % (groups[0], groups[1]))	
Chris PeBenito 17de1b7
				module_buf.append("<summary>\n")
Chris PeBenito 17de1b7
				module_buf.append("Summary is missing!\n")
Chris PeBenito 17de1b7
				module_buf.append("</summary>\n")
Chris PeBenito 17de1b7
				module_buf.append("<param name=\"?\">\n")
Chris PeBenito 17de1b7
				module_buf.append("<summary>\n")
Chris PeBenito 17de1b7
				module_buf.append("Parameter descriptions are missing!\n")
Chris PeBenito 17de1b7
				module_buf.append("</summary>\n")
Chris PeBenito 17de1b7
				module_buf.append("</param>\n")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
			# Close the interface/template tag.
Chris PeBenito 17de1b7
			module_buf.append("</%s>\n" % interface.group(1))
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
			interface = None
Chris PeBenito 17de1b7
			continue
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# If the file just had a header, add the comments to the module buffer.
Chris PeBenito 17de1b7
	if finding_header:
Chris PeBenito 17de1b7
		module_buf += temp_buf
Chris PeBenito 17de1b7
	# Otherwise there are some lingering XML comments at the bottom, warn
Chris PeBenito 17de1b7
	#  the user.
Chris PeBenito 17de1b7
	elif temp_buf:
Chris PeBenito 17de1b7
		warning("orphan XML comments at bottom of file %s" % file_name)
Chris PeBenito 17de1b7
Chris PeBenito 56e1b3d
	# Process the TE file if it exists.
Chris PeBenito 56e1b3d
	module_buf = module_buf + getTunableXML(module_te, "both")
Chris PeBenito 56e1b3d
Chris PeBenito 17de1b7
	module_buf.append("</module>\n")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	return module_buf
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
def getTunableXML(file_name, kind):
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
	Return all the XML for the tunables/bools in the file specified.
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Try to open the file, if it cant, just ignore it.
Chris PeBenito 17de1b7
	try:
Chris PeBenito 17de1b7
		tunable_file = open(file_name, "r")
Chris PeBenito 17de1b7
		tunable_code = tunable_file.readlines()
Chris PeBenito 17de1b7
		tunable_file.close()
Chris PeBenito 17de1b7
	except:
Chris PeBenito 17de1b7
		warning("cannot open file %s for read, skipping" % file_name)
Chris PeBenito 17de1b7
		return []
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	tunable_buf = []
Chris PeBenito 17de1b7
	temp_buf = []
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Find tunables and booleans line by line and use the comments above
Chris PeBenito 17de1b7
	# them.
Chris PeBenito 17de1b7
	for line in tunable_code:
Chris PeBenito 17de1b7
		# If it is an XML comment, add it to the buffer and go on.
Chris PeBenito 17de1b7
		comment = XML_COMMENT.match(line)
Chris PeBenito 17de1b7
		if comment:
Chris PeBenito 17de1b7
			temp_buf.append(comment.group(1) + "\n")
Chris PeBenito 17de1b7
			continue
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
		# Get the boolean/tunable data.
Chris PeBenito 17de1b7
		boolean = BOOLEAN.match(line)
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
		# If we reach a boolean/tunable declaration, attribute all XML
Chris PeBenito 17de1b7
		#  in the temp buffer to it and add XML to the tunable buffer.
Chris PeBenito 17de1b7
		if boolean:
Chris PeBenito 17de1b7
			# If there is a gen_bool in a tunable file or a
Chris PeBenito 17de1b7
			# gen_tunable in a boolean file, error and exit.
Chris PeBenito 56e1b3d
			# Skip if both kinds are valid.
Chris PeBenito 56e1b3d
			if kind != "both":
Chris PeBenito 56e1b3d
				if boolean.group(1) != kind:
Chris PeBenito 56e1b3d
					error("%s in a %s file." % (boolean.group(1), kind))
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
			tunable_buf.append("<%s name=\"%s\" dftval=\"%s\">\n" % boolean.groups())
Chris PeBenito 17de1b7
			tunable_buf += temp_buf
Chris PeBenito 17de1b7
			temp_buf = []
Chris PeBenito 17de1b7
			tunable_buf.append("</%s>\n" % boolean.group(1))
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# If there are XML comments at the end of the file, they arn't
Chris PeBenito 17de1b7
	# attributed to anything. These are ignored.
Chris PeBenito 17de1b7
	if len(temp_buf):
Chris PeBenito 17de1b7
		warning("orphan XML comments at bottom of file %s" % file_name)
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# If the caller requested a the global_tunables and global_booleans to be
Chris PeBenito 17de1b7
	# output to a file output them now
Chris PeBenito 17de1b7
	if len(output_dir) > 0:
Chris PeBenito 17de1b7
		xmlfile = os.path.split(file_name)[1] + ".xml"
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
		try:
Chris PeBenito 17de1b7
			xml_outfile = open(output_dir + "/" + xmlfile, "w")
Chris PeBenito 17de1b7
			for tunable_line in tunable_buf:
Chris PeBenito 17de1b7
				xml_outfile.write (tunable_line)
Chris PeBenito 17de1b7
			xml_outfile.close()
Chris PeBenito 17de1b7
		except:
Chris PeBenito 17de1b7
			warning ("cannot write to file %s, skipping creation" % xmlfile)
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	return tunable_buf
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
def getXMLFileContents (file_name):
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
	Return all the XML in the file specified.
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	tunable_buf = []
Chris PeBenito 17de1b7
	# Try to open the xml file for this type of file
Chris PeBenito 17de1b7
	# append the contents to the buffer.
Chris PeBenito 17de1b7
	try:
Chris PeBenito 17de1b7
		tunable_xml = open(file_name, "r")
Chris PeBenito 17de1b7
		tunable_buf += tunable_xml.readlines()
Chris PeBenito 17de1b7
		tunable_xml.close()
Chris PeBenito 17de1b7
	except:
Chris PeBenito 17de1b7
		warning("cannot open file %s for read, assuming no data" % file_name)
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	return tunable_buf
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
def getPolicyXML():
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
	Return the compelete reference policy XML documentation through a list,
Chris PeBenito 17de1b7
	one line per item.
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	policy_buf = []
Chris PeBenito 17de1b7
	policy_buf.append("<policy>\n")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Add to the XML each layer specified by the user.
Chris PeBenito 17de1b7
	for layer in layers.keys ():
Chris PeBenito 17de1b7
		policy_buf += getLayerXML(layer, layers[layer])
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Add to the XML each tunable file specified by the user.
Chris PeBenito 17de1b7
	for tunable_file in tunable_files:
Chris PeBenito 17de1b7
		policy_buf += getTunableXML(tunable_file, "tunable")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Add to the XML each XML tunable file specified by the user.
Chris PeBenito 17de1b7
	for tunable_file in xml_tunable_files:
Chris PeBenito 17de1b7
		policy_buf += getXMLFileContents (tunable_file)
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Add to the XML each bool file specified by the user.
Chris PeBenito 17de1b7
	for bool_file in bool_files:
Chris PeBenito 17de1b7
		policy_buf += getTunableXML(bool_file, "bool")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	# Add to the XML each XML bool file specified by the user.
Chris PeBenito 17de1b7
	for bool_file in xml_bool_files:
Chris PeBenito 17de1b7
		policy_buf += getXMLFileContents (bool_file)
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	policy_buf.append("</policy>\n")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	return policy_buf
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
def usage():
Chris PeBenito 17de1b7
	"""
Chris PeBenito 17de1b7
	Displays a message describing the proper usage of this script.
Chris PeBenito 17de1b7
	"""
Chris PeBenito 17de1b7
Chris PeBenito 56e1b3d
	sys.stdout.write("usage: %s [-w] [-mtb] <file>\n\n" % sys.argv[0])
Chris PeBenito 56e1b3d
	sys.stdout.write("-w --warn\t\t\tshow warnings\n"+\
Chris PeBenito 56e1b3d
	"-m --module <file>\t\tname of module to process\n"+\
Chris PeBenito 56e1b3d
	"-t --tunable <file>\t\tname of global tunable file to process\n"+\
Chris PeBenito 56e1b3d
	"-b --boolean <file>\t\tname of global boolean file to process\n\n")
Chris PeBenito 17de1b7
Chris PeBenito 56e1b3d
	sys.stdout.write("examples:\n")
Chris PeBenito 56e1b3d
	sys.stdout.write("> %s -w -m policy/modules/apache\n" % sys.argv[0])
Chris PeBenito 56e1b3d
	sys.stdout.write("> %s -t policy/global_tunables\n" % sys.argv[0])
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
def warning(description):
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
	Warns the user of a non-critical error.
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	if warn:
Chris PeBenito 17de1b7
		sys.stderr.write("%s: " % sys.argv[0] )
Chris PeBenito 17de1b7
		sys.stderr.write("warning: " + description + "\n")
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
def error(description):
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
	Describes an error and exists the program.
Chris PeBenito 17de1b7
	'''
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
	sys.stderr.write("%s: " % sys.argv[0] )
Chris PeBenito 17de1b7
        sys.stderr.write("error: " + description + "\n")
Chris PeBenito 17de1b7
        sys.stderr.flush()
Chris PeBenito 17de1b7
        sys.exit(1)
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
Chris PeBenito 17de1b7
# MAIN PROGRAM
Chris PeBenito 56e1b3d
Chris PeBenito 56e1b3d
# Defaults
Chris PeBenito 56e1b3d
warn = False
Chris PeBenito 56e1b3d
module = False
Chris PeBenito 56e1b3d
tunable = False
Chris PeBenito 56e1b3d
boolean = False
Chris PeBenito 56e1b3d
Chris PeBenito 17de1b7
# Check that there are command line arguments.
Chris PeBenito 17de1b7
if len(sys.argv) <= 1:
Chris PeBenito 17de1b7
	usage()
Chris PeBenito 17de1b7
	sys.exit(1)
Chris PeBenito 17de1b7
Chris PeBenito 56e1b3d
# Parse command line args
Chris PeBenito 56e1b3d
try:
Chris PeBenito 56e1b3d
	opts, args = getopt.getopt(sys.argv[1:], 'whm:t:b:', ['warn', 'help', 'module=', 'tunable=', 'boolean='])
Chris PeBenito 56e1b3d
except getopt.GetoptError:
Chris PeBenito 56e1b3d
	usage()
Chris PeBenito 56e1b3d
	sys.exit(2)
Chris PeBenito 56e1b3d
for o, a in opts:
Chris PeBenito 56e1b3d
	if o in ('-w', '--warn'):
Chris PeBenito 17de1b7
		warn = True
Chris PeBenito 56e1b3d
	elif o in ('-h', '--help'):
Chris PeBenito 56e1b3d
		usage()
Chris PeBenito 56e1b3d
		sys.exit(0)
Chris PeBenito 56e1b3d
	elif o in ('-m', '--module'):
Chris PeBenito 56e1b3d
		module = a
Chris PeBenito 56e1b3d
		break
Chris PeBenito 56e1b3d
	elif o in ('-t', '--tunable'):
Chris PeBenito 56e1b3d
		tunable = a
Chris PeBenito 56e1b3d
		break
Chris PeBenito 56e1b3d
	elif o in ('-b', '--boolean'):
Chris PeBenito 56e1b3d
		boolean = a
Chris PeBenito 56e1b3d
		break
Chris PeBenito 17de1b7
	else:
Chris PeBenito 56e1b3d
		usage()
Chris PeBenito 56e1b3d
		sys.exit(2)
Chris PeBenito 56e1b3d
Chris PeBenito 56e1b3d
if module:
Chris PeBenito 56e1b3d
	sys.stdout.writelines(getModuleXML(module))
Chris PeBenito 56e1b3d
elif tunable:
Chris PeBenito 56e1b3d
	sys.stdout.writelines(getTunableXML(tunable, "tunable"))
Chris PeBenito 56e1b3d
elif boolean:
Chris PeBenito 56e1b3d
	sys.stdout.writelines(getTunableXML(boolean, "bool"))
Chris PeBenito 56e1b3d
else:
Chris PeBenito 56e1b3d
	usage()
Chris PeBenito 56e1b3d
	sys.exit(2)
Chris PeBenito 17de1b7