. "$BST_LIB"
# BST-TIMEOUT: 400 # 161 cases, ~150 execs, no loops and no corpus. MEASURED at
# # elapsed=103s on fra2 (2026-08-26,
# # ==BST-SUITE mmc-utils elapsed=103s bound=300s cases=161==)
# # and declared at ~4x that. Nothing here waits: every mmc call
# # either decides in argv, reads a 32-byte file out of tmpfs, or
# # is refused at open(2)/ioctl(2), and returns at once.
# mmc-utils -- the eMMC/SD userland on a machine with no MMC controller.
#
# WHAT THIS MACHINE CAN AND CANNOT TEST. mmc-utils is ONE program, /usr/bin/mmc,
# dispatching 29 verbs. Most of them are ioctl clients: they open a device node
# and drive it with MMC_IOC_CMD / MMC_IOC_MULTI_CMD from linux/mmc/ioctl.h. This
# kernel registers no MMC host -- there is no /sys/class/mmc_host, no mmcblk
# node, and no block layer at all (CONFIG_BLOCK is not set, the same fact
# 89-hdparm.test records) -- so the cards those verbs exist to talk to are not
# here. Whether that is still true is NOT assumed: the probe below reads the
# live system for a controller, and every gated case runs the real assertion the
# moment one appears.
#
# WHAT IS THEREFORE ASSERTED FOR REAL, and it is most of the program:
#
# - THE WHOLE DISPATCHER. mmc.c matches argv against the verb table by PREFIX,
# so `mmc ci r
` is `mmc cid read `; check_ambiguity rejects a
# prefix that fits more than one verb; and the per-verb nargs field is
# checked before any device is touched. Every one of those decisions is
# arithmetic on argv and calls to fprintf, and each has its own exit status.
#
# - THE OFFLINE REGISTER DECODERS, WHICH ARE THE BULK OF THE PORT. This is the
# finding that shaped the suite: `mmc cid read` / `csd read` / `scr read`
# take a DIRECTORY, not a device. lsmmc.c's process_dir() chdir()s into it
# and fopen()s ordinary files named `type`, `cid`, `csd` and `scr` -- the
# sysfs layout, but nothing checks that it IS sysfs. No ioctl, no device, no
# controller. Staging that directory in tmpfs therefore drives print_mmc_cid,
# print_sd_cid, print_mmc_csd, print_sd_csd and print_sd_scr -- with
# parse_bin/to_binstr underneath them -- end to end, exactly the way
# `hdparm --Istdin` carries 89-hdparm.test. Every payload below is synthetic
# and every asserted field was CHOSEN when it was generated, so each case is
# a round trip through the decoder rather than a tautology; the capacity
# lines go further and check the arithmetic the decoder does on top of the
# fields.
#
# - AND THE DEEPEST REACHABLE POINT, WITH ITS OWN CONTROL. open(2) on a path
# that is not a device SUCCEEDS when the path is an ordinary file, so an
# empty regular file carries every ioctl verb past the open into a real
# ioctl(MMC_IOC_CMD) on a real descriptor. The kernel answers ENOTTY and
# upstream reports it with perror + its own diagnostic. The control is the
# SAME argv against a path that does not exist, which must fail at open(2)
# instead: the only thing that differs between the two is whether the ioctl
# was reached. A binary that trapped on the first ioctl would produce none of
# this, so these cases are also the runtime no-trap proof.
#
# EVERY EXPECTATION HERE WAS READ OFF A NATIVE x86-64 BUILD of the same SRCREV
# (b5ca140312, poky/meta recipes-devtools/mmc) during the port -- the exit
# statuses, the message wording, and which stream each goes to -- rather than
# transcribed from the source.
#
# FOUR UPSTREAM BEHAVIOURS ARE PINNED RATHER THAN PATCHED, because they are
# mmc-utils' on every architecture and a future change to either should be
# visible here rather than silent (mmc-utils is a third-party public repository;
# see no-public-upstream-reports.md):
# - `mmc read -h` prints its usage on STDOUT and exits 255, not 0.
# - a process_dir() failure returns -1, which main() passes to exit(), so every
# register-file error exits 255.
# - softreset and preidle discard issue_cmd0()'s result and return 0 whatever
# the ioctl did, so they are the two verbs that "succeed" with no controller.
# - the three bootbus operands are keywords, and each has its own diagnostic.
require mmc mmc-utils/present
W=${TMPDIR:-/tmp}/bst-mmc.$$
out=$W.out; reg=$W.reg
mkdir -p "$W.d" 2>/dev/null
: > "$out"
: > "$reg"
# stage [ ...] -- a fake sysfs card directory.
stage() {
_d=$W.d/$1; _t=$2; shift 2
mkdir -p "$_d" 2>/dev/null
printf '%s\n' "$_t" > "$_d/type"
while [ $# -ge 2 ]; do printf '%s\n' "$2" > "$_d/$1"; shift 2; done
printf '%s' "$_d"
}
# ------------------------------------------------------------------ probe ----
# Read the live system for an MMC controller, by the routes the kernel would
# have to provide first. Nothing below is hardcoded: `host` is set only from
# what this machine actually reports.
host=""
for h in /sys/class/mmc_host/mmc*; do
[ -d "$h" ] && { host=$h; break; }
done
blk=""
for b in /dev/mmcblk*; do
[ -e "$b" ] && { blk=$b; break; }
done
# --------------------------------------------------------------- identity ----
check_out mmc-utils/path "/usr/bin/mmc" command -v mmc
# VERSION is -DVERSION=$(git describe --abbrev=6 --always --tags) taken at build
# time, and this recipe's tree carries no tags, so it is the abbreviated SRCREV.
# Asserting it pins the version the image ships: a poky SRCREV bump reddens this
# case rather than passing quietly against a different program.
check_out mmc-utils/version "b5ca14" mmc help
# With no arguments mmc prints the usage on STDOUT and exits 0 -- help is the
# documented no-argument behaviour here, not an error path.
check_rc mmc-utils/noargs-rc 0 sh -c "mmc > '$out' 2>&1"
check_out mmc-utils/noargs-usage "Usage:" cat "$out"
# `help`, `-h` and `--help` are the same three spellings of that path.
check_rc mmc-utils/help-rc 0 sh -c "mmc help > '$out' 2>&1"
check_rc mmc-utils/dash-h-rc 0 sh -c "mmc -h > '$out' 2>&1"
check_rc mmc-utils/dashdash-rc 0 sh -c "mmc --help > '$out' 2>&1"
# The verb table is printed from the same array the dispatcher matches against,
# so these assert the table itself, across all four of its shapes: a two-word
# verb, a three-word verb, a one-word verb, and one carrying an optional operand.
check_out mmc-utils/help-extcsd "mmc extcsd read " cat "$out"
check_out mmc-utils/help-wpboot "mmc writeprotect boot get " cat "$out"
check_out mmc-utils/help-cid "mmc cid read " cat "$out"
check_out mmc-utils/help-sanit "mmc sanitize [timeout_ms]" cat "$out"
check_out mmc-utils/help-trailer "mmc help|--help|-h" cat "$out"
# ------------------------------------------------------------- dispatcher ----
# An unmatched verb is exit 1, with the diagnostic on stderr and the usage on
# stdout -- two different streams, asserted as two cases.
check_rc mmc-utils/unknown-rc 1 sh -c "mmc nosuchverb > /dev/null 2>'$out'"
check_out mmc-utils/unknown-msg "ERROR: unknown command 'nosuchverb'" cat "$out"
check_rc mmc-utils/unknown-usage-rc 1 sh -c "mmc nosuchverb 2>/dev/null > '$out'"
check_out mmc-utils/unknown-usage "Usage:" cat "$out"
# A single word cannot match a two-word verb (argc-1 < ncmds), so `mmc cid` is
# not an incomplete command -- it is an unknown one.
check_rc mmc-utils/partial-rc 1 sh -c "mmc cid > /dev/null 2>'$out'"
check_out mmc-utils/partial-msg "ERROR: unknown command 'cid'" cat "$out"
# Prefix matching: argv is matched against the verb WORD BY WORD and each word
# need only be a prefix. Both of these are the full command.
check_out mmc-utils/abbrev-cid "manufacturer: 0x15" mmc ci r "$(stage ab MMC cid 15014242535431323313deadbeefc554)"
check_out mmc-utils/abbrev-csd "SPEC_VERS: 0x4" mmc cs r "$(stage ab2 MMC csd 903200320f5903ffedb7ffef8a404066)"
# ...and a prefix that fits more than one verb is refused with exit 2, naming
# which word was ambiguous. `c` fits `cache`, `csd` and `cid`.
check_rc mmc-utils/ambiguous-rc 2 sh -c "mmc c e /dev/null > /dev/null 2>'$out'"
check_out mmc-utils/ambiguous-msg "ERROR: in command 'c', 'c' is ambiguous" cat "$out"
# The nargs field is checked before any device is opened, and it has two forms:
# a minimum (negative nargs) and an exact count.
check_rc mmc-utils/nargs-min-rc 2 sh -c "mmc cid read > /dev/null 2>'$out'"
check_out mmc-utils/nargs-min-msg "ERROR: 'cid read' requires minimum 1 arg(s)" cat "$out"
check_rc mmc-utils/nargs-exact-rc 2 sh -c "mmc extcsd write '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/nargs-exact-msg "ERROR: 'extcsd write' requires 3 arg(s)" cat "$out"
check_rc mmc-utils/nargs-min3-rc 2 sh -c "mmc bootpart enable 0 0 > /dev/null 2>'$out'"
check_out mmc-utils/nargs-min3-msg "ERROR: 'bootpart enable' requires minimum 3 arg(s)" cat "$out"
# `--help` after a PARTIAL verb prints the advanced help of every verb that
# still matches, then the version, and exits 0. Two words match `extcsd`.
check_rc mmc-utils/adv-help-rc 0 sh -c "mmc extcsd --help > '$out' 2>&1"
check_out mmc-utils/adv-help-read "mmc extcsd read " cat "$out"
check_out mmc-utils/adv-help-write "mmc extcsd write " cat "$out"
check_out mmc-utils/adv-help-vers "b5ca14" cat "$out"
# There is no --version / -V: they take the unknown-command path like any other
# unmatched word, which is worth pinning because it is the spelling a script
# reaches for first.
check_rc mmc-utils/no-version-opt-rc 1 sh -c "mmc --version > /dev/null 2>'$out'"
check_out mmc-utils/no-version-opt-msg "ERROR: unknown command '--version'" cat "$out"
# ------------------------------------------------- the offline CID decoder ----
# 0x15 is in lsmmc.c's MMC manufacturer table; every other field was chosen when
# the payload was generated, so each case round-trips the bit slicing:
# MID 0x15 CBX 1(BGA) OID 0x42 PNM "BST123" PRV 1.3 PSN 0xdeadbeef
# MDT year nibble 0xc -> 1997+12 month 5 -> jun CRC 0x2a
D=$(stage mmc0 MMC cid 15014242535431323313deadbeefc554)
check_rc mmc-utils/cid-mmc-rc 0 sh -c "mmc cid read '$D' > '$out' 2>&1"
check_out mmc-utils/cid-mmc-mid "manufacturer: 0x15 (Samsung/SanDisk/LG) oid: 0x42" cat "$out"
check_out mmc-utils/cid-mmc-product "product: 'BST123' 1.3" cat "$out"
check_out mmc-utils/cid-mmc-serial "serial: 0xdeadbeef" cat "$out"
check_out mmc-utils/cid-mmc-mdt "manufacturing date: 2009 jun" cat "$out"
# The MMC CID path talks to no device, so anything on stderr would mean it tried.
sh -c "mmc cid read '$D' > /dev/null 2>'$out'"
if [ -s "$out" ]; then bst_notok mmc-utils/cid-mmc-silent "stderr not empty: $(_bst_1line "$(cat "$out")")"
else bst_ok mmc-utils/cid-mmc-silent; fi
# -v is a different renderer over the same decode, and it prints three fields the
# plain form never does -- CBX, PRV as raw hex, and the CRC.
sh -c "mmc cid read -v '$D' > '$out' 2>&1"
check_out mmc-utils/cid-mmc-v-head "======MMC/CID======" cat "$out"
check_out mmc-utils/cid-mmc-v-cbx "CBX: 0x1 (BGA)" cat "$out"
check_out mmc-utils/cid-mmc-v-prv "PRV: 0x13 (1.3)" cat "$out"
check_out mmc-utils/cid-mmc-v-psn "PSN: 0xdeadbeef" cat "$out"
check_out mmc-utils/cid-mmc-v-crc "CRC: 0x2a" cat "$out"
# MDT is rendered month-nibble-first, which is the reverse of the on-wire order
# the parse reads it in. Pinned as upstream's, not corrected.
check_out mmc-utils/cid-mmc-v-mdt "MDT: 0x5c 2009 jun" cat "$out"
# A MID absent from the table takes the other branch of get_manufacturer, and
# CBX 2 is a different arm of the same switch.
DU=$(stage mmcU MMC cid 9a02074e4f4c4953540100c0ffee3b22)
check_out mmc-utils/cid-mmc-unlisted "manufacturer: 0x9a (Unlisted) oid: 0x7" mmc cid read "$DU"
check_out mmc-utils/cid-mmc-v-pop "CBX: 0x2 (PoP)" mmc cid read -v "$DU"
# `type` selects the decoder, and the SD CID is a DIFFERENT bit layout from the
# MMC one -- 16-bit ASCII OID, 40-bit PNM, an 8-bit year with a 2000 epoch --
# so this is a second decoder, not the same one with a different table.
DS=$(stage sd0 SD cid 035344425354534427123456780179aa)
check_rc mmc-utils/cid-sd-rc 0 sh -c "mmc cid read '$DS' > '$out' 2>&1"
check_out mmc-utils/cid-sd-mid "manufacturer: 'SanDisk' 'SD'" cat "$out"
check_out mmc-utils/cid-sd-product "product: 'BSTSD' 2.7" cat "$out"
check_out mmc-utils/cid-sd-serial "serial: 0x12345678" cat "$out"
check_out mmc-utils/cid-sd-mdt "manufacturing date: 2023 oct" cat "$out"
check_out mmc-utils/cid-sd-v-oid "OID: SD" mmc cid read -v "$DS"
# ------------------------------------------------- the offline CSD decoder ----
# MMC CSD. The plain renderer prints only two lines -- upstream's choice, pinned
# here -- and -v prints the whole of it.
DC=$(stage mmcc MMC csd 903200320f5903ffedb7ffef8a404066)
check_rc mmc-utils/csd-mmc-rc 0 sh -c "mmc csd read '$DC' > '$out' 2>&1"
check_out mmc-utils/csd-mmc-spec "SPEC_VERS: 0x4 (v4.0-v4.3)" cat "$out"
check_out mmc-utils/csd-mmc-ccc "CCC: 0x0f5 (class: 7, 6, 5, 4, 2, 0," cat "$out"
sh -c "mmc csd read -v '$DC' > '$out' 2>&1"
check_out mmc-utils/csd-mmc-v-head "======MMC/CSD======" cat "$out"
check_out mmc-utils/csd-mmc-v-struct "CSD_STRUCTURE: 0x2 (v1.2)" cat "$out"
# TAAC and TRAN_SPEED are each recomposed from two fields (value<<3 | unit) and
# then rendered through a units table, so these check arithmetic, not a slice.
check_out mmc-utils/csd-mmc-v-taac "TAAC: 0x32 (250.00ns)" cat "$out"
check_out mmc-utils/csd-mmc-v-tran "TRAN_SPEED: 0x32 (26.00MHz/s)" cat "$out"
check_out mmc-utils/csd-mmc-v-nsac "NSAC: 0 clocks" cat "$out"
check_out mmc-utils/csd-mmc-v-rbl "READ_BL_LEN: 0x9 (512 bytes)" cat "$out"
check_out mmc-utils/csd-mmc-v-rbp "READ_BL_PARTIAL: 0x0 (only 512 byte and READ_BL_LEN block size)" cat "$out"
check_out mmc-utils/csd-mmc-v-dsr "DSR_IMP: 0x0 (configurable driver stage not available)" cat "$out"
# The four VDD fields index two different current tables -- min and max are not
# the same lookup -- so a decoder that used one table for both would print 35mA
# four times and fail here.
check_out mmc-utils/csd-mmc-v-vddrmin "VDD_R_CURR_MIN: 0x5 (35mA)" cat "$out"
check_out mmc-utils/csd-mmc-v-vddrmax "VDD_R_CURR_MAX: 0x5 (45mA)" cat "$out"
check_out mmc-utils/csd-mmc-v-erase "ERASE_GRP_MULT: 0x1f (1024 write blocks/erase group)" cat "$out"
check_out mmc-utils/csd-mmc-v-wpgrp "WP_GRP_SIZE: 0x0f (16 blocks/write protect group)" cat "$out"
check_out mmc-utils/csd-mmc-v-r2w "R2W_FACTOR: 0x2 (Write 2 times read)" cat "$out"
check_out mmc-utils/csd-mmc-v-fmt "FILE_FORMAT: 0x0 (partition table)" cat "$out"
check_out mmc-utils/csd-mmc-v-crc "CRC: 0x33" cat "$out"
# SD CSD v0. C_SIZE 0xea7, C_SIZE_MULT 7 and READ_BL_LEN 9 give
# (3751+1) * 2^(7+2) * 2^9 = 983564288 bytes -- the capacity line is the decoder
# doing that arithmetic, which no single-field case can check.
D0=$(stage sd_v0 SD csd 001a00325b5983a9edb7ffff0a400056)
check_rc mmc-utils/csd-sdv0-rc 0 sh -c "mmc csd read '$D0' > '$out' 2>&1"
check_out mmc-utils/csd-sdv0-classes "card classes: 10 switch, 8 application specific, 7 lock card, 5 erase, 4 block write, 2 block read, 0 basic," cat "$out"
check_out mmc-utils/csd-sdv0-capacity "capacity: 938.00Mbyte (983564288 bytes, 1921024 sectors, 512 bytes each)" cat "$out"
sh -c "mmc csd read -v '$D0' > '$out' 2>&1"
check_out mmc-utils/csd-sdv0-v-head "======SD/CSD======" cat "$out"
check_out mmc-utils/csd-sdv0-v-struct "CSD_STRUCTURE: 0" cat "$out"
check_out mmc-utils/csd-sdv0-v-csize "C_SIZE: 0xea7" cat "$out"
check_out mmc-utils/csd-sdv0-v-mult "C_SIZE_MULT: 0x7" cat "$out"
check_out mmc-utils/csd-sdv0-v-tran "TRAN_SPEED: 0x32 (25.00Mbit/s)" cat "$out"
# SD CSD v1 (SDHC/SDXC) is a THIRD layout: a 22-bit C_SIZE where v0 has 12, no
# VDD or C_SIZE_MULT at all, and a different capacity formula --
# (30719+1) * 512 * 1024 = 16106127360 bytes.
D1=$(stage sd_v1 SD csd 4070001a5b59000077ff7f800a4000ee)
check_rc mmc-utils/csd-sdv1-rc 0 sh -c "mmc csd read '$D1' > '$out' 2>&1"
check_out mmc-utils/csd-sdv1-capacity "capacity: 15.00Gbyte (16106127360 bytes, 31457280 sectors, 512 bytes each)" cat "$out"
sh -c "mmc csd read -v '$D1' > '$out' 2>&1"
check_out mmc-utils/csd-sdv1-v-struct "CSD_STRUCTURE: 1" cat "$out"
check_out mmc-utils/csd-sdv1-v-csize "C_SIZE: 0x0077ff" cat "$out"
check_out mmc-utils/csd-sdv1-v-sector "SECTOR_SIZE: 0x7f (Erasable sector: 128 blocks)" cat "$out"
check_out mmc-utils/csd-sdv1-v-wpgrp "WP_GRP_SIZE: 0x00 (Write protect group: 1 blocks)" cat "$out"
# This payload's TAAC and TRAN_SPEED are deliberately values the SD spec does not
# permit, so it also exercises the two validity warnings -- the only branch in
# the decoder that judges its input rather than rendering it.
check_out mmc-utils/csd-sdv1-warn-taac "Warn: Invalid TAAC (should be 0x0e)" cat "$out"
check_out mmc-utils/csd-sdv1-warn-tran "Warn: Invalid TRAN_SPEED (should be 0x32, 0x5a, 0x0b or 0x2b" cat "$out"
# A CSD_STRUCTURE the decoder has no layout for is reported and abandoned -- on
# stdout, and still exit 0.
D3=$(stage sd_v3 SD csd c0000000000000000000000000000000)
check_rc mmc-utils/csd-unknown-rc 0 sh -c "mmc csd read '$D3' > '$out' 2>&1"
check_out mmc-utils/csd-unknown-msg "Unknown CSD structure: 0x3" cat "$out"
# ------------------------------------------------- the offline SCR decoder ----
DR=$(stage sd_scr SD scr 0285800300000000)
check_rc mmc-utils/scr-rc 0 sh -c "mmc scr read '$DR' > '$out' 2>&1"
check_out mmc-utils/scr-version "version: SD 3.0x" cat "$out"
check_out mmc-utils/scr-widths "bus widths: 4bit, 1bit," cat "$out"
sh -c "mmc scr read -v '$DR' > '$out' 2>&1"
check_out mmc-utils/scr-v-head "======SD/SCR======" cat "$out"
check_out mmc-utils/scr-v-struct "SCR_STRUCTURE: 0x0 (SCR v1.0)" cat "$out"
check_out mmc-utils/scr-v-spec "SD_SPEC: 0x2 (SD v2.00/v3.0x)" cat "$out"
check_out mmc-utils/scr-v-sec "SD_SECURITY: 0x0 (no security)" cat "$out"
check_out mmc-utils/scr-v-cmd "CMD_SUPPORT: 0x3 (CMD23 CMD20" cat "$out"
# ------------------------------------- the register-file error lattice --------
# Each of these fails at a DIFFERENT point of process_dir, and each has its own
# diagnostic. All exit 255: process_dir returns -1 and main() hands that to
# exit(), which truncates to 255 -- upstream's, pinned rather than corrected.
check_rc mmc-utils/err-nodir-rc 255 sh -c "mmc cid read '$W.d/nosuchdir' > /dev/null 2>'$out'"
check_out mmc-utils/err-nodir "MMC/SD information directory" cat "$out"
DN=$W.d/notype; mkdir -p "$DN" 2>/dev/null
check_rc mmc-utils/err-notype-rc 255 sh -c "mmc cid read '$DN' > /dev/null 2>'$out'"
check_out mmc-utils/err-notype-open "Could not open MMC/SD file 'type'." cat "$out"
check_out mmc-utils/err-notype-msg "Could not read card interface type in directory" cat "$out"
DB=$(stage badtype FOO)
check_rc mmc-utils/err-badtype-rc 255 sh -c "mmc cid read '$DB' > /dev/null 2>'$out'"
check_out mmc-utils/err-badtype "Unknown type: 'FOO'" cat "$out"
DM=$(stage nocid MMC)
check_rc mmc-utils/err-nocid-rc 255 sh -c "mmc cid read '$DM' > /dev/null 2>'$out'"
check_out mmc-utils/err-nocid "Could not read card identity in directory" cat "$out"
DE=$(stage emptycid MMC); : > "$DE/cid"
check_rc mmc-utils/err-emptycid-rc 255 sh -c "mmc cid read '$DE' > /dev/null 2>'$out'"
check_out mmc-utils/err-emptycid "Could not read data from MMC/SD file 'cid'." cat "$out"
DK=$(stage nocsd MMC)
check_rc mmc-utils/err-nocsd-rc 255 sh -c "mmc csd read '$DK' > /dev/null 2>'$out'"
check_out mmc-utils/err-nocsd "Could not read card specific data in" cat "$out"
# -h and an unknown option both leave through parse_opts, printing the option
# usage on STDOUT and exiting 255. getopt's own complaint names argv[0], which
# prepare_args() rewrote to the full verb -- so this also asserts that rewrite.
check_rc mmc-utils/opt-h-rc 255 sh -c "mmc cid read -h > '$out' 2>&1"
check_out mmc-utils/opt-h-usage "Usage: print mmc [-h] [-v] " cat "$out"
check_rc mmc-utils/opt-bad-rc 255 sh -c "mmc cid read -Z x > /dev/null 2>'$out'"
check_out mmc-utils/opt-bad-getopt "mmc cid read: invalid option -- 'Z'" cat "$out"
check_out mmc-utils/opt-bad-msg "Unknown option '?' encountered." cat "$out"
# ----------------------------------------------- what read_file() tolerates ---
# read_file trims surrounding whitespace and to_binstr accepts either case, and
# parse_bin stops when the format is consumed rather than when the string is --
# so a longer value decodes to the same card. Three spellings, one answer, which
# is a stronger statement than any of them alone.
DW=$(stage ws MMC cid " 15014242535431323313deadbeefc554 ")
DUP=$(stage up MMC cid "15014242535431323313DEADBEEFC554")
DL=$(stage lng MMC cid "15014242535431323313deadbeefc554ffff")
want="product: 'BST123' 1.3"
check_out mmc-utils/tol-whitespace "$want" mmc cid read "$DW"
check_out mmc-utils/tol-uppercase "$want" mmc cid read "$DUP"
check_out mmc-utils/tol-trailing "$want" mmc cid read "$DL"
# --------------------------------------------- the argv validation lattice ----
# These reject before any device is opened, so they say nothing about MMC and
# everything about the program. The three bootbus operands are keywords and each
# has its own message -- a lattice, walked one rung at a time.
check_rc mmc-utils/bb-mode-rc 1 sh -c "mmc bootbus set bogus x1 x1 '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/bb-mode "illegal specified" cat "$out"
check_rc mmc-utils/bb-reset-rc 1 sh -c "mmc bootbus set dual bogus x1 '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/bb-reset "illegal specified" cat "$out"
check_rc mmc-utils/bb-width-rc 1 sh -c "mmc bootbus set dual retain bogus '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/bb-width "illegal specified" cat "$out"
check_rc mmc-utils/erase-type-rc 1 sh -c "mmc erase bogustype 0 100 '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/erase-type "Unknown erase type: bogustype" cat "$out"
# start > end is arithmetic on two parsed integers, and the diagnostic prints
# both back in a fixed 8-digit hex form -- so it checks the parse and the format.
check_rc mmc-utils/erase-range-rc 1 sh -c "mmc erase legacy 100 0 '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/erase-range "erase start [0x00000064] > erase end [0x00000000]" cat "$out"
check_rc mmc-utils/wp-type-rc 1 sh -c "mmc writeprotect user set bogus 0 1 '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/wp-type 'Error, invalid "type"' cat "$out"
# ffu and rpmb open their own file operands before touching the device, so an
# absent one fails at open(2) with the tool's own wording.
check_rc mmc-utils/ffu-noimage-rc 1 sh -c "mmc ffu '$W.d/nosuchimage' '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/ffu-noimage "image open failed: No such file or directory" cat "$out"
check_rc mmc-utils/rpmb-nokey-rc 1 sh -c "mmc rpmb write-key '$reg' '$W.d/nosuchkey' > /dev/null 2>'$out'"
check_out mmc-utils/rpmb-nokey "can't open key file: No such file or directory" cat "$out"
# rpmb read-block's own usage check is a fourth arity form: nargs allows it, the
# verb re-checks, and the message is the full usage line.
check_rc mmc-utils/rpmb-usage-rc 1 sh -c "mmc rpmb read-block '$reg' 0 1 > /dev/null 2>'$out'"
check_out mmc-utils/rpmb-usage "Usage: mmc rpmb read-block" cat "$out"
# --------------------------------------- the device path reaches the OS -------
# mmc does not check that its argument is an MMC device: it opens whatever path
# it is given and issues the ioctl. On this target that is what makes the path
# testable -- ENOTTY comes back from the kernel with an errno the tool prints,
# rather than the binary trapping the way an unresolved symbol would. Each of
# these is a different ioctl call site with a different follow-up diagnostic.
check_rc mmc-utils/notty-extcsd-rc 1 sh -c "mmc extcsd read '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/notty-extcsd-ioctl "ioctl: Inappropriate ioctl for device" cat "$out"
check_out mmc-utils/notty-extcsd-msg "Could not read EXT_CSD from" cat "$out"
check_rc mmc-utils/notty-status-rc 1 sh -c "mmc status get '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/notty-status "Could not read response to SEND_STATUS from" cat "$out"
check_rc mmc-utils/notty-wpboot-rc 1 sh -c "mmc writeprotect boot get '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/notty-wpboot "Could not read EXT_CSD from" cat "$out"
check_rc mmc-utils/notty-cache-rc 1 sh -c "mmc cache enable '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/notty-cache "Could not read EXT_CSD from" cat "$out"
# A WRITE path, which fails at a different call site and names the byte it meant
# to write and the offset it meant to write it to.
check_rc mmc-utils/notty-sanitize-rc 1 sh -c "mmc sanitize '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/notty-sanitize "Could not write 0x01 to EXT_CSD[165] in" cat "$out"
check_rc mmc-utils/notty-extwrite-rc 1 sh -c "mmc extcsd write 300 1 '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/notty-extwrite "Could not write 0x01 to EXT_CSD[300] in" cat "$out"
# The RPMB ioctl is MMC_IOC_MULTI_CMD, a different ioctl number reported by its
# own wording -- so this is a second ioctl entry point, not the same one again.
check_rc mmc-utils/notty-rpmb-rc 1 sh -c "mmc rpmb read-counter '$reg' > /dev/null 2>'$out'"
check_out mmc-utils/notty-rpmb "RPMB ioctl failed: Inappropriate ioctl for device" cat "$out"
# THE CONTROL for every case above: the same argv against a path that does not
# exist must fail at open(2) instead, with a different errno and no ioctl
# diagnostic at all. Without this pair the ENOTTY cases would be consistent with
# the open having failed too.
check_rc mmc-utils/enoent-rc 1 sh -c "mmc extcsd read '$W.d/nosuchdev' > /dev/null 2>'$out'"
check_out mmc-utils/enoent-open "open: No such file or directory" cat "$out"
if grep -q 'Inappropriate ioctl for device' "$out"; then
bst_notok mmc-utils/enoent-no-ioctl "an absent path still reached the ioctl"
else
bst_ok mmc-utils/enoent-no-ioctl
fi
# Running eight failed ioctls in one suite without dying is itself the runtime
# no-trap statement for this binary; count the distinct diagnostics as one case.
sh -c "mmc extcsd read '$reg'; mmc status get '$reg'; mmc cache disable '$reg'; mmc hwreset enable '$reg'" > /dev/null 2>"$out"
n=$(grep -c 'Inappropriate ioctl for device' "$out")
if [ "$n" -ge 4 ]; then bst_ok mmc-utils/multi-ioctl-survives
else bst_notok mmc-utils/multi-ioctl-survives "expected >=4 ioctl diagnostics, got $n"; fi
# softreset and preidle call issue_cmd0() and DISCARD its result, returning 0
# whatever the ioctl did -- so they are the two verbs that report success with no
# controller present. Pinned as upstream's; a future version that propagated the
# error would redden these, which is the point.
check_rc mmc-utils/softreset-rc 0 sh -c "mmc softreset '$reg' > /dev/null 2>&1"
check_rc mmc-utils/preidle-rc 0 sh -c "mmc preidle '$reg' > /dev/null 2>&1"
# ------------------------------------------------ controller-gated cases ------
# Each runs the real assertion the moment this kernel registers an MMC host.
if [ -n "$host" ]; then
check mmc-utils/host-extcsd mmc extcsd read "$host"
check_out mmc-utils/host-cid "manufacturer" mmc cid read "$host"
else
bst_skip mmc-utils/host-extcsd "no MMC controller on this kernel: no /sys/class/mmc_host/mmc* -- EXT_CSD has no card to be read from"
bst_skip mmc-utils/host-cid "no MMC controller: the CID decoder itself is covered by the cid-* cases above, which need no device"
fi
if [ -n "$blk" ]; then
check mmc-utils/blk-status mmc status get "$blk"
else
bst_skip mmc-utils/blk-status "no block layer on this kernel (CONFIG_BLOCK not set): no mmcblk node in /dev for SEND_STATUS to be issued to"
fi
rm -rf "$W".* 2>/dev/null