. "$BST_LIB" # BST-TIMEOUT: 300 # ~45 execs, three of them of nbd-server's 1 340 307 B # module, plus two deliberately BOUNDED runs of 10s each # (the listen arm and the connect-refused arm). NOW # MEASURED: ==BST-SUITE nbd elapsed=26s bound=600s # cases=85== on the BRINTOS-2048 batch verify of # 2026-09-03, so the original 600 was 23x the run. Trimmed # to 300, which is still 11x, because the run this bound # exists to cut short is a HANG and every second of slack # in it is a second every sibling suite waits. # nbd 3.24 (meta-openembedded/meta-networking recipes-support/nbd, with a # meta-brintos bbappend carrying one patch and one do_configure:prepend) -- the # Network Block Device userland. FOUR programs in four packages: # # /usr/sbin/nbd-client 535 199 B nbd-client # /usr/bin/nbd-server 1 340 307 B nbd-server # /usr/bin/nbd-trdump 22 683 B nbd-trdump # /usr/bin/nbd-trplay 40 976 B nbd-trplay # # THIS MACHINE HAS NO /dev/nbd0 AND NO PEER, AND BOTH ABSENCES ARE THE # ASSERTION rather than an obstacle to one. What that leaves is more than it # sounds like, because three quarters of this package's scriptable surface never # touches a device or a socket: # # * nbd-trdump is a PURE FILTER. It reads a transaction log on stdin and # writes decoded lines on stdout, and that is the whole program -- no # device, no socket, no configuration. Every one of its decode cases below # is a full end-to-end assertion on a fixture this file writes byte by byte. # # * nbd-trplay is a PURE FILE-TO-FILE REPLAYER. It applies the write half of # a transaction log to a disk image. The replay cases below write a log, # write an image, run the tool and COMPARE THE IMAGE AGAINST ONE BUILT # INDEPENDENTLY -- the strongest thing this suite asserts, and it needs # nothing this machine does not have. # # * nbd-server's config parser runs to completion before anything is bound. # Every parse refusal below is reached with no socket in play. # # THE FIXTURES ARE BUILT FROM THE PROTOCOL, NOT SHIPPED AS BLOBS. A binary blob # would be one file smaller and unreadable in a diff; the record builders below # (req/rep/trc) spell out nbd.h's struct nbd_request (packed, 28 bytes) and # struct nbd_reply (16 bytes) in network byte order, so a reader can check the # fixture against the header rather than against a hexdump. They emit through a # single printf %b per file and fork NOTHING per byte -- 2 KiB of fixture at one # fork per byte is a minute of this runtime, and the arithmetic-to-octal helper # is what avoids it. # # THE VERSION EVERY TOOL PRINTS IS 3.24 BECAUSE THE RECIPE PUTS IT THERE, and # that is worth a case of its own. configure.ac takes the version from # `support/genver.sh`, which is `git describe` falling back to the literal # "0.unknown"; upstream evaluates it once when rolling the tarball, and # `inherit autotools` re-runs autoreconf, which re-evaluates it in an unpacked # tarball with no git. Measured 2026-09-02: without the bbappend's # do_configure:prepend all four programs report "nbd 0.unknown". The version # cases below are therefore asserting the RECIPE, not the source, and they are # the thing that notices if that prepend is ever dropped. # # WHAT IS NOT ASSERTED, AND WHY. Two of the port ticket's assertions are # narrowed here, both because the source does not do what the ticket expected: # # * nbd-server DOES NOT REJECT AN UNKNOWN KEY in its config file. parse_cfile # iterates over the keys it KNOWS and looks each one up with # g_key_file_get_*; a key nobody looks up is never seen. There is no # g_key_file_get_keys() call in nbd-server.c and no "unknown key" string in # the binary. That is GKeyFile semantics and upstream's deliberate use of # them, not a defect, so the case below asserts the ignoring rather than a # rejection that does not exist -- and the genuine unknown-key rejection in # this package, nbd-client's nbdtab parser, is asserted separately. # # * nbd-trdump DOES NOT REJECT A TRUNCATED LOG. doread() calls exit(0) the # moment read(2) returns 0, wherever in a record that happens, so a log cut # mid-record ends the program cleanly with the complete records already # printed and no diagnostic. The case below pins exactly that -- the # records before the cut, nothing for the cut one, rc 0 -- because it is what # the program does. The genuine rejection is the UNKNOWN-MAGIC path, which # does print "? Unknown transaction type", and that has its own case. # # EVERY LITERAL BELOW IS MEASURED, NOT PREDICTED. The expected strings and # exit statuses in this file come from a NATIVE x86-64 build of the identical # 3.24 source, driven by the identical fixtures, on 2026-09-02 -- nbd-trdump and # nbd-trplay whole, nbd-server against these six config files, and nbd-client in # BOTH arms (HAVE_NETLINK 0 and 1, the latter with the libnl entry points stubbed # so the paths that return before the first libnl call could be measured). That # is what turns "the source looks like it prints X" into a reference: a wasm32 # build that answers differently is answering differently from the same source on # another machine, which is the only kind of finding this suite is trying to make. # # THREE CASES ARE NOT COVERED BY THAT REFERENCE, and they are named here so a # reader does not have to work out which: # # * nbd/client-disconnect-netlink -- it reaches the generic-netlink layer, which # is exactly what the stub could not stand in for. It is written to accept # either of the two documented refusals, and what it really pins is that the # tool REPORTS and EXITS rather than waiting on a reply that will not come. # * nbd/server-serve-or-report and nbd/server-listening -- whether this machine # lets a process bind a TCP port is the question, so a native answer would be # no evidence at all. MEASURED 2026-09-03: it does NEITHER of the two things # this pair was written to accept. nbd-server aborts (rc=133) before any # bind, in GLib's pool-spawner, on linux-in-the-browser#85 -- so # server-serve-or-report is an ATTRIBUTED red and server-listening skips as # its consequence. Both flip when #85 closes. Every other case in this file # is green. # * the presence, install-path and man-page cases -- facts about the image. # # NOTHING HERE BLOCKS WITHOUT A BOUND. Two cases deliberately start something # that may not return -- nbd-server against a config it can serve, and # nbd-client against a host that does not answer -- and both go through the # /proc/uptime wait loop below rather than a bare wait, so an overrun is one # red naming what it was doing instead of a suite that dies and takes every # sibling's result with it. bst_ok nbd/suite-canary # first line: absorbs brintos/linux#96, which drops it NC=/usr/sbin/nbd-client NS=/usr/bin/nbd-server ND=/usr/bin/nbd-trdump NP=/usr/bin/nbd-trplay # The absolute paths, not the PATH names: nbd-client installs into ${sbindir} # and /usr/sbin is not on every login's PATH here, so a `require nbd-client` # that missed it would SKIP this whole file rather than red -- an absent suite # that reads as a legitimate one. Whether the names also resolve through PATH # is asserted below as its own case. require "$ND" nbd/present W=${TMPDIR:-/tmp}/nbd.$$ mkdir -p "$W" 2>/dev/null # --- byte emitters ----------------------------------------------------------- # # _ESC accumulates printf %b escapes; flush writes them out in ONE printf. The # octal conversion is arithmetic on purpose: `$(printf %03o ...)` per byte forks # a subshell per byte, and the write fixture alone is 512 of them. _ESC= byte() { _b=$(( $1 & 255 )) _ESC="$_ESC\\0$(( _b / 64 ))$(( (_b / 8) % 8 ))$(( _b % 8 ))" } # put : the value big-endian, which is what the wire is put() { _pn=$1; _pv=$2 while [ "$_pn" -gt 0 ]; do byte $(( (_pv >> ((_pn - 1) * 8)) & 255 )) _pn=$(( _pn - 1 )) done } fill() { _fn=$1; while [ "$_fn" -gt 0 ]; do byte "$2"; _fn=$(( _fn - 1 )); done; } flush() { printf %b "$_ESC" > "$1"; _ESC=; } # struct nbd_request: magic, type, handle[8], from, len -- 28 bytes, packed req() { put 4 $((0x25609513)); put 4 "$1"; put 8 "$2"; put 8 "$3"; put 4 "$4"; } # struct nbd_reply: magic, error, handle[8] -- 16 bytes rep() { put 4 $((0x67446698)); put 4 "$1"; put 8 "$2"; } # NBD_TRACELOG_MAGIC record: SET_DATALOG(1), from == NBD_TRACELOG_FROM_MAGIC trc() { put 4 $((0x25609514)); put 4 1; put 8 0; put 8 $((0x4A93BA39A54F31B6)); put 4 "$1"; } # --- case helpers ------------------------------------------------------------ # # Every run is inside $( ), which forks before any redirect: a stdin redirect the # TOP-LEVEL shell performs on the virtiofs root makes dup2(2) return 513 and ash # exits, ending the suite silently (brintos/linux#73). # # nb -- nb() { _id=$1; _want=$2; _needle=$3; _prog=$4; shift 4 _o=$("$_prog" "$@" 2>&1 -- nb_absent() { _id=$1; _want=$2; _needle=$3; _prog=$4; shift 4 _o=$("$_prog" "$@" 2>&1 : nbd-trdump reads stdin and only stdin td() { _id=$1; _want=$2; _needle=$3; _log=$4 # BST-REDIRECT-OK: forked by $( ) before the dup2, and every caller passes a # path under $W, this suite's ${TMPDIR:-/tmp} workdir -- never the rootfs _o=$( "$ND" < "$_log" 2>&1 ); _r=$? if bst_execfail "$_o"; then bst_unrun "$_id" "$_o"; return; fi if [ "$_r" -ne "$_want" ]; then bst_notok "$_id" "rc=$_r want=$_want out:'$(_bst_1line "$_o")'"; return fi case "$_o" in *"$_needle"*) bst_ok "$_id" ;; *) bst_notok "$_id" "rc=$_r as wanted, but output lacks '$_needle': $(_bst_1line "$_o")" ;; esac } # td_absent td_absent() { _id=$1; _want=$2; _needle=$3; _log=$4 # BST-REDIRECT-OK: forked by $( ), and $_log is always under $W _o=$( "$ND" < "$_log" 2>&1 ); _r=$? if bst_execfail "$_o"; then bst_unrun "$_id" "$_o"; return; fi if [ "$_r" -ne "$_want" ]; then bst_notok "$_id" "rc=$_r want=$_want out:'$(_bst_1line "$_o")'"; return fi case "$_o" in *"$_needle"*) bst_notok "$_id" "output carries '$_needle', which must not be there: $(_bst_1line "$_o")" ;; *) bst_ok "$_id" ;; esac } # --- 1. presence and inventory ---------------------------------------------- for _p in "$NC" "$NS" "$ND" "$NP"; do if [ -x "$_p" ]; then bst_ok "nbd/installed-${_p##*/}" else bst_notok "nbd/installed-${_p##*/}" "$_p is not present or not executable"; fi done # The four programs are four separate packages (PACKAGES in the meta-networking # recipe), so a packaging change that dropped one would leave the others. The # loop above is what notices; this case is about the split itself: nbd-client is # the only one in ${sbindir}, and a recipe that moved it would break every # caller resolving it through a PATH without /usr/sbin. if [ -x /usr/sbin/nbd-client ] && [ -x /usr/bin/nbd-server ]; then bst_ok nbd/install-paths else bst_notok nbd/install-paths "expected nbd-client in /usr/sbin and nbd-server in /usr/bin" fi if command -v nbd-trdump >/dev/null 2>&1; then bst_ok nbd/trdump-on-path else bst_notok nbd/trdump-on-path "/usr/bin/nbd-trdump exists but the name does not resolve through PATH"; fi # --- 2. version and usage ---------------------------------------------------- # # 3.24, not 0.unknown -- see the header. These four cases are the bbappend's # do_configure:prepend under test. nb nbd/client-version 0 "This is nbd-client, from nbd 3.24" "$NC" -V nb nbd/server-version 0 "This is nbd-server version 3.24" "$NS" -V nb nbd/trdump-version 0 "This is nbd-trdump, part of nbd 3.24." "$ND" --help nb nbd/trplay-version 0 "This is nbd-trplay, part of nbd 3.24." "$NP" -h # usage(NULL) prints " version " and the option summary on STDERR and # exits 0 -- nbd-client's -h is a success, not an error. nb nbd/client-help-rc0 0 "nbd-client version 3.24" "$NC" -h nb nbd/client-help-usage 0 "Usage: nbd-client -name|-N name host [port] nbd_device" "$NC" -h # HAVE_NETLINK is on (libnl-genl-3.0 >= 3.1 found at configure), so the usage # line carries -nonetlink|-L. Asserted against the binary's own text rather # than against a guess about what configure found. nb nbd/client-usage-netlink 0 "[-nonetlink|-L]" "$NC" -h # HAVE_GNUTLS is off (gnutls >= 2.12.0 not found), and nbd_client_CFLAGS carries # -DNOTLS in that arm, so the TLS option block is not in the usage text... nb_absent nbd/client-usage-no-tls 0 "-certfile" "$NC" -h # ...and the options themselves report the absence rather than being eaten. nb nbd/client-tls-not-compiled 1 "E: TLS support not compiled in" "$NC" -certfile /dev/null # nbd-server's usage goes to STDOUT and its exit is 1 -- an unknown option is an # error there, unlike nbd-client's -h. nb nbd/server-usage 1 "Usage: [ip:|ip6@]port file_to_export" "$NS" -Z nb nbd/server-usage-cfile 1 "Using configuration file /etc/nbd-server/config" "$NS" -Z # nbd-trdump takes no options at all: anything but -h/--help is refused by name # and still prints the identity line, with rc 1. nb nbd/trdump-unknown-opt 1 "E: unknown option -z." "$ND" -z nb nbd/trplay-no-log 1 "Log file not specified, this is mandatory." "$NP" # --- 3. argument validation that precedes every device and socket ------------ nb nbd/client-no-args 1 "ERROR: no information specified" "$NC" nb nbd/client-bad-blocksize 1 "E: blocksize is not a multiple of 512! This is not allowed" \ "$NC" -b 500 -N export 127.0.0.1 10809 /dev/nbd0 nb nbd/client-bad-size 1 "E: Invalid size" "$NC" -B notanumber -N export 127.0.0.1 10809 /dev/nbd0 # -d takes the device name apart with sscanf("/dev/nbd%d") before it touches # netlink, so this refusal is reached on a machine with no netlink at all. nb nbd/client-disconnect-bad-target 1 "Invalid nbd device target" "$NC" -d /dev/notanbd # --- 4. the two absences, asserted directly ---------------------------------- # # THERE IS NO /dev/nbd0. Asserted first as a fact about the machine, so the two # cases after it are reporting on a state this file has established rather than # assumed. if [ -e /dev/nbd0 ]; then bst_notok nbd/no-device-node "/dev/nbd0 exists on this image; the two absence cases below no longer assert what they say" else bst_ok nbd/no-device-node fi # -L turns netlink off, and THAT path opens the device node before it opens a # socket -- which is what makes the missing node the thing reported. Without # -L the netlink path never opens the node at all, so this case would assert # nothing. nb nbd/client-nonetlink-no-device 1 "Cannot open NBD: No such file or directory" \ "$NC" -L -N export 127.0.0.1 10809 /dev/nbd0 nb nbd/client-nonetlink-hint 1 "Please ensure the 'nbd' module is loaded." \ "$NC" -L -N export 127.0.0.1 10809 /dev/nbd0 # check_conn() reads /sys/block/nbd0/pid and returns 1 on ENOENT -- the # documented "not connected" status. No device, no socket, no netlink. _o=$("$NC" -c /dev/nbd0 2>&1 &1 "$W/conn.out" 2>&1; echo $? >"$W/conn.rc" ) & _cpid=$! _t=0 while [ ! -e "$W/conn.rc" ] && [ "$_t" -lt 20 ]; do sleep 1; _t=$(( _t + 1 )); done if [ -e "$W/conn.rc" ]; then bst_ok nbd/client-connect-bounded else kill -9 "$_cpid" 2>/dev/null bst_notok nbd/client-connect-bounded "still trying to connect after 20s; last line: $(_bst_1line "$(tail -n 1 "$W/conn.out" 2>/dev/null)")" fi # --- 5. nbd-trdump: the decode fixture -------------------------------------- # # log-basic, with no datalog trace option in it, so a WRITE record carries no # data and the records are back to back. Five records: # READ h=1 off=0x1000 len=0x200 # reply h=1 err=0 # WRITE|FUA h=2 off=0x2000 len=0x200 # reply h=2 err=5 # DISC h=3 off=0 len=0 req 0 1 $((0x1000)) $((0x200)) rep 0 1 req $((0x00010001)) 2 $((0x2000)) $((0x200)) rep 5 2 req 2 3 0 0 flush "$W/log-basic" td nbd/trdump-read-request 0 "> H=0000000000000001 C=0x00000000" "$W/log-basic" td nbd/trdump-read-name 0 "NBD_CMD_READ+NONE" "$W/log-basic" td nbd/trdump-read-offlen 0 "O=0000000000001000 L=00000200" "$W/log-basic" td nbd/trdump-reply-ok 0 "< H=0000000000000001 E=0x00000000" "$W/log-basic" td nbd/trdump-write-fua 0 "NBD_CMD_WRITE+ FUA" "$W/log-basic" td nbd/trdump-write-flags 0 "> H=0000000000000002 C=0x00010001" "$W/log-basic" td nbd/trdump-reply-error 0 "< H=0000000000000002 E=0x00000005" "$W/log-basic" td nbd/trdump-disc 0 "NBD_CMD_DISC+NONE" "$W/log-basic" # Five records in, five lines out: nothing skipped, nothing invented, and no # trailing diagnostic. The count is the case that would notice a decoder that # silently swallowed a record the substring cases do not cover. _n=$( "$ND" < "$W/log-basic" 2>/dev/null | wc -l ) if [ "$_n" = "5" ]; then bst_ok nbd/trdump-line-count else bst_notok nbd/trdump-line-count "5 records in, $_n lines out"; fi # log-trace: the datalog trace option, then a WRITE whose 512 data bytes must be # CONSUMED by the decoder -- if it does not consume them, the reply after it is # read out of the middle of the payload and decodes as garbage. This is the one # fixture where a correct decoder and a broken one differ in the LAST line # rather than in a message. trc 1 req 1 4 $((0x200)) $((0x200)) fill 512 $((0x41)) rep 0 4 flush "$W/log-trace" td nbd/trdump-tracelog-line 0 "TRACE_OPTION C=0x00000001" "$W/log-trace" td nbd/trdump-tracelog-name 0 "NBD_TRACELOG_SET_DATALOG" "$W/log-trace" td nbd/trdump-tracelog-set 0 "TRACE_OPTION DATALOG set to 1." "$W/log-trace" td nbd/trdump-datalog-consumed 0 "< H=0000000000000004 E=0x00000000" "$W/log-trace" td_absent nbd/trdump-datalog-no-garbage 0 "? Unknown transaction type" "$W/log-trace" _n=$( "$ND" < "$W/log-trace" 2>/dev/null | wc -l ) if [ "$_n" = "4" ]; then bst_ok nbd/trdump-trace-line-count else bst_notok nbd/trdump-trace-line-count "expected 4 lines (trace, set, write, reply), got $_n"; fi # The genuine rejection: a magic nothing recognises is named and skipped, and # the decoder keeps going rather than stopping. put 4 $((0xdeadbeef)) req 0 9 0 $((0x200)) flush "$W/log-badmagic" td nbd/trdump-unknown-magic 0 "? Unknown transaction type deadbeef" "$W/log-badmagic" td nbd/trdump-continues-after-unknown 0 "H=0000000000000009" "$W/log-badmagic" # NARROWED, and deliberately so -- see the header. A log cut mid-record is not # rejected: doread() exits 0 as soon as read(2) returns 0, so the complete # records are printed and the partial one is silently dropped. req 0 7 0 $((0x200)) put 4 $((0x25609513)) put 4 0 flush "$W/log-trunc" _o=$( "$ND" < "$W/log-trunc" 2>&1 ); _r=$? _n=$( "$ND" < "$W/log-trunc" 2>/dev/null | wc -l ) if bst_execfail "$_o"; then bst_unrun nbd/trdump-truncated "$_o" elif [ "$_r" -eq 0 ] && [ "$_n" = "1" ]; then bst_ok nbd/trdump-truncated else bst_notok nbd/trdump-truncated "rc=$_r lines=$_n want rc=0 lines=1 (the complete record only): $(_bst_1line "$_o")"; fi : > "$W/log-empty" _o=$( "$ND" < "$W/log-empty" 2>&1 ); _r=$? if [ "$_r" -eq 0 ] && [ -z "$_o" ]; then bst_ok nbd/trdump-empty else bst_notok nbd/trdump-empty "rc=$_r out:'$(_bst_1line "$_o")' want rc=0 and no output"; fi # --- 6. nbd-trplay: the replay, compared against an image built independently - # # The strongest assertion in this file. The log writes 512 bytes of 0x41 at # offset 512 of a 2048-byte image of zeroes; the expected image is built here # from the same primitives, and the two are compared byte for byte. trc 1 req 1 1 512 512 fill 512 $((0x41)) rep 0 1 flush "$W/replay.log" fill 2048 0; flush "$W/img" fill 512 0; fill 512 $((0x41)); fill 1024 0; flush "$W/img-want" _o=$( "$NP" -i "$W/img" -l "$W/replay.log" 2>&1 &1 "$W/cfg-nogeneric" nb nbd/server-cfile-no-generic 1 "Config file does not contain the [generic] group!" \ "$NS" -d -C "$W/cfg-nogeneric" printf '%s\n' "[generic]" > "$W/cfg-noexports" nb nbd/server-cfile-no-exports 1 "The config file does not specify any exports" \ "$NS" -d -C "$W/cfg-noexports" # exportname is the one required key in an export group. printf '%s\n' "[generic]" "" "[export]" " readonly = true" > "$W/cfg-noexportname" nb nbd/server-cfile-missing-required 1 "Could not find required value exportname in group export" \ "$NS" -d -C "$W/cfg-noexportname" # A typed key with an untypeable value is a parse error naming the key and the # group -- parse_cfile's DEFAULT_ERROR. printf '%s\n' "[generic]" " max_threads = notanumber" "" "[export]" " exportname = $W/img" \ > "$W/cfg-badint" nb nbd/server-cfile-invalid-value 1 "Could not parse max_threads in group generic" \ "$NS" -d -C "$W/cfg-badint" # An absent config file is NBDS_ERR_CFILE_NOTFOUND, which main() deliberately # does NOT warn about -- it is the ordinary "no configuration" case -- and the # server quits with the message that says so. nb nbd/server-cfile-absent 1 "No configured exports; quitting." \ "$NS" -d -C "$W/no-such-config" # NARROWED -- see the header. An unknown key is IGNORED, not rejected: this # config differs from a good one only by `bogus_key`, and the assertion is that # the parser says nothing about it. It is written as its own case rather than # left unsaid, because "the parser rejects an unknown key" is what the port # ticket expected and a reader has to be able to see that it was checked. printf '%s\n' "[generic]" " bogus_key = 42" > "$W/cfg-unknownkey" _o=$( "$NS" -d -C "$W/cfg-unknownkey" 2>&1 "$W/cfg-good" ( "$NS" -d -C "$W/cfg-good" >"$W/srv.out" 2>&1; echo $? >"$W/srv.rc" ) & _srv=$! _t=0 while [ ! -e "$W/srv.rc" ] && [ "$_t" -lt 10 ]; do sleep 1; _t=$(( _t + 1 )); done if [ -e "$W/srv.rc" ]; then # BST-REDIRECT-OK: $W is this suite's ${TMPDIR:-/tmp} workdir, never the rootfs read -r _srv_rc < "$W/srv.rc" _srv_out=$(cat "$W/srv.out" 2>/dev/null) if bst_execfail "$_srv_out"; then bst_unrun nbd/server-serve-or-report "$_srv_out" elif [ "$_srv_rc" -ge 128 ]; then # MEASURED 2026-09-03 (BRINTOS-2048 batch verify): rc=133, GLib-ERROR # "creating thread 'pool-spawner'". nbd-server is single-threaded and never # calls pthread_create; GLib starts a pool-spawner thread for the first # GThreadPool and g_error()s -- i.e. aborts -- when it cannot. The console # carries the cause: REFUSING thread-mode clone flags=0x3d0f00, a genuine # CLONE_THREAD, which is linux-in-the-browser#85. ATTRIBUTED, so the red # ships; it flips green when #85 closes. bst_notok nbd/server-serve-or-report "killed by signal (rc=$_srv_rc) -- linux-in-the-browser#85 (https://brintos.io/brintos/linux-in-the-browser/issues/85) if this is GLib's pool-spawner g_error(): $(_bst_1line "$_srv_out")" elif [ "$_srv_rc" -eq 1 ]; then bst_ok nbd/server-serve-or-report else bst_notok nbd/server-serve-or-report "exited rc=$_srv_rc, which is neither serving nor the documented refusal: $(_bst_1line "$_srv_out")" fi bst_skip nbd/server-listening "nbd-server exited (rc=$_srv_rc) rather than binding; nothing to observe" else bst_ok nbd/server-serve-or-report # It is still up. 10809 is 0x2A39; /proc/net/tcp and tcp6 list the local port # in hex, so a listening socket on the default port is observable without any # networking tool at all. if [ ! -r /proc/net/tcp ] && [ ! -r /proc/net/tcp6 ]; then bst_skip nbd/server-listening "this kernel exposes neither /proc/net/tcp nor /proc/net/tcp6, so a bound port cannot be observed" elif grep -qiE ':2A39 ' /proc/net/tcp /proc/net/tcp6 2>/dev/null; then bst_ok nbd/server-listening else bst_notok nbd/server-listening "nbd-server is running but nothing is bound to 10809 (0x2A39) in /proc/net/tcp{,6}" fi kill -9 "$_srv" 2>/dev/null fi # --- 9. nbd-client's nbdtab parser ------------------------------------------- # # THE GENUINE UNKNOWN-KEY REJECTION IN THIS PACKAGE. nbdtab_set_property() and # nbdtab_set_flag() compare against a fixed list and warn by name on anything # else -- which is what the port ticket asked for, in the parser that actually # does it. The path is only reachable through /etc/nbdtab, whose name is # compiled in (SYSCONFDIR "/nbdtab"), so this section writes that file and puts # it back. A pre-existing one is saved rather than overwritten: nothing in this # suite is entitled to destroy another package's configuration. _tab=/etc/nbdtab _saved= if [ -e "$_tab" ]; then _saved=$W/nbdtab.saved; cp "$_tab" "$_saved" 2>/dev/null; fi if printf '%s\n' "nbd0 127.0.0.1 someexport bogusopt=1" > "$_tab" 2>/dev/null; then nb nbd/nbdtab-unknown-option 1 "Warning: unknown option 'bogusopt' found in nbdtab file" \ "$NC" nbd0 # A leading underscore is upstream's own escape hatch for a key it should not # complain about, and it is asserted so the warning above is known to be a # decision rather than a catch-all. printf '%s\n' "nbd0 127.0.0.1 someexport _private=1" > "$_tab" nb_absent nbd/nbdtab-underscore-quiet 1 "unknown option" "$NC" nbd0 # A syntax error is reported by the generated parser with the file's compiled-in # name, which is the other half of "this really is /etc/nbdtab". printf '%s\n' "=== not an nbdtab line ===" > "$_tab" nb nbd/nbdtab-parse-error 1 "parse error parsing /etc/nbdtab" "$NC" nbd0 # A device the file does not mention is "no valid configuration", not a crash. printf '%s\n' "nbd9 127.0.0.1 someexport" > "$_tab" nb nbd/nbdtab-no-config-for-device 1 "no valid configuration for specified device found" \ "$NC" nbd0 rm -f "$_tab" [ -n "$_saved" ] && cp "$_saved" "$_tab" 2>/dev/null else for _c in nbdtab-unknown-option nbdtab-underscore-quiet nbdtab-parse-error nbdtab-no-config-for-device; do bst_skip "nbd/$_c" "/etc is not writable on this image, so the nbdtab parser cannot be reached" done fi # With no /etc/nbdtab at all, nbd-client says which file it could not open -- # and this is the arm the image ships in, so it is asserted unconditionally # after the block above has put things back. if [ ! -e "$_tab" ]; then nb nbd/nbdtab-absent 1 "while opening /etc/nbdtab" "$NC" nbd0 else bst_skip nbd/nbdtab-absent "this image ships an /etc/nbdtab; the open-failure path is unreachable" fi # --- 10. the man pages the -doc package ships -------------------------------- # # Six pages in three sections. Not a formality: nbd's man pages are GENERATED # at build time from DocBook SGML through a shell template, so a missing one is # a build that silently skipped a step rather than a packaging list that forgot # a name. for _m in man8/nbd-client.8 man1/nbd-server.1 man5/nbd-server.5 man5/nbdtab.5 \ man1/nbd-trdump.1 man1/nbd-trplay.1; do if [ -s "/usr/share/man/$_m" ]; then bst_ok "nbd/man-${_m##*/}" else bst_notok "nbd/man-${_m##*/}" "/usr/share/man/$_m is missing or empty"; fi done rm -rf "$W"