# BST-TIMEOUT: 300 # NOT MEASURED ON TARGET YET. Chosen from 79-libndp, whose # # shape this suite copies exactly -- one probe exec plus a # # shell fork per scored value -- and which measured 83 s for # # 160 cases on an idle host. This suite scores ~45, so 300 # # is deep headroom rather than a fit. The one thing here # # libndp does not do is I/O: the probe opens and rewrites a # # 52-byte tmpfs file 53 times for the truncation sweep, # # inside its own process. Replace this note with a measured # # elapsed the first time the suite runs on target. . "$BST_LIB" # libXau 1.0.11 (poky recipes-graphics/xorg-lib) -- the X authority file reader # and writer. What ships is /usr/lib/libXau.a, /usr/include/X11/Xauth.h, # /usr/lib/pkgconfig/xau.pc and this port's probe. # # --------------------------------------------------------------------------- # THIS LIBRARY NEEDS NO SERVER, AND THAT IS WHY IT CAN BE MEASURED IN FULL # # Nothing in libXau opens a socket. Every entry point is a file-format operation # over .Xauthority -- the file an X client consults to find the cookie for a # display -- plus the lock beside it and the $XAUTHORITY/$HOME rule that names # it. So unlike the rest of this epic, there is no "it fails honestly with no # display" half here: the whole of the package is reachable on this image and # the whole of it is asserted below. # # --------------------------------------------------------------------------- # THE ORACLE IS A NATIVE x86-64 RUN, AND THAT IS THE POINT # # Every W, R, T, F, G and L value below is pinned to what libxau_probe.c printed # when built against libXau 1.0.11 on x86-64 (2026-08-27). The .Xauthority # format is fixed -- a two-byte BIG-ENDIAN family followed by four two-byte- # counted strings, the same bytes every X server and xauth(1) read -- so the two # architectures must agree exactly and a mismatch is a real defect rather than # an expected difference. # # It is also the assertion a target-only run cannot make. Writing an entry and # reading it back proves the writer and the reader are consistent; it does not # prove they are RIGHT. A port that emitted the counts in host byte order would # round-trip through its own mistake and report every field correct. Only the # pinned bytes catch that, and they are hand-checked against the format rather # than merely copied: # # W02 = 0100 0007 6272696e746f73 0001 30 0012 4d49...31 0010 000102...0f # ^family 256 ^"brintos" ^1 ^"0" ^18 ^"MIT-MAGIC-COOKIE-1" # ^16 ^cookie # # Both of the families used (256 FamilyLocal, 65535 FamilyWild) are outside # the 8-bit range ON PURPOSE: a host-order slip is invisible in a family of 0. # # THE ONE GROUP THAT IS NOT THE x86-64 ANSWER IS C. struct Xauth is an in-memory # layout, not a wire format, and this arm is ILP32 against the reference host's # LP64 -- 32 bytes here against 64 there. Those numbers are derived by hand from # the declaration in Xauth.h and pinned as a statement about this toolchain's # ABI. Reusing the reference host's would have been wrong, and would have looked # exactly as convincing. # # --------------------------------------------------------------------------- # UPSTREAM'S OWN TEST CANNOT SERVE HERE, which is why the probe exists at all. # libXau ships Autest.c as its check program: it writes ONE entry, reads nothing # back, asserts nothing, and returns `(state = 1) ? 0 : 1` -- an assignment, so # it exits 0 whether XauWriteAuth succeeded or not. It is not installed and it # is not run. That is freedesktop's, in a public repository, and this project # reports nothing to those (docs/conventions/no-public-upstream-reports.md). PROBE=${BST_LIBXAU_PROBE:-/usr/libexec/libxau-tests/libxau-probe} ARCHIVE=/usr/lib/libXau.a PCFILE=/usr/lib/pkgconfig/xau.pc HDR=/usr/include/X11/Xauth.h # The version the recipe pins. Asserted rather than read back, so a recipe # bumped without revisiting this suite is a red here instead of a silent change # of subject -- the pinned bytes above are the oracle for THIS version only. WANT_VERSION=1.0.11 # The first BST result line of a suite is dropped by the guest console # (brintos/linux#96), consistently and every run. This case asserts something # already true so that what is lost is a line that costs nothing; remove it when # #96 lands. if [ -f "$ARCHIVE" ]; then bst_ok libxau/suite-canary else bst_notok libxau/suite-canary "$ARCHIVE is not a file"; fi if [ ! -f "$ARCHIVE" ]; then bst_skip libxau/present "libxau not installed on this image" exit 0 fi bst_ok libxau/present # --- the package is whole ----------------------------------------------------- check libxau/staticlib test -s "$ARCHIVE" check libxau/pkgconfig test -s "$PCFILE" check libxau/hdr-xauth test -s "$HDR" # Shape, not absence: this arm converts to shared libraries per recipe # (BRINTOS-1740), so a .so here is a conversion, not a policy breach. bst_lib_shape libxau/no-shared "/usr/lib/libXau.so" "/usr/lib/libXau.so.6" pcver=$(sed -n 's/^Version: *//p' "$PCFILE" 2>/dev/null | head -1) check_eq libxau/pkgconfig-version "$WANT_VERSION" "$pcver" # The archive carries the API. grep rather than nm: the image ships no binutils # nm, and the names are present as plain bytes. -a where the grep supports it -- # on this arm the archive members are LLVM IR bitcode (ThinLTO), so a grep that # suppresses matches in a file containing NULs reports nothing; GNU grep needs # -a, busybox grep as shipped does not. Probing keeps this measuring libXau # rather than measuring the image's grep. if echo x | grep -aq x 2>/dev/null; then _grepq="grep -aq"; else _grepq="grep -q"; fi for sym in XauFileName XauReadAuth XauWriteAuth XauLockAuth XauUnlockAuth \ XauGetAuthByAddr XauGetBestAuthByAddr XauDisposeAuth; do if $_grepq "$sym" "$ARCHIVE" 2>/dev/null; then bst_ok "libxau/sym-$sym" else bst_notok "libxau/sym-$sym" "$sym absent from $ARCHIVE" fi done # The header must declare the whole of that API, since it is the only thing a # consumer recipe compiles against. for decl in XauFileName XauReadAuth XauWriteAuth XauLockAuth XauUnlockAuth \ XauGetAuthByAddr XauGetBestAuthByAddr XauDisposeAuth; do if grep -q "$decl" "$HDR" 2>/dev/null; then bst_ok "libxau/hdr-decl-$decl" else bst_notok "libxau/hdr-decl-$decl" "$decl is not declared in $HDR" fi done # --- the probe ---------------------------------------------------------------- if [ ! -x "$PROBE" ]; then bst_skip libxau/probe-runs "$PROBE absent from the image" exit 0 fi pout=${TMPDIR:-/tmp}/bst-libxau-out.$$ "$PROBE" > "$pout" 2>&1 prc=$? if [ "$prc" -eq 0 ]; then bst_ok libxau/probe-runs elif bst_execfail "$(head -c 200 "$pout" 2>/dev/null)"; then bst_unrun libxau/probe-runs "$(head -c 200 "$pout" 2>/dev/null)" rm -f "$pout" exit 0 else bst_notok libxau/probe-runs "probe exited $prc: $(_bst_1line "$(head -c 300 "$pout")")" fi if grep -q '^PROBE-END$' "$pout" 2>/dev/null; then bst_ok libxau/probe-complete else bst_notok libxau/probe-complete "probe output has no PROBE-END terminator (last line: $(tail -1 "$pout" 2>/dev/null))" fi # val -- the probe's value for one case, empty when the probe stopped # first. Matches on the ID in field 1 rather than taking the line by position, # because the probe's output is captured with 2>&1 and libXau writes nothing to # stdout of its own but a platform diagnostic could still land in the middle. val() { awk -v k="$1" '$1==k { $1=""; sub(/^ /,""); print; exit }' "$pout"; } # want -- score one probe value against a pinned answer. # A missing value is reported as the probe having stopped early rather than as a # mismatch against '', which is a different fault and localises to a different # line. want() { _got=$(val "$1") if [ -z "$_got" ]; then bst_notok "libxau/$2" "no value on target (probe stopped before $1); want='$3'" elif [ "$_got" = "$3" ]; then bst_ok "libxau/$2" else bst_notok "libxau/$2" "want:'$3' got:'$_got'" fi } # --- C: the in-memory ABI, derived by hand for ILP32 -------------------------- # struct xauth is five unsigned shorts interleaved with four pointers. On this # arm a pointer is 4 bytes and aligns to 4, so each short is followed by two # bytes of padding: 0/2/4, 8/12, 16/20, 24/28, size 32. The reference host # reports 64 with 8-byte pointers, which is the same declaration and a different # ABI -- so these are the numbers that say the port's struct is laid out as a # 32-bit consumer of this header expects. want C01 abi-sizeof 32 want C02 abi-offsets "0 2 4 8 12 16 20 24 28" want C03 abi-lock-rc "0 1 2" want C04 abi-families "256 65535 254 253 252" # --- W: the bytes XauWriteAuth puts on disk ----------------------------------- want W00 write-ok 1 want W01 file-size 167 want W02 write-entry-local-mit 010000076272696e746f7300013000124d49542d4d414749432d434f4f4b49452d310010000102030405060708090a0b0c0d0e0f want W03 write-entry-inet-xdm 000000047f000001000131001358444d2d415554484f52495a4154494f4e2d310008a0a1a2a3a4a5a6a7 # The zero-length case, and the reason it is in the fixture: every one of the # four counted strings is empty here except the name, so a writer that emitted a # length prefix wrongly for an empty field is caught in one entry. want W04 write-entry-wild-empty ffff0000000000124d49542d4d414749432d434f4f4b49452d310000 want W05 write-entry-local-xdm 010000076272696e746f73000130001358444d2d415554484f52495a4154494f4e2d310008b0b1b2b3b4b5b6b7 # --- R: XauReadAuth's parse of those same bytes ------------------------------- # `-` is a NULL pointer, not an empty string. XauReadAuth documents NULL for a # count of zero, and a suite that could not tell the two apart would pass over a # reader that lost the pointer -- which is exactly what R03 pins. want R01 read-entry-local-mit "fam=256 a=6272696e746f73 n=30 N=4d49542d4d414749432d434f4f4b49452d31 d=000102030405060708090a0b0c0d0e0f" want R02 read-entry-inet-xdm "fam=0 a=7f000001 n=31 N=58444d2d415554484f52495a4154494f4e2d31 d=a0a1a2a3a4a5a6a7" want R03 read-entry-wild-empty "fam=65535 a=- n=- N=4d49542d4d414749432d434f4f4b49452d31 d=-" want R04 read-entry-local-xdm "fam=256 a=6272696e746f73 n=30 N=58444d2d415554484f52495a4154494f4e2d31 d=b0b1b2b3b4b5b6b7" want R05 read-count 4 # --- T: a truncated file is refused, not read past ---------------------------- # Every proper prefix of a one-entry file: 52 of them, covering a cut inside # each of the five length fields and inside each of the four payloads. want T00 trunc-fixture-size 52 want T01 trunc-all-refused 0 # The control. Without it a reader that returned NULL for everything would score # T01 perfect. want T02 trunc-control-reads 1 # --- F: XauFileName's environment contract ------------------------------------ want F01 filename-xauthority "/xau/explicit/path" want F02 filename-home "/home/brintos/.Xauthority" # The one special case in the code: a HOME of exactly "/" must not produce # "//.Xauthority". want F03 filename-home-root "/.Xauthority" want F04 filename-neither "(null)" # --- G: lookup and selection order -------------------------------------------- want G01 getauth-by-addr "000102030405060708090a0b0c0d0e0f" # THE LOAD-BEARING PAIR. The MIT entry is EARLIER in the file than the XDM one, # so a selector that merely took the first match would answer MIT for both. G02 # asks with XDM first in the types list and must get the XDM cookie; G03 flips # the list and must get the MIT one, off the same file. want G02 getbest-prefers-first-type "b0b1b2b3b4b5b6b7" want G03 getbest-order-is-the-list "000102030405060708090a0b0c0d0e0f" # An empty type list is documented as "no preference": first match wins. want G04 getbest-no-types-first-match "000102030405060708090a0b0c0d0e0f" want G05 getauth-wild-query "000102030405060708090a0b0c0d0e0f" # A FamilyWild ENTRY matches an address that is in the file nowhere, and its # cookie is zero-length, so the answer is a NULL data pointer rather than a # miss. G07 is the same query against a fixture with that entry removed, which # is the only way to see a real miss. want G06 getauth-wild-entry-matches "-" want G07 getauth-no-match "(none)" # access(2) gates the open: a named file that is not there is NULL, not a # diagnostic and not a crash. want G08 getauth-absent-file "(none)" # --- L: XauLockAuth / XauUnlockAuth ------------------------------------------- # THE ONE GROUP WHOSE EXPECTATION IS COMPUTED RATHER THAN PINNED, and the reason # is upstream's, not this port's. XauLockAuth creates "-c" and hard-links # it to "-l"; where pathconf(_PC_LINK_MAX) reports 1 it renames instead. # The two differ in an observable way: the link path leaves both files and # refuses a second lock with LOCK_TIMEOUT, while the rename path leaves only the # link name and rename(2) over an existing file SUCCEEDS -- so a second lock is # granted. That is a real weakness of upstream's fallback and it is not # something this port can fix or should hide, so the mechanism is reported (L02) # and the second-lock case is scored against it. Both shapes are a correct # libXau; anything else is not. want L01 lock-succeeds 0 lockmech=$(val L02) case "$lockmech" in 11) bst_ok libxau/lock-mechanism want L03 lock-second-refused 2 ;; 01) bst_ok libxau/lock-mechanism # Reported, not hidden: on this filesystem libXau's lock does not exclude. want L03 lock-second-refused 0 ;; "") bst_notok libxau/lock-mechanism "no value on target (probe stopped before L02)" bst_notok libxau/lock-second-refused "the lock mechanism is unknown, so the second-lock answer could not be scored" ;; *) bst_notok libxau/lock-mechanism "after a successful XauLockAuth the -c/-l pair is '$lockmech'; neither the link path (11) nor the pathconf/rename path (01)" bst_notok libxau/lock-second-refused "the lock mechanism is unknown, so the second-lock answer could not be scored" ;; esac want L04 unlock-returns 1 want L05 unlock-removes-both "00" want L06 relock-after-unlock 0 # The documented refusal: a name too long for the 1025-byte buffers. Both calls # check it, and they answer differently -- LOCK_ERROR from the lock, 0 from the # unlock -- which is upstream's contract and worth pinning so a rewrite of # either does not quietly change it. want L07 lock-name-too-long 1 want L08 unlock-name-too-long 0 rm -f "$pout"