summaryrefslogtreecommitdiffstats
path: root/scripts/runqemu
diff options
context:
space:
mode:
authorEd Bartosh <ed.bartosh@linux.intel.com>2017-07-11 17:34:23 +0300
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-07-17 14:01:36 +0100
commit96a87592d41c9813f7b8c4f87dd3acdd3933ae50 (patch)
treeb28643220a877ae0d3397df4fac233ac1312b26c /scripts/runqemu
parent81498aac9560fbeaeb58eaada32ce80e0ea51628 (diff)
downloadpoky-96a87592d41c9813f7b8c4f87dd3acdd3933ae50.tar.gz
runqemu: reworked exception handling
Introduced custom RunQemuException that script raises on known errors. This exception is handled in one place and prints error output without printing Python traceback. This shoud make error output less scary for the end user. Handling of unknown errors has not been changed - both error and traceback will be printed. Reimplemented OEPathError exception code to handle it similarly to RunQemuException. Moved exception handling code into main() to keep it in one place. [YOCTO #11719] (From OE-Core rev: a779a382b66e7b43ac53286758b4370dc14b193b) Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com> Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/runqemu')
-rwxr-xr-xscripts/runqemu113
1 files changed, 56 insertions, 57 deletions
diff --git a/scripts/runqemu b/scripts/runqemu
index 41b870c9f7..c33741d804 100755
--- a/scripts/runqemu
+++ b/scripts/runqemu
@@ -28,14 +28,18 @@ import shutil
28import glob 28import glob
29import configparser 29import configparser
30 30
31class OEPathError(Exception): 31class RunQemuError(Exception):
32 """Custom exception to raise on known errors."""
33 pass
34
35class OEPathError(RunQemuError):
32 """Custom Exception to give better guidance on missing binaries""" 36 """Custom Exception to give better guidance on missing binaries"""
33 def __init__(self, message): 37 def __init__(self, message):
34 self.message = "In order for this script to dynamically infer paths\n \ 38 super().__init__("In order for this script to dynamically infer paths\n \
35kernels or filesystem images, you either need bitbake in your PATH\n \ 39kernels or filesystem images, you either need bitbake in your PATH\n \
36or to source oe-init-build-env before running this script.\n\n \ 40or to source oe-init-build-env before running this script.\n\n \
37Dynamic path inference can be avoided by passing a *.qemuboot.conf to\n \ 41Dynamic path inference can be avoided by passing a *.qemuboot.conf to\n \
38runqemu, i.e. `runqemu /path/to/my-image-name.qemuboot.conf`\n\n %s" % message 42runqemu, i.e. `runqemu /path/to/my-image-name.qemuboot.conf`\n\n %s" % message)
39 43
40 44
41def create_logger(): 45def create_logger():
@@ -101,10 +105,10 @@ def check_tun():
101 """Check /dev/net/tun""" 105 """Check /dev/net/tun"""
102 dev_tun = '/dev/net/tun' 106 dev_tun = '/dev/net/tun'
103 if not os.path.exists(dev_tun): 107 if not os.path.exists(dev_tun):
104 raise Exception("TUN control device %s is unavailable; you may need to enable TUN (e.g. sudo modprobe tun)" % dev_tun) 108 raise RunQemuError("TUN control device %s is unavailable; you may need to enable TUN (e.g. sudo modprobe tun)" % dev_tun)
105 109
106 if not os.access(dev_tun, os.W_OK): 110 if not os.access(dev_tun, os.W_OK):
107 raise Exception("TUN control device %s is not writable, please fix (e.g. sudo chmod 666 %s)" % (dev_tun, dev_tun)) 111 raise RunQemuError("TUN control device %s is not writable, please fix (e.g. sudo chmod 666 %s)" % (dev_tun, dev_tun))
108 112
109def check_libgl(qemu_bin): 113def check_libgl(qemu_bin):
110 cmd = 'ldd %s' % qemu_bin 114 cmd = 'ldd %s' % qemu_bin
@@ -137,7 +141,7 @@ def check_libgl(qemu_bin):
137 logger.error("You need libGL.so and libGLU.so to exist in your library path to run the QEMU emulator.") 141 logger.error("You need libGL.so and libGLU.so to exist in your library path to run the QEMU emulator.")
138 logger.error("Ubuntu package names are: libgl1-mesa-dev and libglu1-mesa-dev.") 142 logger.error("Ubuntu package names are: libgl1-mesa-dev and libglu1-mesa-dev.")
139 logger.error("Fedora package names are: mesa-libGL-devel mesa-libGLU-devel.") 143 logger.error("Fedora package names are: mesa-libGL-devel mesa-libGLU-devel.")
140 raise Exception('%s requires libGLU, but not found' % qemu_bin) 144 raise RunQemuError('%s requires libGLU, but not found' % qemu_bin)
141 145
142def get_first_file(cmds): 146def get_first_file(cmds):
143 """Return first file found in wildcard cmds""" 147 """Return first file found in wildcard cmds"""
@@ -273,7 +277,7 @@ class BaseConfig(object):
273 fst = 'cpio.gz' 277 fst = 'cpio.gz'
274 self.fstype = fst 278 self.fstype = fst
275 else: 279 else:
276 raise Exception("Conflicting: FSTYPE %s and %s" % (self.fstype, fst)) 280 raise RunQemuError("Conflicting: FSTYPE %s and %s" % (self.fstype, fst))
277 281
278 def set_machine_deploy_dir(self, machine, deploy_dir_image): 282 def set_machine_deploy_dir(self, machine, deploy_dir_image):
279 """Set MACHINE and DEPLOY_DIR_IMAGE""" 283 """Set MACHINE and DEPLOY_DIR_IMAGE"""
@@ -329,7 +333,7 @@ class BaseConfig(object):
329 else: 333 else:
330 logger.warn("%s doesn't exist" % qb) 334 logger.warn("%s doesn't exist" % qb)
331 else: 335 else:
332 raise Exception("Can't find FSTYPE from: %s" % p) 336 raise RunQemuError("Can't find FSTYPE from: %s" % p)
333 337
334 elif os.path.isdir(p) or re.search(':', p) and re.search('/', p): 338 elif os.path.isdir(p) or re.search(':', p) and re.search('/', p):
335 if self.is_deploy_dir_image(p): 339 if self.is_deploy_dir_image(p):
@@ -341,16 +345,16 @@ class BaseConfig(object):
341 elif os.path.basename(p).startswith('ovmf'): 345 elif os.path.basename(p).startswith('ovmf'):
342 self.ovmf_bios.append(p) 346 self.ovmf_bios.append(p)
343 else: 347 else:
344 raise Exception("Unknown path arg %s" % p) 348 raise RunQemuError("Unknown path arg %s" % p)
345 349
346 def check_arg_machine(self, arg): 350 def check_arg_machine(self, arg):
347 """Check whether it is a machine""" 351 """Check whether it is a machine"""
348 if self.get('MACHINE') == arg: 352 if self.get('MACHINE') == arg:
349 return 353 return
350 elif self.get('MACHINE') and self.get('MACHINE') != arg: 354 elif self.get('MACHINE') and self.get('MACHINE') != arg:
351 raise Exception("Maybe conflicted MACHINE: %s vs %s" % (self.get('MACHINE'), arg)) 355 raise RunQemuError("Maybe conflicted MACHINE: %s vs %s" % (self.get('MACHINE'), arg))
352 elif re.search('/', arg): 356 elif re.search('/', arg):
353 raise Exception("Unknown arg: %s" % arg) 357 raise RunQemuError("Unknown arg: %s" % arg)
354 358
355 logger.info('Assuming MACHINE = %s' % arg) 359 logger.info('Assuming MACHINE = %s' % arg)
356 360
@@ -381,7 +385,7 @@ class BaseConfig(object):
381 if s: 385 if s:
382 deploy_dir_image = s.group(1) 386 deploy_dir_image = s.group(1)
383 else: 387 else:
384 raise Exception("bitbake -e %s" % self.bitbake_e) 388 raise RunQemuError("bitbake -e %s" % self.bitbake_e)
385 if self.is_deploy_dir_image(deploy_dir_image): 389 if self.is_deploy_dir_image(deploy_dir_image):
386 self.set_machine_deploy_dir(arg, deploy_dir_image) 390 self.set_machine_deploy_dir(arg, deploy_dir_image)
387 else: 391 else:
@@ -435,7 +439,9 @@ class BaseConfig(object):
435 if (not unknown_arg) or unknown_arg == arg: 439 if (not unknown_arg) or unknown_arg == arg:
436 unknown_arg = arg 440 unknown_arg = arg
437 else: 441 else:
438 raise Exception("Can't handle two unknown args: %s %s" % (unknown_arg, arg)) 442 raise RunQemuError("Can't handle two unknown args: %s %s\n"
443 "Try 'runqemu help' on how to use it" % \
444 (unknown_arg, arg))
439 # Check to make sure it is a valid machine 445 # Check to make sure it is a valid machine
440 if unknown_arg: 446 if unknown_arg:
441 if self.get('MACHINE') == unknown_arg: 447 if self.get('MACHINE') == unknown_arg:
@@ -461,7 +467,7 @@ class BaseConfig(object):
461 return 467 return
462 468
463 if not self.get('QB_CPU_KVM'): 469 if not self.get('QB_CPU_KVM'):
464 raise Exception("QB_CPU_KVM is NULL, this board doesn't support kvm") 470 raise RunQemuError("QB_CPU_KVM is NULL, this board doesn't support kvm")
465 471
466 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU_KVM')) 472 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU_KVM'))
467 yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu" 473 yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
@@ -473,30 +479,30 @@ class BaseConfig(object):
473 if not kvm_cap: 479 if not kvm_cap:
474 logger.error("You are trying to enable KVM on a cpu without VT support.") 480 logger.error("You are trying to enable KVM on a cpu without VT support.")
475 logger.error("Remove kvm from the command-line, or refer:") 481 logger.error("Remove kvm from the command-line, or refer:")
476 raise Exception(yocto_kvm_wiki) 482 raise RunQemuError(yocto_kvm_wiki)
477 483
478 if not os.path.exists(dev_kvm): 484 if not os.path.exists(dev_kvm):
479 logger.error("Missing KVM device. Have you inserted kvm modules?") 485 logger.error("Missing KVM device. Have you inserted kvm modules?")
480 logger.error("For further help see:") 486 logger.error("For further help see:")
481 raise Exception(yocto_kvm_wiki) 487 raise RunQemuError(yocto_kvm_wiki)
482 488
483 if os.access(dev_kvm, os.W_OK|os.R_OK): 489 if os.access(dev_kvm, os.W_OK|os.R_OK):
484 self.qemu_opt_script += ' -enable-kvm' 490 self.qemu_opt_script += ' -enable-kvm'
485 else: 491 else:
486 logger.error("You have no read or write permission on /dev/kvm.") 492 logger.error("You have no read or write permission on /dev/kvm.")
487 logger.error("Please change the ownership of this file as described at:") 493 logger.error("Please change the ownership of this file as described at:")
488 raise Exception(yocto_kvm_wiki) 494 raise RunQemuError(yocto_kvm_wiki)
489 495
490 if self.vhost_enabled: 496 if self.vhost_enabled:
491 if not os.path.exists(dev_vhost): 497 if not os.path.exists(dev_vhost):
492 logger.error("Missing virtio net device. Have you inserted vhost-net module?") 498 logger.error("Missing virtio net device. Have you inserted vhost-net module?")
493 logger.error("For further help see:") 499 logger.error("For further help see:")
494 raise Exception(yocto_paravirt_kvm_wiki) 500 raise RunQemuError(yocto_paravirt_kvm_wiki)
495 501
496 if not os.access(dev_kvm, os.W_OK|os.R_OK): 502 if not os.access(dev_kvm, os.W_OK|os.R_OK):
497 logger.error("You have no read or write permission on /dev/vhost-net.") 503 logger.error("You have no read or write permission on /dev/vhost-net.")
498 logger.error("Please change the ownership of this file as described at:") 504 logger.error("Please change the ownership of this file as described at:")
499 raise Exception(yocto_kvm_wiki) 505 raise RunQemuError(yocto_kvm_wiki)
500 506
501 def check_fstype(self): 507 def check_fstype(self):
502 """Check and setup FSTYPE""" 508 """Check and setup FSTYPE"""
@@ -505,7 +511,7 @@ class BaseConfig(object):
505 if fstype: 511 if fstype:
506 self.fstype = fstype 512 self.fstype = fstype
507 else: 513 else:
508 raise Exception("FSTYPE is NULL!") 514 raise RunQemuError("FSTYPE is NULL!")
509 515
510 def check_rootfs(self): 516 def check_rootfs(self):
511 """Check and set rootfs""" 517 """Check and set rootfs"""
@@ -517,7 +523,7 @@ class BaseConfig(object):
517 if not self.rootfs: 523 if not self.rootfs:
518 self.rootfs = self.get('ROOTFS') 524 self.rootfs = self.get('ROOTFS')
519 elif self.get('ROOTFS') != self.rootfs: 525 elif self.get('ROOTFS') != self.rootfs:
520 raise Exception("Maybe conflicted ROOTFS: %s vs %s" % (self.get('ROOTFS'), self.rootfs)) 526 raise RunQemuError("Maybe conflicted ROOTFS: %s vs %s" % (self.get('ROOTFS'), self.rootfs))
521 527
522 if self.fstype == 'nfs': 528 if self.fstype == 'nfs':
523 return 529 return
@@ -533,10 +539,10 @@ class BaseConfig(object):
533 cmds = (cmd_name, cmd_link) 539 cmds = (cmd_name, cmd_link)
534 self.rootfs = get_first_file(cmds) 540 self.rootfs = get_first_file(cmds)
535 if not self.rootfs: 541 if not self.rootfs:
536 raise Exception("Failed to find rootfs: %s or %s" % cmds) 542 raise RunQemuError("Failed to find rootfs: %s or %s" % cmds)
537 543
538 if not os.path.exists(self.rootfs): 544 if not os.path.exists(self.rootfs):
539 raise Exception("Can't find rootfs: %s" % self.rootfs) 545 raise RunQemuError("Can't find rootfs: %s" % self.rootfs)
540 546
541 def check_ovmf(self): 547 def check_ovmf(self):
542 """Check and set full path for OVMF firmware and variable file(s).""" 548 """Check and set full path for OVMF firmware and variable file(s)."""
@@ -550,7 +556,7 @@ class BaseConfig(object):
550 self.ovmf_bios[index] = path 556 self.ovmf_bios[index] = path
551 break 557 break
552 else: 558 else:
553 raise Exception("Can't find OVMF firmware: %s" % ovmf) 559 raise RunQemuError("Can't find OVMF firmware: %s" % ovmf)
554 560
555 def check_kernel(self): 561 def check_kernel(self):
556 """Check and set kernel, dtb""" 562 """Check and set kernel, dtb"""
@@ -573,10 +579,10 @@ class BaseConfig(object):
573 cmds = (kernel_match_name, kernel_match_link, kernel_startswith) 579 cmds = (kernel_match_name, kernel_match_link, kernel_startswith)
574 self.kernel = get_first_file(cmds) 580 self.kernel = get_first_file(cmds)
575 if not self.kernel: 581 if not self.kernel:
576 raise Exception('KERNEL not found: %s, %s or %s' % cmds) 582 raise RunQemuError('KERNEL not found: %s, %s or %s' % cmds)
577 583
578 if not os.path.exists(self.kernel): 584 if not os.path.exists(self.kernel):
579 raise Exception("KERNEL %s not found" % self.kernel) 585 raise RunQemuError("KERNEL %s not found" % self.kernel)
580 586
581 dtb = self.get('QB_DTB') 587 dtb = self.get('QB_DTB')
582 if dtb: 588 if dtb:
@@ -586,7 +592,7 @@ class BaseConfig(object):
586 cmds = (cmd_match, cmd_startswith, cmd_wild) 592 cmds = (cmd_match, cmd_startswith, cmd_wild)
587 self.dtb = get_first_file(cmds) 593 self.dtb = get_first_file(cmds)
588 if not os.path.exists(self.dtb): 594 if not os.path.exists(self.dtb):
589 raise Exception('DTB not found: %s, %s or %s' % cmds) 595 raise RunQemuError('DTB not found: %s, %s or %s' % cmds)
590 596
591 def check_biosdir(self): 597 def check_biosdir(self):
592 """Check custombiosdir""" 598 """Check custombiosdir"""
@@ -606,7 +612,7 @@ class BaseConfig(object):
606 self.qemu_opt_script += ' -L %s' % biosdir 612 self.qemu_opt_script += ' -L %s' % biosdir
607 else: 613 else:
608 logger.error("Custom BIOS directory not found. Tried: %s, %s, and %s" % (self.custombiosdir, biosdir_native, biosdir_host)) 614 logger.error("Custom BIOS directory not found. Tried: %s, %s, and %s" % (self.custombiosdir, biosdir_native, biosdir_host))
609 raise Exception("Invalid custombiosdir: %s" % self.custombiosdir) 615 raise RunQemuError("Invalid custombiosdir: %s" % self.custombiosdir)
610 616
611 def check_mem(self): 617 def check_mem(self):
612 s = re.search('-m +([0-9]+)', self.qemu_opt_script) 618 s = re.search('-m +([0-9]+)', self.qemu_opt_script)
@@ -634,7 +640,7 @@ class BaseConfig(object):
634 # Check audio 640 # Check audio
635 if self.audio_enabled: 641 if self.audio_enabled:
636 if not self.get('QB_AUDIO_DRV'): 642 if not self.get('QB_AUDIO_DRV'):
637 raise Exception("QB_AUDIO_DRV is NULL, this board doesn't support audio") 643 raise RunQemuError("QB_AUDIO_DRV is NULL, this board doesn't support audio")
638 if not self.get('QB_AUDIO_OPT'): 644 if not self.get('QB_AUDIO_OPT'):
639 logger.warn('QB_AUDIO_OPT is NULL, you may need define it to make audio work') 645 logger.warn('QB_AUDIO_OPT is NULL, you may need define it to make audio work')
640 else: 646 else:
@@ -689,7 +695,7 @@ class BaseConfig(object):
689 return 695 return
690 696
691 if not os.path.exists(self.qemuboot): 697 if not os.path.exists(self.qemuboot):
692 raise Exception("Failed to find %s (wrong image name or BSP does not support running under qemu?)." % self.qemuboot) 698 raise RunQemuError("Failed to find %s (wrong image name or BSP does not support running under qemu?)." % self.qemuboot)
693 699
694 logger.info('CONFFILE: %s' % self.qemuboot) 700 logger.info('CONFFILE: %s' % self.qemuboot)
695 701
@@ -815,12 +821,12 @@ class BaseConfig(object):
815 elif os.path.exists(src2): 821 elif os.path.exists(src2):
816 src = src2 822 src = src2
817 if not src: 823 if not src:
818 raise Exception("No NFS_DIR is set, and can't find %s or %s to extract" % (src1, src2)) 824 raise RunQemuError("No NFS_DIR is set, and can't find %s or %s to extract" % (src1, src2))
819 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest)) 825 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
820 cmd = 'runqemu-extract-sdk %s %s' % (src, dest) 826 cmd = 'runqemu-extract-sdk %s %s' % (src, dest)
821 logger.info('Running %s...' % cmd) 827 logger.info('Running %s...' % cmd)
822 if subprocess.call(cmd, shell=True) != 0: 828 if subprocess.call(cmd, shell=True) != 0:
823 raise Exception('Failed to run %s' % cmd) 829 raise RunQemuError('Failed to run %s' % cmd)
824 self.clean_nfs_dir = True 830 self.clean_nfs_dir = True
825 self.rootfs = dest 831 self.rootfs = dest
826 832
@@ -828,7 +834,7 @@ class BaseConfig(object):
828 cmd = 'runqemu-export-rootfs start %s' % self.rootfs 834 cmd = 'runqemu-export-rootfs start %s' % self.rootfs
829 logger.info('Running %s...' % cmd) 835 logger.info('Running %s...' % cmd)
830 if subprocess.call(cmd, shell=True) != 0: 836 if subprocess.call(cmd, shell=True) != 0:
831 raise Exception('Failed to run %s' % cmd) 837 raise RunQemuError('Failed to run %s' % cmd)
832 838
833 self.nfs_running = True 839 self.nfs_running = True
834 840
@@ -911,7 +917,7 @@ class BaseConfig(object):
911 if os.path.exists(nosudo_flag): 917 if os.path.exists(nosudo_flag):
912 logger.error("Error: There are no available tap devices to use for networking,") 918 logger.error("Error: There are no available tap devices to use for networking,")
913 logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag) 919 logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
914 raise Exception("a new one with sudo.") 920 raise RunQemuError("a new one with sudo.")
915 921
916 gid = os.getgid() 922 gid = os.getgid()
917 uid = os.getuid() 923 uid = os.getuid()
@@ -1053,7 +1059,7 @@ class BaseConfig(object):
1053 if not qemu_system: 1059 if not qemu_system:
1054 qemu_system = self.guess_qb_system() 1060 qemu_system = self.guess_qb_system()
1055 if not qemu_system: 1061 if not qemu_system:
1056 raise Exception("Failed to boot, QB_SYSTEM_NAME is NULL!") 1062 raise RunQemuError("Failed to boot, QB_SYSTEM_NAME is NULL!")
1057 1063
1058 qemu_bin = '%s/%s' % (self.bindir_native, qemu_system) 1064 qemu_bin = '%s/%s' % (self.bindir_native, qemu_system)
1059 1065
@@ -1202,42 +1208,35 @@ class BaseConfig(object):
1202 if os.path.exists(result): 1208 if os.path.exists(result):
1203 self.set('STAGING_BINDIR_NATIVE', result) 1209 self.set('STAGING_BINDIR_NATIVE', result)
1204 return result 1210 return result
1205 raise Exception("Native sysroot directory %s doesn't exist" % result) 1211 raise RunQemuError("Native sysroot directory %s doesn't exist" % result)
1206 else: 1212 else:
1207 raise Exception("Can't find STAGING_BINDIR_NATIVE in '%s' output" % cmd) 1213 raise RunQemuError("Can't find STAGING_BINDIR_NATIVE in '%s' output" % cmd)
1208 1214
1209 1215
1210def main(): 1216def main():
1211 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv: 1217 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv:
1212 print_usage() 1218 print_usage()
1213 return 0 1219 return 0
1214 config = BaseConfig()
1215 try: 1220 try:
1221 config = BaseConfig()
1216 config.check_args() 1222 config.check_args()
1217 except Exception as esc: 1223 config.read_qemuboot()
1218 logger.error(esc) 1224 config.check_and_set()
1219 logger.error("Try 'runqemu help' on how to use it") 1225 config.print_config()
1220 return 1
1221 config.read_qemuboot()
1222 config.check_and_set()
1223 config.print_config()
1224 try:
1225 config.setup_network() 1226 config.setup_network()
1226 config.setup_rootfs() 1227 config.setup_rootfs()
1227 config.setup_final() 1228 config.setup_final()
1228 config.start_qemu() 1229 config.start_qemu()
1230 except RunQemuError as err:
1231 logger.error(err)
1232 return 1
1233 except Exception as err:
1234 import traceback
1235 traceback.print_exc()
1236 return 1
1229 finally: 1237 finally:
1238 print("Cleanup")
1230 config.cleanup() 1239 config.cleanup()
1231 return 0
1232 1240
1233if __name__ == "__main__": 1241if __name__ == "__main__":
1234 try: 1242 sys.exit(main())
1235 ret = main()
1236 except OEPathError as err:
1237 ret = 1
1238 logger.error(err.message)
1239 except Exception as esc:
1240 ret = 1
1241 import traceback
1242 traceback.print_exc()
1243 sys.exit(ret)