. "$BST_LIB" # zlog 1.2.16 -- "a reliable, thread-safe, flexible pure-C logging library" # (meta-oe recipes-extended). See zlog_%.bbappend for what the port adds and why. # # --------------------------------------------------------------------------- # WHERE THE EVIDENCE COMES FROM # # zlog installs exactly ONE program -- zlog-chk-conf, a config linter -- and # ships no reference-output corpus of its own (unlike log4c, whose upstream # .ref files carry the expected bytes). So "the files are present" would have # been the whole of the on-target evidence, which is the BRINTOS-217 shape: # oniguruma compiled and packaged perfectly and then returned silently wrong # offsets to every caller. # # Two independent sources are used instead: # # THE LINTER, driven over its whole contract -- help, a good config, a # syntactically bad one, and no arguments -- because it is the one shipped # binary and its exit codes are upstream's own (0 / 2 / 255, measured). # # A PROBE. data/zlog-probe (src/zlog_probe.c) is cross-linked with # wasmcc-glibc against THE VERY ARCHIVE THAT SHIPS (/usr/lib/libzlog.a) and # drives the library: config parse, the category tree, level filtering, the # format specs, MDC, the hex dumper, rotation, fsync, reload and the # user-record plug-in path. # # EVERY EXPECTED VALUE IS THE VALUE A NATIVE x86_64 BUILD OF THE IDENTICAL # SOURCE PRODUCES. data/zlog-native.txt is that control, and # zlog/native-byte-identical asserts it ON TARGET rather than by eyeballing two # logs off-target. The probe splits its output for exactly this: # ZLOG- platform-INDEPENDENT -> compared byte-for-byte # ZLOGV- platform-DEPENDENT (pids, tids, hostnames) -> reported only # # --------------------------------------------------------------------------- # THE ROWS WRITTEN FOR PLATFORM REASONS, AND WHAT EACH IS HOLDING # # Six cases are red on this arm today. Every one is left FAILING rather than # skipped, so it flips green by itself the day its issue lands -- the libevent # and iperf3 precedent. They are also the reason native-byte-identical compares # a SUBSET: without the exclusion below those same six facts would be reported # twice, once as themselves and once as an opaque "the files differ". # # zlog/gettid, zlog/ktid-matches-syscall # syscall(SYS_gettid) returns -1/ENOSYS on this arm, so zlog's %k spec # renders 4294967295 -- the (unsigned int) cast of -1. This is a LIVE # WRONG VALUE in every log line that uses %k, not a missing feature, and # it is why the case asserts %k against the syscall's own answer rather # than merely that %k printed something. zlog/gettid-wrapper asks glibc's # gettid(2) separately, because syscall(2) is a generic dispatcher and # the wrapper is a direct route: they can fail independently, and "gettid # is missing" and "the dispatcher has no entry for it" are different bugs. # # zlog/lockfile-setlk, zlog/rotate # fcntl(F_SETLK) returns EINVAL, so zlog's rotater cannot take its lock # and SIZE-BASED ROTATION SILENTLY DOES NOT HAPPEN: the log grows past # its configured window with no error reaching the application. Measured # here at 3840 bytes against a 1 KB * 3 window with no .1/.2 produced. # Held by brintos/linux#16 (glibc on this 32-bit target always sends the # LFS lock commands and sys_fcntl64 is unwired). # # zlog/pipe-output # A pipe rule (`cat.* | prog`) makes zlog_init() FAIL OUTRIGHT -- the # whole config is rejected, not just that rule -- because rule.c calls # popen(3) at config-parse time and glibc routes popen through # __posix_spawn, which is unwired. Held by brintos/linux#14. Worth # stating as its own case because the blast radius is larger than the # feature: one pipe rule costs the application all of its logging. # # zlog/threads-join # Both pthread_create() calls RETURN 0 and the process then dies before # pthread_join() returns -- the libevent/iperf3 signature. Held by # brintos/hardwarejs#12. # # The two guarded probe runs are invoked under setsid, marked # BRINTOS-WORKAROUND against those issues: a thread trap or a spawn trap can # poison a lane a later unrelated exec then hits, and under brintos-selftest's # supervisor that wedges the guest rather than the process (BRINTOS-347). # Without the session boundary these two expected reds would forfeit the rest # of the batch slice, which is other packages' coverage. # --------------------------------------------------------------------------- require zlog-chk-conf zlog/present D=${TMPDIR:-/tmp}/bst-zlog.$$ rm -rf "$D"; mkdir -p "$D" # has # # A red carries THE LINE THE PROBE ACTUALLY PRINTED, not just the needle that # was missing -- every probe case prints its value on both the OK and the FAIL # path so a failure is self-describing. has() { case "$3" in *"$2"*) bst_ok "$1" ;; *) _n=${2% OK} [ "$_n" = "$2" ] && _n=${2%% *} _got=$(printf '%s\n' "$3" | grep "^$_n " | head -1) bst_notok "$1" "${_got:-no $_n line}" ;; esac } # --- payload shape ------------------------------------------------------------ # The three artifacts the bbappend's do_install names, and the standing # static-only invariant: NO shared object, on an arm whose linker cannot make # one and whose stock recipe would have installed one plus two symlinks. inv="" for f in /usr/lib/libzlog.a /usr/include/zlog.h /usr/bin/zlog-chk-conf; do [ -e "$f" ] || inv="$inv $f" done if [ -n "$inv" ]; then bst_notok zlog/payload "absent:$inv"; else bst_ok zlog/payload; fi so=$(find /usr/lib /lib -name 'libzlog*.so*' 2>/dev/null | head -3) if [ -n "$so" ]; then bst_notok zlog/no-shared-object "found: $so"; else bst_ok zlog/no-shared-object; fi # --- zlog-chk-conf, over its whole contract ----------------------------------- # Exit codes measured from upstream's source and confirmed on an x86_64 build: # -h -> 0, good conf -> 0, bad conf -> 2, no arguments -> 255 (main returns -1). check_out zlog/chk-help "usage: zlog-chk-conf" zlog-chk-conf -h check_out zlog/chk-help-version "zlog version: 1.2.12" zlog-chk-conf -h printf '[rules]\n*.*\t>stdout;\n' > "$D/good.conf" check_out zlog/chk-good "syntax right" zlog-chk-conf "$D/good.conf" check zlog/chk-good-rc zlog-chk-conf -q "$D/good.conf" printf '[rules]\nnot a rule at all\n' > "$D/bad.conf" check_rc zlog/chk-bad-rc 2 zlog-chk-conf "$D/bad.conf" # zlog-chk-conf sets ZLOG_PROFILE_ERROR=/dev/stderr itself, so this also asks # whether /dev/stderr is openable on this image -- without it the linter would # still exit 2 but print no reason, which is the unhelpful half. bad_err=$(zlog-chk-conf "$D/bad.conf" 2>&1 >/dev/null) case "$bad_err" in *"zlog_rule_new fail"*) bst_ok zlog/chk-bad-diagnostic ;; *) bst_notok zlog/chk-bad-diagnostic "stderr was: $(printf '%s' "$bad_err" | head -1 | cut -c1-70)" ;; esac check_rc zlog/chk-noargs-rc 255 zlog-chk-conf # --- the probe ---------------------------------------------------------------- probe=$D/zlog-probe if cp "$BST_DATA/zlog-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then out=$(ZLOG_PROBE_DIR=$D/run "$probe" 2>/dev/null) has zlog/probe-ran "ZLOG-probe-end OK" "$out" has zlog/gethostname "ZLOG-gethostname gethostname(2) succeeded" "$out" has zlog/lockfile-open "ZLOG-lockfile-open the" "$out" has zlog/version "ZLOG-version zlog_version() = 1.2.12" "$out" has zlog/init "ZLOG-init zlog_init()" "$out" has zlog/get-category "ZLOG-get-category zlog_get_category(stable) returned" "$out" # Exact rendered bytes, not "it logged something". has zlog/render-stable 'ZLOG-render-stable wrote exactly "stable INFO hello-42\n"' "$out" has zlog/level-filter 'ZLOG-level-filter wrote exactly "kept\nkept-too\n"' "$out" has zlog/level-enabled-info "ZLOG-level-enabled-info OK" "$out" has zlog/level-enabled-debug "ZLOG-level-enabled-debug OK" "$out" has zlog/spec-level-case 'ZLOG-spec-level-case wrote exactly "warn|WARN|w\n"' "$out" has zlog/spec-func-line "ZLOG-spec-func-line OK" "$out" has zlog/spec-env 'ZLOG-spec-env wrote exactly "envvalue\n"' "$out" has zlog/mdc-put "ZLOG-mdc-put OK" "$out" has zlog/mdc-get "ZLOG-mdc-get OK" "$out" has zlog/mdc-remove "ZLOG-mdc-remove OK" "$out" has zlog/mdc-render 'ZLOG-mdc-render wrote exactly "alice|m1\n|m2\n"' "$out" has zlog/hexdump "ZLOG-hexdump OK" "$out" has zlog/fsync-period 'ZLOG-fsync-period wrote exactly "a\nb\nc\n"' "$out" has zlog/reload-rc "ZLOG-reload-rc OK" "$out" has zlog/reload-render 'ZLOG-reload-render wrote exactly "before\nR2 after\n"' "$out" has zlog/record-set "ZLOG-record-set OK" "$out" has zlog/record-called "ZLOG-record-called OK" "$out" # --- the six platform rows (see the header). Asserted as the value a WORKING # --- platform gives, so each turns green by itself when its issue lands. has zlog/gettid "ZLOG-gettid syscall(SYS_gettid) returned a non-negative tid" "$out" has zlog/gettid-wrapper "ZLOG-gettid-wrapper gettid(2) returned a non-negative tid" "$out" has zlog/ktid-matches-syscall "ZLOG-spec-ktid-matches-syscall %k equals syscall(SYS_gettid)" "$out" has zlog/lockfile-setlk "ZLOG-lockfile-setlk fcntl(F_SETLK, F_WRLCK) acquired" "$out" has zlog/rotate "ZLOG-rotate-happened OK" "$out" has zlog/rotate-window "ZLOG-rotate-window OK" "$out" # --- byte-identity against the x86_64 control, over the SUBSET that a # --- platform defect does not legitimately change. The six excluded cases # --- are each asserted above; comparing them here too would report the same # --- six facts a second time as one opaque diff. ctl=$BST_DATA/zlog-native.txt gotf=$D/got.txt ctlf=$D/ctl.txt ex='^ZLOG-(gettid|gettid-wrapper|lockfile-setlk|lockfile-unlck|spec-ktid-matches-syscall|rotate-happened|rotate-window) ' printf '%s\n' "$out" | grep '^ZLOG-' | grep -Ev "$ex" > "$gotf" grep '^ZLOG-' "$ctl" 2>/dev/null | grep -Ev "$ex" > "$ctlf" if [ ! -s "$ctlf" ]; then bst_notok zlog/native-byte-identical "control absent or empty: $ctl" elif cmp -s "$ctlf" "$gotf"; then bst_ok zlog/native-byte-identical else bst_notok zlog/native-byte-identical \ "first diff: $(diff "$ctlf" "$gotf" 2>/dev/null | sed -n '2,3p' | tr '\n' ' ' | cut -c1-90)" fi # --- guarded families, each in its own session ----------------------------- # BRINTOS-WORKAROUND: brintos/linux#14 remove -- popen(3) is routed through # __posix_spawn, which is unwired, so a pipe rule takes zlog_init() down with # it; setsid keeps that from poisoning the rest of this batch slice. pout=$(ZLOG_PROBE_DIR=$D/pp ZLOG_PROBE_PIPE=1 setsid "$probe" 2>/dev/null) has zlog/pipe-output "ZLOG-pipe-output OK" "$pout" # BRINTOS-WORKAROUND: brintos/hardwarejs#12 remove -- pthread_create returns # 0 and the process dies before pthread_join returns; setsid contains it. tout=$(ZLOG_PROBE_DIR=$D/tt ZLOG_PROBE_THREADS=1 setsid "$probe" 2>/dev/null) has zlog/threads-create "ZLOG-threads-create OK pthread_create[0] = 0" "$tout" has zlog/threads-join "ZLOG-threads-join OK pthread_join[0] = 0" "$tout" has zlog/threads-output "ZLOG-threads-output OK" "$tout" else bst_skip zlog/probe "data/zlog-probe not installed or not executable" fi rm -rf "$D"