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