# Make sure the path exists, we aren't going to create it if (os.path.exists(clOutputPath) != True): out.error("The given output path %s does not exist!" % clOutputPath) out.error("Please create the output directory and run again") exit(1) # Debug printing clDebug = args.debug # Create separate tvpd files for each record clCreateRecords = args.create_records ################################################ # Read in the VPD file and break it apart out.setIndent(0) out.msg("==== Stage 1: Parsing the VPD file") out.setIndent(2) # Create our output name from the input name vpdName = os.path.splitext(os.path.basename(clVpdFile))[0] # Open the vpdfile vpdContents = open(clVpdFile, mode='rb').read() # Jump right to where the VTOC should be and make sure it says VTOC offset = 61 if (vpdContents[offset:(offset + 4)].decode() != "VTOC"): out.error("Did not find VTOC at the expected offset!") exit(1) offset += 4
# Create separate binary files for each keyword clBinaryKeywords = args.binary_keywords # We are going to do this in 3 stages # 1 - Read in the manifest and any other referenced files. This will create a complete XML description of the VPD # We will also check to make sure that all required tags are given and no extra tags exist # 2 - Parse thru the tvpd description and make sure the data with in the tags is valid. This is checks like data not greater than length, etc.. # 3 - With the XML and contents verified correct, loop thru it again and write out the VPD data # Note: Looping thru the XML twice between stage 1 and 2 makes it easier to surface multiple errors to the user at once. # If we were trying to both validate the xml and data at once, it would be harder to continue and gather multiple errors like we do now ################################################ # Work with the manifest out.setIndent(0) out.msg("==== Stage 1: Parsing tvpd XML") out.setIndent(2) errorsFound = 0 # Get the full path to the file given manifestfile = findFile(clManifestFile, clInputPath) if (manifestfile == None): out.error("The manifest file %s could not be found! Please check your -m or -i cmdline options for typos" % (clManifestFile)) exit(1) # Read in the manifest (rc, manifest) = parseTvpd(manifestfile, True) if (rc): out.error("Problem reading in the manifest! - %s" % manifestfile) exit(rc)
def parseTvpd(tvpdFile, topLevel): # Accumulate errors and return the total at the end # This allows the user to see all mistakes at once instead of iteratively running errorsFound = 0 # Let the user know what file we are reading # We could make this optional with a new function param in the future out.msg("Parsing tvpd %s" % tvpdFile) # Read in the file # If there are tag mismatch errors or other general gross format problems, it will get caught here # Once we return from this function, then we'll check to make sure only supported tags were given, etc.. tvpdRoot = ET.parse(tvpdFile).getroot() # Print the top level tags from the parsing if (clDebug): out.debug("Top level tag/attrib found") for child in tvpdRoot: out.debug("%s %s" % (child.tag, child.attrib)) # Do some basic error checking of what we've read in # Make sure the root starts with the vpd tag # If it doesn't, it's not worth syntax checking any further # This is the only time we'll just bail instead of accumulating if (tvpdRoot.tag != "vpd"): out.error("%s does not start with a <vpd> tag. No further checking will be done until fixed!" % tvpdFile) return(1, None) # We at least have a proper top level vpd tag, so loop thru the rest of the levels and check for any unknown tags # This will also be a good place to check for the required tags # Define the expected tags at this level vpdTags = {"name" : 0, "size" : 0, "VD" : 0, "record" : 0} # Go thru the tags at this level for vpd in tvpdRoot: # See if this is a tag we even expect if vpd.tag not in vpdTags: out.error("Unsupported tag <%s> found while parsing the <vpd> level" % vpd.tag) errorsFound+=1 # We continue here because we don't want to parse down this hierarcy path when we don't know what it is continue # It was a supported tag else: vpdTags[vpd.tag]+=1 # Do the record level checks if (vpd.tag == "record"): # Define the expected tags at this level recordTags = {"rdesc" : 0, "keyword" : 0, "rtvpdfile" : 0, "rbinfile" : 0} # Make sure the record has a name attrib, save for later use recordName = vpd.attrib.get("name") if (recordName == None): out.error("A <record> tag is missing the name attribute") errorsFound+=1 recordName = "INVALID" # Set the invalid name so the code below can use it without issue # Loop thru the tags defined for this record for record in vpd: # See if this is a tag we even expect if record.tag not in recordTags: out.error("Unsupported tag <%s> found while parsing the <record> level for record %s" % (record.tag, recordName)) errorsFound+=1 # We continue here because we don't want to parse down this hierarcy path when we don't know what it is continue # It was a supported tag else: recordTags[record.tag]+=1 # Do the keyword level checks if (record.tag == "keyword"): # Define the expected tags at this level keywordTags = {"kwdesc" : 0, "kwformat" : 0, "kwlen" : 0, "kwdata" : 0} # Make sure the keyword has a name attrib, save for later use keywordName = record.attrib.get("name") if (keywordName == None): out.error("<keyword> tag in record %s is missing the name attribute" % (recordName)) errorsFound+=1 keywordName = "INVALID" # Set the invalid name so the code below can use it without issue # Loop thru the tags defined for this keyword for keyword in record: # See if this is a tag we even expect if keyword.tag not in keywordTags: out.error("Unsupported tag <%s> found while parsing the <keyword> level for keyword %s in record %s" % (keyword.tag, keywordName, recordName)) errorsFound+=1 # We continue here because we don't want to parse down this hierarcy path when we don't know what it is continue # It was a supported tag else: keywordTags[keyword.tag] +=1 # We've checked for unknown keyword tags, now make sure we have the right number of each # This is a simple one, we can only have 1 of each for tag in keywordTags: if (keywordTags[tag] != 1): out.error("The tag <%s> was expected to have a count of 1, but was found with a count of %d for keyword %s in record %s" % (tag, keywordTags[tag], keywordName, recordName)) errorsFound+=1 # We've checked for unknown record tags, now make sure we've got the right number, they don't conflict, etc.. recordTagTotal = bool(recordTags["keyword"]) + bool(recordTags["rbinfile"]) + bool(recordTags["rtvpdfile"]) # keyword, rbinfile and rtvpdfile are mutually exclusive. Make sure we have only one if (recordTagTotal > 1): out.error("For record %s, more than one tag of type keyword, rbinfile or rtvpdfile was given!" % (recordName)) out.error("Use of only 1 at a time is supported for a given record!") errorsFound+=1 # We checked if we had more than 1, let's make sure we have at least 1 if (recordTagTotal < 1): out.error("For record %s, 0 tags of type keyword, rbinfile or rtvpdfile were given!" % (recordName)) out.error("1 tag of the 3 must be in use for the record to be valid!") errorsFound+=1 # Make sure the rdesc is available if (recordTags["keyword"] and recordTags["rdesc"] != 1): out.error("The tag <rdesc> was expected to have a count of 1, but was found with a count of %d for record %s" % (recordTags["rdesc"], recordName)) errorsFound+=1 # Do some checking of what we found at the vpd level # Top level is the manifest passed in on the command line # When false, it's just a record description and doesn't require the high level descriptors if (topLevel == True): comparer = 1 else: comparer = 0 # Don't go thru all of them, "record" has special handling below for tag in ["name", "size", "VD"]: if (vpdTags[tag] != comparer): out.error("The tag <%s> was expected to have a count of %d, but was found with a count of %d" % (tag, comparer, vpdTags[tag])) errorsFound+=1 # Make sure at least one record tag was found if (vpdTags["record"] == 0): out.error("At least one <record> must be defined for the file to be valid!") errorsFound+=1 # If this is an included tvpd, it can only have 1 record in it # This check is just by convention. If a compelling case to change it was provided, it could be done if (topLevel == False): if (vpdTags["record"] > 1): out.error("More than 1 record entry found in %s. Only 1 record is allowed!" % (tvpdFile)) errorsFound+=1 ###### # All done, vary our return based upon the errorsFound if (errorsFound): return (errorsFound, None) else: return(0, tvpdRoot)
# Make sure the path exists, we aren't going to create it if (os.path.exists(clOutputPath) != True): out.error("The given output path %s does not exist!" % clOutputPath) out.error("Please create the output directory and run again") exit(1) # Debug printing clDebug = args.debug # Create separate tvpd files for each record clCreateRecords = args.create_records ################################################ # Read in the VPD file and break it apart out.setIndent(0) out.msg("==== Stage 1: Parsing the VPD file") out.setIndent(2) # Create our output name from the input name vpdName = os.path.splitext(os.path.basename(clVpdFile))[0] # Open the vpdfile vpdContents = open(clVpdFile, mode='rb').read() # Jump right to where the VTOC should be and make sure it says VTOC offset = 61 if (vpdContents[offset:(offset+4)].decode() != "VTOC"): out.error("Did not find VTOC at the expected offset!") exit(1) offset+=4