. "$BST_LIB" # BST-TIMEOUT: 300 # ~50 execs of one 616 216 B wasm module, no loops and no # corpus; nothing here waits, every invocation either fails # in argv parsing or is refused by libusb_init and returns # at once. NOT MEASURED -- this port's suite has never run; # 300 is the 60s default scaled for a module ~7x the size of # evtest's, which declares none. Trim it against the first # ==BST-SUITE uhubctl elapsed=..== line rather than leaving # a bound nobody has checked. # uhubctl 2.5.0 (meta-openembedded/meta-oe recipes-support/uhubctl at SRCREV # 20276ad5, with a meta-brintos bbappend carrying one LDFLAGS line) -- per-port # USB power control for smart hubs. ONE binary, /usr/sbin/uhubctl, 616 216 B, # out of one 1245-line uhubctl.c. The -dev and -dbg packages are empty and are # not on the image. # # THE ANSWER THIS MACHINE GIVES IS NOT THE ONE THE PORT TICKET EXPECTED, and the # difference is measured rather than argued. BRINTOS-1890 was written against # "no compatible devices found" -- the empty-enumeration path at uhubctl.c:1149. # That path is UNREACHABLE here, because libusb_init fails first: # # poky's libusb1 is built --disable-udev on this arm (eudev's do_compile is # refused by the toolchain, BRINTOS-1576). find_usbfs_path() looks for # /dev/bus/usb, then /dev/usbdev*.*, and its last line is # # #if defined(HAVE_LIBUDEV) || defined(__ANDROID__) # return USB_DEVTMPFS_PATH; /* assume /dev/bus/usb */ # #else # return NULL; # #endif # # so WITHOUT udev op_init() finds no usbfs and libusb_init returns # LIBUSB_ERROR_OTHER (-99). BRINTOS-1576 built both arms natively from the # identical 1.0.27 source with /dev/bus and /sys/bus/usb bind-mounted empty -- # exactly this guest's state -- and measured --enable-udev rc=0 with an empty # device list against --disable-udev rc=-99. 99-libusb1.test pins that choice # from three independent places in the shipped archive. # # uhubctl checks that return (uhubctl.c:1130) and stops at # # Error initializing USB! # # on stderr with exit 1. So on THIS image every USB-touching invocation ends # there, one call earlier than the ticket predicted, and the empty-enumeration # message is a string the binary contains and never prints. # # NEITHER ARM IS HARDCODED BELOW. The usbfs state is read at runtime, exactly as # 99-libusb1.test reads it, and each USB-dependent case asserts the arm the probe # is in -- so the day this image grows a host controller these cases assert the # enumeration answer instead of skipping, on their own evidence rather than on # this comment. Both arms are rc 1 with a diagnostic on stderr, which is the # invariant the port is really being held to. # # WHAT IS THEREFORE ASSERTED FOR REAL, and it is most of the program's # scriptable surface: ARGUMENT VALIDATION PRECEDES libusb_init. main() runs the # whole getopt_long loop -- including ports2bitmap(), which exit(1)s on a bad # port spec -- before the first libusb call at uhubctl.c:1130. That ordering is # not assumed here: parse-precedes-init makes it a case, by handing a bad port # spec together with a location filter and requiring the port-spec diagnostic # rather than the USB one. Everything in that half is arithmetic on argv and # calls to fprintf; a wasm32 build that got it wrong has no environmental excuse. # # THE ONE THING A SUITE MUST NOT DO WITH THIS PROGRAM IS LET IT BLOCK. uhubctl # has no interactive mode, but sleep_ms() and the cycle action can hold it for # seconds, and a hub scan on a machine whose USB layer misbehaves is exactly the # shape of hang the runner's suite bound exists for. The no-argument run -- the # ticket's headline case -- goes through bst_probe with its own 20s bound, so an # overrun is reported as one case naming the last line printed, rather than # killing the suite and taking every sibling's result with it. # # THE SYSFS OPTION IS ASSERTED AGAINST THE BINARY'S OWN USAGE TEXT, not against # a guess about the triple. -S/--nosysfs is compiled in only under # __gnu_linux__, and so is its usage line; the case below requires the two to # agree, so it stays correct whichever way this toolchain defines the macro. bst_ok uhubctl/suite-canary # first line: absorbs brintos/linux#96, which drops it UH=/usr/sbin/uhubctl # The absolute path, not the PATH name: /usr/sbin is not on every login's PATH # here, and a `require uhubctl` that missed it would SKIP this whole file rather # than red -- an absent suite that reads as a legitimate one. Whether the name # also resolves through PATH is asserted below as its own case. require "$UH" uhubctl/present # uh -- # Run inside a command substitution with stdin on /dev/null. The fork is what # keeps any invocation that reads stdin away from the suite's own shell, and # /dev/null is devtmpfs -- not the virtiofs root the top-level-redirect rule is # about (brintos/linux#73). uh() { _id=$1; _want=$2; _needle=$3; shift 3 _o=$("$UH" "$@" 2>&1 -- uh_absent() { _id=$1; _want=$2; _needle=$3; shift 3 _o=$("$UH" "$@" 2>&1 /dev/null | wc -l | tr -d ' ')" # --- --version ---------------------------------------------------------------- # # `case 'v'` is printf("%s\n", PROGRAM_VERSION) then exit(0): the ONLY path in # this program that exits 0 without touching libusb. PROGRAM_VERSION is a -D on # the compile line, and it is there only because the recipe's do_configure:append # seds out the Makefile's `GIT_VERSION := $(shell git describe ...)` -- an OE # build has no tags to describe, so without that sed the banner would read empty. # Pinning the exact string is therefore pinning that sed, not just a constant. uh uhubctl/version-rc 0 "2.5.0" -v uh uhubctl/version-long-rc 0 "2.5.0" --version check_eq uhubctl/version-exact "2.5.0" "$("$UH" -v 2>/dev/null /dev/null &1, # so if the block ever moved to stderr it comes back empty and the case reds. usage_out=$("$UH" -h 2>/dev/null &1 /dev/null | sed -n 1p) noargs_out=$(grep -v '^BSTRC=' "$work/noargs" 2>/dev/null) check_eq uhubctl/no-args-bounded "0" "$probe_rc" check_eq uhubctl/no-args-rc "1" "$noargs_rc" noargs_err=$(cat "$work/noargs.err" 2>/dev/null) case "$noargs_err" in *"$usb_needle"*) bst_ok uhubctl/no-args-diagnostic ;; *) bst_notok uhubctl/no-args-diagnostic "arm=$usb_arm want:'$usb_needle' got:'$(_bst_1line "$noargs_err")'" ;; esac # The diagnostic is on stderr and stdout stays empty: uhubctl prints hub status # to stdout and it found none, so a byte there would mean it reported a hub. check_eq uhubctl/no-args-stdout-empty "" "$noargs_out" # The same refusal through the other entry points the ticket names. Each is a # distinct path into the same first libusb call, and each is asserted against the # arm the probe measured rather than against a transcribed string. uh uhubctl/location-absent 1 "$usb_needle" -l 1-2 uh uhubctl/location-deep 1 "$usb_needle" -l 1-2.3.4 uh uhubctl/action-off 1 "$usb_needle" -a off -p 1 uh uhubctl/action-on-numeric 1 "$usb_needle" -a 1 -p 1 uh uhubctl/action-toggle 1 "$usb_needle" -a toggle -p 1 uh uhubctl/exact-location 1 "$usb_needle" -e -l 1-2 # On the enumerating arm the location is echoed back into the message; on this # one it is not, because the run never reaches that fprintf. Asserted only where # it is meaningful, with the probe's own reason on the skip. if [ "$usb_arm" = enumerates ]; then uh uhubctl/location-echoed 1 "at location 1-2" -l 1-2 else bst_skip uhubctl/location-echoed "libusb_init returns -99 on this image (no usbfs: /dev/bus/usb=$devtmpfs /proc/bus/usb=$procusb), so uhubctl.c:1149 is never reached and the location is never echoed" fi # AN UNRECOGNISED --action VALUE IS SILENTLY IGNORED, not refused: `case 'a'` is # four strcasecmp arms and no else, so opt_action keeps POWER_KEEP and the run # continues exactly as an unqualified one. That is upstream's behaviour and not a # defect of this port; it is pinned because a reader of the usage text would # expect otherwise, and because a future upstream that started refusing it would # change what `-a` means to every caller. uh_absent uhubctl/action-bogus-not-syntax-error 1 "Invalid command line syntax!" -a bst-bogus uh uhubctl/action-bogus-falls-through 1 "$usb_needle" -a bst-bogus rm -rf "$work"