diff --git a/skills.json b/skills.json index 8e613d0..c592e46 100644 --- a/skills.json +++ b/skills.json @@ -308,7 +308,7 @@ "homepage": "https://github.com/qualcomm-linux/qcom-linux-skills", "versions": [ { - "version": "0.1", + "version": "0.2", "path": "skills/qcom-boot-validate", "docPath": "skills/qcom-boot-validate/SKILL.md", "files": ["skills/qcom-boot-validate/**"], diff --git a/skills/qcom-boot-validate/SKILL.md b/skills/qcom-boot-validate/SKILL.md index 062bfd8..6fa5fcd 100644 --- a/skills/qcom-boot-validate/SKILL.md +++ b/skills/qcom-boot-validate/SKILL.md @@ -11,7 +11,7 @@ description: >- over ssh). Do NOT use for flashing (see qcom-flash-qdl) or for diagnosing a healthy-but-degraded system. metadata: - version: "0.1" + version: "0.2" --- # Validate a board boots over the serial console @@ -59,7 +59,11 @@ ssh "python3 - --port /dev/ttyUSB0 --password oelinux123" \ after) resetting, e.g. right after a flash completes. - `--power-cycle-cmd` runs a host command once at startup for setups that can drive board power programmatically (lab automation, smart PDU). Keep - site-specific automation in that command, not in this skill. + site-specific automation in that command, not in this skill. The command + is split shell-style and run without a shell; wrap it in `sh -c '...'` + if it needs pipes, redirection, variable or `~` expansion, or is a script + without a `#!` line. If it cannot be started, the script warns and keeps + watching the console, so the board must then be reset by hand. - Exit code `0` on `BOOT-VALIDATION: PASS`, non-zero on failure. The full console capture is mirrored to the log file (default `/tmp/qcom-boot-validate-.log`) for evidence. diff --git a/skills/qcom-boot-validate/scripts/boot-validate.py b/skills/qcom-boot-validate/scripts/boot-validate.py index 4f91be7..a0bf8d0 100755 --- a/skills/qcom-boot-validate/scripts/boot-validate.py +++ b/skills/qcom-boot-validate/scripts/boot-validate.py @@ -16,7 +16,8 @@ By default the script only watches the console: start it, then power-cycle or reset the board (or start it right after flashing). Alternatively pass --power-cycle-cmd with a host command that power-cycles the board (e.g. a -lab automation wrapper); it is run once at startup. +lab automation wrapper); it is run once at startup, without a shell (wrap it +in sh -c '...' for shell syntax). Prints "BOOT-VALIDATION: PASS ..." and exits 0 on success; prints "BOOT-VALIDATION: FAIL ..." and exits non-zero otherwise. The full console @@ -26,6 +27,7 @@ import argparse import os import re +import shlex import subprocess import sys import time @@ -77,7 +79,8 @@ def main(): ap.add_argument("--timeout", type=float, default=300.0, help="seconds to wait for the login prompt") ap.add_argument("--power-cycle-cmd", default=None, - help="optional host command that power-cycles the board; run once at startup") + help="optional host command that power-cycles the board; run once at " + "startup, without a shell (use sh -c '...' for shell syntax)") ap.add_argument("--logfile", default=None, help="console capture path (default: /tmp/qcom-boot-validate-.log)") args = ap.parse_args() @@ -183,12 +186,22 @@ def wait_for_text(needle, timeout): # 1) trigger a clean boot ------------------------------------------------- if args.power_cycle_cmd: log("power-cycling board via: %s" % args.power_cycle_cmd) - r = subprocess.run(args.power_cycle_cmd, shell=True, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - log("power-cycle rc=%d: %s" % (r.returncode, - r.stdout.decode(errors="replace").strip())) - if r.returncode != 0: - log("WARNING: power-cycle command returned non-zero; continuing to watch console") + # No shell: the command is split into argv; wrap it in sh -c '...' + # explicitly if it needs shell syntax (pipes, redirection, $VAR, ~) + # or is a script without a #! line. + try: + argv = shlex.split(args.power_cycle_cmd) + if not argv: + raise ValueError("empty command") + r = subprocess.run(argv, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except (OSError, ValueError) as e: + log("WARNING: could not run power-cycle command (%s); " + "continuing to watch console" % e) + else: + log("power-cycle rc=%d: %s" % (r.returncode, + r.stdout.decode(errors="replace").strip())) + if r.returncode != 0: + log("WARNING: power-cycle command returned non-zero; continuing to watch console") else: log("no --power-cycle-cmd given: power-cycle or reset the board now " "if it is not already booting")