. "$BST_LIB" require beep beep/present # BST-TIMEOUT: 300 # measured 42s on hz1 2026-08-27; the default 60 is only 1.4x that # beep 1.4.12 (meta-oe recipes-extended/beep, the spkr-beep git at SRCREV # 11453a79, plus meta-oe's c99 patch and our GNUmakefile linker-flag patch). # One binary, /usr/bin/beep, plus the man page and contrib docs from beep-doc: # it drives the PC speaker at a frequency, for a length, repeated, with delays, # optionally as a sequence of such tones. # # THERE IS NO PC SPEAKER HERE AND THE SUITE DOES NOT PRETEND OTHERWISE -- but # it does not hardcode the absence either. beep finds its output device by # asking, in order, the evdev driver for # /dev/input/by-path/platform-pcspkr-event-spkr and the console driver for # /dev/tty0 then /dev/vc/0, and BOTH drivers require an ioctl (EVIOCGSND(0), # KIOCSOUND) to succeed after the node opens O_WRONLY. A node existing settles # nothing, and this kernel carries CONFIG_VT=y, so /dev/tty0 is a live question # rather than a foregone one. The device half is therefore PROBED at runtime # and both arms written out in full: the day a speaker appears the result # changes visibly instead of passing either way. # # EVERY DIAGNOSTIC beep PRINTS GOES TO STDOUT. beep-log.c's log_internal_vf() # fprintf()s to stdout for Error, Warning and Verbose alike, and print_usage() # fputs() the banner to stdout too -- so `beep ... 2>/dev/null' still shows the # error and `beep ... >/dev/null' hides it. Only getopt's own "invalid option" # reaches stderr. Four cases pin that split in both directions, because a suite # that captured only stderr would find nothing and read as though beep had said # nothing at all. # # THE PARSER IS ASSERTABLE WITHOUT A DEVICE, and that is what makes this port # testable here at all. parse_command_line() runs to completion BEFORE any # device is touched, and its only rejection path is usage_bail() -- # print_usage() then exit(EXIT_FAILURE). So "the banner appeared" means # rejected and "it did not" means accepted, whatever happened afterwards at the # device. parse_ok/parse_no below are that oracle, every range is asserted on # BOTH sides of its `if' so a dropped comparison cannot pass, and the accepted # forms name a device that cannot exist (-e /nonexistent/dev) so that a machine # which DOES grow a speaker never plays a 300-second tone from this suite. BIN=/usr/bin/beep MAN=/usr/share/man/man1/beep.1 DOC=/usr/share/doc/beep ND="-e /nonexistent/dev" tmp=${TMPDIR:-/tmp}/bst-beep.$$ mkdir -p "$tmp" 2>/dev/null # `check_out' passes only when the command ALSO exits 0. Almost every message # below is printed on a path that exits 1 -- they are the error paths -- so # check_out would report a red whose "want" and "got" are identical. out_rc # asserts the substring and the status together, which is the pair that # actually documents each of those paths. out_rc() { _oid=$1; _ow=$2; _oe=$3; shift 3 _oo=$("$@" 2>&1); _og=$? case "$_oo" in *"$_ow"*) _oh=1 ;; *) _oh=0 ;; esac if [ "$_og" -eq "$_oe" ] && [ "$_oh" -eq 1 ]; then bst_ok "$_oid" elif bst_execfail "$_oo"; then bst_unrun "$_oid" "$_oo" else bst_notok "$_oid" "rc=$_og want-rc=$_oe want:'$_ow' got:'$(_bst_1line "$_oo")'"; fi } # substring only, no status: for a claim that must hold in BOTH device arms, # where the exit code legitimately differs between them. has() { _hid=$1; _hw=$2; shift 2 _ho=$("$@" 2>&1) case "$_ho" in *"$_hw"*) bst_ok "$_hid" ;; *) if bst_execfail "$_ho"; then bst_unrun "$_hid" "$_ho" else bst_notok "$_hid" "want:'$_hw' got:'$(_bst_1line "$_ho")'"; fi ;; esac } # accepted := the parser did NOT bail to the usage banner. parse_ok() { _pid=$1; shift _po=$("$@" 2>&1) case "$_po" in *"Usage:"*) bst_notok "$_pid" "rejected an accepted form: $(_bst_1line "$_po")" ;; *) if bst_execfail "$_po"; then bst_unrun "$_pid" "$_po"; else bst_ok "$_pid"; fi ;; esac } # rejected := the usage banner AND exit 1. Both halves: usage_bail() is a print # followed by an exit, and either could be lost on its own. parse_no() { _pid=$1; shift _po=$("$@" 2>&1); _prc=$? case "$_po" in *"Usage:"*) _ph=1 ;; *) _ph=0 ;; esac if [ "$_prc" -eq 1 ] && [ "$_ph" -eq 1 ]; then bst_ok "$_pid" elif bst_execfail "$_po"; then bst_unrun "$_pid" "$_po" else bst_notok "$_pid" "rc=$_prc usage=$_ph : $(_bst_1line "$_po")"; fi } # --------------------------------------------------------------------------- # 1. what shipped # --------------------------------------------------------------------------- check_eq beep/which "$BIN" "$(command -v beep 2>/dev/null)" check beep/binary-is-file test -f "$BIN" # `[ -x ]' is NOT an oracle on this root: the rootfs files are owned 1000:1001 # while the guest runs as root, so busybox test falls through to the # supplementary-group check and getgroups(2) answers ENOSYS (brintos/linux#19). # The mode comes off `ls -l' instead -- and the fact that beep RAN, which every # other case here rests on, is the real proof of the execute bit. MODE=$(ls -l "$BIN" 2>/dev/null | cut -c1-10) case "$MODE" in -rwxr-xr-x) bst_ok beep/binary-mode ;; *) bst_notok beep/binary-mode "want:'-rwxr-xr-x' got:'$MODE'" ;; esac # a genuine WebAssembly module, not a host binary that slipped through MAGIC=$(od -An -tx1 -N 4 "$BIN" 2>/dev/null | tr -d ' \n') check_eq beep/binary-is-wasm 0061736d "$MAGIC" if [ "$MAGIC" = "7f454c46" ]; then bst_notok beep/binary-not-elf "the shipped beep is ELF -- this is a NATIVE build, not wasm32" else bst_ok beep/binary-not-elf; fi # The man page, which the ticket names as a deliverable. It reaches the image # only because EMCRAFT_TOOLS names beep-doc as well as beep: Yocto's default # packaging puts ${mandir} in ${PN}-doc, so a bare `beep' would carry the # binary and nothing else. check beep/man-page test -f "$MAN" check_out beep/man-page-th ".TH BEEP 1" head -20 "$MAN" check_out beep/man-page-name "beep the pc speaker any number of ways" head -20 "$MAN" check_out beep/man-page-freq-default "Default value: 440 Hz." head -80 "$MAN" check beep/man-page-synopsis grep -qF ".SH SYNOPSIS" "$MAN" check beep/man-page-options grep -qF ".SH OPTIONS" "$MAN" check beep/man-page-exit grep -qF ".SH EXIT STATUS" "$MAN" check beep/man-page-environ grep -qF ".SH ENVIRONMENT" "$MAN" check beep/man-page-files grep -qF ".SH FILES" "$MAN" check beep/doc-copying test -f "$DOC/COPYING" check beep/doc-readme test -f "$DOC/README.md" check beep/doc-news test -f "$DOC/NEWS.md" check beep/doc-permissions test -f "$DOC/PERMISSIONS.md" check beep/doc-credits test -f "$DOC/CREDITS.md" check beep/doc-contrib-pl test -f "$DOC/contrib/morse2beep.pl" check beep/doc-contrib-sed test -f "$DOC/contrib/morse2beep.sed" check beep/doc-contrib-success test -f "$DOC/contrib/success-beeps" check beep/doc-contrib-failure test -f "$DOC/contrib/failure-beeps" # --------------------------------------------------------------------------- # 2. --version (the ticket's first named criterion) # --------------------------------------------------------------------------- check_out beep/version-string "beep 1.4.12" beep --version check_out beep/version-short-v "beep 1.4.12" beep -v check_out beep/version-short-V "beep 1.4.12" beep -V check_out beep/version-copy-jn "Copyright (C) 2002-2016 Johnathan Nightingale" beep --version check_out beep/version-copy-hun "Copyright (C) 2013-2022 Hans Ulrich Niedermann" beep --version check_out beep/version-gpl "Use and Distribution subject to GPL." beep --version check_out beep/version-url "http://www.gnu.org/copyleft/" beep --version check_rc beep/version-rc0 0 beep --version check_rc beep/version-v-rc0 0 beep -v check_rc beep/version-V-rc0 0 beep -V check_eq beep/version-first-line "beep 1.4.12" "$(beep --version 2>/dev/null | head -1)" check_eq beep/version-line-count "5" "$(beep --version 2>/dev/null | wc -l | tr -d ' ')" # -V is handled in the getopt case, so it wins over a LATER bad argument... check_out beep/version-precedes-bad-arg "beep 1.4.12" beep --version -f 99999 # ...and loses to an EARLIER one, which is parsed first and bails parse_no beep/version-after-bad-arg beep -f 99999 --version # the stream split check_eq beep/version-stdout "beep 1.4.12" "$(beep --version 2>/dev/null | head -1)" check_eq beep/version-stderr-empty "" "$(beep --version 2>&1 >/dev/null)" # --------------------------------------------------------------------------- # 3. --help (the ticket's second named criterion: the documented options) # --------------------------------------------------------------------------- check_rc beep/help-rc0 0 beep --help check_rc beep/help-h-rc0 0 beep -h check_out beep/help-usage-head "Usage:" beep --help check_out beep/help-synopsis-1 "beep [--verbose|--debug] [-e DEVICE]" beep --help check_out beep/help-synopsis-2 "[-f FREQ_Hz] [-l LEN_ms] [-r REPS] [<-d|-D> DELAY_ms] [-s] [-c]" beep --help check_out beep/help-synopsis-3 "beep [OPTIONS] [-n|--new TONE_OPTS...]" beep --help check_out beep/help-synopsis-4 "beep [-h|--help]" beep --help check_out beep/help-synopsis-5 "beep [-v|-V|--version]" beep --help check_out beep/help-tagline "Beep the PC speaker in a number of ways." beep --help check_out beep/help-sec-info "Information options:" beep --help check_out beep/help-sec-global "Global options:" beep --help check_out beep/help-sec-tone "Tone options:" beep --help check_out beep/help-opt-help "-h, --help" beep --help check_out beep/help-opt-version "-V, -v, --version" beep --help check_out beep/help-opt-device "-e, --device=DEVICE" beep --help check_out beep/help-opt-verbose "--debug, --verbose" beep --help check_out beep/help-opt-f "-f FREQ_Hz frequency of the tone in Hertz (Hz) (default: 440)" beep --help check_out beep/help-opt-l "-l LENGTH_ms length of the tone in milliseconds (ms) (default: 200)" beep --help check_out beep/help-opt-d "-d DELAY_ms delay between repetitions of the tone *without* delay after last" beep --help check_out beep/help-opt-D "-D DELAY_ms delay between repetitions of the tone *with* delay after last" beep --help check_out beep/help-opt-d-dflt "repetition of the tone (default: 100)" beep --help check_out beep/help-opt-D-dflt "(default: no delay after last note)" beep --help check_out beep/help-opt-r "-r REPS number of repetitions of the last tone" beep --help check_out beep/help-opt-r-dflt "(default: 1 note without repeats)" beep --help check_out beep/help-opt-n "-n, --new start a new tone" beep --help check_out beep/help-opt-s "-s read text from stdin and write it through to stdout," beep --help check_out beep/help-opt-c "-c like -s, but beep for every character in the text" beep --help check_out beep/help-exit-status "Exit status:" beep --help check_out beep/help-exit-0 "0 if OK" beep --help check_out beep/help-exit-non0 "non-0 if any problems occurred" beep --help check_out beep/help-manref "man 1 beep" beep --help # the three @DEFAULT_*@ substitutions the build performs. An unsubstituted # banner would still list every option and still read as correct. case "$(beep --help 2>&1)" in *"@DEFAULT_"*) bst_notok beep/help-defaults-substituted "the usage text still carries an unsubstituted @DEFAULT_*@" ;; *) bst_ok beep/help-defaults-substituted ;; esac check_eq beep/help-h-equals-help "$(beep -h 2>&1)" "$(beep --help 2>&1)" check_eq beep/help-stderr-empty "" "$(beep --help 2>&1 >/dev/null)" # --------------------------------------------------------------------------- # 4. the parser accepts the documented forms # (the ticket's third named criterion: -f -l -d -r -n as one pattern) # --------------------------------------------------------------------------- parse_ok beep/parse-full-pattern beep $ND -f 440 -l 0 -d 0 -r 2 -n -f 880 -l 0 parse_ok beep/parse-f beep $ND -f 440 -l 0 parse_ok beep/parse-l beep $ND -l 0 parse_ok beep/parse-d beep $ND -d 0 -l 0 parse_ok beep/parse-D beep $ND -D 0 -l 0 parse_ok beep/parse-r beep $ND -r 3 -l 0 -d 0 parse_ok beep/parse-n beep $ND -f 440 -l 0 -n -f 880 -l 0 parse_ok beep/parse-new-long beep $ND -f 440 -l 0 --new -f 880 -l 0 parse_ok beep/parse-n-chain beep $ND -f 100 -l 0 -n -f 200 -l 0 -n -f 300 -l 0 -n -f 400 -l 0 parse_ok beep/parse-verbose beep $ND --verbose -l 0 parse_ok beep/parse-debug beep $ND --debug -l 0 parse_ok beep/parse-verbose-x2 beep $ND --verbose --debug -l 0 parse_ok beep/parse-device-long beep --device=/nonexistent/dev -l 0 parse_ok beep/parse-device-short beep -e /nonexistent/dev -l 0 parse_ok beep/parse-float-freq beep $ND -f 440.5 -l 0 parse_ok beep/parse-freq-zero beep $ND -f 0 -l 0 parse_ok beep/parse-no-args beep $ND parse_ok beep/parse-s sh -c "$BIN -e /nonexistent/dev -s -l 0 < /dev/null" parse_ok beep/parse-c sh -c "$BIN -e /nonexistent/dev -c -l 0 < /dev/null" # both sides of every range test, so a dropped comparison cannot pass parse_ok beep/bound-f-20000 beep $ND -f 20000 -l 0 parse_no beep/bound-f-20001 beep $ND -f 20001 -l 0 parse_ok beep/bound-l-300000 beep $ND -l 300000 parse_no beep/bound-l-300001 beep $ND -l 300001 parse_ok beep/bound-r-300000 beep $ND -r 300000 -l 0 parse_no beep/bound-r-300001 beep $ND -r 300001 -l 0 parse_ok beep/bound-d-300000 beep $ND -d 300000 -l 0 parse_no beep/bound-d-300001 beep $ND -d 300001 -l 0 parse_ok beep/bound-D-300000 beep $ND -D 300000 -l 0 parse_no beep/bound-D-300001 beep $ND -D 300001 -l 0 # --------------------------------------------------------------------------- # 5. the parser rejects, with the documented message and status # (the ticket's fourth named criterion) # --------------------------------------------------------------------------- parse_no beep/reject-freq-high beep -f 20001 -l 0 parse_no beep/reject-freq-huge beep -f 1000000 -l 0 parse_no beep/reject-freq-negative beep -f -1 -l 0 parse_no beep/reject-freq-garbage beep -f abc parse_no beep/reject-freq-empty beep -f "" parse_no beep/reject-reps-garbage beep -r abc parse_no beep/reject-reps-high beep -r 300001 parse_no beep/reject-reps-negative beep -r -1 parse_no beep/reject-len-garbage beep -l abc parse_no beep/reject-len-high beep -l 300001 parse_no beep/reject-delay-garbage beep -d abc parse_no beep/reject-delay-high beep -d 300001 parse_no beep/reject-Delay-high beep -D 300001 parse_no beep/reject-unknown-short beep -Z parse_no beep/reject-unknown-long beep --nosuchoption parse_no beep/reject-missing-optarg-f beep -f parse_no beep/reject-missing-optarg-e beep -e parse_no beep/reject-stray-arg beep foo parse_no beep/reject-stray-after beep -f 440 -l 0 foo # the diagnostics that are NOT the bare usage banner out_rc beep/reject-stray-message "beep: Error: non-option arguments left on command line" 1 beep foo out_rc beep/reject-device-twice-message "beep: Error: You cannot give the --device parameter more than once." 1 beep -e /dev/null -e /dev/zero -l 0 # getopt's own complaint is the ONE thing beep puts on stderr... check_eq beep/reject-unknown-on-stderr "beep: invalid option -- 'Z'" "$(beep -Z 2>&1 >/dev/null)" check_eq beep/reject-missing-optarg-on-stderr "beep: option requires an argument -- 'f'" "$(beep -f 2>&1 >/dev/null)" # ...while usage_bail()'s own banner is on stdout, as everything else is out_rc beep/reject-banner-on-stdout "Usage:" 1 sh -c "$BIN -Z 2>/dev/null" # the multiple-tone warning, and the branch that must NOT warn: the test is # `result->freq != 0', so a first -f of 0 leaves the sentinel in place has beep/warn-multiple-f "beep: Warning: main: multiple -f values given, only last one is used." beep $ND -f 440 -f 880 -l 0 case "$(beep $ND -f 0 -f 880 -l 0 2>&1)" in *"multiple -f values"*) bst_notok beep/warn-not-after-zero "warned although the first -f left freq at the 0 sentinel the test reads" ;; *) bst_ok beep/warn-not-after-zero ;; esac # --------------------------------------------------------------------------- # 6. the sudo refusal, which runs BEFORE the parser # --------------------------------------------------------------------------- UID0=$(id -u 2>/dev/null) if [ "$UID0" = "0" ]; then out_rc beep/root-sudo-refused "beep: Error: Running as root under sudo, which is not supported for security reasons." 1 env SUDO_USER=x beep --version out_rc beep/root-sudo-hint "beep: Error: Set up permissions for the pcspkr evdev device file and run as non-root user instead." 1 env SUDO_USER=x beep --version check_rc beep/root-sudo-rc 1 env SUDO_USER=x beep --version check_rc beep/root-sudo-command-rc 1 env SUDO_COMMAND=/bin/true beep --version check_rc beep/root-sudo-uid-rc 1 env SUDO_UID=0 beep --version check_rc beep/root-sudo-gid-rc 1 env SUDO_GID=0 beep --version # it precedes parse_command_line(), so even --help does not get through check_rc beep/root-sudo-precedes-parse 1 env SUDO_USER=x beep --help # the negative control: the same invocation with no SUDO_* in the environment check_rc beep/root-no-sudo-rc0 0 beep --version else for c in root-sudo-refused root-sudo-hint root-sudo-rc root-sudo-command-rc \ root-sudo-uid-rc root-sudo-gid-rc root-sudo-precedes-parse root-no-sudo-rc0; do bst_skip "beep/$c" "the sudo refusal is reachable only as root; this guest runs as uid $UID0" done fi # --------------------------------------------------------------------------- # 7. the drivers registered themselves -- a wasm32 statement, not a beep one # --------------------------------------------------------------------------- # # Both drivers are linked as plain objects and register through # __attribute__((constructor)) at .init_array time; beep_drivers_detect() exits # with "beep has been built without any driver" if the list is empty. # # THE ORACLE IS THE DETECT TRACE, NOT THE REGISTRATION TRACE. beep prints one # `beep_drivers_register .. ()' line per driver, but at LOG_VERBOSE and # from a constructor -- so it is visible only when BEEP_LOG_LEVEL raised the # level before main() ran, and that variable has no effect on this image (§ the # probe below). What IS visible is `: driver_detect', printed by each # driver's own detect function, which runs only for a driver that is IN the # list. Naming a device that cannot exist makes every driver be tried, so both # lines appear whether or not this machine has something beepable -- which is # what makes this section independent of § 8's probe. DT=$(beep --verbose -e /nonexistent/dev -l 0 2>&1) case "$DT" in *"evdev: driver_detect"*) bst_ok beep/ctor-evdev-registered ;; *) bst_notok beep/ctor-evdev-registered "the evdev driver is not in the list: $(_bst_1line "$DT")" ;; esac case "$DT" in *"console: driver_detect"*) bst_ok beep/ctor-console-registered ;; *) bst_notok beep/ctor-console-registered "the console driver is not in the list: $(_bst_1line "$DT")" ;; esac case "$DT" in *"built without any driver"*) bst_notok beep/ctor-list-nonempty "beep_drivers_detect() found an empty driver list" ;; *) bst_ok beep/ctor-list-nonempty ;; esac # Link order decides detection order: console is listed first in beep_OBJS, so # it registers first, is pushed down the head-insert list, and evdev is tried # first. The GNUmakefile says so in as many words above beep_OBJS, and this is # the only externally visible consequence of it. DE=$(printf '%s\n' "$DT" | grep -n "evdev: driver_detect" | head -1 | cut -d: -f1) DC=$(printf '%s\n' "$DT" | grep -n "console: driver_detect" | head -1 | cut -d: -f1) if [ -n "$DE" ] && [ -n "$DC" ] && [ "$DE" -lt "$DC" ]; then bst_ok beep/ctor-order-evdev-tried-first else bst_notok beep/ctor-order-evdev-tried-first "evdev trace at line '$DE', console trace at '$DC'"; fi # --- BEEP_LOG_LEVEL: documented, and inert on this image --------------------- # # beep-log.c reads it with secure_getenv(3) from a constructor. Measured on the # wasm32-hwjs glibc image 2026-08-27: it has NO effect at any value, while # --verbose does raise the level in the same binary, and the constructors # demonstrably ran (both cases above pass). The variable is in the exec'd # process's environment -- the control below proves it -- so what is missing is # the constructor's ability to read it, and the two candidate mechanisms are # __libc_enable_secure being set on this port and __environ not yet being # populated when .init_array runs. Neither can be settled from here: # /proc/self/auxv reads back EMPTY on this kernel, so AT_SECURE is unreadable. # Held by brintos/glibc#10, with the auxv half at brintos/linux#112. The # facility is ABSENT rather than the tool broken, so this is a probe and a # skip, not a red -- the day it works the case runs for real. # the two controls first: the variable IS in the exec'd environment, and the # --verbose flag DOES raise the level in this very binary. Without both, an # inert BEEP_LOG_LEVEL would be consistent with a dozen duller explanations. check_eq beep/env-visible-to-exec "1" "$(BEEP_LOG_LEVEL=1 sh -c 'echo $BEEP_LOG_LEVEL')" VN=$(beep --verbose -e /nonexistent/dev -l 0 2>&1 | grep -c Verbose) if [ "$VN" -gt 0 ]; then bst_ok beep/flag-verbose-works else bst_notok beep/flag-verbose-works "--verbose produced no 'Verbose:' line at all, so the log level is not reachable by any route"; fi ENVN=$(BEEP_LOG_LEVEL=1 beep -e /nonexistent/dev -l 0 2>&1 | grep -c Verbose) bst_ok beep/probe-env-log-level if [ "$ENVN" -gt 0 ]; then ENVR=$(BEEP_LOG_LEVEL=1 beep -e /nonexistent/dev -l 0 2>&1) case "$ENVR" in *"beep_drivers_register"*"(console)"*) bst_ok beep/env-log-level-console-register ;; *) bst_notok beep/env-log-level-console-register "the level rose but no console registration line appeared: $(_bst_1line "$ENVR")" ;; esac case "$ENVR" in *"beep_drivers_register"*"(evdev)"*) bst_ok beep/env-log-level-evdev-register ;; *) bst_notok beep/env-log-level-evdev-register "the level rose but no evdev registration line appeared: $(_bst_1line "$ENVR")" ;; esac else bst_skip beep/env-log-level-console-register "brintos/glibc#10: BEEP_LOG_LEVEL is inert on this image -- secure_getenv(3) from a constructor returns nothing, while the same variable is visible to an exec'd shell and --verbose works in the same binary" bst_skip beep/env-log-level-evdev-register "brintos/glibc#10: BEEP_LOG_LEVEL is inert on this image, so the constructor-time registration trace cannot be reached" fi # and 0 must be as quiet as unset, which holds either way check_eq beep/log-level-0-quiet 0 "$(BEEP_LOG_LEVEL=0 beep --version 2>&1 | grep -c Verbose)" check_eq beep/log-level-unset-quiet 0 "$(beep --version 2>&1 | grep -c Verbose)" # --------------------------------------------------------------------------- # 8. the device: probed, then asserted in whichever arm the probe found # (the ticket's fifth named criterion) # --------------------------------------------------------------------------- PROBE=$(beep --verbose -f 440 -l 0 -r 1 2>&1); PRC=$? case "$PROBE" in *"Could not open any device"*) DEV=none ;; *"using "*" driver"*) DEV=$(printf '%s\n' "$PROBE" | sed -n 's/.*using \([a-z][a-z]*\) driver.*/\1/p' | head -1) ;; *) DEV=unknown ;; esac if [ "$DEV" = none ] && [ "$PRC" -eq 1 ]; then bst_ok beep/probe-device elif [ "$DEV" != none ] && [ "$DEV" != unknown ] && [ "$PRC" -eq 0 ]; then bst_ok beep/probe-device else bst_notok beep/probe-device "probe is self-inconsistent: dev='$DEV' rc=$PRC : $(_bst_1line "$PROBE")" fi # evdev is tried first in both arms, so these two hold whatever the probe found has beep/verbose-tries-evdev "/dev/input/by-path/platform-pcspkr-event-spkr" beep --verbose -f 440 -l 0 has beep/verbose-module-evdev "beep: Verbose: evdev: driver_detect" beep --verbose -f 440 -l 0 EV=$(printf '%s\n' "$PROBE" | grep -n "Verbose: evdev: driver_detect" | head -1 | cut -d: -f1) CN=$(printf '%s\n' "$PROBE" | grep -n "Verbose: console: driver_detect" | head -1 | cut -d: -f1) if [ "$DEV" = none ]; then out_rc beep/no-device-message "beep: Error: Could not open any device" 1 beep -f 440 -l 0 check_rc beep/no-device-rc 1 beep -f 440 -l 0 check_rc beep/no-device-rc-full-pattern 1 beep -f 440 -l 0 -d 0 -r 2 -n -f 880 -l 0 # the diagnostic is on stdout and stderr is empty -- the split a suite reading # stderr would report as silence check_eq beep/no-device-on-stdout "beep: Error: Could not open any device" "$(beep -f 440 -l 0 2>/dev/null | tail -1)" check_eq beep/no-device-stderr-empty "" "$(beep -f 440 -l 0 2>&1 >/dev/null)" out_rc beep/verbose-tries-tty0 "/dev/tty0" 1 beep --verbose -f 440 -l 0 out_rc beep/verbose-tries-vc0 "/dev/vc/0" 1 beep --verbose -f 440 -l 0 out_rc beep/verbose-module-console "beep: Verbose: console: driver_detect" 1 beep --verbose -f 440 -l 0 if [ -n "$EV" ] && [ -n "$CN" ] && [ "$EV" -lt "$CN" ]; then bst_ok beep/detect-order-evdev-first else bst_notok beep/detect-order-evdev-first "evdev trace at line '$EV', console trace at '$CN'"; fi bst_skip beep/device-plays "no device answered the probe: $(_bst_1line "$PROBE")" bst_skip beep/device-driver-named "no device answered the probe: $(_bst_1line "$PROBE")" bst_skip beep/device-repeats "no device answered the probe: $(_bst_1line "$PROBE")" bst_skip beep/device-sequence "no device answered the probe: $(_bst_1line "$PROBE")" else check_rc beep/device-plays 0 beep -f 440 -l 0 -r 1 out_rc beep/device-driver-named "using $DEV driver" 0 beep --verbose -f 440 -l 0 check_rc beep/device-repeats 0 beep -f 440 -l 0 -d 0 -r 4 check_rc beep/device-sequence 0 beep -f 440 -l 0 -n -f 880 -l 0 -n -f 1320 -l 0 bst_skip beep/no-device-message "a $DEV device answered the probe, so the no-device path is unreachable" bst_skip beep/no-device-rc "a $DEV device answered the probe, so the no-device path is unreachable" bst_skip beep/no-device-rc-full-pattern "a $DEV device answered the probe, so the no-device path is unreachable" bst_skip beep/no-device-on-stdout "a $DEV device answered the probe, so the no-device path is unreachable" bst_skip beep/no-device-stderr-empty "a $DEV device answered the probe, so the no-device path is unreachable" bst_skip beep/verbose-tries-tty0 "the $DEV driver answered first, so the console candidates are not reached" bst_skip beep/verbose-tries-vc0 "the $DEV driver answered first, so the console candidates are not reached" bst_skip beep/verbose-module-console "the $DEV driver answered first, so the console candidates are not reached" bst_skip beep/detect-order-evdev-first "only one driver was tried, so there is no order to observe" fi # --- a NAMED device: assertable in either arm, because -e bypasses the search out_rc beep/named-device-enoent "beep: Error: Could not open /nonexistent/dev for writing: No such file or directory" 1 beep -e /nonexistent/dev -f 440 -l 0 check_rc beep/named-device-enoent-rc 1 beep -e /nonexistent/dev -f 440 -l 0 out_rc beep/named-device-enoent-verbose "could not stat(2) /nonexistent/dev" 1 beep --verbose -e /nonexistent/dev -f 440 -l 0 : > "$tmp/plain" out_rc beep/named-device-notchar-verbose "$tmp/plain is not a character device" 1 beep --verbose -e "$tmp/plain" -f 440 -l 0 check_rc beep/named-device-notchar-rc 1 beep -e "$tmp/plain" -f 440 -l 0 out_rc beep/named-device-notchar-prefix "beep: Error: Could not open $tmp/plain for writing:" 1 beep -e "$tmp/plain" -f 440 -l 0 # ...and the REASON on that line is a stale errno, which is why this asserts the # form and not the value. open_checked_char_device() returns -1 from its S_ISCHR # test without touching errno, so main() prints strerror() of whatever the last # syscall left behind: "Success" (errno 0) on x86-64/glibc, "Cannot allocate # memory" here -- both measured, and stable across runs on each. Pinning the # string would pin an accident and would go red on any platform whose residual # errno differs, which is the opposite of what the case is for. So: the reason # must be non-empty, and it must be the SAME on two consecutive runs -- an # unstable one would mean the value is not merely stale but uninitialised. E1=$(beep -e "$tmp/plain" -f 440 -l 0 2>&1 | sed -n 's/.*for writing: //p' | head -1) E2=$(beep -e "$tmp/plain" -f 440 -l 0 2>&1 | sed -n 's/.*for writing: //p' | head -1) if [ -n "$E1" ]; then bst_ok beep/named-device-notchar-reason-nonempty else bst_notok beep/named-device-notchar-reason-nonempty "no reason printed after 'for writing: '"; fi if [ "$E1" = "$E2" ]; then bst_ok beep/named-device-notchar-reason-stable else bst_notok beep/named-device-notchar-reason-stable "run 1 said '$E1', run 2 said '$E2'"; fi check_rc beep/named-device-dir-rc 1 beep -e "$tmp" -f 440 -l 0 out_rc beep/named-device-dir-verbose "$tmp is not a character device" 1 beep --verbose -e "$tmp" -f 440 -l 0 # a character device that answers neither ioctl: past the open, stopped by the # ioctl -- the one arm of open_checked_device() the search itself cannot reach # here, since no candidate node opens if [ -c /dev/null ]; then check_rc beep/named-device-null-rc 1 beep -e /dev/null -f 440 -l 0 out_rc beep/named-device-null-opened "opened /dev/null as fd=" 1 beep --verbose -e /dev/null -f 440 -l 0 out_rc beep/named-device-null-evsnd "does not implement EV_SND API" 1 beep --verbose -e /dev/null -f 440 -l 0 out_rc beep/named-device-null-kiocsound "does not implement KIOCSOUND API" 1 beep --verbose -e /dev/null -f 440 -l 0 else bst_skip beep/named-device-null-rc "/dev/null is not a character device on this image" bst_skip beep/named-device-null-opened "/dev/null is not a character device on this image" bst_skip beep/named-device-null-evsnd "/dev/null is not a character device on this image" bst_skip beep/named-device-null-kiocsound "/dev/null is not a character device on this image" fi rm -rf "$tmp"