With qdl_parse_args() self-contained, move it plus print_usage() and
the shared long-option ids into cli.c, out of main()'s compilation
unit, so unit tests can link the option parser directly.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
patch_load_xml() and read_op_load() turn XML into firehose op lists
and had no direct coverage. Add a cmocka suite (linking util.c for
the real attribute accessors and stubbing the device/ux layers) that
checks a valid entry produces the expected op, that an unrecognized
child tag is skipped, and - locking in the recently fixed error
propagation - that a malformed entry or a missing file makes the
loader return an error instead of reporting success.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
How a positional argument is classified - verb, rawprogram, patch,
read, ufs or contents document - decides the whole shape of a flashing
run, yet the logic lived as private helpers of the CLI front-end where
no test could reach it, and misclassification bugs (an erase-only
rawprogram failing as "unknown file type") could only be found by
flashing. Give the classification its own module so it can be tested
directly. The contents.xml sniff used by the sahara-archive subcommand
is the same kind of decision and moves along with it.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The archive decoder parses an untrusted blob with hand-rolled bounds
checks, and the audit found real holes there - unvalidated image ids
and entry names among them. Those hardened paths could previously only
be exercised by handing qdl a corrupt archive on the command line.
With the decoder extracted into its own module, craft newc archives in
memory and pin the contract: a valid archive maps its images, and a
truncated header, an out-of-range or zero image id and an unterminated
name are each rejected without touching the image table.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
qdl.c has grown into the tool's junk drawer, and the Sahara programmer
plumbing is its largest self-contained tenant: the specifier-to-image
mapping, the CPIO archive decoder and, since the sahara-archive
subcommand arrived, the matching writer. None of it depends on the CLI
front-end it lives in, but burying it there couples it to main()'s
compilation unit, keeps the decoder and writer of the same format at
opposite ends of a 1500-line file, and puts the logic out of unit
tests' reach. Move the lot into programmer.c, where the format has one
home and the front-end shrinks to argument handling.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The loader's failure handling is exactly what the context refactor
changed, and nothing exercised it before - the module globals made
the loader untestable, so its error paths could only be reached with
a malformed provisioning XML in a real flashing session. Pin the new
contract while it is fresh: a malformed document must leave the
context empty rather than half-populated, cleanup must be safe to
repeat, and under ASAN the error paths must leak nothing.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
qdl unconditionally links against libzip, although zip archives are
just one of the supported input formats: both the flash-from-zip path
and the create-zip subcommand are conveniences on top of the plain
contents.xml / flashmap.json flows.
That unconditional dependency gets in the way of integrating qdl into
minimal embedded distributions. In Yocto, for example, libzip lives in
meta-openembedded rather than oe-core, so packaging qdl means pulling
in a whole extra layer for a feature many products never use.
Introduce a zip-container feature option. Rather than switching code
paths with preprocessor conditionals, select whole files in the build
system: the libzip implementation moves out of file.c into file_zip.c,
which is compiled together with zipper.c (the create-zip backend) only
when the feature is enabled. Builds without it compile file_nozip.c
instead, which provides the same entry points as inert stubs, so the
headers declare a single unconditional interface and file.c keeps just
the plain POSIX file handling.
The stubbed qdl_zip_open() reports "not a zip archive" for every
input, which keeps the contents.xml and flashmap.json flows working
unchanged, while create-zip and a failed flash of a zip archive report
that this qdl was built without zip-container support. As real symbols
in a single compilation unit, the stubs also remain replaceable by the
mock definitions the unit tests link in.
The feature defaults to enabled rather than auto, so a missing libzip
is a hard configure error instead of a silently skipped dependency:
distro builds cannot accidentally lose zip support, and producing a
leaner qdl requires an explicit -Dzip-container=disabled opt-out.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Inspecting or editing a device's flash previously meant dumping partitions
to files and reflashing them; there was no way to treat the live storage as
a random-access block device. Exposing a LUN over nbdkit lets ordinary host
tools - parted, mount, dd, imaging tools - operate on it directly.
Add an nbdkit plugin that uploads the firehose programmer and serves a
physical partition (LUN) as a read/write block device:
$ modprobe nbd
$ nbdkit -fv ./nbdkit-qdl-plugin.so programmer=prog_firehose_ddr.elf lun=0
meson builds it only when the nbdkit dependency is present (pass
-Dnbdkit=enabled to require it), producing nbdkit-qdl-plugin.so from the
shared qdl sources; the qdl binary is unaffected.
An EDL device can only be programmed once per session - uploading the
programmer is a one-shot transition and a reset reboots it out of firehose
- but nbdkit calls .open/.close several times per client (NBD_OPT_INFO to
probe, then NBD_OPT_GO to transfer). Programming per open and resetting per
close therefore made the first close reboot the board and every later open
time out. To solve this the plugin sets the device up once, on the first
open, keeps it configured across connections, and resets it only when the
plugin unloads.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
decode_sahara_config() was defined in qdl.c - the command-line front-end -
but it is also called from contents.c, which is part of the shared qdl
library. The qdl binary links both, so it built and ran fine; but any
program that links the library without qdl.c ends up with an undefined
reference to decode_sahara_config().
That is exactly what happens to the nbdkit plugin, which is built from
the shared sources plus its own entry point and no qdl.c: loading the
resulting shared object aborts with "undefined symbol:
decode_sahara_config".
Move the function into a dedicated src/sahara_config.c that is part of
the shared source set, so the library is self-contained. It is kept in
its own translation unit rather than folded into contents.c so that the
contents unit tests, which #include contents.c and stub this function,
keep working.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The flashmap coverage was implemented as a shell integration test that
generated a flat build tree, created a zip archive, and invoked the qdl
binary in dry-run mode. That made the test slower and tied it to the
CLI, filesystem layout, and generated fixture data.
Replace it with a cmocka unit test around flashmap_load(). The new test
provides mock flashmap JSON, XML files, zip/file access, programmer
loading, and Firehose operation collection in-process. It preserves the
existing coverage for loading flashmap.json, loading a zip containing
flashmap.json, and applying a storage selector.
Register the test with the existing cmocka test group and remove the
shell TAP test.
Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
With kickstart now available as `qdl ks`, the standalone qdl-ks binary
is the same redundancy qdl-ramdump was: a second entry point, meson
target and manpage for code the main binary already carries. Removing
it completes the consolidation onto a single qdl binary.
Drop the binary and its build/doc scaffolding, and rewrite the README
kickstart section to use `qdl ks`. The description is kept, not
removed -- the feature lives on, only its entry point changed.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
qdl-ramdump exposed crash-dump collection as its own binary, but the
exact same code is already reachable as `qdl ramdump`. Keeping a second
entry point for it costs a meson target, a manpage and README real
estate, and gives users a second name to learn, all for functionality
the main binary already provides. Consolidating on a single qdl binary
(as suggested in review) removes that duplication.
Drop the standalone binary and everything that only existed to build
and document it; the `qdl ramdump` subcommand is unchanged.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Every source change funnells through the single ~200-line
root meson.build that enumerated the sources for all binaries,
so touching one area means editing a file that mostly described
unrelated code.
Declare the source lists in src/meson.build and the tests in
tests/meson.build and pull them in with subdir(). The root meson.build
is then left to compose (dependencies, version header, targets) while
the list of files to build lives next to the files themselves, so
adding or removing a source is a one-line edit in one obvious place.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>