1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4""" 5Convert a legacy migration stream to a v2 stream. 6""" 7 8from __future__ import print_function 9from __future__ import division 10 11import sys 12import os, os.path 13import syslog 14import traceback 15 16from struct import calcsize, unpack, pack 17 18from xen.util import open_file_or_fd as open_file_or_fd 19from xen.migration import legacy, public, libxc, libxl, xl 20 21__version__ = 1 22 23fin = None # Input file/fd 24fout = None # Output file/fd 25twidth = 0 # Legacy toolstack bitness (32 or 64) 26pv = None # Boolean (pv or hvm) 27qemu = True # Boolean - process qemu record? 28log_to_syslog = False # Boolean - Log to syslog instead of stdout/err? 29verbose = False # Boolean - Summarise stream contents 30 31def stream_read(_ = None): 32 """Read from the input""" 33 return fin.read(_) 34 35def stream_write(_): 36 """Write to the output""" 37 return fout.write(_) 38 39def info(msg): 40 """Info message, routed to appropriate destination""" 41 if verbose: 42 if log_to_syslog: 43 for line in msg.split("\n"): 44 syslog.syslog(syslog.LOG_INFO, line) 45 else: 46 print(msg) 47 48def err(msg): 49 """Error message, routed to appropriate destination""" 50 if log_to_syslog: 51 for line in msg.split("\n"): 52 syslog.syslog(syslog.LOG_ERR, line) 53 print(msg, file = sys.stderr) 54 55class StreamError(Exception): 56 """Error with the incoming migration stream""" 57 pass 58 59class VM(object): 60 """Container of VM parameters""" 61 62 def __init__(self, fmt): 63 # Common 64 self.p2m_size = 0 65 66 # PV 67 self.max_vcpu_id = 0 68 self.online_vcpu_map = [] 69 self.width = 0 70 self.levels = 0 71 self.basic_len = 0 72 self.extd = False 73 self.xsave_len = 0 74 75 # libxl 76 self.libxl = fmt == "libxl" 77 self.emu_xenstore = b"" # NUL terminated key&val pairs from "toolstack" records 78 79def write_libxc_ihdr(): 80 stream_write(pack(libxc.IHDR_FORMAT, 81 libxc.IHDR_MARKER, # Marker 82 libxc.IHDR_IDENT, # Ident 83 3, # Version 84 libxc.IHDR_OPT_LE, # Options 85 0, 0)) # Reserved 86 87def write_libxc_dhdr(): 88 if pv: 89 dtype = libxc.DHDR_TYPE_x86_pv 90 else: 91 dtype = libxc.DHDR_TYPE_x86_hvm 92 93 stream_write(pack(libxc.DHDR_FORMAT, 94 dtype, # Type 95 12, # Page size 96 0, # Reserved 97 0, # Xen major (converted) 98 __version__)) # Xen minor (converted) 99 100def write_libxl_hdr(): 101 stream_write(pack(libxl.HDR_FORMAT, 102 libxl.HDR_IDENT, # Ident 103 libxl.HDR_VERSION, # Version 2 104 libxl.HDR_OPT_LE | # Options 105 libxl.HDR_OPT_LEGACY # Little Endian and Legacy 106 )) 107 108def write_record(rt, *argl): 109 alldata = b''.join(argl) 110 length = len(alldata) 111 112 record = pack(libxc.RH_FORMAT, rt, length) + alldata 113 plen = (8 - (length & 7)) & 7 114 record += b'\x00' * plen 115 116 stream_write(record) 117 118def write_libxc_pv_info(vm): 119 write_record(libxc.REC_TYPE_x86_pv_info, 120 pack(libxc.X86_PV_INFO_FORMAT, 121 vm.width, vm.levels, 0, 0)) 122 123def write_libxc_pv_p2m_frames(vm, pfns): 124 write_record(libxc.REC_TYPE_x86_pv_p2m_frames, 125 pack(libxc.X86_PV_P2M_FRAMES_FORMAT, 126 0, vm.p2m_size - 1), 127 pack("Q" * len(pfns), *pfns)) 128 129def write_libxc_pv_vcpu_basic(vcpu_id, data): 130 write_record(libxc.REC_TYPE_x86_pv_vcpu_basic, 131 pack(libxc.X86_PV_VCPU_HDR_FORMAT, vcpu_id, 0), data) 132 133def write_libxc_pv_vcpu_extd(vcpu_id, data): 134 write_record(libxc.REC_TYPE_x86_pv_vcpu_extended, 135 pack(libxc.X86_PV_VCPU_HDR_FORMAT, vcpu_id, 0), data) 136 137def write_libxc_pv_vcpu_xsave(vcpu_id, data): 138 write_record(libxc.REC_TYPE_x86_pv_vcpu_xsave, 139 pack(libxc.X86_PV_VCPU_HDR_FORMAT, vcpu_id, 0), data) 140 141def write_page_data(pfns, pages): 142 if fout is None: # Save copying 1M buffers around for no reason 143 return 144 145 new_pfns = [(((x & 0xf0000000) << 32) | (x & 0x0fffffff)) for x in pfns] 146 147 # Optimise the needless buffer copying in write_record() 148 stream_write(pack(libxc.RH_FORMAT, 149 libxc.REC_TYPE_page_data, 150 8 + (len(new_pfns) * 8) + len(pages))) 151 stream_write(pack(libxc.PAGE_DATA_FORMAT, len(new_pfns), 0)) 152 stream_write(pack("Q" * len(new_pfns), *new_pfns)) 153 stream_write(pages) 154 155def write_libxc_tsc_info(mode, khz, nsec, incarn): 156 write_record(libxc.REC_TYPE_tsc_info, 157 pack(libxc.X86_TSC_INFO_FORMAT, 158 mode, khz, nsec, incarn, 0)) 159 160def write_libxc_hvm_params(params): 161 if pv: 162 raise StreamError("HVM-only param in PV stream") 163 elif len(params) % 2: 164 raise RuntimeError("Expected even length list of hvm parameters") 165 166 write_record(libxc.REC_TYPE_hvm_params, 167 pack(libxc.HVM_PARAMS_FORMAT, len(params) // 2, 0), 168 pack("Q" * len(params), *params)) 169 170def write_libxc_static_data_end(): 171 write_record(libxc.REC_TYPE_static_data_end) 172 173def write_libxl_end(): 174 write_record(libxl.REC_TYPE_end) 175 176def write_libxl_libxc_context(): 177 write_record(libxl.REC_TYPE_libxc_context) 178 179def write_libxl_emulator_xenstore_data(data): 180 write_record(libxl.REC_TYPE_emulator_xenstore_data, 181 pack(libxl.EMULATOR_HEADER_FORMAT, 182 libxl.EMULATOR_ID_unknown, 0) + data) 183 184def write_libxl_emulator_context(blob): 185 write_record(libxl.REC_TYPE_emulator_context, 186 pack(libxl.EMULATOR_HEADER_FORMAT, 187 libxl.EMULATOR_ID_unknown, 0) + blob) 188 189def rdexact(nr_bytes): 190 """Read exactly nr_bytes from fin""" 191 _ = stream_read(nr_bytes) 192 if len(_) != nr_bytes: 193 raise IOError("Stream truncated") 194 return _ 195 196def unpack_exact(fmt): 197 """Unpack a format from fin""" 198 sz = calcsize(fmt) 199 return unpack(fmt, rdexact(sz)) 200 201def unpack_ulongs(nr_ulongs): 202 if twidth == 32: 203 return unpack_exact("I" * nr_ulongs) 204 else: 205 return unpack_exact("Q" * nr_ulongs) 206 207def read_pv_extended_info(vm): 208 209 marker, = unpack_ulongs(1) 210 211 if twidth == 32: 212 expected = 0xffffffff 213 else: 214 expected = 0xffffffffffffffff 215 216 if marker != expected: 217 raise StreamError("Unexpected extended info marker 0x%x" % (marker, )) 218 219 total_length, = unpack_exact("I") 220 so_far = 0 221 222 info("Extended Info: length 0x%x" % (total_length, )) 223 224 while so_far < total_length: 225 226 blkid, datasz = unpack_exact("=4sI") 227 so_far += 8 228 229 info(" Record type: %s, size 0x%x" % (blkid, datasz)) 230 231 data = rdexact(datasz) 232 so_far += datasz 233 234 # Eww, but this is how it is done :( 235 if blkid == b"vcpu": 236 237 vm.basic_len = datasz 238 239 if datasz == 0x1430: 240 vm.width = 8 241 vm.levels = 4 242 info(" 64bit domain, 4 levels") 243 elif datasz == 0xaf0: 244 vm.width = 4 245 vm.levels = 3 246 info(" 32bit domain, 3 levels") 247 else: 248 raise StreamError("Unable to determine guest width/level") 249 250 write_libxc_pv_info(vm) 251 252 elif blkid == b"extv": 253 vm.extd = True 254 255 elif blkid == b"xcnt": 256 vm.xsave_len, = unpack("I", data[:4]) 257 info("xcnt sz 0x%x" % (vm.xsave_len, )) 258 259 else: 260 raise StreamError("Unrecognised extended block") 261 262 263 if so_far != total_length: 264 raise StreamError("Overshot Extended Info size by %d bytes" % 265 (so_far - total_length, )) 266 267def read_pv_p2m_frames(vm): 268 fpp = 4096 // vm.width 269 p2m_frame_len = (vm.p2m_size - 1) // fpp + 1 270 271 info("P2M frames: fpp %d, p2m_frame_len %d" % (fpp, p2m_frame_len)) 272 write_libxc_pv_p2m_frames(vm, unpack_ulongs(p2m_frame_len)) 273 274def read_pv_tail(vm): 275 276 nr_unmapped_pfns, = unpack_exact("I") 277 278 if nr_unmapped_pfns != 0: 279 # "Unmapped" pfns are bogus 280 _ = unpack_ulongs(nr_unmapped_pfns) 281 info("discarding %d bogus 'unmapped pfns'" % (nr_unmapped_pfns, )) 282 283 for vcpu_id in vm.online_vcpu_map: 284 285 basic = rdexact(vm.basic_len) 286 info("Got VCPU basic (size 0x%x)" % (vm.basic_len, )) 287 write_libxc_pv_vcpu_basic(vcpu_id, basic) 288 289 if vm.extd: 290 extd = rdexact(128) 291 info("Got VCPU extd (size 0x%x)" % (128, )) 292 write_libxc_pv_vcpu_extd(vcpu_id, extd) 293 294 if vm.xsave_len: 295 mask, size = unpack_exact("QQ") 296 assert vm.xsave_len - 16 == size 297 298 xsave = rdexact(size) 299 info("Got VCPU xsave (mask 0x%x, size 0x%x)" % (mask, size)) 300 write_libxc_pv_vcpu_xsave(vcpu_id, xsave) 301 302 shinfo = rdexact(4096) 303 info("Got shinfo") 304 305 write_record(libxc.REC_TYPE_shared_info, shinfo) 306 write_record(libxc.REC_TYPE_end) 307 308 309def read_libxl_toolstack(vm, data): 310 311 if len(data) < 8: 312 raise StreamError("Overly short libxl toolstack data") 313 314 ver, count = unpack("=II", data[:8]) 315 data = data[8:] 316 317 if ver != 1: 318 raise StreamError("Cannot decode libxl toolstack version %u" % (ver, )) 319 info(" Version %u, count %u" % (ver, count)) 320 321 for x in range(count): 322 323 if len(data) < 28: 324 raise StreamError("Remaining data too short for physmap header") 325 326 phys, start, size, namelen = unpack("=QQQI", data[:28]) 327 data = data[28:] 328 329 if namelen == 0: 330 raise StreamError("No physmap info name") 331 332 # 64bit leaked 4 bytes of padding onto the end of name 333 if twidth == 64: 334 namelen += 4 335 336 if len(data) < namelen: 337 raise StreamError("Remaining data too short for physmap name") 338 339 name = data[:namelen] 340 data = data[namelen:] 341 342 # Strip padding off the end of name 343 if twidth == 64: 344 name = name[:-4] 345 346 if bytearray(name)[-1] != 0: 347 raise StreamError("physmap name not NUL terminated") 348 349 root = ("physmap/%x" % (phys, )).encode('ascii') 350 kv = [root + b"/start_addr", ("%x" % (start, )).encode('ascii'), 351 root + b"/size", ("%x" % (size, )).encode('ascii'), 352 root + b"/name", name[:-1]] 353 354 for key, val in zip(kv[0::2], kv[1::2]): 355 info(" '%s' = '%s'" % (key.decode(), val.decode())) 356 357 vm.emu_xenstore += b'\x00'.join(kv) + b'\x00' 358 359 360def read_chunks(vm): 361 362 hvm_params = [] 363 364 while True: 365 366 marker, = unpack_exact("=i") 367 if marker <= 0: 368 info("Chunk: %d - %s" % 369 (marker, legacy.chunk_type_to_str.get(marker, "unknown"))) 370 371 if marker == legacy.CHUNK_end: 372 info(" End") 373 374 if hvm_params: 375 write_libxc_hvm_params(hvm_params) 376 377 return 378 379 elif marker > 0: 380 381 if marker > legacy.MAX_BATCH: 382 raise StreamError("Page batch (%d) exceeded MAX_BATCH (%d)" % 383 (marker, legacy.MAX_BATCH)) 384 pfns = unpack_ulongs(marker) 385 386 # xc_domain_save() leaves many XEN_DOMCTL_PFINFO_XTAB records for 387 # sequences of pfns it cant map. Drop these. 388 pfns = [ x for x in pfns if x != 0xf0000000 ] 389 390 if len(set(pfns)) != len(pfns): 391 raise StreamError("Duplicate pfns in batch") 392 393 nr_pages = len([x for x in pfns if (x & 0xf0000000) < 0xd0000000]) 394 pages = rdexact(nr_pages * 4096) 395 396 write_page_data(pfns, pages) 397 398 elif marker == legacy.CHUNK_enable_verify_mode: 399 info("This is a debug stream") 400 401 elif marker == legacy.CHUNK_vcpu_info: 402 max_id, = unpack_exact("i") 403 404 if max_id > legacy.MAX_VCPU_ID: 405 raise StreamError("Vcpu max_id out of range: %d > %d" % 406 (max_id, legacy.MAX_VCPU_ID)) 407 408 vm.max_vcpu_id = max_id 409 bitmap = unpack_exact("Q" * ((max_id // 64) + 1)) 410 411 for idx, word in enumerate(bitmap): 412 bit_idx = 0 413 414 while word > 0: 415 if word & 1: 416 vm.online_vcpu_map.append((idx * 64) + bit_idx) 417 418 bit_idx += 1 419 word >>= 1 420 421 info(" Vcpu info: max_id %d, online map %s" % 422 (vm.max_vcpu_id, vm.online_vcpu_map)) 423 424 elif marker == legacy.CHUNK_hvm_ident_pt: 425 _, ident_pt = unpack_exact("=IQ") 426 info(" EPT Identity Pagetable: 0x%x" % (ident_pt, )) 427 hvm_params.extend([public.HVM_PARAM_IDENT_PT, ident_pt]) 428 429 elif marker == legacy.CHUNK_hvm_vm86_tss: 430 _, vm86_tss = unpack_exact("=IQ") 431 info(" VM86 TSS: 0x%x" % (vm86_tss, )) 432 hvm_params.extend([public.HVM_PARAM_VM86_TSS, vm86_tss]) 433 434 elif marker == legacy.CHUNK_tmem: 435 raise RuntimeError("todo") 436 437 elif marker == legacy.CHUNK_tmem_extra: 438 raise RuntimeError("todo") 439 440 elif marker == legacy.CHUNK_tsc_info: 441 mode, nsec, khz, incarn = unpack_exact("=IQII") 442 info(" X86_TSC_INFO: mode %s, %d ns, %d khz, %d incarn" 443 % (mode, nsec, khz, incarn)) 444 write_libxc_tsc_info(mode, khz, nsec, incarn) 445 446 elif marker == legacy.CHUNK_hvm_console_pfn: 447 _, console_pfn = unpack_exact("=IQ") 448 info(" Console pfn: 0x%x" % (console_pfn, )) 449 hvm_params.extend([public.HVM_PARAM_CONSOLE_PFN, console_pfn]) 450 451 elif marker == legacy.CHUNK_last_checkpoint: 452 info(" Last Checkpoint") 453 # Nothing to do 454 455 elif marker == legacy.CHUNK_hvm_acpi_ioports_location: 456 _, loc = unpack_exact("=IQ") 457 info(" ACPI ioport location: 0x%x" % (loc, )) 458 hvm_params.extend([public.HVM_PARAM_ACPI_IOPORTS_LOCATION, loc]) 459 460 elif marker == legacy.CHUNK_hvm_viridian: 461 _, loc = unpack_exact("=IQ") 462 info(" Viridian location: 0x%x" % (loc, )) 463 hvm_params.extend([public.HVM_PARAM_VIRIDIAN, loc]) 464 465 elif marker == legacy.CHUNK_compressed_data: 466 sz, = unpack_exact("I") 467 data = rdexact(sz) 468 info(" Compressed Data: sz 0x%x" % (sz, )) 469 raise RuntimeError("todo") 470 471 elif marker == legacy.CHUNK_enable_compression: 472 raise RuntimeError("todo") 473 474 elif marker == legacy.CHUNK_hvm_generation_id_addr: 475 _, genid_loc = unpack_exact("=IQ") 476 info(" Generation ID Address: 0x%x" % (genid_loc, )) 477 hvm_params.extend( 478 [public.HVM_PARAM_VM_GENERATION_ID_ADDR, genid_loc]) 479 480 elif marker == legacy.CHUNK_hvm_paging_ring_pfn: 481 _, pfn = unpack_exact("=IQ") 482 info(" Paging ring pfn: 0x%x" % (pfn, )) 483 hvm_params.extend([public.HVM_PARAM_PAGING_RING_PFN, pfn]) 484 485 elif marker == legacy.CHUNK_hvm_monitor_ring_pfn: 486 _, pfn = unpack_exact("=IQ") 487 info(" Monitor ring pfn: 0x%x" % (pfn, )) 488 hvm_params.extend([public.HVM_PARAM_MONITOR_RING_PFN, pfn]) 489 490 elif marker == legacy.CHUNK_hvm_sharing_ring_pfn: 491 _, pfn = unpack_exact("=IQ") 492 info(" Sharing ring pfn: 0x%x" % (pfn, )) 493 hvm_params.extend([public.HVM_PARAM_SHARING_RING_PFN, pfn]) 494 495 elif marker == legacy.CHUNK_toolstack: 496 sz, = unpack_exact("I") 497 498 if sz: 499 data = rdexact(sz) 500 info(" Toolstack Data: sz 0x%x" % (sz, )) 501 502 if vm.libxl: 503 read_libxl_toolstack(vm, data) 504 else: 505 info(" Discarding") 506 507 elif marker == legacy.CHUNK_hvm_ioreq_server_pfn: 508 _, pfn = unpack_exact("=IQ") 509 info(" IOREQ server pfn: 0x%x" % (pfn, )) 510 hvm_params.extend([public.HVM_PARAM_IOREQ_SERVER_PFN, pfn]) 511 512 elif marker == legacy.CHUNK_hvm_nr_ioreq_server_pages: 513 _, nr_pages = unpack_exact("=IQ") 514 info(" IOREQ server pages: %d" % (nr_pages, )) 515 hvm_params.extend( 516 [public.HVM_PARAM_NR_IOREQ_SERVER_PAGES, nr_pages]) 517 518 else: 519 raise StreamError("Unrecognised chunk %d" % (marker, )) 520 521def read_hvm_tail(vm): 522 523 io, bufio, store = unpack_exact("QQQ") 524 info("Magic pfns: 0x%x 0x%x 0x%x" % (io, bufio, store)) 525 write_libxc_hvm_params([public.HVM_PARAM_IOREQ_PFN, io, 526 public.HVM_PARAM_BUFIOREQ_PFN, bufio, 527 public.HVM_PARAM_STORE_PFN, store]) 528 529 blobsz, = unpack_exact("I") 530 info("Got HVM Context (0x%x bytes)" % (blobsz, )) 531 blob = rdexact(blobsz) 532 533 write_record(libxc.REC_TYPE_hvm_context, blob) 534 write_record(libxc.REC_TYPE_end) 535 536 537 538def read_qemu(vm): 539 540 rawsig = rdexact(21) 541 sig, = unpack("21s", rawsig) 542 info("Qemu signature: %s" % (sig, )) 543 544 if sig == b"DeviceModelRecord0002": 545 rawsz = rdexact(4) 546 sz, = unpack("I", rawsz) 547 qdata = rdexact(sz) 548 549 if vm.libxl: 550 write_libxl_emulator_context(qdata) 551 else: 552 stream_write(rawsig) 553 stream_write(rawsz) 554 stream_write(qdata) 555 556 else: 557 raise RuntimeError("Unrecognised Qemu sig '%s'" % (sig, )) 558 559 560def skip_xl_header(fmt): 561 """Skip over an xl header in the stream""" 562 563 hdr = rdexact(len(xl.MAGIC)) 564 if hdr != xl.MAGIC: 565 raise StreamError("No xl header") 566 567 byteorder, mflags, oflags, optlen = unpack_exact(xl.HEADER_FORMAT) 568 569 if fmt == "libxl": 570 mflags |= xl.MANDATORY_FLAG_STREAMV2 571 572 opts = pack(xl.HEADER_FORMAT, byteorder, mflags, oflags, optlen) 573 574 optdata = rdexact(optlen) 575 576 info("Processed xl header") 577 578 stream_write(hdr) 579 stream_write(opts) 580 stream_write(optdata) 581 582def read_legacy_stream(vm): 583 584 try: 585 vm.p2m_size, = unpack_ulongs(1) 586 info("P2M Size: 0x%x" % (vm.p2m_size, )) 587 588 if vm.libxl: 589 write_libxl_hdr() 590 write_libxl_libxc_context() 591 592 write_libxc_ihdr() 593 write_libxc_dhdr() 594 595 if pv: 596 read_pv_extended_info(vm) 597 598 write_libxc_static_data_end() 599 600 if pv: 601 read_pv_p2m_frames(vm) 602 603 read_chunks(vm) 604 605 if pv: 606 read_pv_tail(vm) 607 else: 608 read_hvm_tail(vm) 609 610 if vm.libxl and len(vm.emu_xenstore): 611 write_libxl_emulator_xenstore_data(vm.emu_xenstore) 612 613 if not pv and (vm.libxl or qemu): 614 read_qemu(vm) 615 616 if vm.libxl: 617 write_libxl_end() 618 619 except (IOError, StreamError): 620 err("Stream Error:") 621 err(traceback.format_exc()) 622 return 1 623 624 except RuntimeError: 625 err("Script Error:") 626 err(traceback.format_exc()) 627 err("Please fix me") 628 return 2 629 return 0 630 631 632def main(): 633 from optparse import OptionParser 634 global fin, fout, twidth, pv, qemu, verbose 635 636 # Change stdout to be line-buffered. 637 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1) 638 639 parser = OptionParser(version = __version__, 640 usage = ("%prog [options] -i INPUT -o OUTPUT" 641 " -w WIDTH -g GUEST"), 642 description = 643 "Convert a legacy stream to a v2 (or later) stream") 644 645 # Required options 646 parser.add_option("-i", "--in", dest = "fin", metavar = "<FD or FILE>", 647 help = "Legacy input to convert") 648 parser.add_option("-o", "--out", dest = "fout", metavar = "<FD or FILE>", 649 help = "v2 (or later) format output") 650 parser.add_option("-w", "--width", dest = "twidth", 651 metavar = "<32/64>", choices = ["32", "64"], 652 help = "Legacy toolstack bitness") 653 parser.add_option("-g", "--guest-type", dest = "gtype", 654 metavar = "<pv/hvm>", choices = ["pv", "hvm"], 655 help = "Type of guest in stream") 656 657 # Optional options 658 parser.add_option("-f", "--format", dest = "format", 659 metavar = "<libxc|libxl>", default = "libxc", 660 choices = ["libxc", "libxl"], 661 help = "Desired format of the outgoing stream " \ 662 "(defaults to libxc)") 663 parser.add_option("-v", "--verbose", action = "store_true", default = False, 664 help = "Summarise stream contents") 665 parser.add_option("-x", "--xl", action = "store_true", default = False, 666 help = ("Is an `xl` header present in the stream?" 667 " (default no)")) 668 parser.add_option("--skip-qemu", action = "store_true", default = False, 669 help = ("Skip processing of the qemu tail?" 670 " (default no)")) 671 parser.add_option("--syslog", action = "store_true", default = False, 672 help = "Log to syslog instead of stdout") 673 674 opts, _ = parser.parse_args() 675 676 if (opts.fin is None or opts.fout is None or 677 opts.twidth is None or opts.gtype is None): 678 679 parser.print_help(sys.stderr) 680 raise SystemExit(1) 681 682 if opts.syslog: 683 global log_to_syslog 684 685 syslog.openlog("convert-legacy-stream", syslog.LOG_PID) 686 log_to_syslog = True 687 688 fin = open_file_or_fd(opts.fin, "rb") 689 fout = open_file_or_fd(opts.fout, "wb") 690 twidth = int(opts.twidth) 691 pv = opts.gtype == "pv" 692 verbose = opts.verbose 693 if opts.skip_qemu: 694 qemu = False 695 696 if opts.xl: 697 skip_xl_header(opts.format) 698 699 rc = read_legacy_stream(VM(opts.format)) 700 fout.close() 701 702 return rc 703 704if __name__ == "__main__": 705 try: 706 sys.exit(main()) 707 except SystemExit as e: 708 sys.exit(e.code) 709 except KeyboardInterrupt: 710 sys.exit(1) 711