. "$BST_LIB" # BST-TIMEOUT: 900 # 65 cases and roughly 140 execs, which is the number that # # matters. On this arm a process's memory is not returned # # when it exits and /bin/sh is a 16 MB wasm module, so a # # suite's cost is dominated by how many programs it STARTS, # # not by how many cases it reports. Counted per oracle # # case: one `timeout', one tool, and three `cat's (the # # captured stderr, the two halves of the rebuilt # # serialization, and the expected file) -- about five, times # # 24, plus the controls, the probes and the table cases. # # At the ~1.5 s per exec 99-fbset-modes measured (56 cases, # # 13 s, five execs) that is ~210 s, so 900 is a little over # # four times the estimate rather than the 2x that 420 -- # # this file's first value, written against an exec count # # less than half the real one -- would have given. # # Neighbouring suites sit at 1200-1800 for less, so this is # # not an outlier. Every tool call is wrapped in `timeout 15' # # regardless, so the worst case is bounded by the case count # # rather than by any one tool -- which matters here because # # inputattach BLOCKS FOREVER on a node it opens. # linuxconsoletools 1.7.1 (sourceforge.net/projects/linuxconsole), packaged by # meta-openembedded/meta-oe recipes-extended/linuxconsole with a meta-brintos # bbappend. The Linux Console Project's input tools: inputattach binds a serial # device to a kernel input protocol, jstest and jscal test and calibrate a # joystick node, fftest / ffset / ffcfstress drive force feedback, and # evdev-joystick adjusts an evdev axis. # # --------------------------------------------------------------------------- # WHAT THIS MACHINE CANNOT TEST, AND WHY IT IS NOT A DEFECT. # # THIS IMAGE EXPOSES NO EVDEV OR JOYSTICK INPUT DEVICE. There is no /dev/input, # no /dev/js*, and no driver behind either. The guest's only human-input path is # the browser's xterm.js console, which arrives as a tty -- 99-serialcheck and # 59-picocom both measure that side -- and a tty is not an input node. So the # ioctl work these tools exist to do (JSIOCG*/JSIOCS* on a joystick node, the # EVIOC* queries and the struct ff_effect write on an event node) has nothing to # be issued against, and that is the platform rather than a bug. # # EVERY ABSENCE BELOW IS READ AT RUNTIME, not asserted from this comment. The # probe block reads /dev, /proc/bus/input/devices and /sys/class/input, and each # skip is written against the live answer -- so the day this image grows an # input device the skips turn back into assertions on their own evidence. # # --------------------------------------------------------------------------- # AND WHAT IS LEFT IS MOST OF EACH PROGRAM, ASSERTED BYTE FOR BYTE. # # The bbappend takes an x86-64 reference at do_install from the same sources it # just cross-compiled, over the arms that return before any open(2) plus the # arms that fail one on a path no machine can have. Twenty-four cases: every # usage text, inputattach's WHOLE 50-row protocol-name table, six of its # argument-validation diagnostics, jstest's three argc arms, jscal's # more-than-one-action and missing-devicename refusals and getopt_long's own # argv[0]-carrying errors, fftest's banner -- and, for all four tools, the exit # status each documents when the named device cannot be opened. # # STDOUT AND STDERR ARE COMPARED SEPARATELY. Two of these programs write a # diagnostic to stderr and their usage text to stdout in the same run, and which # order the two appear in a MERGED capture is a property of libc's buffering # rather than of the program: inputattach --baud puts its stderr line first into # a pipe and last onto a terminal, from one unchanged binary. Merging them would # assert glibc's buffering policy on wasm32 against glibc's on x86-64, which is # not what this port claims. Separated, each stream is compared for exactly what # the program put in it, and the exit status travels with them so that a case # which prints the right text and exits wrong is not a pass. # # ARGV[0] IS PART OF THE OUTPUT for two of the four -- jscal's getopt_long # errors print it and fftest's usage line prints it -- so every case runs the # binary as ./TOOL from inside ${bindir}, exactly as the oracle did from inside # its own directory. Anything else would compare two invocations rather than two # architectures. # # THE OPEN-FAILURE PATH IS ASSERTED, NOT SKIPPED. It is the one device-shaped # behaviour a machine with no input devices can measure, all four tools reach it # by a different route (strerror(3) by hand in inputattach, perror(3) in jstest # and jscal, perror(3) after a hardcoded default in fftest), and every such case # names a path under /dev that cannot exist -- so what is measured is ENOENT and # not this machine's hardware. # # AND THE CONTROLS ARE WHAT MAKE THE SKIPS MEAN ANYTHING. "There is no input # device" and "this process cannot open device nodes at all" produce the same # ENOENT-shaped story from every tool here, so three cases open /dev/null and # carry jstest, jscal and fftest PAST the open and into their first ioctl, which # answers ENOTTY. If those hold while /dev/input is absent, the difference is # the device and nothing else. If they stop holding, this suite reds rather than # quietly skipping. inputattach has no such control on purpose: it BLOCKS on a # node it opens successfully, so a control case for it would hang the guest. # # THE ioctl ABI ITSELF IS GATED AT BUILD TIME, in the bbappend's # do_compile:append -- struct js_event, struct js_corr, struct ff_effect, the # JSIOC*/EVIOC* request numbers, and that struct input_event's type/code/value # tail sits immediately after a timestamp two __kernel_ulong_t wide. That last # one is the load-bearing statement on an ILP32 arm and it is the one fact no # test here can reach: with no node to write to, a struct wider than the # kernel's would ship unnoticed. A _Static_assert is the right instrument for # it, and the build failing IS the assertion. # # THAT GATE FAILED ON ITS FIRST BUILD, and what it caught is worth knowing here # because no case below can show it: struct ff_effect is NOT the same size on # this arm as on the LP64 host every reference number came from. Its union # carries ff_periodic_effect, which holds an `__s16 *custom_data', so the struct # is 44 bytes here against 48 on x86-64 -- and EVIOCSFF is therefore 0x402C4580 # rather than 0x40304580, since _IOC packs the payload size into the request # number. The kernel this image runs is built for the same 32-bit arch from the # same UAPI header and so agrees with userspace; what would NOT have agreed is a # port that carried the LP64 number across, which is what the first draft did. # fftest's EVIOCSFF is skipped below for want of a device, so this arm's request # number is asserted at build time or nowhere. # # --------------------------------------------------------------------------- # TWO UPSTREAM FINDINGS ARE PINNED HERE AS FINDINGS, NOT AS ENDORSEMENTS. # # 1. The four tools DISAGREE about --help's exit status. inputattach and jscal # exit 0; jstest and fftest exit 1. Each is pinned individually below # rather than normalised by a rule, because the disagreement is real and a # script that trusts one of them is wrong about the others. # 2. jscal's `-v' is in the optstring ("chpqu:s:vVt") with NO case to handle # it. It falls to `default:', which prints "jscal: option parsing error" # and does NOT exit -- so the run continues to the device open with no # action set. `-V' is the version option; `-v' is a typo that upstream # accepts and half-diagnoses. # 3. ONLY inputattach NAMES THE DEVICE IT COULD NOT OPEN. It builds its own # message with strerror(3) -- "inputattach: '' - " -- while # jstest calls perror("jstest"), jscal calls perror("jscal: can't open # joystick device") and fftest calls perror("Open device file"), none of # which carries the path. A user with two joysticks is told only that one # of them is missing. # # THIS ONE GETS NO CASE OF ITS OWN, deliberately. The four *-open-enoent # comparisons above already pin each diagnostic BYTE FOR BYTE, so the # presence of the path in one and its absence in the other three is # already asserted -- and a fifth case re-running the same four programs # to say so again would cost four execs on a guest whose per-exec price is # the dominant term in this file's runtime. It is recorded here, and in # the recipe's own do_install guard, which is shaped around it. bst_ok linuxconsole/suite-canary # first line: absorbs brintos/linux#96, which drops it require inputattach linuxconsole/present LCT=/usr/libexec/linuxconsole-tests LCBIN=/usr/bin NOSUCH=/dev/brintos-no-such-input work=${TMPDIR:-/tmp}/bst-linuxconsole.$$ mkdir -p "$work" || { bst_notok linuxconsole/workdir "cannot create $work"; exit 0; } # --- what upstream installs -------------------------------------------------- # # The recipe splits ten programs across three packages the way Debian does # (inputattach / joystick / joystick-jscal), each with an explicit FILES, so a # rename upstream would leave one of them empty and half this file skipping # quietly. The names are checked in ${bindir} rather than on PATH because every # case below runs them as ./TOOL from there. for t in inputattach inputattachctl jstest jscal jscal-restore jscal-store \ fftest ffset ffcfstress evdev-joystick; do if [ -x "$LCBIN/$t" ]; then bst_ok "linuxconsole/installed/$t" else bst_notok "linuxconsole/installed/$t" "not executable at $LCBIN/$t -- upstream's Makefile installs all ten to PREFIX/bin" fi done # ffmvforce is the ELEVENTH program and it is deliberately ABSENT: it needs # libsdl2, which this image does not carry, and PACKAGECONFIG = "" in the # bbappend is upstream's own supported arm for dropping it. Asserted as an # absence so that a PACKAGECONFIG that silently regained "sdl" -- and with it a # dependency on a library nothing else here wants -- is visible. if [ -e "$LCBIN/ffmvforce" ]; then bst_notok "linuxconsole/ffmvforce-absent" "ffmvforce is installed; PACKAGECONFIG is supposed to be empty on this image, and it links against libsdl2" else bst_ok "linuxconsole/ffmvforce-absent" fi # --- the oracle --------------------------------------------------------------- if [ -r "$LCT/oracle.txt" ]; then bst_ok "linuxconsole/oracle/present" else bst_notok "linuxconsole/oracle/present" "$LCT/oracle.txt is missing -- linuxconsole-tests did not reach the image, so nothing below can be compared" exit 0 fi # --- is there an input device on this machine? -------------------------------- # # Read, not assumed. Three independent facts, because they fail for different # reasons: /dev/input is what a devtmpfs or a mdev rule would populate, # /proc/bus/input/devices is what the kernel's input CORE publishes if it is # compiled in at all, and /sys/class/input is the driver-model side. A machine # missing all three has no input subsystem to speak of; a machine missing only # the first has one and no nodes, which is a different story and would want # different skips. have_dev=no; [ -d /dev/input ] && [ -n "$(ls -A /dev/input 2>/dev/null)" ] && have_dev=yes have_js=no; for j in /dev/js* /dev/input/js*; do [ -e "$j" ] && have_js=yes; done have_proc=no; [ -s /proc/bus/input/devices ] && have_proc=yes have_sys=no; [ -d /sys/class/input ] && [ -n "$(ls -A /sys/class/input 2>/dev/null)" ] && have_sys=yes probe="dev-input=$have_dev js-node=$have_js proc-devices=$have_proc sys-class=$have_sys" # The path every open-failure case names, on both sides. If it ever exists, those # cases stop being about ENOENT and this suite says so instead of comparing. if [ -e "$NOSUCH" ]; then bst_notok "linuxconsole/nosuch-absent" "$NOSUCH exists on this image, so every open-failure case below would be measuring it rather than ENOENT" exit 0 else bst_ok "linuxconsole/nosuch-absent" fi # --- the oracle comparison ---------------------------------------------------- # # lc_case ID TOOL [args...] -- run ./TOOL from ${bindir} with the given # arguments, rebuild the four-part serialization the bbappend wrote, and compare # it whole against $LCT/ID.expected. # # The `( cd ... )' subshell is what makes ./TOOL resolve, and it is also why the # redirects below are safe: they are performed by a forked child, on a path # under $TMPDIR, and the suite's own shell never dup2()s anything. # # `timeout 15' is not decoration. inputattach BLOCKS forever on a device it # opens successfully -- measured on /dev/null -- so a case that unexpectedly # reached a real node would otherwise sit past this file's whole budget and take # every sibling suite in the boot down with it. lc_case() { _lc_id=$1; _lc_t=$2; shift 2 _lc_rc=0 ( cd "$LCBIN" && bst_bound 15 ./"$_lc_t" "$@" ) > "$work/out" 2> "$work/err" || _lc_rc=$? _lc_err=$(cat "$work/err") if bst_execfail "$_lc_err"; then bst_unrun "linuxconsole/$_lc_id" "$_lc_err"; return; fi _lc_act=$(cat "$work/out"; echo "==BST-ERR=="; cat "$work/err"; echo "==BST-RC== $_lc_rc") _lc_exp=$(cat "$LCT/$_lc_id.expected" 2>/dev/null) if [ -z "$_lc_exp" ]; then bst_notok "linuxconsole/$_lc_id" "no expected capture at $LCT/$_lc_id.expected" return fi check_eq "linuxconsole/$_lc_id" "$_lc_exp" "$_lc_act" } # inputattach -- --help carries the WHOLE protocol-name table, which is by some # distance the largest single thing this port asserts, and then six arms of the # argv loop that each return before any open(2). lc_case ia-help inputattach --help lc_case ia-no-mode inputattach lc_case ia-invalid-mode inputattach --bogus lc_case ia-missing-device inputattach --dump lc_case ia-mode-twice inputattach --dump "$NOSUCH-a" --dump "$NOSUCH-b" lc_case ia-crtscts-conflict inputattach --crtscts --no-crtscts --dump "$NOSUCH" lc_case ia-baud-missing inputattach --baud lc_case ia-open-enoent inputattach --dump "$NOSUCH" lc_case ia-short-alias inputattach -dump "$NOSUCH" # jstest -- the three argc arms that print usage, and the open. lc_case jt-help jstest --help lc_case jt-no-args jstest lc_case jt-too-many jstest a b c lc_case jt-open-enoent jstest "$NOSUCH" lc_case jt-open-enoent-mode jstest --normal "$NOSUCH" # jscal -- jc-unknown-opt and jc-optarg-missing are getopt_long's OWN # diagnostics, which carry argv[0]; they are as much an assertion about this # arm's glibc as about jscal. jc-lower-v is finding 2 in the header. lc_case jc-no-args jscal lc_case jc-help jscal --help lc_case jc-two-actions jscal -c -t "$NOSUCH" lc_case jc-unknown-opt jscal -Z "$NOSUCH" lc_case jc-optarg-missing jscal -s lc_case jc-missing-dev jscal -c lc_case jc-open-enoent jscal "$NOSUCH" lc_case jc-lower-v jscal -v "$NOSUCH" # fftest -- the banner and the argv[0]-carrying usage line, and the open. NOT # the no-argument arm, which falls back to /dev/input/event0: on a build host # with a keyboard that opens or gives EACCES and here it gives ENOENT, so it has # no oracle and is asserted against the probe further down instead. lc_case ff-help fftest --help lc_case ff-open-enoent fftest "$NOSUCH" # --- the protocol table, counted as well as compared --------------------------- # # ia-help above already compares the table byte for byte, so this looks # redundant and is not: it is the case that says WHAT WENT WRONG when that one # reds. A whole-output comparison that fails reports "want:... got:..." # truncated to 100 characters, which for a 60-line capture tells the reader # nothing about whether the table was short, reordered, or absent. The row count # and the two ends of the table are three small assertions that localise it. # # ONE exec, guarded, feeding all four cases. The first draft ran ./inputattach # twice and threw the row count's stderr away, so an exec that never happened # arrived as a row count of zero. Measured on the batch-1528 image: the count red # as want:'50' got:'0' while the three row cases on the next three lines, running # the SAME binary, all passed -- so the table was there and the exec was not. A # command that could not be exec'd has measured nothing, and bst_unrun is how # this suite says so; a bare comparison turns a transient exec failure into a # false statement about the port. _ia_rc=0 ( cd "$LCBIN" && bst_bound 15 ./inputattach --help ) > "$work/iaout" 2> "$work/iaerr" || _ia_rc=$? ia_help_out=$(cat "$work/iaout") _ia_err=$(cat "$work/iaerr") modes_want=$(sed -n 's/^modes=//p' "$LCT/oracle.txt") if bst_execfail "$_ia_err"; then for _id in ia-table-rows ia-table-row/--microsoft ia-table-row/--zhen-hua \ ia-table-row/--pulse8-cec; do bst_unrun "linuxconsole/$_id" "$_ia_err" done else modes_got=$(sed -n '/^Modes:$/,$p' "$work/iaout" | grep -c '^ --') if [ -n "$modes_want" ]; then check_eq "linuxconsole/ia-table-rows" "$modes_want" "$modes_got" else bst_notok "linuxconsole/ia-table-rows" "oracle.txt carries no modes= line" fi for row in \ " --microsoft -bare 2-button Microsoft mouse" \ " --zhen-hua -zhen Zhen Hua 5-byte protocol" \ " --pulse8-cec -pulse8-cec Pulse Eight HDMI CEC dongle"; do case "$ia_help_out" in *"$row"*) bst_ok "linuxconsole/ia-table-row/$(echo "$row" | awk '{print $1}')" ;; *) bst_notok "linuxconsole/ia-table-row/$(echo "$row" | awk '{print $1}')" "missing from the table: '$row'" ;; esac done fi # --- the controls ------------------------------------------------------------- # # These are what separate "there is no input device" from "this process cannot # open a device node". Each opens /dev/null -- which exists on every machine and # is not an input device -- and is carried PAST the open into its first ioctl, # which answers ENOTTY. They assert a substring and the exit status rather than # a byte comparison, and deliberately so: jstest prints a line whose wording # depends on a stack buffer the failed JSIOCGBTNMAP left untouched, so pinning # its whole output would be pinning uninitialised memory. # # inputattach gets NO control. It BLOCKS forever on a node it opens # successfully -- measured -- so the case that would prove its open works is the # case that would hang the guest. Its open is covered by the ENOENT arm only, # and this comment is the reason the asymmetry is deliberate. ctl_case() { _ct_id=$1; _ct_want=$2; _ct_needle=$3; shift 3 _ct_rc=0 ( cd "$LCBIN" && bst_bound 15 ./"$@" ) > "$work/cout" 2> "$work/cerr" || _ct_rc=$? _ct_all=$(cat "$work/cout" "$work/cerr") if bst_execfail "$_ct_all"; then bst_unrun "linuxconsole/$_ct_id" "$_ct_all"; return; fi case "$_ct_all" in *"$_ct_needle"*) _ct_hit=1 ;; *) _ct_hit=0 ;; esac if [ "$_ct_rc" -eq "$_ct_want" ] && [ "$_ct_hit" -eq 1 ]; then bst_ok "linuxconsole/$_ct_id" else bst_notok "linuxconsole/$_ct_id" "rc=$_ct_rc want=$_ct_want want:'$_ct_needle' got:'$(_bst_1line "$_ct_all")'" fi } # jstest reaches JSIOCGVERSION, is refused, and falls back to its compiled-in # default of 0.8.0 -- which is the assertion: the ioctl was ISSUED and the # refusal was handled, rather than the tool stopping at the open. ctl_case ctl/jstest-opens-devnull 1 "Driver version is 0.8.0." jstest /dev/null # jscal reaches the same ioctl and, unlike jstest, treats the failure as fatal. ctl_case ctl/jscal-opens-devnull 1 "jscal: error getting version" jscal /dev/null # fftest says so in its own words before it queries anything. ctl_case ctl/fftest-opens-devnull 1 "Device /dev/null opened" fftest /dev/null # And the errno all three get is ENOTTY, which is the kernel telling us the file # is real and the request is not for it. A different errno here would mean the # controls above proved something else, so it is asserted rather than assumed. ctl_case ctl/enotty-on-devnull 1 "Inappropriate ioctl for device" jscal /dev/null # --- the two upstream findings, pinned ---------------------------------------- # # Neither is a defect in the PORT, and neither is asserted as correct behaviour. # They are pinned so that the day upstream fixes one, this suite says so instead # of the change arriving unnoticed in a package nobody reads the source of. # FINDING 1: the four tools disagree about --help's exit status. Two exit 0 and # two exit 1, and the oracle carries each separately for exactly this reason. for pair in "inputattach:ia_help_rc" "jstest:jt_help_rc" "jscal:jc_help_rc" "fftest:ff_help_rc"; do _t=${pair%%:*}; _k=${pair##*:} _want=$(sed -n "s/^$_k=//p" "$LCT/oracle.txt") _got=0 ( cd "$LCBIN" && bst_bound 15 ./"$_t" --help ) > /dev/null 2>&1 || _got=$? if [ -z "$_want" ]; then bst_notok "linuxconsole/help-rc/$_t" "oracle.txt carries no $_k line" else check_eq "linuxconsole/help-rc/$_t" "$_want" "$_got" fi done # FINDING 2: jscal's `-v' is in the optstring and has no case, so it falls to # `default:', prints, and CONTINUES -- it does not exit, and no action is set. # jc-lower-v above compares the whole capture; this case states the finding in # one line so a reader of the results does not have to reconstruct it from a # byte comparison. _v_rc=0 ( cd "$LCBIN" && bst_bound 15 ./jscal -v "$NOSUCH" ) > "$work/vout" 2> "$work/verr" || _v_rc=$? _v_all=$(cat "$work/vout" "$work/verr") case "$_v_all" in *"jscal: option parsing error"*"can't open joystick device"*) bst_ok "linuxconsole/finding/jscal-lower-v-continues" ;; *) bst_notok "linuxconsole/finding/jscal-lower-v-continues" "expected -v to print 'option parsing error' and CONTINUE to the device open; got rc=$_v_rc '$(_bst_1line "$_v_all")'" ;; esac # --- what needs an input device, and is therefore skipped --------------------- # # Each of these is the work its tool exists to do, and each is skipped ONLY on # the probe's live answer -- never on this file's say-so. The detail carries the # probe verbatim, so a reader of the results can see which of the four facts was # read and can tell a machine with no input subsystem from one with no nodes. if [ "$have_dev" = no ] && [ "$have_js" = no ] && [ "$have_proc" = no ] && [ "$have_sys" = no ]; then bst_ok "linuxconsole/probe/no-input-device" # the absence is itself measured for s in \ "jstest/read-events:jstest reading struct js_event from a joystick node" \ "jstest/axis-button-map:JSIOCGAXMAP and JSIOCGBTNMAP against a real map" \ "jscal/calibrate:jscal -c, which drives JSIOCSCORR against a live axis" \ "jscal/print-correction:jscal -p, which reads JSIOCGCORR" \ "jscal/set-mappings:jscal -u, which drives JSIOCSAXMAP and JSIOCSBTNMAP" \ "jscal/test-center:jscal -t and its exit codes 2 and 3" \ "fftest/play-effect:fftest uploading a struct ff_effect through EVIOCSFF and playing it" \ "ffset/gain-autocenter:ffset writing EV_FF gain and autocentre events" \ "ffcfstress/constant-force:ffcfstress driving a constant force at a fixed rate" \ "evdev-joystick/set-deadzone:evdev-joystick adjusting an axis through EVIOCSABS" \ "inputattach/bind-serial:inputattach binding a serial line with TIOCSETD and SPIOCSTYPE"; do bst_skip "linuxconsole/${s%%:*}" "${s#*:} -- this image has no evdev or joystick input device ($probe)" done else # The machine grew an input device. Say so loudly: every skip above was # written against its absence, and they are now unearned rather than merely # unnecessary. bst_notok "linuxconsole/probe/no-input-device" "an input device is present ($probe) -- the device-driven cases above are skipped on the assumption that none is, and that assumption no longer holds; this suite needs its device arms written" fi # fftest with NO arguments falls back to a hardcoded /dev/input/event0, and it is # the FALLBACK that is asserted here, not the string. It has no oracle -- on a # build host with a keyboard that path opens or gives EACCES, so a reference # taken over it would be about that machine. # # WHAT IS MEASURABLE IS THE ARM, NOT THE PATH. fftest never prints the device it # failed to open: the no-argument route is open() then perror("Open device # file"), which carries no path at all (finding 3 in the header), and the only # line that names the device -- printf("Device %s opened") -- is on the success # side, which a machine with no input node cannot reach. The first draft asserted # that the no-argument OUTPUT names /dev/input/event0, which is unsatisfiable by # construction on the very machine the case is gated to run on. It red on the # batch-1528 image, as it would on any image with no /dev/input. # # So the two reachable statements are pinned instead: the arm must fail the open # with ENOENT, and it must behave EXACTLY as if the documented default had been # named on the command line -- same stdout, same stderr, same exit status. That # reds the day upstream makes the no-argument arm print a usage and refuse rather # than fall back, which is the change this case exists to catch. ff_default=$(sed -n 's/^ff_default_device=//p' "$LCT/oracle.txt") if [ "$have_dev" = no ]; then ctl_case ff-default-enoent 1 "No such file or directory" fftest if [ -z "$ff_default" ]; then bst_notok "linuxconsole/ff-default-path" "oracle.txt carries no ff_default_device line" elif [ -e "$ff_default" ]; then # Read, not inferred. have_dev=no already implies this, but the equality # below only means "the no-argument arm took the default route" while the # default cannot be opened -- so the precondition is measured, the way # nosuch-absent measures its own. bst_notok "linuxconsole/ff-default-path" "$ff_default exists on this image, so the no-argument arm may open it and this comparison would be measuring the node rather than the fallback ($probe)" else _d_rc=0; _e_rc=0 ( cd "$LCBIN" && bst_bound 15 ./fftest ) > "$work/dout" 2> "$work/derr" || _d_rc=$? ( cd "$LCBIN" && bst_bound 15 ./fftest "$ff_default" ) > "$work/eout" 2> "$work/eerr" || _e_rc=$? _d_err=$(cat "$work/derr"); _e_err=$(cat "$work/eerr") if bst_execfail "$_d_err" || bst_execfail "$_e_err"; then bst_unrun "linuxconsole/ff-default-path" "$_d_err$_e_err" else _d_all=$(cat "$work/dout"; echo "==BST-ERR=="; cat "$work/derr"; echo "==BST-RC== $_d_rc") _e_all=$(cat "$work/eout"; echo "==BST-ERR=="; cat "$work/eerr"; echo "==BST-RC== $_e_rc") check_eq "linuxconsole/ff-default-path" "$_e_all" "$_d_all" fi fi else bst_skip "linuxconsole/ff-default-enoent" "an input device is present, so fftest's default path may open ($probe)" bst_skip "linuxconsole/ff-default-path" "an input device is present, so fftest's default path may open ($probe)" fi rm -rf "$work"