summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrent s <r00t@square-r00t.net>2019-08-18 23:17:31 -0400
committerbrent s <r00t@square-r00t.net>2019-08-18 23:17:31 -0400
commitaf732a1d64cb6fc3b75f9cb1c2cec3b95a643c97 (patch)
tree08ec1f992e808a9810b411b1d7e2d72d9097f2c2
parent0c0f6ee81bd89be5bfcc892b60889b0fc0830c4f (diff)
downloadOpTools-af732a1d64cb6fc3b75f9cb1c2cec3b95a643c97.tar.xz
adding XML/XSD support for hashtype attr
-rwxr-xr-xsys/BootSync/bootsync.py29
-rw-r--r--sys/BootSync/bootsync.xsd28
-rw-r--r--sys/BootSync/sample.config.xml59
3 files changed, 100 insertions, 16 deletions
diff --git a/sys/BootSync/bootsync.py b/sys/BootSync/bootsync.py
index 774ba1b..b42195d 100755
--- a/sys/BootSync/bootsync.py
+++ b/sys/BootSync/bootsync.py
@@ -15,14 +15,15 @@ from lxml import etree
class BootSync(object):
- def __init__(self, cfg = None, *args, **kwargs):
+ def __init__(self, cfg = None, validate = True, *args, **kwargs):
if not cfg:
self.cfgfile = '/etc/bootsync.xml'
else:
self.cfgfile = os.path.abspath(os.path.expanduser(cfg))
- self.ns = '{http://git.square-r00t.net/OpTools/tree/sys/BootSync/}'
+ self.ns = None
self.cfg = None
self.xml = None
+ self.schema = None
# This is the current live kernel.
self.currentKernVer = self._getRunningKernel()
# This is the installed kernel from the package manager.
@@ -33,15 +34,13 @@ class BootSync(object):
self.dummy_uuid = None
self.syncs = {}
##
- self.getCfg()
+ self.getCfg(validate = validate)
self.chkMounts()
self.chkReboot()
self.getHashes()
self.getBlkids()
- # self.sync()
- # self.writeConfs()
- def getCfg(self):
+ def getCfg(self, validate = True):
if not os.path.isfile(self.cfgfile):
raise FileNotFoundError('Configuration file {0} does not exist!'.format(self.cfgfile))
try:
@@ -53,6 +52,19 @@ class BootSync(object):
# self.logger.error('{0} is invalid XML'.format(self.cfgfile))
raise ValueError(('{0} does not seem to be valid XML. '
'See sample.config.xml for an example configuration.').format(self.cfgfile))
+ self.ns = self.cfg.nsmap.get(None, 'http://git.square-r00t.net/OpTools/tree/sys/BootSync/')
+ self.ns = '{{{0}}}'.format(self.ns)
+ if validate:
+ if not self.schema:
+ from urllib.request import urlopen
+ xsi = self.cfg.nsmap.get('xsi', 'http://www.w3.org/2001/XMLSchema-instance')
+ schemaLocation = '{{{0}}}schemaLocation'.format(xsi)
+ schemaURL = self.cfg.attrib.get(schemaLocation,
+ ('http://git.square-r00t.net/OpTools/plain/sys/BootSync/bootsync.xsd'))
+ with urlopen(schemaURL) as url:
+ self.schema = url.read()
+ self.schema = etree.XMLSchema(etree.XML(self.schema))
+ self.schema.assertValid(self.xml)
return()
def chkMounts(self):
@@ -278,6 +290,11 @@ class BootSync(object):
def parseArgs():
args = argparse.ArgumentParser(description = ('Sync files to assist using mdadm RAID arrays with UEFI'))
+ args.add_argument('-V', '--no-validate',
+ dest = 'validate',
+ action = 'store_false',
+ help = ('If specified, do not attempt to validate the configuration file (-c/--cfg) against'
+ 'its schema (otherwise it is fetched dynamically and requires network connection)'))
args.add_argument('-c', '--cfg',
dest = 'cfg',
default = '/etc/bootsync.xml',
diff --git a/sys/BootSync/bootsync.xsd b/sys/BootSync/bootsync.xsd
index 4ab4c7d..6ea587e 100644
--- a/sys/BootSync/bootsync.xsd
+++ b/sys/BootSync/bootsync.xsd
@@ -24,6 +24,28 @@
</xs:restriction>
</xs:simpleType>
+ <xs:simpleType name="hashtype_choice">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="false"/>
+ <!-- https://docs.python.org/3/library/hashlib.html#hash-algorithms -->
+ <xs:enumeration value="md5"/><!-- Not available on FIPS-compliant Python -->
+ <xs:enumeration value="sha1"/>
+ <xs:enumeration value="sha224"/>
+ <xs:enumeration value="sha256"/>
+ <xs:enumeration value="sha384"/>
+ <xs:enumeration value="sha512"/>
+ <xs:enumeration value="blake2b"/>
+ <xs:enumeration value="blake2s"/>
+ <!-- The below are only available for more recent versions of system's OpenSSL. -->
+ <xs:enumeration value="sha3_224"/>
+ <xs:enumeration value="sha3_256"/>
+ <xs:enumeration value="sha3_384"/>
+ <xs:enumeration value="sha3_512"/>
+ <xs:enumeration value="shake_128"/>
+ <xs:enumeration value="shake_256"/>
+ </xs:restriction>
+ </xs:simpleType>
+
<xs:element name="bootsync">
<xs:complexType>
<xs:sequence>
@@ -56,11 +78,14 @@
<xs:extension base="relpath">
<xs:attribute name="isKernel" type="xs:boolean"
use="optional" default="false"/>
+ <xs:attribute name="hashtype" type="hashtype_choice"
+ use="optional" default="md5"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
+ <xs:attribute name="hashtype" type="hashtype_choice" use="optional" default="md5"/>
</xs:complexType>
<xs:unique name="filechk_unique">
<xs:selector xpath="bootsync:file"/>
@@ -76,9 +101,12 @@
<xs:attribute name="target" type="relpath" use="required"/>
<!-- TODO: make this optional? -->
<xs:attribute name="pattern" type="xs:string" use="required"/>
+ <xs:attribute name="hashtype" type="hashtype_choice"
+ use="optional" default="md5"/>
</xs:complexType>
</xs:element>
</xs:sequence>
+ <xs:attribute name="hashtype" type="hashtype_choice" use="optional" default="md5"/>
</xs:complexType>
<xs:unique name="syncpath_unique_source">
<xs:selector xpath="bootsync:path"/>
diff --git a/sys/BootSync/sample.config.xml b/sys/BootSync/sample.config.xml
index b982ae9..43e564c 100644
--- a/sys/BootSync/sample.config.xml
+++ b/sys/BootSync/sample.config.xml
@@ -17,33 +17,72 @@ SEE prep.txt FOR WHAT MUST BE DONE BEFORE RUNNING BOOTSYNC.
<part path="/dev/sdb1" mount="/mnt/boot1"/>
<part path="/dev/sdd1" mount="/mnt/boot2"/>
</partitions>
- <!-- If specified, the files in this container are checksummed to determine if a sync is required.
- If fileChecks isn't provided, we will always sync no matter what.
+ <!--
+ If fileChecks isn't provided, we will still sync syncPaths (which IS required).
These files will be evaluated to and synced to the ESP partitions with the same relative path.
i.e. (part[@mount])/(file)
+ fileChecks[@hashtype] attribute is used to checksum all <file> children,
+ unless they specify their own hashtype attribute (the default is hashtype="md5" for speed optimizations).
+
+ Guaranteed valid hashtype values are:
+
+ sha1
+ sha224
+ sha256
+ sha384
+ sha512
+ blake2b
+ blake2s
+
+ If you have a non-FIPS-compliant Python (you very most likely do), the following hashtype is also available:
+
+ md5
+
+ If you have a recent enough OpenSSL (and python3), you have the additional hashtype values available:
+
+ sha3_224
+ sha3_256
+ sha3_384
+ sha3_512
+ shake_128
+ shake_256
+
+ Additionally, the value "false" is always available to disable hashing for a specific <file> object or to set
+ the default. No checksumming will be done in this case and the file will always be overwritten on every run.
+
+ This is *highly not recommended* for solid-state disks or if you have large files you plan on syncing to
+ the alternate ESPs (e.g. loop-mounted ISO/IMG files).
+
"isKernel" is by default false, but if true it is treated specially to get a kernel version.
This is to notify you if a reboot is required. If no <file> item is isKernel="true", no reboot requirement
detection will be done.
- Only *the last* <file> with isKernel="true" listed is used as the kernel identifier. -->
- <fileChecks>
- <!-- RELATIVE paths to /boot -->
+ Only *the last* <file> with isKernel="true" listed is used as the kernel identifier.
+ -->
+ <fileChecks hashtype="sha1">
+ <!-- RELATIVE paths to /boot on your / mount. -->
<file>initramfs-linux.img</file>
<file>intel-ucode.img</file>
<file>memtest86+/memtest.bin</file>
- <file isKernel="true">vmlinuz-linux</file>
+ <file isKernel="true" hashtype="sha512">vmlinuz-linux</file>
</fileChecks>
- <!-- These are system paths to sync to the ESPs. They are synced recursively.
+ <!--
+ These are system paths to sync to the ESPs. They are synced recursively.
+
+ "hashtype" is also supported for syncPaths and path objects just as the same with fileChecks
+ and file objects (see above).
+
"source" should be absolute.
"target" should be relative (to the ESP mount).
- "pattern" is a regex to match to restrict *filenames* to sync. Use ".*" for all files. -->
- <syncPaths>
+ "pattern" is a regex to match to restrict *filenames* to sync. Use ".*" for all files.
+ -->
+ <syncPaths hashtype="sha1">
<!-- For example, these are grub theme files. -->
<path source="/usr/share/grub/themes" target="grub/themes" pattern=".*"/>
<!-- These are grub modules - specifically, UEFI. -->
<path source="/usr/lib/grub/x86_64-efi" target="grub/x86_64-efi" pattern="^.*\.(mod|lst|sh)$"/>
<!-- And these are ISO files, in case you're like me and do loop mounting in Grub for rescue situations.
(e.g. https://wiki.archlinux.org/index.php/Multiboot_USB_drive#Using_GRUB_and_loopback_devices) -->
- <path source="/boot/iso" target="iso" pattern="^.*\.(iso|img)$"/>
+ <path hashtype="false" source="/boot/iso" target="iso" pattern="^.*\.(iso|img)$"/>
</syncPaths>
</bootsync> \ No newline at end of file