diff options
author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2022-09-13 10:29:01 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2022-09-13 23:03:36 +0100 |
commit | 2d96d3f5ace29bb886d825609bd042310019a620 (patch) | |
tree | 15309efefd7d7181d8344f8eefba3fb7ad7a7720 /meta/lib/oeqa/utils/qemurunner.py | |
parent | 8d5cb0399f255eca906e960ce7fe05c62a24e891 (diff) | |
download | poky-2d96d3f5ace29bb886d825609bd042310019a620.tar.gz |
selftest/qemurunner: Work around possible control character contamination
Using a binary string as the login banner search expression is fraught with
risks. We've seen cases on the autobuilder where "login:" is clearly shown
but the code hasn't triggered. The most likely cause is hidden control characters
in the output causing the search to fail.
Take the opportunity to remove the horrible binary string search, at the expense of
decoding the bootlog multiple times.
Tweak the logging so we can know which log was printed (self.msg or bootlog)
just in case this isn't the issue and we need more information in future.
(From OE-Core rev: 91b9e30e08695e715ef14c3df7471e8c99f9deb5)
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oeqa/utils/qemurunner.py')
-rw-r--r-- | meta/lib/oeqa/utils/qemurunner.py | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/meta/lib/oeqa/utils/qemurunner.py b/meta/lib/oeqa/utils/qemurunner.py index 948f8adc9f..6a85f57e49 100644 --- a/meta/lib/oeqa/utils/qemurunner.py +++ b/meta/lib/oeqa/utils/qemurunner.py | |||
@@ -85,7 +85,7 @@ class QemuRunner: | |||
85 | accepted_patterns = ['search_reached_prompt', 'send_login_user', 'search_login_succeeded', 'search_cmd_finished'] | 85 | accepted_patterns = ['search_reached_prompt', 'send_login_user', 'search_login_succeeded', 'search_cmd_finished'] |
86 | default_boot_patterns = defaultdict(str) | 86 | default_boot_patterns = defaultdict(str) |
87 | # Default to the usual paterns used to communicate with the target | 87 | # Default to the usual paterns used to communicate with the target |
88 | default_boot_patterns['search_reached_prompt'] = b' login:' | 88 | default_boot_patterns['search_reached_prompt'] = ' login:' |
89 | default_boot_patterns['send_login_user'] = 'root\n' | 89 | default_boot_patterns['send_login_user'] = 'root\n' |
90 | default_boot_patterns['search_login_succeeded'] = r"root@[a-zA-Z0-9\-]+:~#" | 90 | default_boot_patterns['search_login_succeeded'] = r"root@[a-zA-Z0-9\-]+:~#" |
91 | default_boot_patterns['search_cmd_finished'] = r"[a-zA-Z0-9]+@[a-zA-Z0-9\-]+:~#" | 91 | default_boot_patterns['search_cmd_finished'] = r"[a-zA-Z0-9]+@[a-zA-Z0-9\-]+:~#" |
@@ -109,12 +109,15 @@ class QemuRunner: | |||
109 | sock.close() | 109 | sock.close() |
110 | raise | 110 | raise |
111 | 111 | ||
112 | def decode_qemulog(self, todecode): | ||
113 | # Sanitize the data received from qemu as it may contain control characters | ||
114 | msg = todecode.decode("utf-8", errors='ignore') | ||
115 | msg = re_control_char.sub('', msg) | ||
116 | return msg | ||
117 | |||
112 | def log(self, msg): | 118 | def log(self, msg): |
113 | if self.logfile: | 119 | if self.logfile: |
114 | # It is needed to sanitize the data received from qemu | 120 | msg = self.decode_qemulog(msg) |
115 | # because is possible to have control characters | ||
116 | msg = msg.decode("utf-8", errors='ignore') | ||
117 | msg = re_control_char.sub('', msg) | ||
118 | self.msg += msg | 121 | self.msg += msg |
119 | with codecs.open(self.logfile, "a", encoding="utf-8") as f: | 122 | with codecs.open(self.logfile, "a", encoding="utf-8") as f: |
120 | f.write("%s" % msg) | 123 | f.write("%s" % msg) |
@@ -468,7 +471,9 @@ class QemuRunner: | |||
468 | self.log(data) | 471 | self.log(data) |
469 | 472 | ||
470 | data = b'' | 473 | data = b'' |
471 | if self.boot_patterns['search_reached_prompt'] in bootlog: | 474 | |
475 | decodedlog = self.decode_qemulog(bootlog) | ||
476 | if self.boot_patterns['search_reached_prompt'] in decodedlog: | ||
472 | self.server_socket = qemusock | 477 | self.server_socket = qemusock |
473 | stopread = True | 478 | stopread = True |
474 | reachedlogin = True | 479 | reachedlogin = True |
@@ -488,10 +493,10 @@ class QemuRunner: | |||
488 | self.logger.warning("Target didn't reach login banner in %d seconds (%s)" % | 493 | self.logger.warning("Target didn't reach login banner in %d seconds (%s)" % |
489 | (self.boottime, time.strftime("%D %H:%M:%S"))) | 494 | (self.boottime, time.strftime("%D %H:%M:%S"))) |
490 | tail = lambda l: "\n".join(l.splitlines()[-25:]) | 495 | tail = lambda l: "\n".join(l.splitlines()[-25:]) |
491 | bootlog = bootlog.decode("utf-8") | 496 | bootlog = self.decode_qemulog(bootlog) |
492 | # in case bootlog is empty, use tail qemu log store at self.msg | 497 | # in case bootlog is empty, use tail qemu log store at self.msg |
493 | lines = tail(bootlog if bootlog else self.msg) | 498 | lines = tail(bootlog if bootlog else self.msg) |
494 | self.logger.warning("Last 25 lines of text:\n%s" % lines) | 499 | self.logger.warning("Last 25 lines of text (%d):\n%s" % (len(bootlog), lines)) |
495 | self.logger.warning("Check full boot log: %s" % self.logfile) | 500 | self.logger.warning("Check full boot log: %s" % self.logfile) |
496 | self._dump_host() | 501 | self._dump_host() |
497 | self.stop() | 502 | self.stop() |