1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4""" Verify a v2 format migration stream """ 5 6from __future__ import print_function 7 8import sys 9import struct 10import os, os.path 11import syslog 12import traceback 13 14from xen.util import open_file_or_fd as open_file_or_fd 15from xen.migration.verify import StreamError, RecordError 16from xen.migration.libxc import VerifyLibxc 17from xen.migration.libxl import VerifyLibxl 18 19fin = None # Input file/fd 20log_to_syslog = False # Boolean - Log to syslog instead of stdout/err? 21verbose = False # Boolean - Summarise stream contents 22quiet = False # Boolean - Suppress error printing 23 24def info(msg): 25 """Info message, routed to appropriate destination""" 26 if not quiet and verbose: 27 if log_to_syslog: 28 for line in msg.split("\n"): 29 syslog.syslog(syslog.LOG_INFO, line) 30 else: 31 print(msg) 32 33def err(msg): 34 """Error message, routed to appropriate destination""" 35 if not quiet: 36 if log_to_syslog: 37 for line in msg.split("\n"): 38 syslog.syslog(syslog.LOG_ERR, line) 39 print(msg, file = sys.stderr) 40 41def stream_read(_ = None): 42 """Read from input""" 43 return fin.read(_) 44 45def rdexact(nr_bytes): 46 """Read exactly nr_bytes from fin""" 47 _ = stream_read(nr_bytes) 48 if len(_) != nr_bytes: 49 raise IOError("Stream truncated") 50 return _ 51 52def unpack_exact(fmt): 53 """Unpack a format from fin""" 54 sz = struct.calcsize(fmt) 55 return struct.unpack(fmt, rdexact(sz)) 56 57 58def skip_xl_header(): 59 """Skip over an xl header in the stream""" 60 61 hdr = rdexact(32) 62 if hdr != b"Xen saved domain, xl format\n \0 \r": 63 raise StreamError("No xl header") 64 65 _, mflags, _, optlen = unpack_exact("=IIII") 66 _ = rdexact(optlen) 67 68 info("Processed xl header") 69 70 if mflags & 2: # XL_MANDATORY_FLAG_STREAMv2 71 return "libxl" 72 else: 73 return "libxc" 74 75def read_stream(fmt): 76 """ Read an entire stream """ 77 78 try: 79 if fmt == "xl": 80 fmt = skip_xl_header() 81 82 if fmt == "libxc": 83 VerifyLibxc(info, stream_read).verify() 84 else: 85 VerifyLibxl(info, stream_read).verify() 86 87 except (IOError, StreamError, RecordError): 88 err("Stream Error:") 89 err(traceback.format_exc()) 90 return 1 91 92 except Exception: 93 err("Script Error:") 94 err(traceback.format_exc()) 95 err("Please fix me") 96 return 2 97 98 return 0 99 100 101def main(): 102 """ main """ 103 from optparse import OptionParser 104 global fin, quiet, verbose 105 106 # Change stdout to be line-buffered. 107 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1) 108 109 parser = OptionParser(usage = "%prog [options]", 110 description = 111 "Verify a stream according to the v2 (or later) spec") 112 113 # Optional options 114 parser.add_option("-i", "--in", dest = "fin", metavar = "<FD or FILE>", 115 default = "0", 116 help = "Stream to verify (defaults to stdin)") 117 parser.add_option("-v", "--verbose", action = "store_true", default = False, 118 help = "Summarise stream contents") 119 parser.add_option("-q", "--quiet", action = "store_true", default = False, 120 help = "Suppress all logging/errors") 121 parser.add_option("-f", "--format", dest = "format", 122 metavar = "<libxc|libxl|xl>", default = "libxc", 123 choices = ["libxc", "libxl", "xl"], 124 help = "Format of the incoming stream (defaults to libxc)") 125 parser.add_option("--syslog", action = "store_true", default = False, 126 help = "Log to syslog instead of stdout") 127 128 opts, _ = parser.parse_args() 129 130 if opts.syslog: 131 global log_to_syslog 132 133 syslog.openlog("verify-stream-v2", syslog.LOG_PID) 134 log_to_syslog = True 135 136 verbose = opts.verbose 137 quiet = opts.quiet 138 fin = open_file_or_fd(opts.fin, "rb", 0) 139 140 return read_stream(opts.format) 141 142if __name__ == "__main__": 143 try: 144 sys.exit(main()) 145 except SystemExit as e: 146 sys.exit(e.code) 147 except KeyboardInterrupt: 148 sys.exit(2) 149