summaryrefslogtreecommitdiff
path: root/tools/python/scripts/verify-stream-v2
blob: fe82b86c11cd5b7c4ebd597f0fd37a79cc00a562 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python
# -*- coding: utf-8 -*-

""" Verify a v2 format migration stream """

from __future__ import print_function

import sys
import struct
import os, os.path
import syslog
import traceback

from xen.util import open_file_or_fd as open_file_or_fd
from xen.migration.verify import StreamError, RecordError
from xen.migration.libxc import VerifyLibxc
from xen.migration.libxl import VerifyLibxl

fin = None             # Input file/fd
log_to_syslog = False  # Boolean - Log to syslog instead of stdout/err?
verbose = False        # Boolean - Summarise stream contents
quiet = False          # Boolean - Suppress error printing

def info(msg):
    """Info message, routed to appropriate destination"""
    if not quiet and verbose:
        if log_to_syslog:
            for line in msg.split("\n"):
                syslog.syslog(syslog.LOG_INFO, line)
        else:
            print(msg)

def err(msg):
    """Error message, routed to appropriate destination"""
    if not quiet:
        if log_to_syslog:
            for line in msg.split("\n"):
                syslog.syslog(syslog.LOG_ERR, line)
        print(msg, file = sys.stderr)

def stream_read(_ = None):
    """Read from input"""
    return fin.read(_)

def rdexact(nr_bytes):
    """Read exactly nr_bytes from fin"""
    _ = stream_read(nr_bytes)
    if len(_) != nr_bytes:
        raise IOError("Stream truncated")
    return _

def unpack_exact(fmt):
    """Unpack a format from fin"""
    sz = struct.calcsize(fmt)
    return struct.unpack(fmt, rdexact(sz))


def skip_xl_header():
    """Skip over an xl header in the stream"""

    hdr = rdexact(32)
    if hdr != b"Xen saved domain, xl format\n \0 \r":
        raise StreamError("No xl header")

    _, mflags, _, optlen = unpack_exact("=IIII")
    _ = rdexact(optlen)

    info("Processed xl header")

    if mflags & 2: # XL_MANDATORY_FLAG_STREAMv2
        return "libxl"
    else:
        return "libxc"

def read_stream(fmt):
    """ Read an entire stream """

    try:
        if fmt == "xl":
            fmt = skip_xl_header()

        if fmt == "libxc":
            VerifyLibxc(info, stream_read).verify()
        else:
            VerifyLibxl(info, stream_read).verify()

    except (IOError, StreamError, RecordError):
        err("Stream Error:")
        err(traceback.format_exc())
        return 1

    except Exception:
        err("Script Error:")
        err(traceback.format_exc())
        err("Please fix me")
        return 2

    return 0


def main():
    """ main """
    from optparse import OptionParser
    global fin, quiet, verbose

    # Change stdout to be line-buffered.
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)

    parser = OptionParser(usage = "%prog [options]",
                          description =
                          "Verify a stream according to the v2 (or later) spec")

    # Optional options
    parser.add_option("-i", "--in", dest = "fin", metavar = "<FD or FILE>",
                      default = "0",
                      help = "Stream to verify (defaults to stdin)")
    parser.add_option("-v", "--verbose", action = "store_true", default = False,
                      help = "Summarise stream contents")
    parser.add_option("-q", "--quiet", action = "store_true", default = False,
                      help = "Suppress all logging/errors")
    parser.add_option("-f", "--format", dest = "format",
                      metavar = "<libxc|libxl|xl>", default = "libxc",
                      choices = ["libxc", "libxl", "xl"],
                      help = "Format of the incoming stream (defaults to libxc)")
    parser.add_option("--syslog", action = "store_true", default = False,
                      help = "Log to syslog instead of stdout")

    opts, _ = parser.parse_args()

    if opts.syslog:
        global log_to_syslog

        syslog.openlog("verify-stream-v2", syslog.LOG_PID)
        log_to_syslog = True

    verbose = opts.verbose
    quiet = opts.quiet
    fin = open_file_or_fd(opts.fin, "rb", 0)

    return read_stream(opts.format)

if __name__ == "__main__":
    try:
        sys.exit(main())
    except SystemExit as e:
        sys.exit(e.code)
    except KeyboardInterrupt:
        sys.exit(2)